aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon')
-rw-r--r--src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/DungeonActionContext.java35
-rwxr-xr-xsrc/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/DungeonContext.java218
-rw-r--r--src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/DungeonFacade.java35
-rwxr-xr-xsrc/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/MapProcessor.java535
-rw-r--r--src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/actions/AbstractAction.java61
-rwxr-xr-xsrc/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/actions/ActionBreakWithSuperBoom.java103
-rwxr-xr-xsrc/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/actions/ActionChangeState.java75
-rwxr-xr-xsrc/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/actions/ActionClick.java82
-rwxr-xr-xsrc/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/actions/ActionClickSet.java90
-rw-r--r--src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/actions/ActionComplete.java41
-rwxr-xr-xsrc/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/actions/ActionDropItem.java82
-rwxr-xr-xsrc/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/actions/ActionInteract.java89
-rwxr-xr-xsrc/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/actions/ActionKill.java90
-rwxr-xr-xsrc/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/actions/ActionMove.java122
-rwxr-xr-xsrc/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/actions/ActionMoveNearestAir.java92
-rwxr-xr-xsrc/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/actions/ActionRoot.java47
-rw-r--r--src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/actions/tree/ActionRoute.java136
-rw-r--r--src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/actions/tree/ActionRouteProperties.java16
-rwxr-xr-xsrc/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/actions/tree/ActionTree.java94
-rw-r--r--src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/actions/tree/ActionTreeUtil.java83
-rwxr-xr-xsrc/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/doorfinder/DungeonDoor.java87
-rwxr-xr-xsrc/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/doorfinder/DungeonSpecificDataProvider.java39
-rwxr-xr-xsrc/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/doorfinder/DungeonSpecificDataProviderRegistry.java42
-rw-r--r--src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/doorfinder/EDungeonDoorType.java38
-rw-r--r--src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/doorfinder/catacombs/CatacombsDataProvider.java75
-rwxr-xr-xsrc/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/doorfinder/catacombs/impl/MasterModeDataProvider.java64
-rwxr-xr-xsrc/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/doorfinder/catacombs/impl/NormalModeDataProvider.java101
-rw-r--r--src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/events/DungeonEvent.java41
-rw-r--r--src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/events/DungeonEventData.java25
-rw-r--r--src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/events/DungeonEventHolder.java32
-rw-r--r--src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/events/SerializableBlockPos.java38
-rw-r--r--src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/events/impl/DungeonCryptBrokenEvent.java35
-rw-r--r--src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/events/impl/DungeonDeathEvent.java36
-rw-r--r--src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/events/impl/DungeonMapUpdateEvent.java34
-rw-r--r--src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/events/impl/DungeonNodataEvent.java29
-rw-r--r--src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/events/impl/DungeonPuzzleFailureEvent.java34
-rw-r--r--src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/events/impl/DungeonRoomDiscoverEvent.java46
-rw-r--r--src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/events/impl/DungeonSecretCountChangeEvent.java37
-rw-r--r--src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/events/impl/DungeonStateChangeEvent.java40
-rw-r--r--src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/map/DungeonMapData.java121
-rw-r--r--src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/pathfinding/AStarCornerCut.java189
-rw-r--r--src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/pathfinding/AStarFineGrid.java182
-rw-r--r--src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/pathfinding/CachedWorld.java85
-rw-r--r--src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/pathfinding/JPSPathfinder.java306
-rw-r--r--src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/pathfinding/NodeProcessorDungeonRoom.java144
-rw-r--r--src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/pathfinding/ThetaStar.java209
-rwxr-xr-xsrc/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/EditingContext.java83
-rwxr-xr-xsrc/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/Parameter.java39
-rwxr-xr-xsrc/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/gui/GuiDungeonAddSet.java136
-rwxr-xr-xsrc/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/gui/GuiDungeonParameterEdit.java173
-rwxr-xr-xsrc/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/gui/GuiDungeonRoomEdit.java68
-rwxr-xr-xsrc/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/gui/GuiDungeonValueEdit.java127
-rwxr-xr-xsrc/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/mechanicedit/ValueEditBreakableWall.java143
-rwxr-xr-xsrc/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/mechanicedit/ValueEditDoor.java157
-rwxr-xr-xsrc/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/mechanicedit/ValueEditDummy.java121
-rwxr-xr-xsrc/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/mechanicedit/ValueEditFairySoul.java118
-rwxr-xr-xsrc/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/mechanicedit/ValueEditJournal.java122
-rwxr-xr-xsrc/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/mechanicedit/ValueEditLever.java133
-rwxr-xr-xsrc/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/mechanicedit/ValueEditNPC.java121
-rwxr-xr-xsrc/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/mechanicedit/ValueEditOnewayDoor.java143
-rwxr-xr-xsrc/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/mechanicedit/ValueEditOnewayLever.java137
-rwxr-xr-xsrc/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/mechanicedit/ValueEditPressurePlate.java136
-rwxr-xr-xsrc/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/mechanicedit/ValueEditSecret.java129
-rwxr-xr-xsrc/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/mechanicedit/ValueEditTomb.java118
-rwxr-xr-xsrc/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/panes/ActionDisplayPane.java82
-rwxr-xr-xsrc/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/panes/ActionTreeDisplayPane.java216
-rwxr-xr-xsrc/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/panes/DynamicEditor.java29
-rwxr-xr-xsrc/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/panes/GeneralEditPane.java286
-rwxr-xr-xsrc/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/panes/ProcessorParameterEditPane.java144
-rwxr-xr-xsrc/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/panes/RoomDataDisplayPane.java126
-rwxr-xr-xsrc/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/panes/RoomMatchDisplayPane.java152
-rwxr-xr-xsrc/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/panes/RoommatchingPane.java84
-rwxr-xr-xsrc/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/panes/SecretEditPane.java156
-rwxr-xr-xsrc/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/valueedit/ValueEdit.java27
-rwxr-xr-xsrc/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/valueedit/ValueEditAColor.java339
-rwxr-xr-xsrc/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/valueedit/ValueEditBoolean.java101
-rwxr-xr-xsrc/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/valueedit/ValueEditColor.java287
-rwxr-xr-xsrc/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/valueedit/ValueEditCreator.java29
-rwxr-xr-xsrc/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/valueedit/ValueEditFloat.java99
-rwxr-xr-xsrc/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/valueedit/ValueEditInteger.java99
-rwxr-xr-xsrc/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/valueedit/ValueEditNull.java38
-rwxr-xr-xsrc/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/valueedit/ValueEditOffsetPoint.java163
-rwxr-xr-xsrc/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/valueedit/ValueEditOffsetPointSet.java250
-rwxr-xr-xsrc/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/valueedit/ValueEditRegistry.java70
-rwxr-xr-xsrc/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/valueedit/ValueEditString.java99
-rwxr-xr-xsrc/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomfinder/DungeonRoom.java381
-rwxr-xr-xsrc/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomfinder/DungeonRoomInfoRegistry.java163
-rwxr-xr-xsrc/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomfinder/RoomMatcher.java145
-rwxr-xr-xsrc/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/GeneralRoomProcessor.java448
-rwxr-xr-xsrc/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/ProcessorFactory.java65
-rwxr-xr-xsrc/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/RoomProcessor.java49
-rwxr-xr-xsrc/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/RoomProcessorBlazeSolver.java201
-rw-r--r--src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/RoomProcessorButtonSolver.java132
-rwxr-xr-xsrc/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/RoomProcessorCreeperSolver.java148
-rwxr-xr-xsrc/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/RoomProcessorGenerator.java25
-rwxr-xr-xsrc/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/RoomProcessorIcePath.java234
-rw-r--r--src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/RoomProcessorRedRoom.java121
-rwxr-xr-xsrc/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/RoomProcessorRiddle.java121
-rwxr-xr-xsrc/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/RoomProcessorTeleportMazeSolver.java145
-rwxr-xr-xsrc/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/RoomProcessorTicTacToeSolver.java214
-rwxr-xr-xsrc/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/RoomProcessorTrivia.java165
-rw-r--r--src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bombdefuse/RoomProcessorBombDefuseSolver.java441
-rw-r--r--src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bombdefuse/chambers/BDChamber.java83
-rw-r--r--src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bombdefuse/chambers/BombDefuseChamberGenerator.java30
-rw-r--r--src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bombdefuse/chambers/ChamberProcessor.java27
-rw-r--r--src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bombdefuse/chambers/DummyDefuseChamberProcessor.java32
-rw-r--r--src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bombdefuse/chambers/GeneralDefuseChamberProcessor.java137
-rw-r--r--src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bombdefuse/chambers/arrow/ArrowLeftProcessor.java138
-rw-r--r--src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bombdefuse/chambers/arrow/ArrowProcessorMatcher.java52
-rw-r--r--src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bombdefuse/chambers/arrow/ArrowRightProcessor.java126
-rw-r--r--src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bombdefuse/chambers/bugged/ImpossibleMatcher.java47
-rw-r--r--src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bombdefuse/chambers/color/ColorLeftProcessor.java230
-rw-r--r--src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bombdefuse/chambers/color/ColorProcessorMatcher.java49
-rw-r--r--src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bombdefuse/chambers/color/ColorRightProcessor.java175
-rw-r--r--src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bombdefuse/chambers/creeper/CreeperLeftProcessor.java95
-rw-r--r--src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bombdefuse/chambers/creeper/CreeperProcessorMatcher.java52
-rw-r--r--src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bombdefuse/chambers/creeper/CreeperRightProcessor.java73
-rw-r--r--src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bombdefuse/chambers/goldenpath/GoldenPathLeftProcessor.java141
-rw-r--r--src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bombdefuse/chambers/goldenpath/GoldenPathProcessorMatcher.java47
-rw-r--r--src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bombdefuse/chambers/goldenpath/GoldenPathRightProcessor.java97
-rw-r--r--src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bombdefuse/chambers/maze/MazeLeftProcessor.java80
-rw-r--r--src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bombdefuse/chambers/maze/MazeProcessorMatcher.java47
-rw-r--r--src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bombdefuse/chambers/maze/MazeRightProcessor.java73
-rw-r--r--src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bombdefuse/chambers/number/NumberLeftProcessor.java125
-rw-r--r--src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bombdefuse/chambers/number/NumberProcessorMatcher.java53
-rw-r--r--src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bombdefuse/chambers/number/NumberRightProcessor.java114
-rw-r--r--src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bossfight/BossfightProcessor.java33
-rw-r--r--src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bossfight/BossfightProcessorBonzo.java85
-rw-r--r--src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bossfight/BossfightProcessorLivid.java90
-rw-r--r--src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bossfight/BossfightProcessorNecron.java77
-rw-r--r--src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bossfight/BossfightProcessorProf.java144
-rw-r--r--src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bossfight/BossfightProcessorSadan.java144
-rw-r--r--src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bossfight/BossfightProcessorScarf.java134
-rw-r--r--src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bossfight/BossfightProcessorThorn.java103
-rw-r--r--src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bossfight/GeneralBossfightProcessor.java155
-rw-r--r--src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bossfight/HealthData.java33
-rwxr-xr-xsrc/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/boxpuzzle/BoxPuzzleSolvingThread.java182
-rwxr-xr-xsrc/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/boxpuzzle/RoomProcessorBoxSolver.java392
-rwxr-xr-xsrc/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/icefill/RoomProcessorIcePath2.java151
-rwxr-xr-xsrc/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/waterpuzzle/LeverState.java33
-rwxr-xr-xsrc/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/waterpuzzle/LeverStateContradict.java25
-rwxr-xr-xsrc/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/waterpuzzle/RoomProcessorWaterPuzzle.java124
-rwxr-xr-xsrc/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/waterpuzzle/Route.java60
-rwxr-xr-xsrc/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/waterpuzzle/SwitchData.java46
-rwxr-xr-xsrc/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/waterpuzzle/WaterBoard.java424
-rwxr-xr-xsrc/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/waterpuzzle/WaterNode.java36
-rwxr-xr-xsrc/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/waterpuzzle/nodes/WaterNodeAir.java59
-rwxr-xr-xsrc/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/waterpuzzle/nodes/WaterNodeEnd.java60
-rwxr-xr-xsrc/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/waterpuzzle/nodes/WaterNodeStart.java66
-rwxr-xr-xsrc/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/waterpuzzle/nodes/WaterNodeToggleable.java71
-rwxr-xr-xsrc/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/waterpuzzle/nodes/WaterNodeWall.java62
151 files changed, 17425 insertions, 0 deletions
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/DungeonActionContext.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/DungeonActionContext.java
new file mode 100644
index 00000000..f9541a3d
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/DungeonActionContext.java
@@ -0,0 +1,35 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon;
+
+import lombok.Getter;
+import net.minecraft.util.Vec3;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class DungeonActionContext {
+ @Getter
+ private static final Map<Integer, Vec3> spawnLocation = new HashMap<>();
+
+ @Getter
+ private static final List<Integer> killeds = new ArrayList<>();
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/DungeonContext.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/DungeonContext.java
new file mode 100755
index 00000000..32a668c0
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/DungeonContext.java
@@ -0,0 +1,218 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon;
+
+import kr.syeyoung.dungeonsguide.mod.chat.ChatTransmitter;
+import kr.syeyoung.dungeonsguide.mod.dungeon.doorfinder.DungeonSpecificDataProvider;
+import kr.syeyoung.dungeonsguide.mod.dungeon.doorfinder.DungeonSpecificDataProviderRegistry;
+import kr.syeyoung.dungeonsguide.mod.dungeon.events.DungeonEvent;
+import kr.syeyoung.dungeonsguide.mod.dungeon.events.DungeonEventData;
+import kr.syeyoung.dungeonsguide.mod.dungeon.events.impl.DungeonCryptBrokenEvent;
+import kr.syeyoung.dungeonsguide.mod.dungeon.events.impl.DungeonNodataEvent;
+import kr.syeyoung.dungeonsguide.mod.dungeon.events.impl.DungeonPuzzleFailureEvent;
+import kr.syeyoung.dungeonsguide.mod.dungeon.events.impl.DungeonSecretCountChangeEvent;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomfinder.DungeonRoom;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.RoomProcessor;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.bossfight.BossfightProcessor;
+import kr.syeyoung.dungeonsguide.mod.events.impl.BossroomEnterEvent;
+import kr.syeyoung.dungeonsguide.mod.features.FeatureRegistry;
+import kr.syeyoung.dungeonsguide.mod.utils.TabListUtil;
+import kr.syeyoung.dungeonsguide.mod.utils.TextUtils;
+import lombok.Getter;
+import lombok.Setter;
+import net.minecraft.client.Minecraft;
+import net.minecraft.util.BlockPos;
+import net.minecraft.util.ChatComponentText;
+import net.minecraft.util.IChatComponent;
+import net.minecraft.world.World;
+import net.minecraftforge.client.event.ClientChatReceivedEvent;
+import net.minecraftforge.common.MinecraftForge;
+
+import java.awt.*;
+import java.util.List;
+import java.util.*;
+
+public class DungeonContext {
+ /**
+ * This is static because its used in the constructor,
+ * it means we cannot set the name without having an object,
+ * and we cannot create an object without the name
+ * so its static :)
+ */
+ @Getter @Setter
+ private static String dungeonName;
+ @Getter
+ @Setter
+ public int percentage;
+ @Getter
+ private final World world;
+ @Getter
+ private final MapProcessor mapProcessor;
+
+ @Getter
+ @Setter
+ private BlockPos dungeonMin;
+
+ @Getter
+ private final Map<Point, DungeonRoom> roomMapper = new HashMap<>();
+ @Getter
+ private final List<DungeonRoom> dungeonRoomList = new ArrayList<>();
+
+ @Getter
+ private final List<RoomProcessor> globalRoomProcessors = new ArrayList<>();
+
+ @Getter
+ private final Map<String, Integer> deaths = new HashMap<>();
+ @Getter
+ private final List<String[]> milestoneReached = new ArrayList<>();
+ @Getter
+ @Setter
+ private long BossRoomEnterSeconds = -1;
+ @Getter
+ @Setter
+ private long init = -1;
+ @Getter
+ @Setter
+ private BlockPos bossroomSpawnPos = null;
+
+ @Getter
+ @Setter
+ private boolean trapRoomGen = false;
+
+ @Getter
+ private boolean gotMimic = false;
+
+ private int latestSecretCnt = 0;
+ private int latestTotalSecret = 0;
+ private int latestCrypts = 0;
+
+ @Getter
+ private int maxSpeed = 600;
+ @Getter
+ private double secretPercentage = 1.0;
+
+ public void setGotMimic(boolean gotMimic) {
+ this.gotMimic = gotMimic;
+ createEvent(new DungeonNodataEvent("MIMIC_KILLED"));
+ }
+
+ @Getter
+ @Setter
+ private BossfightProcessor bossfightProcessor;
+
+ @Getter
+ private final Set<String> players = new HashSet<>();
+
+ @Getter
+ private final List<DungeonEvent> events = new ArrayList<>();
+
+ public DungeonContext(World world) {
+ this.world = world;
+ createEvent(new DungeonNodataEvent("DUNGEON_CONTEXT_CREATION"));
+ mapProcessor = new MapProcessor(this);
+ DungeonSpecificDataProvider doorFinder = DungeonSpecificDataProviderRegistry.getDoorFinder(getDungeonName());
+ if (doorFinder != null) {
+ trapRoomGen = doorFinder.isTrapSpawn(getDungeonName());
+
+ secretPercentage = doorFinder.secretPercentage(getDungeonName());
+ maxSpeed = doorFinder.speedSecond(getDungeonName());
+ } else {
+ mapProcessor.setBugged(true);
+ }
+ init = System.currentTimeMillis();
+ }
+
+ public void createEvent(DungeonEventData eventData) {
+// events.add(new DungeonEvent(eventData));
+ }
+
+
+ private final Rectangle roomBoundary = new Rectangle(-10, -10, 138, 138);
+
+ public void tick() {
+
+
+ if (mapProcessor.isInitialized() && BossRoomEnterSeconds == -1 && !roomBoundary.contains(mapProcessor.worldPointToMapPoint(Minecraft.getMinecraft().thePlayer.getPositionVector()))) {
+ BossRoomEnterSeconds = FeatureRegistry.DUNGEON_SBTIME.getTimeElapsed() / 1000;
+ bossroomSpawnPos = Minecraft.getMinecraft().thePlayer.getPosition();
+ MinecraftForge.EVENT_BUS.post(new BossroomEnterEvent());
+ createEvent(new DungeonNodataEvent("BOSSROOM_ENTER"));
+ DungeonSpecificDataProvider doorFinder = DungeonSpecificDataProviderRegistry.getDoorFinder(getDungeonName());
+ if (doorFinder != null) {
+ bossfightProcessor = doorFinder.createBossfightProcessor(world, getDungeonName());
+ } else {
+ ChatTransmitter.sendDebugChat(new ChatComponentText("Error:: Null Data Providier"));
+ }
+ }
+
+ players.clear();
+ players.addAll(TabListUtil.getPlayersInDungeon());
+
+
+ if (latestSecretCnt != FeatureRegistry.DUNGEON_SECRETS.getSecretsFound()) {
+ int newSecretCnt = FeatureRegistry.DUNGEON_SECRETS.getSecretsFound();
+ createEvent(new DungeonSecretCountChangeEvent(latestSecretCnt, newSecretCnt, latestTotalSecret, FeatureRegistry.DUNGEON_SECRETS.sureOfTotalSecrets()));
+ latestSecretCnt = newSecretCnt;
+ }
+ if (latestTotalSecret != FeatureRegistry.DUNGEON_SECRETS.getTotalSecretsInt()) {
+ latestTotalSecret = FeatureRegistry.DUNGEON_SECRETS.getTotalSecretsInt();
+ createEvent(new DungeonSecretCountChangeEvent(latestSecretCnt, latestSecretCnt, latestTotalSecret, FeatureRegistry.DUNGEON_SECRETS.sureOfTotalSecrets()));
+ }
+ if (latestCrypts != FeatureRegistry.DUNGEON_TOMBS.getTombsFound()) {
+ int newlatestCrypts = FeatureRegistry.DUNGEON_TOMBS.getTombsFound();
+ createEvent(new DungeonCryptBrokenEvent(latestCrypts, newlatestCrypts));
+ this.latestCrypts = newlatestCrypts;
+ }
+ }
+
+ @Getter
+ private boolean ended = false;
+ @Getter
+ private boolean defeated = false;
+
+ public void onChat(ClientChatReceivedEvent event) {
+ IChatComponent component = event.message;
+ String formatted = component.getFormattedText();
+ if (formatted.contains("$DG-Comm")) {
+ event.setCanceled(true);
+ String data = component.getFormattedText().substring(component.getFormattedText().indexOf("$DG-Comm"));
+ String actual = TextUtils.stripColor(data);
+ String coords = actual.split(" ")[1];
+ String secrets = actual.split(" ")[2];
+ int x = Integer.parseInt(coords.split("/")[0]);
+ int z = Integer.parseInt(coords.split("/")[1]);
+ int secrets2 = Integer.parseInt(secrets);
+ Point roomPt = mapProcessor.worldPointToRoomPoint(new BlockPos(x, 70, z));
+ ChatTransmitter.sendDebugChat(new ChatComponentText("Message from Other dungeons guide :: " + roomPt.x + " / " + roomPt.y + " total secrets " + secrets2));
+ DungeonRoom dr = roomMapper.get(roomPt);
+ if (dr != null) {
+ dr.setTotalSecrets(secrets2);
+ }
+ } else if (formatted.contains("$DG-Mimic")) {
+ setGotMimic(true);
+ } else if (formatted.startsWith("§r§c§lPUZZLE FAIL! ") && formatted.endsWith(" §r§4Y§r§ci§r§6k§r§ee§r§as§r§2!§r")) {
+ createEvent(new DungeonPuzzleFailureEvent(TextUtils.stripColor(formatted.split(" ")[2]), formatted));
+ } else if (formatted.contains("§6> §e§lEXTRA STATS §6<")) {
+ createEvent(new DungeonNodataEvent("DUNGEON_END"));
+ ended = true;
+ } else if (formatted.contains("§r§c☠ §r§eDefeated ")) {
+ defeated = true;
+ }
+ }
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/DungeonFacade.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/DungeonFacade.java
new file mode 100644
index 00000000..96a951fd
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/DungeonFacade.java
@@ -0,0 +1,35 @@
+package kr.syeyoung.dungeonsguide.mod.dungeon;
+
+import kr.syeyoung.dungeonsguide.Main;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomfinder.DungeonRoomInfoRegistry;
+import kr.syeyoung.dungeonsguide.mod.events.listener.DungeonListener;
+import lombok.Getter;
+import lombok.Setter;
+import net.minecraftforge.common.MinecraftForge;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.NoSuchPaddingException;
+import java.io.IOException;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+
+public class DungeonFacade {
+
+ @Getter
+ @Setter
+ private DungeonContext context;
+
+ public void init() {
+ DungeonListener dgEventListener = new DungeonListener();
+ MinecraftForge.EVENT_BUS.register(dgEventListener);
+
+ try {
+ DungeonRoomInfoRegistry.loadAll(Main.getConfigDir());
+ } catch (BadPaddingException | InvalidKeyException | NoSuchPaddingException | IllegalBlockSizeException |
+ IOException | NoSuchAlgorithmException | InvalidAlgorithmParameterException e) {
+ e.printStackTrace();
+ }
+ }
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/MapProcessor.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/MapProcessor.java
new file mode 100755
index 00000000..9c2462ea
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/MapProcessor.java
@@ -0,0 +1,535 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon;
+
+import com.google.common.collect.BiMap;
+import com.google.common.collect.HashBiMap;
+import com.google.common.collect.Sets;
+import com.google.common.util.concurrent.ThreadFactoryBuilder;
+import kr.syeyoung.dungeonsguide.mod.DungeonsGuide;
+import kr.syeyoung.dungeonsguide.mod.chat.ChatTransmitter;
+import kr.syeyoung.dungeonsguide.mod.dungeon.doorfinder.EDungeonDoorType;
+import kr.syeyoung.dungeonsguide.mod.dungeon.events.SerializableBlockPos;
+import kr.syeyoung.dungeonsguide.mod.dungeon.events.impl.DungeonMapUpdateEvent;
+import kr.syeyoung.dungeonsguide.mod.dungeon.events.impl.DungeonRoomDiscoverEvent;
+import kr.syeyoung.dungeonsguide.mod.dungeon.map.DungeonMapData;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomfinder.DungeonRoom;
+import kr.syeyoung.dungeonsguide.mod.features.FeatureRegistry;
+import kr.syeyoung.dungeonsguide.mod.utils.MapUtils;
+import lombok.Getter;
+import lombok.Setter;
+import net.minecraft.client.Minecraft;
+import net.minecraft.entity.player.EntityPlayer;
+import net.minecraft.item.ItemMap;
+import net.minecraft.item.ItemStack;
+import net.minecraft.util.*;
+import net.minecraft.world.storage.MapData;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
+import javax.vecmath.Vector2d;
+import java.awt.*;
+import java.util.List;
+import java.util.Queue;
+import java.util.*;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+public class MapProcessor {
+
+ private static final Set<Vector2d> directions = Sets.newHashSet(new Vector2d(0, 1), new Vector2d(0, -1), new Vector2d(1, 0), new Vector2d(-1, 0));
+ private static final Set<Vector2d> door_dirs = Sets.newHashSet(new Vector2d(0, 0.5), new Vector2d(0, -0.5), new Vector2d(0.5, 0), new Vector2d(-0.5, 0));
+ private static final Minecraft mc = Minecraft.getMinecraft();
+ private final DungeonContext context;
+ @Getter
+ private final BiMap<String, String> mapIconToPlayerMap = HashBiMap.create();
+ private final List<Point> roomsFound = new ArrayList<>();
+ Logger logger = LogManager.getLogger("MapProcessor");
+ /**
+ * If the player on the map is closer than value this it won't save it
+ * this should be done with render-distance but whateva
+ */
+ int clossnessDistance = 50;
+ @Getter
+ @Setter
+ private Dimension unitRoomDimension;
+ @Getter @Setter
+ private Dimension doorDimensions; // width: width of door, height: gap between rooms
+ @Getter
+ @Setter
+ private Point topLeftMapPoint;
+ @Setter
+ private boolean bugged = false;
+ @Getter
+ private boolean initialized = false;
+ @Getter
+ private int undiscoveredRoom = 0;
+ private boolean processed = false;
+ @Getter
+ private MapData latestMapData;
+ private int waitDelay = 0;
+ private boolean processlock;
+
+ public MapProcessor(DungeonContext context) {
+ this.context = context;
+ }
+
+ private static void error(String prefix) {
+ ChatTransmitter.addToQueue(new ChatComponentText(ChatTransmitter.prefix + prefix));
+ }
+
+
+ ExecutorService es = Executors.newSingleThreadExecutor(new ThreadFactoryBuilder().setNameFormat("Dg-MapProcessor-%d").build());
+
+
+ int processMapThroddle;
+
+ public void tick() {
+ if (waitDelay < 5) {
+ waitDelay++;
+ return;
+ }
+ if (bugged) {
+ return;
+ }
+ ItemStack stack = Minecraft.getMinecraft().thePlayer.inventory.getStackInSlot(8);
+
+ if (stack == null || !(stack.getItem() instanceof ItemMap)) {
+ return;
+ }
+
+ MapData mapData = ((ItemMap) stack.getItem()).getMapData(stack, mc.theWorld);
+
+ if (mapData != null) {
+
+ if(processMapThroddle > 5 && !processlock){
+ processMapData(mapData.colors);
+ processMapThroddle = 0;
+ }
+ processMapThroddle++;
+
+ }
+
+ latestMapData = mapData;
+
+ if (latestMapData != null && mapIconToPlayerMap.size() < context.getPlayers().size() && initialized) {
+ getPlayersFromMap(latestMapData);
+ }
+
+ }
+
+ private void processMapData(byte[] mapColorData) {
+
+ // i just cant get this to work sad
+ if (isThereDifference(latestMapData.colors, mapColorData)) {
+ context.createEvent(new DungeonMapUpdateEvent(mapColorData));
+
+ es.execute(() -> {
+ processlock = true;
+ if (doorDimensions == null || !initialized) {
+ assembleMap(mapColorData);
+ } else {
+ processMap(mapColorData);
+ }
+
+ if (context.isEnded()) {
+ processFinishedMap(mapColorData);
+ }
+ processlock = false;
+ });
+
+ }
+
+ }
+
+ void assembleMap(final byte[] mapData){
+ DungeonMapData data = new DungeonMapData(context, Minecraft.getMinecraft());
+
+ data.eat(mapData);
+
+ bugged = data.bugged;
+
+ unitRoomDimension = data.unitRoomDimension;
+
+ topLeftMapPoint = data.topLeftMapPoint;
+
+ initialized = data.initialized;
+
+ doorDimensions = data.doorDimensions;
+
+ }
+
+
+ public static Point mapPointToRoomPoint(Point mapPoint, Point topLeftMapPoint, Dimension unitRoomDimension, Dimension doorDimensions) {
+ int x = (int) ((mapPoint.x - topLeftMapPoint.x) / ((double) unitRoomDimension.width + doorDimensions.height));
+ int y = (int) ((mapPoint.y - topLeftMapPoint.y) / ((double) unitRoomDimension.height + doorDimensions.height));
+ return new Point(x, y);
+ }
+
+ public BlockPos mapPointToWorldPoint(Point mapPoint) {
+ int x = (int) ((mapPoint.x - topLeftMapPoint.x) / ((double) unitRoomDimension.width + doorDimensions.height) * 32 + context.getDungeonMin().getX());
+ int y = (int) ((mapPoint.y - topLeftMapPoint.y) / ((double) unitRoomDimension.height + doorDimensions.height) * 32 + context.getDungeonMin().getZ());
+ return new BlockPos(x, 70, y);
+ }
+
+ public Point roomPointToMapPoint(Point roomPoint) {
+ return new Point(roomPoint.x * (unitRoomDimension.width + doorDimensions.height) + topLeftMapPoint.x, roomPoint.y * (unitRoomDimension.height + doorDimensions.height) + topLeftMapPoint.y);
+ }
+
+ public BlockPos roomPointToWorldPoint(Point roomPoint) {
+ return new BlockPos(context.getDungeonMin().getX() + (roomPoint.x * 32), context.getDungeonMin().getY(), context.getDungeonMin().getZ() + (roomPoint.y * 32));
+ }
+
+ public Point worldPointToRoomPoint(BlockPos worldPoint) {
+ if (context.getDungeonMin() == null) return null;
+ return new Point((worldPoint.getX() - context.getDungeonMin().getX()) / 32, (worldPoint.getZ() - context.getDungeonMin().getZ()) / 32);
+ }
+
+ public Point worldPointToMapPoint(Vec3 worldPoint) {
+ if (context.getDungeonMin() == null) return null;
+ return new Point(topLeftMapPoint.x + (int) ((worldPoint.xCoord - context.getDungeonMin().getX()) / 32.0f * (unitRoomDimension.width + doorDimensions.height)), topLeftMapPoint.y + (int) ((worldPoint.zCoord - context.getDungeonMin().getZ()) / 32.0f * (unitRoomDimension.height + doorDimensions.height)));
+ }
+
+ public Vector2d worldPointToMapPointFLOAT(Vec3 worldPoint) {
+ if (context.getDungeonMin() == null) return null;
+ double x = topLeftMapPoint.x + ((worldPoint.xCoord - context.getDungeonMin().getX()) / 32.0f * (unitRoomDimension.width + doorDimensions.height));
+ double y = topLeftMapPoint.y + ((worldPoint.zCoord - context.getDungeonMin().getZ()) / 32.0f * (unitRoomDimension.height + doorDimensions.height));
+ return new Vector2d(x, y);
+ }
+
+ private void processMap(byte[] mapData) {
+ int roomHeight = (int) ((128.0 - topLeftMapPoint.y) / (unitRoomDimension.height + doorDimensions.height));
+ int roomWidth = (int) ((128.0 - topLeftMapPoint.x) / (unitRoomDimension.width + doorDimensions.height));
+ if (MapUtils.getMapColorAt(mapData, 0, 0) != 0) return;
+ undiscoveredRoom = 0;
+ for (int y = 0; y <= roomHeight; y++) {
+ for (int x = 0; x <= roomWidth; x++) {
+ Point mapPoint = roomPointToMapPoint(new Point(x, y));
+ byte color = MapUtils.getMapColorAt(mapData, mapPoint.x, mapPoint.y);
+ MapUtils.record(mapData, mapPoint.x, mapPoint.y, new Color(255, 255, 0, 80));
+ if (roomsFound.contains(new Point(x, y))) {
+ DungeonRoom dungeonRoom = context.getRoomMapper().get(new Point(x, y));
+ if (color == 18 && dungeonRoom.getCurrentState() != DungeonRoom.RoomState.FINISHED) {
+ dungeonRoom.setCurrentState(DungeonRoom.RoomState.COMPLETE_WITHOUT_SECRETS);
+ dungeonRoom.setTotalSecrets(0);
+ } else if (color == 30) {
+ dungeonRoom.setCurrentState(DungeonRoom.RoomState.FINISHED);
+ dungeonRoom.setTotalSecrets(0);
+ } else if (dungeonRoom.getCurrentState() != DungeonRoom.RoomState.FINISHED) {
+ byte centerColor = MapUtils.getMapColorAt(mapData, mapPoint.x + unitRoomDimension.width / 2, mapPoint.y + unitRoomDimension.height / 2);
+ MapUtils.record(mapData, mapPoint.x + unitRoomDimension.width / 2, mapPoint.y + unitRoomDimension.height / 2, new Color(0, 255, 0, 80));
+ if (centerColor == 34) {
+ dungeonRoom.setCurrentState(DungeonRoom.RoomState.COMPLETE_WITHOUT_SECRETS);
+ } else if (centerColor == 30) {
+ dungeonRoom.setCurrentState(DungeonRoom.RoomState.FINISHED);
+ } else if (centerColor == 18) { // red
+ dungeonRoom.setCurrentState(DungeonRoom.RoomState.FAILED);
+ }
+ }
+ if (dungeonRoom.getTotalSecrets() == -1) {
+ if (dungeonRoom.getColor() == 82 || dungeonRoom.getColor() == 74) {
+ dungeonRoom.setTotalSecrets(0);
+ }
+ MapUtils.record(mapData, mapPoint.x, mapPoint.y + 1, new Color(0, 255, 0, 80));
+ }
+ continue;
+ }
+
+ if (color != 0 && color != 85) {
+ MapUtils.record(mapData, mapPoint.x, mapPoint.y, new Color(0, 255, 255, 80));
+ DungeonRoom room = buildRoom(mapData, new Point(x, y));
+
+
+ // USELESS DEBUG CODE
+ context.createEvent(new DungeonRoomDiscoverEvent(room.getUnitPoints().get(0), room.getRoomMatcher().getRotation(), new SerializableBlockPos(room.getMin()), new SerializableBlockPos(room.getMax()), room.getShape(), room.getColor(), room.getDungeonRoomInfo().getUuid(), room.getDungeonRoomInfo().getName(), room.getDungeonRoomInfo().getProcessorId()));
+ ChatTransmitter.sendDebugChat(new ChatComponentText("New Map discovered! shape: " + room.getShape() + " color: " + room.getColor() + " unitPos: " + x + "," + y));
+ ChatTransmitter.sendDebugChat(new ChatComponentText("New Map discovered! mapMin: " + room.getMin() + " mapMx: " + room.getMax()));
+ StringBuilder builder = new StringBuilder();
+ for (int dy = 0; dy < 4; dy++) {
+ builder.append("\n");
+ for (int dx = 0; dx < 4; dx++) {
+ boolean isSet = ((room.getShape() >> (dy * 4 + dx)) & 0x1) != 0;
+ builder.append(isSet ? "O" : "X");
+ }
+ }
+ ChatTransmitter.sendDebugChat(new ChatComponentText("Shape visual: " + builder));
+ // END
+
+
+ context.getDungeonRoomList().add(room);
+ for (Point p : room.getUnitPoints()) {
+ roomsFound.add(p);
+ context.getRoomMapper().put(p, room);
+ }
+ if (room.getRoomProcessor() != null && room.getRoomProcessor().readGlobalChat()) {
+ context.getGlobalRoomProcessors().add(room.getRoomProcessor());
+ }
+ } else if (color == 85) {
+ undiscoveredRoom++;
+ }
+
+ }
+ }
+ }
+
+ private DungeonRoom buildRoom(byte[] mapData, Point unitPoint) {
+ Queue<Point[]> toCheck = new LinkedList<>();
+ toCheck.add(new Point[]{unitPoint, unitPoint}); // requestor, target
+ Set<Point> checked = new HashSet<>();
+ List<Point> ayConnected = new ArrayList<>();
+
+ int minX = Integer.MAX_VALUE;
+ int minY = Integer.MAX_VALUE;
+ int maxX = 0;
+ int maxY = 0;
+ while (toCheck.peek() != null) {
+ Point[] check = toCheck.poll();
+ if (checked.contains(check[1])) {
+ continue;
+ }
+ checked.add(check[1]);
+
+ if (checkIfConnected(mapData, check[0], check[1])) {
+ ayConnected.add(check[1]);
+ if (check[1].x < minX) minX = check[1].x;
+ if (check[1].y < minY) minY = check[1].y;
+ if (check[1].x > maxX) maxX = check[1].x;
+ if (check[1].y > maxY) maxY = check[1].y;
+ for (Vector2d dir : directions) {
+ Point newPt = new Point(check[1].x + (int) dir.x, check[1].y + (int) dir.y);
+ toCheck.add(new Point[]{check[1], newPt});
+ }
+ }
+ }
+
+ short shape = 0;
+ for (Point p : ayConnected) {
+ int localX = p.x - minX;
+ int localY = p.y - minY;
+ shape |= 1 << (localY * 4 + localX);
+ }
+ Set<Vector2d> doors = new HashSet<>();
+ for (Point p : ayConnected) {
+ for (Vector2d v : door_dirs) {
+ Vector2d v2 = new Vector2d(p.x + v.x, p.y + v.y);
+ if (doors.contains(v2)) doors.remove(v2);
+ else doors.add(v2);
+ }
+ }
+ Point pt2 = roomPointToMapPoint(ayConnected.get(0));
+ byte unit1 = MapUtils.getMapColorAt(mapData, pt2.x, pt2.y);
+
+ // 0: none 1: open door 2. unopen door 3: wither door 4. red door
+ Set<Tuple<Vector2d, EDungeonDoorType>> doorsAndStates = new HashSet<>();
+ final int halfWidth = unitRoomDimension.width + 4;
+ for (Vector2d door : doors) {
+ int floorX = (int) Math.floor(door.x);
+ int floorY = (int) Math.floor(door.y);
+ Point mapPt = roomPointToMapPoint(new Point(floorX, floorY));
+ Point target = new Point(mapPt.x + unitRoomDimension.width / 2 + (int) (halfWidth * (door.x - floorX)), mapPt.y + unitRoomDimension.height / 2 + (int) (halfWidth * (door.y - floorY)));
+ MapUtils.record(mapData, target.x, target.y, Color.green);
+
+ byte color = MapUtils.getMapColorAt(mapData, target.x, target.y);
+
+ Vector2d vector2d = new Vector2d(door.x - minX, door.y - minY);
+
+ if (color == 0) {
+ doorsAndStates.add(new Tuple<>(vector2d, EDungeonDoorType.NONE));
+ } else if (color == 85) {
+ doorsAndStates.add(new Tuple<>(vector2d, EDungeonDoorType.UNOPEN));
+ } else if (color == 119) {
+ doorsAndStates.add(new Tuple<>(vector2d, EDungeonDoorType.WITHER));
+ } else if (color == 18 && unit1 != 18) {
+ doorsAndStates.add(new Tuple<>(vector2d, EDungeonDoorType.BLOOD));
+ } else {
+ doorsAndStates.add(new Tuple<>(vector2d, EDungeonDoorType.ENTRANCE));
+ }
+
+ }
+
+
+ return new DungeonRoom(ayConnected, shape, unit1, roomPointToWorldPoint(new Point(minX, minY)), roomPointToWorldPoint(new Point(maxX + 1, maxY + 1)).add(-1, 0, -1), context, doorsAndStates);
+
+ }
+
+ private boolean checkIfConnected(byte[] mapData, Point unitPoint1, Point unitPoint2) {
+ if (unitPoint1 == unitPoint2) return true;
+ if (unitPoint1.equals(unitPoint2)) return true;
+
+
+ Point high;
+ if (unitPoint2.y > unitPoint1.y) {
+ high = unitPoint2;
+ } else {
+ if (unitPoint2.x > unitPoint1.x) {
+ high = unitPoint2;
+ } else {
+ high = unitPoint1;
+ }
+ }
+
+ Point low;
+ if (high == unitPoint2) {
+ low = unitPoint1;
+ } else {
+ low = unitPoint2;
+ }
+
+ int xOff = low.x - high.x;
+ int yOff = low.y - high.y;
+ Point pt = roomPointToMapPoint(high);
+ Point pt2 = roomPointToMapPoint(low);
+ byte unit1 = MapUtils.getMapColorAt(mapData, pt.x, pt.y);
+ byte unit2 = MapUtils.getMapColorAt(mapData, pt2.x, pt2.y);
+ pt.translate(xOff, yOff);
+ byte unit3 = MapUtils.getMapColorAt(mapData, pt.x, pt.y);
+
+ return unit1 == unit2 && unit2 == unit3 && unit1 != 0;
+ }
+
+ public boolean isThereDifference(byte[] colorData, byte[] colorData1) {
+
+ return true;
+// boolean equals = Arrays.equals(colorData1, colorData);
+//
+// boolean foundDIffrentThen0 = false;
+//
+//
+// for (byte colorDatum : colorData) {
+// if(colorDatum != 0){
+// foundDIffrentThen0 = true;
+// break;
+// }
+// }
+//
+//
+// return !(equals && foundDIffrentThen0);
+ }
+
+ private void processFinishedMap(byte[] mapData) {
+ if (MapUtils.getMapColorAt(mapData, 0, 0) == 0) {
+ return;
+ }
+ if (processed) {
+ return;
+ }
+ processed = true;
+
+ MapUtils.clearMap();
+ MapUtils.record(mapData, 0, 0, Color.GREEN);
+
+
+ FeatureRegistry.ETC_COLLECT_SCORE.collectDungeonRunData(mapData, context);
+
+ }
+
+ private void getPlayersFromMap(MapData mapdata) {
+
+ if (DungeonsGuide.getDungeonsGuide().verbose) logger.info("Getting players from map");
+
+ for (Map.Entry<String, Vec4b> stringVec4bEntry : mapdata.mapDecorations.entrySet()) {
+ String mapDecString = stringVec4bEntry.getKey();
+ Vec4b vec4 = stringVec4bEntry.getValue();
+
+ if (!mapIconToPlayerMap.containsValue(mapDecString)) {
+ if (DungeonsGuide.getDungeonsGuide().verbose) logger.info("mapIconToPlayerMap dosent have Player");
+
+ int x = vec4.func_176112_b() / 2 + 64;
+ int y = vec4.func_176113_c() / 2 + 64;
+ BlockPos mapPos = mapPointToWorldPoint(new Point(x, y));
+ String potentialPlayer = null;
+
+ for (String player : context.getPlayers()) {
+ if (DungeonsGuide.getDungeonsGuide().verbose)
+ logger.info("Player: {} isNear: {} ", player, isPlayerNear(player, mapPos));
+// if (!mapIconToPlayerMap.containsKey(player) && isPlayerNear(player, mapPos)) {
+ if (!mapIconToPlayerMap.containsKey(player)) {
+ if (DungeonsGuide.getDungeonsGuide().verbose) logger.info("Potential profile is: " + player);
+ potentialPlayer = player;
+ break;
+ }
+ }
+
+
+ if (potentialPlayer != null) {
+ if (DungeonsGuide.getDungeonsGuide().verbose) logger.info("potentialPlayer is not null");
+ boolean shouldSave = true;
+
+ for (Map.Entry<String, Vec4b> vec4bEntry : mapdata.mapDecorations.entrySet()) {
+// String aaa = vec4bEntry.getKey();
+ Vec4b bbb = vec4bEntry.getValue();
+
+// if (mapIconToPlayerMap.containsValue(aaa) || mapDecString.equals(aaa)) {
+// shouldSave = false;
+// break;
+// }
+// else {
+ int x2 = bbb.func_176112_b() / 2 + 64;
+ int y2 = bbb.func_176113_c() / 2 + 64;
+ int dx = x2 - x;
+ int dy = y2 - y;
+ if (dx * dx + dy * dy < clossnessDistance) {
+ shouldSave = false;
+ break;
+ }
+// }
+ }
+
+ if (shouldSave) {
+ if (DungeonsGuide.getDungeonsGuide().verbose)
+ logger.info("added {} to mapIconPlayerMap with {}", potentialPlayer, stringVec4bEntry.getKey());
+ if (mapIconToPlayerMap.containsKey(potentialPlayer)) {
+ mapIconToPlayerMap.replace(potentialPlayer, stringVec4bEntry.getKey());
+ } else {
+ mapIconToPlayerMap.put(potentialPlayer, stringVec4bEntry.getKey());
+ }
+ if (DungeonsGuide.getDungeonsGuide().verbose) logger.info("mapIconToPlayerMap:");
+ if (DungeonsGuide.getDungeonsGuide().verbose)
+ mapIconToPlayerMap.forEach((key, value) -> logger.info(" {}: {}", key, value));
+ } else {
+ if (DungeonsGuide.getDungeonsGuide().verbose) logger.info("shouldSave is false");
+ }
+
+
+ } else {
+ if (DungeonsGuide.getDungeonsGuide().verbose) logger.info("potentialPlayer is null");
+ }
+
+ } else {
+ if (DungeonsGuide.getDungeonsGuide().verbose) logger.info("mapIconToPlayerMap has player ");
+ }
+ }
+
+
+ }
+
+ private boolean isPlayerNear(String player, BlockPos mapPos) {
+ EntityPlayer entityPlayer = Minecraft.getMinecraft().theWorld.getPlayerEntityByName(player);
+
+ if (entityPlayer != null && !entityPlayer.isInvisible()) {
+ BlockPos pos = entityPlayer.getPosition();
+ int dx = mapPos.getX() - pos.getX();
+ int dz = mapPos.getZ() - pos.getZ();
+ return dx * dx + dz * dz < clossnessDistance;
+
+ }
+
+ return false;
+ }
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/actions/AbstractAction.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/actions/AbstractAction.java
new file mode 100644
index 00000000..d465fd47
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/actions/AbstractAction.java
@@ -0,0 +1,61 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.actions;
+
+import kr.syeyoung.dungeonsguide.mod.dungeon.actions.tree.ActionRouteProperties;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomfinder.DungeonRoom;
+import kr.syeyoung.dungeonsguide.mod.events.impl.PlayerInteractEntityEvent;
+import net.minecraftforge.event.entity.living.LivingDeathEvent;
+import net.minecraftforge.event.entity.player.PlayerInteractEvent;
+
+import java.util.Set;
+
+public abstract class AbstractAction {
+ public void onPlayerInteract(DungeonRoom dungeonRoom, PlayerInteractEvent event, ActionRouteProperties actionRouteProperties){
+
+ }
+
+ public void onRenderWorld(DungeonRoom dungeonRoom, float partialTicks, ActionRouteProperties actionRouteProperties, boolean flag) {
+
+ }
+
+ public void onLivingDeath(DungeonRoom dungeonRoom, LivingDeathEvent event, ActionRouteProperties actionRouteProperties) {
+
+ }
+
+ public void onRenderScreen(DungeonRoom dungeonRoom, float partialTicks, ActionRouteProperties actionRouteProperties) {
+
+ }
+
+ public void onLivingInteract(DungeonRoom dungeonRoom, PlayerInteractEntityEvent event, ActionRouteProperties actionRouteProperties) {
+
+ }
+
+ public void onTick(DungeonRoom dungeonRoom, ActionRouteProperties actionRouteProperties) {
+
+ }
+
+ public Set<AbstractAction> getPreRequisites(DungeonRoom dungeonRoom) {
+ return null;
+ }
+
+ public boolean isComplete(DungeonRoom dungeonRoom) {
+ return false;
+ }
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/actions/ActionBreakWithSuperBoom.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/actions/ActionBreakWithSuperBoom.java
new file mode 100755
index 00000000..baab261f
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/actions/ActionBreakWithSuperBoom.java
@@ -0,0 +1,103 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.actions;
+
+import kr.syeyoung.dungeonsguide.mod.dungeon.actions.tree.ActionRouteProperties;
+import kr.syeyoung.dungeonsguide.dungeon.data.OffsetPoint;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomfinder.DungeonRoom;
+import kr.syeyoung.dungeonsguide.mod.utils.RenderUtils;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.renderer.BlockRendererDispatcher;
+import net.minecraft.client.renderer.GlStateManager;
+import net.minecraft.client.renderer.Tessellator;
+import net.minecraft.client.renderer.WorldRenderer;
+import net.minecraft.client.renderer.texture.TextureMap;
+import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
+import net.minecraft.entity.Entity;
+import net.minecraft.init.Blocks;
+import net.minecraft.util.BlockPos;
+
+import java.awt.*;
+import java.util.HashSet;
+import java.util.Set;
+
+@Data
+@EqualsAndHashCode(callSuper=false)
+public class ActionBreakWithSuperBoom extends AbstractAction {
+ private Set<AbstractAction> preRequisite = new HashSet<AbstractAction>();
+ private OffsetPoint target;
+
+ @Override
+ public Set<AbstractAction> getPreRequisites(DungeonRoom dungeonRoom) {
+ return preRequisite;
+ }
+
+ @Override
+ public boolean isComplete(DungeonRoom dungeonRoom) {
+ return false;
+ }
+
+ public ActionBreakWithSuperBoom(OffsetPoint target) {
+ this.target = target;
+ }
+
+ @Override
+ public void onRenderWorld(DungeonRoom dungeonRoom, float partialTicks, ActionRouteProperties actionRouteProperties, boolean flag) {
+ Minecraft.getMinecraft().renderEngine.bindTexture(TextureMap.locationBlocksTexture);
+
+ BlockPos blockpos = target.getBlockPos(dungeonRoom);
+
+ Entity viewing_from = Minecraft.getMinecraft().getRenderViewEntity();
+
+ double x_fix = viewing_from.lastTickPosX + ((viewing_from.posX - viewing_from.lastTickPosX) * partialTicks);
+ double y_fix = viewing_from.lastTickPosY + ((viewing_from.posY - viewing_from.lastTickPosY) * partialTicks);
+ double z_fix = viewing_from.lastTickPosZ + ((viewing_from.posZ - viewing_from.lastTickPosZ) * partialTicks);
+
+ GlStateManager.pushMatrix();
+ GlStateManager.translate(-x_fix, -y_fix, -z_fix);
+ GlStateManager.disableLighting();
+ GlStateManager.enableAlpha();
+ GlStateManager.disableDepth();
+ GlStateManager.depthMask(false);
+ GlStateManager.enableBlend();
+
+ Tessellator tessellator = Tessellator.getInstance();
+ WorldRenderer vertexbuffer = tessellator.getWorldRenderer();
+ vertexbuffer.begin(7, DefaultVertexFormats.BLOCK);
+
+ BlockRendererDispatcher blockrendererdispatcher = Minecraft.getMinecraft().getBlockRendererDispatcher();
+ blockrendererdispatcher.getBlockModelRenderer().renderModel(Minecraft.getMinecraft().theWorld,
+ blockrendererdispatcher.getBlockModelShapes().getModelForState(Blocks.tnt.getDefaultState()),
+ Blocks.tnt.getDefaultState(), blockpos, vertexbuffer, false);
+ tessellator.draw();
+
+ GlStateManager.enableLighting();
+ GlStateManager.popMatrix();
+
+ RenderUtils.highlightBlock(blockpos, new Color(0, 255,255,50), partialTicks, true);
+ RenderUtils.drawTextAtWorld("Superboom", blockpos.getX() + 0.5f, blockpos.getY() + 0.5f, blockpos.getZ() + 0.5f, 0xFFFFFF00, 0.03f, false, false, partialTicks);
+ }
+
+ @Override
+ public String toString() {
+ return "BreakWithSuperboom\n- target: "+target.toString();
+ }
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/actions/ActionChangeState.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/actions/ActionChangeState.java
new file mode 100755
index 00000000..634129c6
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/actions/ActionChangeState.java
@@ -0,0 +1,75 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.actions;
+
+import kr.syeyoung.dungeonsguide.dungeon.mechanics.DungeonDummy;
+import kr.syeyoung.dungeonsguide.dungeon.mechanics.DungeonSecret;
+import kr.syeyoung.dungeonsguide.dungeon.mechanics.dunegonmechanic.DungeonMechanic;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomfinder.DungeonRoom;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.util.HashSet;
+import java.util.Set;
+
+@Data
+@EqualsAndHashCode(callSuper=false)
+public class ActionChangeState extends AbstractAction {
+ @EqualsAndHashCode.Exclude
+ private Set<AbstractAction> preRequisite2 = new HashSet<AbstractAction>();
+
+ private String mechanicName;
+ private String state;
+
+ public ActionChangeState(String mechanicName, String state) {
+ this.mechanicName = mechanicName;
+ this.state = state;
+ }
+
+ @Override
+ public Set<AbstractAction> getPreRequisites(DungeonRoom dungeonRoom) {
+ Set<AbstractAction> set = new HashSet<>(preRequisite2);
+ DungeonMechanic mechanic = dungeonRoom.getMechanics().get(mechanicName);
+ if (mechanic!= null)
+ set.addAll(mechanic.getAction(state, dungeonRoom));
+ return set;
+ }
+ @Override
+ public String toString() {
+ return "ChangeState\n- target: "+mechanicName+"\n- state: "+state;
+ }
+
+ @Override
+ public boolean isComplete(DungeonRoom dungeonRoom) {
+ DungeonMechanic mechanic = dungeonRoom.getMechanics().get(mechanicName);
+ if (state.equalsIgnoreCase("navigate")) {
+ return true;
+ }
+ if (mechanic == null) {
+ return false;
+ }
+ if (mechanic instanceof DungeonSecret && ((DungeonSecret) mechanic).getSecretType() != DungeonSecret.SecretType.CHEST) {
+ return true;
+ }
+ if (mechanic instanceof DungeonDummy) {
+ return true;
+ }
+ return mechanic.getCurrentState(dungeonRoom).equalsIgnoreCase(state);
+ }
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/actions/ActionClick.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/actions/ActionClick.java
new file mode 100755
index 00000000..c9ffb81c
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/actions/ActionClick.java
@@ -0,0 +1,82 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.actions;
+
+import com.google.common.base.Predicate;
+import com.google.common.base.Predicates;
+import kr.syeyoung.dungeonsguide.mod.chat.ChatTransmitter;
+import kr.syeyoung.dungeonsguide.mod.dungeon.actions.tree.ActionRouteProperties;
+import kr.syeyoung.dungeonsguide.dungeon.data.OffsetPoint;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomfinder.DungeonRoom;
+import kr.syeyoung.dungeonsguide.mod.utils.RenderUtils;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import net.minecraft.item.ItemStack;
+import net.minecraft.util.BlockPos;
+import net.minecraftforge.event.entity.player.PlayerInteractEvent;
+
+import java.awt.*;
+import java.util.HashSet;
+import java.util.Set;
+
+@Data
+@EqualsAndHashCode(callSuper=false)
+public class ActionClick extends AbstractAction {
+ private Set<AbstractAction> preRequisite = new HashSet<AbstractAction>();
+ private OffsetPoint target;
+ private Predicate<ItemStack> predicate = Predicates.alwaysTrue();
+
+ private boolean clicked = false;
+
+ public ActionClick(OffsetPoint target) {
+ this.target = target;
+ }
+
+ @Override
+ public Set<AbstractAction> getPreRequisites(DungeonRoom dungeonRoom) {
+ return preRequisite;
+ }
+
+ @Override
+ public boolean isComplete(DungeonRoom dungeonRoom) {
+ return clicked;
+ }
+
+ @Override
+ public void onPlayerInteract(DungeonRoom dungeonRoom, PlayerInteractEvent event, ActionRouteProperties actionRouteProperties) {
+ if (clicked) return;
+ if (target.getBlockPos(dungeonRoom).equals(event.pos) &&
+ (predicate == null || predicate.apply(event.entityLiving.getHeldItem()))) {
+ clicked = true;
+ ChatTransmitter.sendDebugChat("ACTION FINISHED: CLICK");
+ }
+ }
+ @Override
+ public void onRenderWorld(DungeonRoom dungeonRoom, float partialTicks, ActionRouteProperties actionRouteProperties, boolean flag) {
+ BlockPos pos = target.getBlockPos(dungeonRoom);
+ RenderUtils.highlightBlock(pos, new Color(0, 255,255,50),partialTicks, true);
+ RenderUtils.drawTextAtWorld("Click", pos.getX() + 0.5f, pos.getY() + 0.3f, pos.getZ() + 0.5f, 0xFFFFFF00, 0.02f, false, false, partialTicks);
+ }
+
+
+ @Override
+ public String toString() {
+ return "Click\n- target: "+target.toString()+"\n- predicate: "+predicate.getClass().getSimpleName();
+ }
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/actions/ActionClickSet.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/actions/ActionClickSet.java
new file mode 100755
index 00000000..01f5b9b2
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/actions/ActionClickSet.java
@@ -0,0 +1,90 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.actions;
+
+import kr.syeyoung.dungeonsguide.mod.dungeon.actions.tree.ActionRouteProperties;
+import kr.syeyoung.dungeonsguide.dungeon.data.OffsetPoint;
+import kr.syeyoung.dungeonsguide.dungeon.data.OffsetPointSet;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomfinder.DungeonRoom;
+import kr.syeyoung.dungeonsguide.mod.utils.RenderUtils;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import net.minecraft.item.ItemStack;
+import net.minecraft.util.BlockPos;
+import net.minecraftforge.event.entity.player.PlayerInteractEvent;
+
+import java.awt.*;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.function.Predicate;
+
+@Data
+@EqualsAndHashCode(callSuper=false)
+public class ActionClickSet extends AbstractAction {
+ private Set<AbstractAction> preRequisite = new HashSet<>();
+ private OffsetPointSet target;
+ private Predicate<ItemStack> predicate = stack -> true;
+
+ public ActionClickSet(OffsetPointSet target) {
+ this.target = target;
+ }
+
+ @Override
+ public Set<AbstractAction> getPreRequisites(DungeonRoom dungeonRoom) {
+ return preRequisite;
+ }
+
+ @Override
+ public String toString() {
+ return "ClickSet\n- targets size: "+target.getOffsetPointList().size()+"\n- predicate: "+predicate.getClass().getSimpleName();
+ }
+
+ private boolean clicked = false;
+ @Override
+ public void onPlayerInteract(DungeonRoom dungeonRoom, PlayerInteractEvent event, ActionRouteProperties actionRouteProperties) {
+ if (clicked) return;
+ for (OffsetPoint pt2: target.getOffsetPointList()) {
+ if (pt2.getBlockPos(dungeonRoom).equals(event.pos) && predicate.test(event.entityLiving.getHeldItem())) {
+ clicked = true;
+ }
+ }
+
+ }
+
+ @Override
+ public void onRenderWorld(DungeonRoom dungeonRoom, float partialTicks, ActionRouteProperties actionRouteProperties, boolean flag) {
+ float xAcc = 0;
+ float yAcc = 0;
+ float zAcc = 0;
+ int size = target.getOffsetPointList().size();
+ for (OffsetPoint offsetPoint : target.getOffsetPointList()) {
+ BlockPos pos = offsetPoint.getBlockPos(dungeonRoom);
+ xAcc += pos.getX() + 0.5f;
+ yAcc += pos.getY()+ 0.5f;
+ zAcc += pos.getZ()+ 0.5f;
+ RenderUtils.highlightBlock(offsetPoint.getBlockPos(dungeonRoom), new Color(0, 255,255,50),partialTicks, true);
+ }
+
+ RenderUtils.drawTextAtWorld("Click", xAcc / size, yAcc / size, zAcc / size, 0xFFFFFF00, 0.02f, false, false, partialTicks);
+ }
+ @Override
+ public boolean isComplete(DungeonRoom dungeonRoom) {
+ return clicked;
+ }
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/actions/ActionComplete.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/actions/ActionComplete.java
new file mode 100644
index 00000000..32d6bfc3
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/actions/ActionComplete.java
@@ -0,0 +1,41 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.actions;
+
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomfinder.DungeonRoom;
+
+import java.util.Collections;
+import java.util.Set;
+
+public class ActionComplete extends AbstractAction {
+ @Override
+ public Set<AbstractAction> getPreRequisites(DungeonRoom dungeonRoom) {
+ return Collections.emptySet();
+ }
+
+ @Override
+ public boolean isComplete(DungeonRoom dungeonRoom) {
+ return false;
+ }
+
+ @Override
+ public String toString() {
+ return "Completed";
+ }
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/actions/ActionDropItem.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/actions/ActionDropItem.java
new file mode 100755
index 00000000..0c94e5ae
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/actions/ActionDropItem.java
@@ -0,0 +1,82 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.actions;
+
+import com.google.common.base.Predicate;
+import com.google.common.base.Predicates;
+import kr.syeyoung.dungeonsguide.mod.dungeon.actions.tree.ActionRouteProperties;
+import kr.syeyoung.dungeonsguide.dungeon.data.OffsetPoint;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomfinder.DungeonRoom;
+import kr.syeyoung.dungeonsguide.mod.utils.RenderUtils;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import net.minecraft.entity.item.EntityItem;
+import net.minecraft.util.AxisAlignedBB;
+import net.minecraft.util.BlockPos;
+
+import java.awt.*;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+@Data
+@EqualsAndHashCode(callSuper = false)
+public class ActionDropItem extends AbstractAction {
+ private Set<AbstractAction> preRequisite = new HashSet<>();
+ private OffsetPoint target;
+ private Predicate<EntityItem> predicate = Predicates.alwaysTrue();
+
+ public ActionDropItem(OffsetPoint target) {
+ this.target = target;
+ }
+
+ @Override
+ public Set<AbstractAction> getPreRequisites(DungeonRoom dungeonRoom) {
+ return preRequisite;
+ }
+
+ @Override
+ public boolean isComplete(DungeonRoom dungeonRoom) {
+ BlockPos secretLocation = target.getBlockPos(dungeonRoom);
+ List<EntityItem> item = dungeonRoom.getContext().getWorld().getEntitiesWithinAABB(EntityItem.class,
+ AxisAlignedBB.fromBounds(
+ secretLocation.getX(),
+ secretLocation.getY(),
+ secretLocation.getZ(),
+ secretLocation.getX() + 1,
+ secretLocation.getY() + 1,
+ secretLocation.getZ() + 1));
+ if (item.isEmpty()) {
+ return false;
+ }
+ return (predicate == null || predicate.apply(item.get(0)));
+ }
+ @Override
+ public void onRenderWorld(DungeonRoom dungeonRoom, float partialTicks, ActionRouteProperties actionRouteProperties, boolean flag) {
+ BlockPos pos = target.getBlockPos(dungeonRoom);
+ RenderUtils.highlightBlock(pos, new Color(0, 255, 255, 50), partialTicks, true);
+ RenderUtils.drawTextAtWorld("Drop Item", pos.getX() + 0.5f, pos.getY() + 0.3f, pos.getZ() + 0.5f, 0xFFFFFF00, 0.02f, false, false, partialTicks);
+ }
+
+
+ @Override
+ public String toString() {
+ return "DropItem\n- target: " + target.toString() + "\n- predicate: " + predicate.getClass().getSimpleName();
+ }
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/actions/ActionInteract.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/actions/ActionInteract.java
new file mode 100755
index 00000000..b41e1b7a
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/actions/ActionInteract.java
@@ -0,0 +1,89 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.actions;
+
+import kr.syeyoung.dungeonsguide.mod.dungeon.DungeonActionContext;
+import kr.syeyoung.dungeonsguide.mod.dungeon.actions.tree.ActionRouteProperties;
+import kr.syeyoung.dungeonsguide.dungeon.data.OffsetPoint;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomfinder.DungeonRoom;
+import kr.syeyoung.dungeonsguide.mod.events.impl.PlayerInteractEntityEvent;
+import kr.syeyoung.dungeonsguide.mod.utils.RenderUtils;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import net.minecraft.entity.Entity;
+import net.minecraft.util.BlockPos;
+import net.minecraft.util.Vec3;
+
+import java.awt.*;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.function.Predicate;
+
+@Data
+@EqualsAndHashCode(callSuper=false)
+public class ActionInteract extends AbstractAction {
+ private Set<AbstractAction> preRequisite = new HashSet<>();
+ private OffsetPoint target;
+ private Predicate<Entity> predicate = entity -> false;
+ private int radius;
+
+ public ActionInteract(OffsetPoint target) {
+ this.target = target;
+ }
+
+ @Override
+ public Set<AbstractAction> getPreRequisites(DungeonRoom dungeonRoom) {
+ return preRequisite;
+ }
+
+ @Override
+ public boolean isComplete(DungeonRoom dungeonRoom) {
+ return interacted;
+ }
+
+ private boolean interacted = false;
+ @Override
+ public void onLivingInteract(DungeonRoom dungeonRoom, PlayerInteractEntityEvent event, ActionRouteProperties actionRouteProperties) {
+ if (interacted) return;
+
+ Vec3 spawnLoc = DungeonActionContext.getSpawnLocation().get(event.getEntity().getEntityId());
+ if (spawnLoc == null) {
+ return;
+ }
+ if (target.getBlockPos(dungeonRoom).distanceSq(spawnLoc.xCoord, spawnLoc.yCoord, spawnLoc.zCoord) > radius * radius) {
+ return;
+ }
+ if (!predicate.test(event.getEntity())) {
+ return;
+ }
+ interacted = true;
+ }
+
+ @Override
+ public void onRenderWorld(DungeonRoom dungeonRoom, float partialTicks, ActionRouteProperties actionRouteProperties, boolean flag) {
+ BlockPos pos = target.getBlockPos(dungeonRoom);
+ RenderUtils.highlightBlock(pos, new Color(0, 255,255,50),partialTicks, true);
+ RenderUtils.drawTextAtWorld("Interact", pos.getX() + 0.5f, pos.getY() + 0.3f, pos.getZ() + 0.5f, 0xFFFFFF00, 0.02f, false, false, partialTicks);
+ }
+
+ @Override
+ public String toString() {
+ return "InteractEntity\n- target: "+target.toString()+"\n- radius: "+radius+"\n- predicate: "+(predicate.test(null) ? "null" : predicate.getClass().getSimpleName());
+ }
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/actions/ActionKill.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/actions/ActionKill.java
new file mode 100755
index 00000000..94569ad1
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/actions/ActionKill.java
@@ -0,0 +1,90 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.actions;
+
+import kr.syeyoung.dungeonsguide.mod.dungeon.DungeonActionContext;
+import kr.syeyoung.dungeonsguide.mod.dungeon.actions.tree.ActionRouteProperties;
+import kr.syeyoung.dungeonsguide.dungeon.data.OffsetPoint;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomfinder.DungeonRoom;
+import kr.syeyoung.dungeonsguide.mod.utils.RenderUtils;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import net.minecraft.entity.Entity;
+import net.minecraft.util.BlockPos;
+import net.minecraft.util.Vec3;
+import net.minecraftforge.event.entity.living.LivingDeathEvent;
+
+import java.awt.*;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.function.Predicate;
+
+@Data
+@EqualsAndHashCode(callSuper=false)
+public class ActionKill extends AbstractAction {
+ private Set<AbstractAction> preRequisite = new HashSet<AbstractAction>();
+ private OffsetPoint target;
+ private Predicate<Entity> predicate = entity -> false;
+ private int radius;
+
+ public ActionKill(OffsetPoint target) {
+ this.target = target;
+ }
+
+ @Override
+ public Set<AbstractAction> getPreRequisites(DungeonRoom dungeonRoom) {
+ return preRequisite;
+ }
+
+ @Override
+ public boolean isComplete(DungeonRoom dungeonRoom) {
+ Vec3 spawn = new Vec3(target.getBlockPos(dungeonRoom));
+ for (Integer killed : DungeonActionContext.getKilleds()) {
+ if (DungeonActionContext.getSpawnLocation().get(killed) == null) continue;
+ if (DungeonActionContext.getSpawnLocation().get(killed).squareDistanceTo(spawn) < 100) {
+ return true;
+ }
+ }
+
+ return killed;
+ }
+
+ private boolean killed = false;
+ @Override
+ public void onLivingDeath(DungeonRoom dungeonRoom, LivingDeathEvent event, ActionRouteProperties actionRouteProperties) {
+ if (killed) return;
+
+ Vec3 spawnLoc = DungeonActionContext.getSpawnLocation().get(event.entity.getEntityId());
+ if (spawnLoc == null) return;
+ if (target.getBlockPos(dungeonRoom).distanceSq(spawnLoc.xCoord, spawnLoc.yCoord, spawnLoc.zCoord) > radius * radius) return;
+ if (!predicate.test(event.entity)) return;
+ killed = true;
+ }
+ @Override
+ public void onRenderWorld(DungeonRoom dungeonRoom, float partialTicks, ActionRouteProperties actionRouteProperties, boolean flag) {
+ BlockPos pos = target.getBlockPos(dungeonRoom);
+ RenderUtils.highlightBlock(pos, new Color(0, 255,255,50),partialTicks, true);
+ RenderUtils.drawTextAtWorld("Spawn", pos.getX() + 0.5f, pos.getY() + 0.3f, pos.getZ() + 0.5f, 0xFFFFFF00, 0.02f, false, false, partialTicks);
+ }
+
+ @Override
+ public String toString() {
+ return "KillEntity\n- target: "+target.toString()+"\n- radius: "+radius+"\n- predicate: "+(predicate.test(null) ? "null" : predicate.getClass().getSimpleName());
+ }
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/actions/ActionMove.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/actions/ActionMove.java
new file mode 100755
index 00000000..f499032d
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/actions/ActionMove.java
@@ -0,0 +1,122 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.actions;
+
+import kr.syeyoung.dungeonsguide.mod.dungeon.actions.tree.ActionRouteProperties;
+import kr.syeyoung.dungeonsguide.dungeon.data.OffsetPoint;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomfinder.DungeonRoom;
+import kr.syeyoung.dungeonsguide.mod.features.FeatureRegistry;
+import kr.syeyoung.dungeonsguide.mod.utils.RenderUtils;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import net.minecraft.client.Minecraft;
+import net.minecraft.util.BlockPos;
+import net.minecraft.util.MathHelper;
+import net.minecraft.util.Vec3;
+
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+
+@Data
+@EqualsAndHashCode(callSuper=false)
+public class ActionMove extends AbstractAction {
+ private Set<AbstractAction> preRequisite = new HashSet<>();
+ private OffsetPoint target;
+
+ public ActionMove(OffsetPoint target) {
+ this.target = target;
+ }
+
+ @Override
+ public Set<AbstractAction> getPreRequisites(DungeonRoom dungeonRoom) {
+ return preRequisite;
+ }
+
+ @Override
+ public boolean isComplete(DungeonRoom dungeonRoom) {
+ return target.getBlockPos(dungeonRoom).distanceSq(Minecraft.getMinecraft().thePlayer.getPosition()) < 25;
+ }
+
+ @Override
+ public void onRenderWorld(DungeonRoom dungeonRoom, float partialTicks, ActionRouteProperties actionRouteProperties, boolean flag) {
+ draw(dungeonRoom, partialTicks, actionRouteProperties, flag, target, poses);
+ }
+
+ static void draw(DungeonRoom dungeonRoom, float partialTicks, ActionRouteProperties actionRouteProperties, boolean flag, OffsetPoint target, List<Vec3> poses) {
+ BlockPos pos = target.getBlockPos(dungeonRoom);
+
+ float distance = MathHelper.sqrt_double(pos.distanceSq(Minecraft.getMinecraft().thePlayer.getPosition()));
+ float multiplier = distance / 120f; //mobs only render ~120 blocks away
+ if (flag) multiplier *= 2.0f;
+ float scale = 0.45f * multiplier;
+ scale *= 25.0 / 6.0;
+ if (actionRouteProperties.isBeacon()) {
+ if(!FeatureRegistry.RENDER_BREACONS.isEnabled()){
+ RenderUtils.renderBeaconBeam(pos.getX(), pos.getY(), pos.getZ(), actionRouteProperties.getBeaconBeamColor(), partialTicks);
+ }
+ RenderUtils.highlightBlock(pos, actionRouteProperties.getBeaconColor(), partialTicks);
+ }
+ if(!FeatureRegistry.RENDER_DESTENATION_TEXT.isEnabled()){
+ RenderUtils.drawTextAtWorld("Destination", pos.getX() + 0.5f, pos.getY() + 0.5f + scale, pos.getZ() + 0.5f, 0xFF00FF00, flag ? 2f : 1f, true, false, partialTicks);
+ }
+ RenderUtils.drawTextAtWorld(String.format("%.2f",MathHelper.sqrt_double(pos.distanceSq(Minecraft.getMinecraft().thePlayer.getPosition())))+"m", pos.getX() + 0.5f, pos.getY() + 0.5f - scale, pos.getZ() + 0.5f, 0xFFFFFF00, flag ? 2f : 1f, true, false, partialTicks);
+
+ if (!FeatureRegistry.SECRET_TOGGLE_KEY.isEnabled() || !FeatureRegistry.SECRET_TOGGLE_KEY.togglePathfindStatus) {
+ if (poses != null){
+ RenderUtils.drawLinesVec3(poses, actionRouteProperties.getLineColor(), actionRouteProperties.getLineWidth(), partialTicks, true);
+ }
+ }
+ }
+
+ private int tick = -1;
+ private List<Vec3> poses;
+ private Future<List<Vec3>> latestFuture;
+
+ @Override
+ public void onTick(DungeonRoom dungeonRoom, ActionRouteProperties actionRouteProperties) {
+ tick = (tick+1) % Math.max(1, actionRouteProperties.getLineRefreshRate());
+ if (latestFuture != null && latestFuture.isDone()) {
+ try {
+ poses = latestFuture.get();
+ latestFuture = null;
+ } catch (InterruptedException | ExecutionException e) {
+ e.printStackTrace();
+ }
+ }
+
+ if (tick == 0 && actionRouteProperties.isPathfind() && latestFuture == null) {
+ if (!FeatureRegistry.SECRET_FREEZE_LINES.isEnabled() || poses == null) {
+ latestFuture = dungeonRoom.createEntityPathTo(dungeonRoom.getContext().getWorld(), Minecraft.getMinecraft().thePlayer, target.getBlockPos(dungeonRoom), Integer.MAX_VALUE, 10000);
+ }
+ }
+ }
+
+ public void forceRefresh(DungeonRoom dungeonRoom) {
+ if (latestFuture == null) {
+ latestFuture = dungeonRoom.createEntityPathTo(dungeonRoom.getContext().getWorld(), Minecraft.getMinecraft().thePlayer, target.getBlockPos(dungeonRoom), Integer.MAX_VALUE, 10000);
+ }
+ }
+ @Override
+ public String toString() {
+ return "Move\n- target: "+target.toString();
+ }
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/actions/ActionMoveNearestAir.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/actions/ActionMoveNearestAir.java
new file mode 100755
index 00000000..54e8b1a8
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/actions/ActionMoveNearestAir.java
@@ -0,0 +1,92 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.actions;
+
+import kr.syeyoung.dungeonsguide.mod.dungeon.actions.tree.ActionRouteProperties;
+import kr.syeyoung.dungeonsguide.dungeon.data.OffsetPoint;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomfinder.DungeonRoom;
+import kr.syeyoung.dungeonsguide.mod.features.FeatureRegistry;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import net.minecraft.client.Minecraft;
+import net.minecraft.util.Vec3;
+
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+
+@Data
+@EqualsAndHashCode(callSuper=false)
+public class ActionMoveNearestAir extends AbstractAction {
+ private Set<AbstractAction> preRequisite = new HashSet<>();
+ private OffsetPoint target;
+
+ public ActionMoveNearestAir(OffsetPoint target) {
+ this.target = target;
+ }
+
+ @Override
+ public Set<AbstractAction> getPreRequisites(DungeonRoom dungeonRoom) {
+ return preRequisite;
+ }
+
+ @Override
+ public boolean isComplete(DungeonRoom dungeonRoom) {
+ return target.getBlockPos(dungeonRoom).distanceSq(Minecraft.getMinecraft().thePlayer.getPosition()) < 25;
+ }
+ @Override
+ public void onRenderWorld(DungeonRoom dungeonRoom, float partialTicks, ActionRouteProperties actionRouteProperties, boolean flag) {
+ ActionMove.draw(dungeonRoom, partialTicks, actionRouteProperties, flag, target, poses);
+ }
+
+ private int tick = -1;
+ private List<Vec3> poses;
+ private Future<List<Vec3>> latestFuture;
+ @Override
+ public void onTick(DungeonRoom dungeonRoom, ActionRouteProperties actionRouteProperties) {
+ tick = (tick+1) % Math.max(1, actionRouteProperties.getLineRefreshRate());
+ if (latestFuture != null && latestFuture.isDone()) {
+ try {
+ poses = latestFuture.get();
+ latestFuture = null;
+ } catch (InterruptedException | ExecutionException e) {
+ e.printStackTrace();
+ }
+ }
+
+ if (tick == 0 && actionRouteProperties.isPathfind() && latestFuture == null) {
+ if (!FeatureRegistry.SECRET_FREEZE_LINES.isEnabled() || poses == null) {
+ latestFuture = dungeonRoom.createEntityPathTo(dungeonRoom.getContext().getWorld(), Minecraft.getMinecraft().thePlayer, target.getBlockPos(dungeonRoom), Integer.MAX_VALUE, 10000);
+ }
+ }
+ }
+
+
+ public void forceRefresh(DungeonRoom dungeonRoom) {
+ if (latestFuture == null) {
+ latestFuture = dungeonRoom.createEntityPathTo(dungeonRoom.getContext().getWorld(), Minecraft.getMinecraft().thePlayer, target.getBlockPos(dungeonRoom), Integer.MAX_VALUE, 10000);
+ }
+ }
+ @Override
+ public String toString() {
+ return "MoveNearestAir\n- target: "+target.toString();
+ }
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/actions/ActionRoot.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/actions/ActionRoot.java
new file mode 100755
index 00000000..23b9fdce
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/actions/ActionRoot.java
@@ -0,0 +1,47 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.actions;
+
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomfinder.DungeonRoom;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.util.HashSet;
+import java.util.Set;
+
+@Data
+@EqualsAndHashCode(callSuper=false)
+public class ActionRoot extends AbstractAction {
+ private Set<AbstractAction> preRequisite = new HashSet<>();
+
+ @Override
+ public Set<AbstractAction> getPreRequisites(DungeonRoom dungeonRoom) {
+ return preRequisite;
+ }
+
+ @Override
+ public boolean isComplete(DungeonRoom dungeonRoom) {
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ return "Action Root";
+ }
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/actions/tree/ActionRoute.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/actions/tree/ActionRoute.java
new file mode 100644
index 00000000..17cea18d
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/actions/tree/ActionRoute.java
@@ -0,0 +1,136 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.actions.tree;
+
+import kr.syeyoung.dungeonsguide.mod.chat.ChatTransmitter;
+import kr.syeyoung.dungeonsguide.mod.dungeon.actions.*;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomfinder.DungeonRoom;
+import kr.syeyoung.dungeonsguide.mod.events.impl.PlayerInteractEntityEvent;
+import lombok.Getter;
+import net.minecraft.client.Minecraft;
+import net.minecraftforge.event.entity.living.LivingDeathEvent;
+import net.minecraftforge.event.entity.player.PlayerInteractEvent;
+
+import java.util.List;
+
+public class ActionRoute {
+ @Getter
+ private final String mechanic;
+ @Getter
+ private final String state;
+
+ @Getter
+ private int current;
+ @Getter
+ private final List<AbstractAction> actions;
+
+ private final DungeonRoom dungeonRoom;
+
+ @Getter
+ private final ActionRouteProperties actionRouteProperties;
+
+ public ActionRoute(DungeonRoom dungeonRoom, String mechanic, String state, ActionRouteProperties actionRouteProperties) {
+ this.mechanic = mechanic;
+ this.state = state;
+ this.actionRouteProperties = actionRouteProperties;
+
+ System.out.println("Creating Action Route with mechanic:" + mechanic + " State:" + state);
+ ActionChangeState actionChangeState = new ActionChangeState(mechanic, state);
+ ActionTree tree= ActionTree.buildActionTree(actionChangeState, dungeonRoom);
+ actions = ActionTreeUtil.linearifyActionTree(tree);
+ actions.add(new ActionComplete());
+ ChatTransmitter.sendDebugChat("Created ActionRoute with " + actions.size() + " steps");
+ ChatTransmitter.sendDebugChat("========== STEPS ==========");
+ for (AbstractAction action : actions) {
+ ChatTransmitter.sendDebugChat(action.toString());
+ }
+ ChatTransmitter.sendDebugChat("=========== END ===========");
+
+
+ current = 0;
+ this.dungeonRoom = dungeonRoom;
+ }
+
+ public AbstractAction next() {
+ current ++;
+ if (current >= actions.size()) {
+ current = actions.size() - 1;
+ }
+ return getCurrentAction();
+ }
+
+ public AbstractAction prev() {
+ current --;
+ if (current < 0) {
+ current = 0;
+ }
+ return getCurrentAction();
+ }
+
+ public AbstractAction getCurrentAction() {
+ return actions.get(current);
+ }
+
+
+
+ public void onPlayerInteract(PlayerInteractEvent event) {
+ getCurrentAction().onPlayerInteract(dungeonRoom, event, actionRouteProperties );
+ }
+ public void onLivingDeath(LivingDeathEvent event) {
+ getCurrentAction().onLivingDeath(dungeonRoom, event, actionRouteProperties );
+ }
+ public void onRenderWorld(float partialTicks, boolean flag) {
+
+ if (current -1 >= 0) {
+ AbstractAction abstractAction = actions.get(current - 1);
+ if(((abstractAction instanceof ActionMove && ((ActionMove) abstractAction).getTarget().getBlockPos(dungeonRoom).distanceSq(Minecraft.getMinecraft().thePlayer.getPosition()) >= 25)
+ || (abstractAction instanceof ActionMoveNearestAir && ((ActionMoveNearestAir) abstractAction).getTarget().getBlockPos(dungeonRoom).distanceSq(Minecraft.getMinecraft().thePlayer.getPosition()) >= 25))){
+ abstractAction.onRenderWorld(dungeonRoom, partialTicks, actionRouteProperties, flag );
+ }
+ }
+ getCurrentAction().onRenderWorld(dungeonRoom, partialTicks, actionRouteProperties, flag);
+
+
+ getCurrentAction().onRenderWorld(dungeonRoom, partialTicks, actionRouteProperties, flag);
+ }
+
+ public void onRenderScreen(float partialTicks) {
+ getCurrentAction().onRenderScreen(dungeonRoom, partialTicks, actionRouteProperties);
+ }
+
+ public void onTick() {
+ AbstractAction currentAction = getCurrentAction();
+
+ currentAction.onTick(dungeonRoom, actionRouteProperties);
+ if (this.current -1 >= 0 && (actions.get(this.current-1) instanceof ActionMove || actions.get(this.current-1) instanceof ActionMoveNearestAir)) actions.get(this.current-1).onTick(dungeonRoom, actionRouteProperties );
+
+ if (dungeonRoom.getMechanics().get(mechanic).getCurrentState(dungeonRoom).equals(state)) {
+ this.current = actions.size() - 1;
+ }
+
+ if (currentAction.isComplete(dungeonRoom)) {
+ next();
+ }
+ }
+
+ public void onLivingInteract(PlayerInteractEntityEvent event) {
+ getCurrentAction().onLivingInteract(dungeonRoom, event, actionRouteProperties );
+ }
+
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/actions/tree/ActionRouteProperties.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/actions/tree/ActionRouteProperties.java
new file mode 100644
index 00000000..df32e718
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/actions/tree/ActionRouteProperties.java
@@ -0,0 +1,16 @@
+package kr.syeyoung.dungeonsguide.mod.dungeon.actions.tree;
+
+import kr.syeyoung.dungeonsguide.mod.config.types.AColor;
+import lombok.Data;
+
+@Data
+public class ActionRouteProperties {
+ private boolean pathfind;
+ private int lineRefreshRate;
+ private AColor lineColor;
+ private float lineWidth;
+
+ private boolean beacon;
+ private AColor beaconColor;
+ private AColor beaconBeamColor;
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/actions/tree/ActionTree.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/actions/tree/ActionTree.java
new file mode 100755
index 00000000..99846fc7
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/actions/tree/ActionTree.java
@@ -0,0 +1,94 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.actions.tree;
+
+import kr.syeyoung.dungeonsguide.mod.dungeon.actions.AbstractAction;
+import kr.syeyoung.dungeonsguide.mod.dungeon.actions.ActionRoot;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomfinder.DungeonRoom;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.*;
+
+@Data
+public class ActionTree implements Cloneable {
+ @EqualsAndHashCode.Exclude
+ private Set<ActionTree> parent;
+ private AbstractAction current;
+ private Set<ActionTree> children;
+
+ @Override
+ public int hashCode() { return current == null ? 0 : current.hashCode(); }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ ActionTree that = (ActionTree) o;
+ return Objects.equals(parent, that.parent) && Objects.equals(current, that.current) && Objects.equals(children, that.children);
+ }
+
+ public static ActionTree buildActionTree(Set<AbstractAction> actions, DungeonRoom dungeonRoom) {
+ ActionRoot root = new ActionRoot();
+ root.setPreRequisite(actions);
+ ActionTree tree = new ActionTree();
+ tree.setParent(new HashSet<>());
+ tree.setCurrent(root);
+ HashSet<ActionTree> set = new HashSet<>();
+ for (AbstractAction action : actions) {
+ set.add(buildActionTree(tree, action, dungeonRoom, new HashMap<>()));
+ }
+ tree.setChildren(set);
+ return tree;
+ }
+ public static ActionTree buildActionTree(AbstractAction actions, DungeonRoom dungeonRoom) {
+ return buildActionTree(null, actions, dungeonRoom, new HashMap<>());
+ }
+
+
+
+ private static ActionTree buildActionTree(ActionTree parent, @NotNull AbstractAction action,@NotNull DungeonRoom dungeonRoom, @NotNull Map<AbstractAction, ActionTree> alreadyBuilt) {
+ if (alreadyBuilt.containsKey(action)) {
+ ActionTree tree = alreadyBuilt.get(action);
+ tree.getParent().add(parent);
+ return tree;
+ }
+
+ ActionTree tree = new ActionTree();
+ alreadyBuilt.put(action, tree);
+ tree.setParent(new HashSet<>());
+ if (parent != null) {
+ tree.getParent().add(parent);
+ }
+ tree.setCurrent(action);
+ HashSet<ActionTree> set = new HashSet<>();
+
+ Set<AbstractAction> preRequisites = action.getPreRequisites(dungeonRoom);
+ if(preRequisites != null){
+ for (AbstractAction action2 : preRequisites) {
+ ActionTree e = buildActionTree(tree, action2, dungeonRoom, alreadyBuilt);
+ set.add(e);
+ }
+ }
+
+ tree.setChildren(set);
+ return tree;
+ }
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/actions/tree/ActionTreeUtil.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/actions/tree/ActionTreeUtil.java
new file mode 100644
index 00000000..18c17c17
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/actions/tree/ActionTreeUtil.java
@@ -0,0 +1,83 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.actions.tree;
+
+import kr.syeyoung.dungeonsguide.mod.dungeon.actions.AbstractAction;
+
+import java.util.*;
+
+public class ActionTreeUtil {
+ public static List<AbstractAction> linearifyActionTree(ActionTree input) {
+ ActionTree tree = copyActionTree(input);
+
+ List<AbstractAction> actions = new ArrayList<AbstractAction>();
+
+ int plsHalt = 0;
+ while (tree.getChildren().size() != 0) {
+ plsHalt ++;
+ if (plsHalt > 1000000) throw new IllegalStateException("Linearifying process ran for 1 million cycle");
+ Set<ActionTree> visited = new HashSet<ActionTree>();
+ ActionTree curr = tree;
+
+ int plsHalt2 = 0;
+ while (curr.getChildren().size() != 0) {
+ plsHalt2 ++;
+ if (plsHalt2 > 1000000) throw new IllegalStateException("Finding the leaf of tree ran for 1 million cycles");
+ if (visited.contains(curr)) throw new IllegalStateException("Circular Reference Detected");
+ visited.add(curr);
+ curr = curr.getChildren().iterator().next();
+ }
+
+ plsHalt2 =0;
+ while(curr.getChildren().size() == 0) {
+ plsHalt2 ++;
+ if (plsHalt2 > 1000000) throw new IllegalStateException("Building of array ran for 1 million cycles");
+
+ actions.add(curr.getCurrent());
+ if (curr.getParent().size() == 0) break;
+ for (ActionTree parentTree:curr.getParent())
+ parentTree.getChildren().remove(curr);
+ curr = curr.getParent().iterator().next();
+ }
+ }
+ return actions;
+ }
+
+ public static ActionTree copyActionTree(ActionTree tree) {
+ Map<ActionTree, ActionTree> built = new HashMap<ActionTree, ActionTree>();
+ if (tree.getParent().size() != 0) throw new IllegalArgumentException("that is not head of tree");
+ return copyActionTree(tree, built);
+ }
+ private static ActionTree copyActionTree(ActionTree tree, Map<ActionTree, ActionTree> preBuilts) {
+ if (preBuilts.containsKey(tree)) return preBuilts.get(tree);
+
+ ActionTree clone = new ActionTree();
+ preBuilts.put(tree, clone);
+
+ clone.setCurrent(tree.getCurrent());
+ clone.setParent(new HashSet<ActionTree>());
+ clone.setChildren(new HashSet<ActionTree>());
+ for (ActionTree tree3 : tree.getChildren()) {
+ ActionTree clone3 = copyActionTree(tree3, preBuilts);
+ clone3.getParent().add(clone);
+ clone.getChildren().add(clone3);
+ }
+ return clone;
+ }
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/doorfinder/DungeonDoor.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/doorfinder/DungeonDoor.java
new file mode 100755
index 00000000..15004dcc
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/doorfinder/DungeonDoor.java
@@ -0,0 +1,87 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.doorfinder;
+
+import com.google.common.collect.Sets;
+import lombok.Getter;
+import net.minecraft.block.Block;
+import net.minecraft.init.Blocks;
+import net.minecraft.util.BlockPos;
+import net.minecraft.world.World;
+
+import java.util.Set;
+
+@Getter
+public class DungeonDoor {
+ private final World w;
+ private final BlockPos position;
+ private final EDungeonDoorType type;
+ private boolean isZDir;
+
+ private static final Set<Block> legalBlocks = Sets.newHashSet(Blocks.coal_block, Blocks.barrier, Blocks.monster_egg, Blocks.air, Blocks.stained_hardened_clay);
+
+ public DungeonDoor(World world, BlockPos pos, EDungeonDoorType type) {
+ this.w = world;
+ this.position = pos;
+ Block itshouldbeall = world.getChunkFromBlockCoords(pos).getBlock(pos);
+
+ if (type == EDungeonDoorType.WITHER && itshouldbeall == Blocks.air) type = EDungeonDoorType.WITHER_FAIRY;
+ this.type = type;
+ boolean exist = type.isExist();
+
+ for (int x = -1; x<=1; x++) {
+ for (int y = -1; y<=1; y++) {
+ for (int z = -1; z<=1; z++) {
+ BlockPos pos2 = pos.add(x,y,z);
+ Block block = world.getChunkFromBlockCoords(pos2).getBlock(pos2);
+ if (itshouldbeall != block) exist = false;
+ }
+ }
+ }
+ if (exist) {
+ BlockPos ZCheck = pos.add(0,0,2);
+ isZDir = world.getChunkFromBlockCoords(ZCheck).getBlock(ZCheck) == Blocks.air;
+
+ if (isZDir) {
+ for (int x = -1; x<=1; x++) {
+ for (int y = -1; y<=1; y++) {
+ for (int z = -2; z<=2; z+=4) {
+ BlockPos pos2 = pos.add(x,y,z);
+ Block block = world.getChunkFromBlockCoords(pos2).getBlock(pos2);
+ if (block != Blocks.air) exist = false;
+ }
+ }
+ }
+ } else {
+ for (int x = -2; x<=2; x+=4) {
+ for (int y = -1; y<=1; y++) {
+ for (int z = -1; z<=1; z++) {
+ BlockPos pos2 = pos.add(x,y,z);
+ Block block = world.getChunkFromBlockCoords(pos2).getBlock(pos2);
+ if (block != Blocks.air) exist = false;
+ }
+ }
+ }
+ }
+ }
+ if (!exist) {
+ isZDir = false;
+ }
+ }
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/doorfinder/DungeonSpecificDataProvider.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/doorfinder/DungeonSpecificDataProvider.java
new file mode 100755
index 00000000..b34986eb
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/doorfinder/DungeonSpecificDataProvider.java
@@ -0,0 +1,39 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.doorfinder;
+
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.bossfight.BossfightProcessor;
+import net.minecraft.util.BlockPos;
+import net.minecraft.world.World;
+
+import javax.vecmath.Vector2d;
+
+public interface DungeonSpecificDataProvider {
+
+ BlockPos findDoor(World w, String dungeonName);
+
+ Vector2d findDoorOffset(World w, String dungeonName);
+ BossfightProcessor createBossfightProcessor(World w, String dungeonName);
+
+ boolean isTrapSpawn(String dungeonName);
+
+ double secretPercentage(String dungeonName);
+
+ int speedSecond(String dungeonName);
+} \ No newline at end of file
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/doorfinder/DungeonSpecificDataProviderRegistry.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/doorfinder/DungeonSpecificDataProviderRegistry.java
new file mode 100755
index 00000000..48b24120
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/doorfinder/DungeonSpecificDataProviderRegistry.java
@@ -0,0 +1,42 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.doorfinder;
+
+import kr.syeyoung.dungeonsguide.mod.dungeon.doorfinder.catacombs.impl.NormalModeDataProvider;
+import kr.syeyoung.dungeonsguide.mod.dungeon.doorfinder.catacombs.impl.MasterModeDataProvider;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.regex.Pattern;
+
+public class DungeonSpecificDataProviderRegistry {
+ public static final Map<Pattern, DungeonSpecificDataProvider> doorFinders = new HashMap<>();
+
+ static {
+ doorFinders.put(Pattern.compile("The Catacombs (?:F[0-9]|E)"), new NormalModeDataProvider());
+ doorFinders.put(Pattern.compile("The Catacombs (?:M[0-9])"), new MasterModeDataProvider());
+ }
+
+ public static DungeonSpecificDataProvider getDoorFinder(String dungeonName) {
+ for (Map.Entry<Pattern, DungeonSpecificDataProvider> doorFinderEntry :doorFinders.entrySet()){
+ if (doorFinderEntry.getKey().matcher(dungeonName).matches()) return doorFinderEntry.getValue();
+ }
+ return null;
+ }
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/doorfinder/EDungeonDoorType.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/doorfinder/EDungeonDoorType.java
new file mode 100644
index 00000000..05915a1a
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/doorfinder/EDungeonDoorType.java
@@ -0,0 +1,38 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.doorfinder;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+@AllArgsConstructor
+@Getter
+public enum EDungeonDoorType {
+ NONE(false, false, false,"?"), ENTRANCE(true, false, false, "entrance"),
+ WITHER(true, true,true,"withergate"),
+ WITHER_FAIRY(true, false,true,"wither-fairy-gate"),
+ BLOOD(true, true,true, "bloodgate"),
+ UNOPEN(true, false, false,"gate");
+
+
+ private final boolean exist;
+ private final boolean keyRequired;
+ private final boolean headToBlood;
+ private final String name;
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/doorfinder/catacombs/CatacombsDataProvider.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/doorfinder/catacombs/CatacombsDataProvider.java
new file mode 100644
index 00000000..b9052353
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/doorfinder/catacombs/CatacombsDataProvider.java
@@ -0,0 +1,75 @@
+package kr.syeyoung.dungeonsguide.mod.dungeon.doorfinder.catacombs;
+
+import com.google.common.collect.Sets;
+import kr.syeyoung.dungeonsguide.mod.dungeon.doorfinder.DungeonSpecificDataProvider;
+import net.minecraft.entity.item.EntityArmorStand;
+import net.minecraft.init.Blocks;
+import net.minecraft.util.BlockPos;
+import net.minecraft.world.World;
+import org.jetbrains.annotations.Nullable;
+
+import javax.vecmath.Vector2d;
+import java.util.Collection;
+import java.util.Set;
+
+public abstract class CatacombsDataProvider implements DungeonSpecificDataProvider {
+
+ private static final Set<Vector2d> directions = Sets.newHashSet(new Vector2d(0,1), new Vector2d(0, -1), new Vector2d(1, 0), new Vector2d(-1 , 0));
+
+ @Nullable
+ static Vector2d getVector2d(World w, Collection<EntityArmorStand> armorStand, Set<Vector2d> directions) {
+ EntityArmorStand mort = armorStand.iterator().next();
+ BlockPos pos = mort.getPosition();
+ pos = pos.add(0, 3, 0);
+ for (int i = 0; i < 5; i++) {
+ for (Vector2d vector2d: directions) {
+ BlockPos test = pos.add(vector2d.x * i, 0, vector2d.y * i);
+ if (w.getChunkFromBlockCoords(test).getBlock(test) == Blocks.iron_bars) {
+ return vector2d;
+ }
+ }
+ }
+ return null;
+ }
+
+ public static Collection<EntityArmorStand> getMorts(World w){
+ return w.getEntities(EntityArmorStand.class, input -> input.getName().equals("§bMort"));
+ }
+
+ /**
+ * This gets all morts checks for iron bars near him
+ * and based on iron bars determine the door location
+ *
+ * @param w World that we are going to look for the door in
+ * world is explicitly specified instead of mc.theWorld bc we can use cached worlds
+ * @param dungeonName dungeon type eg master mode, currently unused
+ * @return Block pos of the dungeon entrance
+ */
+ public BlockPos findDoor(World w, String dungeonName) {
+ Collection<EntityArmorStand> armorStand = getMorts(w);
+
+ if (!armorStand.isEmpty()) {
+ EntityArmorStand mort = armorStand.iterator().next();
+ BlockPos pos = mort.getPosition();
+ pos = pos.add(0, 3, 0);
+ for (int i = 0; i < 5; i++) {
+ for (Vector2d vector2d:directions) {
+ BlockPos test = pos.add(vector2d.x * i, 0, vector2d.y * i);
+ if (w.getChunkFromBlockCoords(test).getBlock(test) == Blocks.iron_bars) {
+ return pos.add(vector2d.x * (i + 2), -2, vector2d.y * (i+2));
+ }
+ }
+ }
+ }
+ return null;
+ }
+
+ public Vector2d findDoorOffset(World w, String dungeonName) {
+ Collection<EntityArmorStand> armorStand = getMorts(w);
+
+ if (!armorStand.isEmpty()) {
+ return getVector2d(w, armorStand, directions);
+ }
+ return null;
+ }
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/doorfinder/catacombs/impl/MasterModeDataProvider.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/doorfinder/catacombs/impl/MasterModeDataProvider.java
new file mode 100755
index 00000000..ab3f5df3
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/doorfinder/catacombs/impl/MasterModeDataProvider.java
@@ -0,0 +1,64 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.doorfinder.catacombs.impl;
+
+import kr.syeyoung.dungeonsguide.mod.chat.ChatTransmitter;
+import kr.syeyoung.dungeonsguide.mod.dungeon.doorfinder.catacombs.CatacombsDataProvider;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.bossfight.BossfightProcessor;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.bossfight.BossfightProcessorLivid;
+import net.minecraft.util.ChatComponentText;
+import net.minecraft.world.World;
+
+public class MasterModeDataProvider extends CatacombsDataProvider {
+
+
+ @Override
+ public BossfightProcessor createBossfightProcessor(World w, String dungeonName) {
+ String floor = dungeonName.substring(14).trim();
+ ChatTransmitter.sendDebugChat(new ChatComponentText("Floor: Master mode "+floor+ " Building bossfight processor"));
+ if (floor.equals("M5")) {
+ return new BossfightProcessorLivid(true);
+ }
+ return null;
+ }
+
+ @Override
+ public boolean isTrapSpawn(String dungeonName) {
+ String floor = dungeonName.substring(14).trim();
+ switch (floor) {
+ case "M3":
+ case "M4":
+ case "M5":
+ case "M6":
+ return true;
+ default:
+ return floor.equals("M7");
+ }
+ }
+
+ @Override
+ public double secretPercentage(String dungeonName) {
+ return 1.0;
+ }
+
+ @Override
+ public int speedSecond(String dungeonName) {
+ return 480;
+ }
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/doorfinder/catacombs/impl/NormalModeDataProvider.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/doorfinder/catacombs/impl/NormalModeDataProvider.java
new file mode 100755
index 00000000..880cf473
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/doorfinder/catacombs/impl/NormalModeDataProvider.java
@@ -0,0 +1,101 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.doorfinder.catacombs.impl;
+
+import kr.syeyoung.dungeonsguide.mod.chat.ChatTransmitter;
+import kr.syeyoung.dungeonsguide.mod.dungeon.doorfinder.catacombs.CatacombsDataProvider;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.bossfight.*;
+import net.minecraft.util.ChatComponentText;
+import net.minecraft.world.World;
+
+public class NormalModeDataProvider extends CatacombsDataProvider {
+
+
+ @Override
+ public BossfightProcessor createBossfightProcessor(World w, String dungeonName) {
+ String floor = dungeonName.substring(14).trim();
+ ChatTransmitter.sendDebugChat(new ChatComponentText("Floor: "+floor+ " Building bossfight processor"));
+ switch (floor) {
+ case "F1":
+ return new BossfightProcessorBonzo();
+ case "F2":
+ return new BossfightProcessorScarf();
+ case "F3":
+ return new BossfightProcessorProf();
+ case "F4":
+ return new BossfightProcessorThorn();
+ case "F5":
+ return new BossfightProcessorLivid(false);
+ case "F6":
+ return new BossfightProcessorSadan();
+ case "F7":
+ return new BossfightProcessorNecron();
+ default:
+ return null;
+ }
+ }
+
+ @Override
+ public boolean isTrapSpawn(String dungeonName) {
+ String floor = dungeonName.substring(14).trim();
+ switch (floor) {
+ case "F3":
+ case "F4":
+ case "F5":
+ case "F6":
+ return true;
+ default:
+ return floor.equals("F7");
+ }
+ }
+
+ @Override
+ public double secretPercentage(String dungeonName) {
+ String floor = dungeonName.substring(14).trim();
+ switch (floor) {
+ case "F1":
+ case "E":
+ return 0.3;
+ case "F2":
+ return 0.4;
+ case "F3":
+ return 0.5;
+ case "F4":
+ return 0.6;
+ case "F5":
+ return 0.7;
+ case "F6":
+ return 0.85;
+ default:
+ return 1.0;
+ }
+ }
+
+ @Override
+ public int speedSecond(String dungeonName) {
+ String floor = dungeonName.substring(14).trim();
+ switch (floor) {
+ case "F5":
+ case "F7":
+ return 720;
+ default:
+ return 600;
+ }
+ }
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/events/DungeonEvent.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/events/DungeonEvent.java
new file mode 100644
index 00000000..0e71a65e
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/events/DungeonEvent.java
@@ -0,0 +1,41 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.events;
+
+import kr.syeyoung.dungeonsguide.mod.features.FeatureRegistry;
+import lombok.Data;
+
+import java.io.Serializable;
+
+@Data
+public class DungeonEvent implements Serializable {
+ private long UTCTime = System.currentTimeMillis();
+ private long realTimeElapsed;
+ private long skyblockTimeElapsed;
+
+ private String eventName;
+ private DungeonEventData data;
+
+ public DungeonEvent(DungeonEventData eventData){
+ this.data = eventData;
+ this.realTimeElapsed = FeatureRegistry.DUNGEON_REALTIME.getTimeElapsed();
+ this.skyblockTimeElapsed = FeatureRegistry.DUNGEON_SBTIME.getTimeElapsed();
+ this.eventName = eventData.getEventName();
+ }
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/events/DungeonEventData.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/events/DungeonEventData.java
new file mode 100644
index 00000000..812e1488
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/events/DungeonEventData.java
@@ -0,0 +1,25 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.events;
+
+import java.io.Serializable;
+
+public interface DungeonEventData extends Serializable {
+ String getEventName();
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/events/DungeonEventHolder.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/events/DungeonEventHolder.java
new file mode 100644
index 00000000..58799f80
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/events/DungeonEventHolder.java
@@ -0,0 +1,32 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.events;
+
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.List;
+import java.util.Set;
+
+@Data
+public class DungeonEventHolder implements Serializable {
+ private long date;
+ private Set<String> players;
+ private List<DungeonEvent> eventDataList;
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/events/SerializableBlockPos.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/events/SerializableBlockPos.java
new file mode 100644
index 00000000..d70ba2c2
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/events/SerializableBlockPos.java
@@ -0,0 +1,38 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.events;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import net.minecraft.util.BlockPos;
+
+import java.io.Serializable;
+
+@Data @AllArgsConstructor
+public class SerializableBlockPos implements Serializable {
+ private int x;
+ private int y;
+ private int z;
+
+ public SerializableBlockPos(BlockPos pos) {
+ this.x = pos.getX();
+ this.y = pos.getY();
+ this.z = pos.getZ();
+ }
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/events/impl/DungeonCryptBrokenEvent.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/events/impl/DungeonCryptBrokenEvent.java
new file mode 100644
index 00000000..c2a4f71e
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/events/impl/DungeonCryptBrokenEvent.java
@@ -0,0 +1,35 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.events.impl;
+
+import kr.syeyoung.dungeonsguide.mod.dungeon.events.DungeonEventData;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+
+@Data
+@AllArgsConstructor
+public class DungeonCryptBrokenEvent implements DungeonEventData {
+ private int prevCrypts;
+ private int newCrypts;
+
+ @Override
+ public String getEventName() {
+ return "CRYPTS_CHANGE";
+ }
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/events/impl/DungeonDeathEvent.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/events/impl/DungeonDeathEvent.java
new file mode 100644
index 00000000..09877b80
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/events/impl/DungeonDeathEvent.java
@@ -0,0 +1,36 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.events.impl;
+
+import kr.syeyoung.dungeonsguide.mod.dungeon.events.DungeonEventData;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+
+@Data
+@AllArgsConstructor
+public class DungeonDeathEvent implements DungeonEventData {
+ private String playerName;
+ private String message;
+ private int cnt;
+
+ @Override
+ public String getEventName() {
+ return "PLAYER_DEATH";
+ }
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/events/impl/DungeonMapUpdateEvent.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/events/impl/DungeonMapUpdateEvent.java
new file mode 100644
index 00000000..023902c8
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/events/impl/DungeonMapUpdateEvent.java
@@ -0,0 +1,34 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.events.impl;
+
+import kr.syeyoung.dungeonsguide.mod.dungeon.events.DungeonEventData;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+
+@Data
+@AllArgsConstructor
+public class DungeonMapUpdateEvent implements DungeonEventData {
+ private byte[] map;
+
+ @Override
+ public String getEventName() {
+ return "MAP_UPDATE";
+ }
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/events/impl/DungeonNodataEvent.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/events/impl/DungeonNodataEvent.java
new file mode 100644
index 00000000..531f5990
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/events/impl/DungeonNodataEvent.java
@@ -0,0 +1,29 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.events.impl;
+
+import kr.syeyoung.dungeonsguide.mod.dungeon.events.DungeonEventData;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+
+@Data
+@AllArgsConstructor
+public class DungeonNodataEvent implements DungeonEventData {
+ private String eventName;
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/events/impl/DungeonPuzzleFailureEvent.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/events/impl/DungeonPuzzleFailureEvent.java
new file mode 100644
index 00000000..64621339
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/events/impl/DungeonPuzzleFailureEvent.java
@@ -0,0 +1,34 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.events.impl;
+
+import kr.syeyoung.dungeonsguide.mod.dungeon.events.DungeonEventData;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+
+@Data
+@AllArgsConstructor
+public class DungeonPuzzleFailureEvent implements DungeonEventData {
+ private String playerName;
+ private String message;
+ @Override
+ public String getEventName() {
+ return "PUZZLE_FAILURE";
+ }
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/events/impl/DungeonRoomDiscoverEvent.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/events/impl/DungeonRoomDiscoverEvent.java
new file mode 100644
index 00000000..09fd64a5
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/events/impl/DungeonRoomDiscoverEvent.java
@@ -0,0 +1,46 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.events.impl;
+
+import kr.syeyoung.dungeonsguide.mod.dungeon.events.DungeonEventData;
+import kr.syeyoung.dungeonsguide.mod.dungeon.events.SerializableBlockPos;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+
+import java.awt.*;
+import java.util.UUID;
+
+@Data
+@AllArgsConstructor
+public class DungeonRoomDiscoverEvent implements DungeonEventData {
+ private Point unitPt;
+ private int rotation;
+ private SerializableBlockPos min;
+ private SerializableBlockPos max;
+ private int shape;
+ private int color;
+ private UUID roomUID;
+ private String roomName;
+ private String roomProc;
+
+ @Override
+ public String getEventName() {
+ return "ROOM_DISCOVER";
+ }
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/events/impl/DungeonSecretCountChangeEvent.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/events/impl/DungeonSecretCountChangeEvent.java
new file mode 100644
index 00000000..21ea853c
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/events/impl/DungeonSecretCountChangeEvent.java
@@ -0,0 +1,37 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.events.impl;
+
+import kr.syeyoung.dungeonsguide.mod.dungeon.events.DungeonEventData;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+
+@Data
+@AllArgsConstructor
+public class DungeonSecretCountChangeEvent implements DungeonEventData {
+ private int prevCount;
+ private int newCount;
+ private int totalSecret;
+ private boolean sureTotalSecret;
+
+ @Override
+ public String getEventName() {
+ return "SECRET_CNT_CHANGE";
+ }
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/events/impl/DungeonStateChangeEvent.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/events/impl/DungeonStateChangeEvent.java
new file mode 100644
index 00000000..f1cb1167
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/events/impl/DungeonStateChangeEvent.java
@@ -0,0 +1,40 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.events.impl;
+
+import kr.syeyoung.dungeonsguide.mod.dungeon.events.DungeonEventData;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomfinder.DungeonRoom;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+
+import java.awt.*;
+
+@Data
+@AllArgsConstructor
+public class DungeonStateChangeEvent implements DungeonEventData {
+ private Point unitPt;
+ private String roomName;
+ private DungeonRoom.RoomState from;
+ private DungeonRoom.RoomState to;
+
+ @Override
+ public String getEventName() {
+ return "ROOM_STATE_CHANGE";
+ }
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/map/DungeonMapData.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/map/DungeonMapData.java
new file mode 100644
index 00000000..9687d554
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/map/DungeonMapData.java
@@ -0,0 +1,121 @@
+package kr.syeyoung.dungeonsguide.mod.dungeon.map;
+
+import com.google.common.collect.Sets;
+import kr.syeyoung.dungeonsguide.mod.chat.ChatTransmitter;
+import kr.syeyoung.dungeonsguide.mod.dungeon.DungeonContext;
+import kr.syeyoung.dungeonsguide.mod.dungeon.MapProcessor;
+import kr.syeyoung.dungeonsguide.mod.dungeon.doorfinder.DungeonSpecificDataProvider;
+import kr.syeyoung.dungeonsguide.mod.dungeon.doorfinder.DungeonSpecificDataProviderRegistry;
+import kr.syeyoung.dungeonsguide.mod.dungeon.events.impl.DungeonNodataEvent;
+import kr.syeyoung.dungeonsguide.mod.events.impl.DungeonContextInitializationEvent;
+import kr.syeyoung.dungeonsguide.mod.utils.MapUtils;
+import net.minecraft.client.Minecraft;
+import net.minecraft.util.BlockPos;
+import net.minecraft.util.ChatComponentText;
+import net.minecraftforge.common.MinecraftForge;
+
+import javax.vecmath.Vector2d;
+import java.awt.*;
+import java.util.Set;
+
+public class DungeonMapData {
+ private static final Set<Vector2d> directions = Sets.newHashSet(new Vector2d(0, 1), new Vector2d(0, -1), new Vector2d(1, 0), new Vector2d(-1, 0));
+ private static final Set<Vector2d> door_dirs = Sets.newHashSet(new Vector2d(0, 0.5), new Vector2d(0, -0.5), new Vector2d(0.5, 0), new Vector2d(-0.5, 0));
+ public Dimension unitRoomDimension;
+ public boolean bugged;
+ public Dimension doorDimensions;
+ public Point topLeftMapPoint;
+ private final DungeonContext context;
+ private final Minecraft mc;
+ public boolean initialized;
+
+ public DungeonMapData(DungeonContext context, Minecraft mc) {
+ this.context = context;
+ this.mc = mc;
+ }
+
+
+ public void eat(final byte[] mapData){
+ final Point firstRoom = MapUtils.findFirstColorWithIn(mapData, (byte) 30, new Rectangle(0, 0, 128, 128));
+ // Determine room dimension
+ int width = MapUtils.getWidthOfColorAt(mapData, (byte) 30, firstRoom);
+ int height = MapUtils.getHeightOfColorAt(mapData, (byte) 30, firstRoom);
+ unitRoomDimension = new Dimension(width, height);
+ Vector2d doorDir = null;
+ Point midfirstRoom = new Point(firstRoom.x + unitRoomDimension.width / 2, firstRoom.y + unitRoomDimension.height / 2);
+ final int halfWidth = unitRoomDimension.width / 2 + 2;
+ for (Vector2d v : directions) {
+ byte color = MapUtils.getMapColorAt(mapData, (int) (v.x * halfWidth + midfirstRoom.x), (int) (v.y * halfWidth + midfirstRoom.y));
+ if (color != 0) {
+ doorDir = v;
+ break;
+ }
+ }
+
+ if (doorDir == null) {
+ bugged = true;
+ return;
+ }
+
+ Point basePoint = new Point(firstRoom.x, firstRoom.y);
+ if (doorDir.x > 0) basePoint.x += unitRoomDimension.width;
+ if (doorDir.x < 0) basePoint.x -= 1;
+ if (doorDir.y > 0) basePoint.y += unitRoomDimension.height;
+ if (doorDir.y < 0) basePoint.y -= 1;
+ int gap = MapUtils.getLengthOfColorExtending(mapData, (byte) 0, basePoint, doorDir);
+ Point pt = MapUtils.findFirstColorWithInNegate(mapData, (byte) 0, new Rectangle(basePoint.x, basePoint.y, (int) Math.abs(doorDir.y) * unitRoomDimension.width + 1, (int) Math.abs(doorDir.x) * unitRoomDimension.height + 1));
+ if (pt == null) {
+ bugged = true;
+ return;
+ }
+ int doorWidth = MapUtils.getLengthOfColorExtending(mapData, MapUtils.getMapColorAt(mapData, pt.x, pt.y), pt, new Vector2d((int) Math.abs(doorDir.y), (int) Math.abs(doorDir.x)));
+ doorDimensions = new Dimension(doorWidth, gap);
+
+ // Determine Top Left
+ int topLeftX = firstRoom.x;
+ int topLeftY = firstRoom.y;
+ while (topLeftX >= unitRoomDimension.width + doorDimensions.height)
+ topLeftX -= unitRoomDimension.width + doorDimensions.height;
+ while (topLeftY >= unitRoomDimension.height + doorDimensions.height)
+ topLeftY -= unitRoomDimension.height + doorDimensions.height;
+ topLeftMapPoint = new Point(topLeftX, topLeftY);
+ // determine door location based on npc, and determine map min from there
+ DungeonSpecificDataProvider doorFinder = DungeonSpecificDataProviderRegistry.getDoorFinder(DungeonContext.getDungeonName());
+ if (doorFinder == null) {
+ bugged = true;
+ return;
+ }
+ BlockPos door = doorFinder.findDoor(mc.theWorld, DungeonContext.getDungeonName());
+ if (door == null) {
+ bugged = true;
+ return;
+ }
+
+ ChatTransmitter.sendDebugChat(new ChatComponentText("door Pos:" + door));
+
+ Point unitPoint = MapProcessor.mapPointToRoomPoint(firstRoom, topLeftMapPoint, unitRoomDimension, doorDimensions);
+ unitPoint.translate(unitPoint.x + 1, unitPoint.y + 1);
+ unitPoint.translate((int) doorDir.x, (int) doorDir.y);
+
+ Vector2d offset = doorFinder.findDoorOffset(mc.theWorld, DungeonContext.getDungeonName());
+ boolean axisMatch = doorDir.equals(offset);
+
+ int worldX = unitPoint.x * 16;
+ int worldY = unitPoint.y * 16;
+ BlockPos worldMin = door.add(-worldX, 0, -worldY);
+ context.setDungeonMin(worldMin);
+
+ ChatTransmitter.sendDebugChat(new ChatComponentText("Found Green room:" + firstRoom));
+ ChatTransmitter.sendDebugChat(new ChatComponentText("Axis match:" + axisMatch));
+ ChatTransmitter.sendDebugChat(new ChatComponentText("World Min:" + context.getDungeonMin()));
+ ChatTransmitter.sendDebugChat(new ChatComponentText("Dimension:" + unitRoomDimension));
+ ChatTransmitter.sendDebugChat(new ChatComponentText("top Left:" + topLeftMapPoint));
+ ChatTransmitter.sendDebugChat(new ChatComponentText("door dimension:" + doorDimensions));
+ context.createEvent(new DungeonNodataEvent("MAP_PROCESSOR_INIT"));
+ initialized = true;
+ MinecraftForge.EVENT_BUS.post(new DungeonContextInitializationEvent());
+
+
+ }
+
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/pathfinding/AStarCornerCut.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/pathfinding/AStarCornerCut.java
new file mode 100644
index 00000000..f6ac1777
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/pathfinding/AStarCornerCut.java
@@ -0,0 +1,189 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.pathfinding;
+
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomfinder.DungeonRoom;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+import net.minecraft.util.*;
+import net.minecraft.world.World;
+
+import java.util.*;
+
+public class AStarCornerCut {
+ private final BlockPos min, max;
+ private final World world;
+
+ int lastSx, lastSy, lastSz;
+ final int dx, dy, dz;
+ private DungeonRoom dungeonRoom;
+
+ @Getter
+ private AxisAlignedBB destinationBB;
+
+ public AStarCornerCut(DungeonRoom dungeonRoom, Vec3 destination) {
+ this.min = new BlockPos(dungeonRoom.getMinx(), 0, dungeonRoom.getMinz());
+ this.max = new BlockPos(dungeonRoom.getMaxx(), 255, dungeonRoom.getMaxz());
+
+ this.world = dungeonRoom.getCachedWorld();
+ this.dungeonRoom = dungeonRoom;
+
+ this.dx = (int) (destination.xCoord * 2);
+ this.dy = (int) (destination.yCoord * 2);
+ this.dz = (int) (destination.zCoord * 2);
+ destinationBB = AxisAlignedBB.fromBounds(dx-2, dy-2, dz-2, dx+2, dy+2, dz+2);
+ }
+
+ private Map<Node.Coordinate, Node> nodeMap = new HashMap<>();
+
+ private Node openNode(int x, int y, int z)
+ {
+ Node.Coordinate coordinate = new Node.Coordinate(x,y,z);
+ Node node = this.nodeMap.get(coordinate);
+
+ if (node == null)
+ {
+ node = new Node(coordinate);
+ this.nodeMap.put(coordinate, node);
+ }
+
+ return node;
+ }
+
+ @Getter
+ private LinkedList<Vec3> route = new LinkedList<>();
+
+ @Getter
+ private PriorityQueue<Node> open = new PriorityQueue<>(Comparator.comparing((Node a) -> a == null ? Float.MAX_VALUE : a.f).thenComparing(a -> a == null ? Float.MAX_VALUE : a.coordinate.x).thenComparing(a -> a == null ? Float.MAX_VALUE : a.coordinate.y).thenComparing(a -> a == null ? Float.MAX_VALUE : a.coordinate.z));
+
+ private int pfindIdx = 0;
+
+ public boolean pathfind(Vec3 from, long timeout) {
+ pfindIdx ++;
+ if (lastSx != (int)Math.round(from.xCoord * 2) || lastSy != (int)Math.round(from.yCoord*2) || lastSz != (int)Math.round(from.zCoord * 2))
+ open.clear();
+
+ this.lastSx = (int) Math.round(from.xCoord * 2);
+ this.lastSy = (int) Math.round(from.yCoord * 2);
+ this.lastSz = (int) Math.round(from.zCoord * 2);
+
+ Node startNode = openNode(dx, dy, dz);
+ Node goalNode = openNode(lastSx, lastSy, lastSz);
+
+ if (goalNode.parent != null) {
+ LinkedList<Vec3> route = new LinkedList<>();
+ Node curr =goalNode;
+ while(curr.parent != null) {
+ route.addLast(new Vec3(curr.coordinate.x / 2.0, curr.coordinate.y / 2.0 + 0.1, curr.coordinate.z/ 2.0));
+ curr = curr.parent;
+ }
+ route.addLast(new Vec3(curr.coordinate.x / 2.0, curr.coordinate.y / 2.0 + 0.1, curr.coordinate.z/ 2.0));
+ this.route = route;
+ return true;
+ }
+
+ startNode.g = 0;
+ startNode.f = 0;
+ goalNode.g = Integer.MAX_VALUE; goalNode.f = Integer.MAX_VALUE;
+
+
+ open.add(startNode);
+
+ long end = System.currentTimeMillis() + timeout;
+
+ while (!open.isEmpty()) {
+ if (System.currentTimeMillis() > end) {
+ return false;
+ }
+
+ Node n = open.poll();
+ if (n.lastVisited == pfindIdx) continue;
+ n.lastVisited = pfindIdx;
+
+ if (n == goalNode) {
+ // route = reconstructPath(startNode)
+ LinkedList<Vec3> route = new LinkedList<>();
+ Node curr =goalNode;
+ while(curr.parent != null) {
+ route.addLast(new Vec3(curr.coordinate.x / 2.0, curr.coordinate.y / 2.0 + 0.1, curr.coordinate.z/ 2.0));
+ curr = curr.parent;
+ }
+ route.addLast(new Vec3(curr.coordinate.x / 2.0, curr.coordinate.y / 2.0 + 0.1, curr.coordinate.z/ 2.0));
+ this.route = route;
+ return true;
+ }
+
+ for (int z = -1; z <= 1; z++) {for (int y = -1; y <= 1; y ++) { for(int x = -1; x <= 1; x++) {
+ if (x == 0 && y == 0 && z == 0) continue;
+ Node neighbor = openNode(n.coordinate.x +x, n.coordinate.y +y, n.coordinate.z + z);
+
+ // check blocked.
+ if (!((destinationBB.minX <= neighbor.coordinate.x && neighbor.coordinate.x <= destinationBB.maxX &&
+ destinationBB.minY <= neighbor.coordinate.y && neighbor.coordinate.y <= destinationBB.maxY &&
+ destinationBB.minZ <= neighbor.coordinate.z && neighbor.coordinate.z <= destinationBB.maxZ) // near destination
+ || !dungeonRoom.isBlocked(neighbor.coordinate.x, neighbor.coordinate.y, neighbor.coordinate.z))) { // not blocked
+ continue;
+ }
+ if (neighbor.lastVisited == pfindIdx) continue;
+
+
+ float gScore = n.g + MathHelper.sqrt_float(x*x + y*y + z*z); // altho it's sq, it should be fine
+ if (gScore < neighbor.g ) {
+ neighbor.parent = n;
+ neighbor.g = gScore;
+ neighbor.f = gScore + distSq(goalNode.coordinate.x - neighbor.coordinate.x, goalNode.coordinate.y - neighbor.coordinate.y, goalNode.coordinate.z - neighbor.coordinate.z);
+ open.add(neighbor);
+ } else if (neighbor.lastVisited != pfindIdx) {
+ neighbor.f = gScore + distSq(goalNode.coordinate.x - neighbor.coordinate.x, goalNode.coordinate.y - neighbor.coordinate.y, goalNode.coordinate.z - neighbor.coordinate.z);
+ open.add(neighbor);
+ }
+ }}}
+ }
+ return true;
+ }
+
+ private int manhatten(int x, int y, int z) {return Math.abs(x)+ Math.abs(y)+ Math.abs(z);}
+ private float distSq(float x, float y, float z) {
+ return MathHelper.sqrt_float(x * x + y * y + z * z);
+ }
+
+ @RequiredArgsConstructor
+ @Data
+ public static final class Node {
+ @Data
+ @RequiredArgsConstructor
+ public static final class Coordinate {
+ private final int x, y, z;
+ }
+ private final Coordinate coordinate;
+
+ private float f = Float.MAX_VALUE, g = Float.MAX_VALUE;
+ private int lastVisited;
+
+ @EqualsAndHashCode.Exclude
+ private Node parent;
+
+ public static long makeHash(int x, int y, int z)
+ {
+ return y & 32767L | ((short)x & 32767L) << 16 | ((short)z & 32767L) << 32;
+ }
+ }
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/pathfinding/AStarFineGrid.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/pathfinding/AStarFineGrid.java
new file mode 100644
index 00000000..8cb49a10
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/pathfinding/AStarFineGrid.java
@@ -0,0 +1,182 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.pathfinding;
+
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomfinder.DungeonRoom;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+import net.minecraft.util.*;
+import net.minecraft.world.World;
+
+import java.util.*;
+
+public class AStarFineGrid {
+ private final BlockPos min, max;
+ private final World world;
+
+ int lastSx, lastSy, lastSz;
+ final int dx, dy, dz;
+ private DungeonRoom dungeonRoom;
+
+ @Getter
+ private AxisAlignedBB destinationBB;
+
+ public AStarFineGrid(DungeonRoom dungeonRoom, Vec3 destination) {
+ this.min = new BlockPos(dungeonRoom.getMinx(), 0, dungeonRoom.getMinz());
+ this.max = new BlockPos(dungeonRoom.getMaxx(), 255, dungeonRoom.getMaxz());
+
+ this.world = dungeonRoom.getCachedWorld();
+ this.dungeonRoom = dungeonRoom;
+
+ this.dx = (int) (destination.xCoord * 2);
+ this.dy = (int) (destination.yCoord * 2);
+ this.dz = (int) (destination.zCoord * 2);
+ destinationBB = AxisAlignedBB.fromBounds(dx-2, dy-2, dz-2, dx+2, dy+2, dz+2);
+ }
+
+ private Map<Node.Coordinate, Node> nodeMap = new HashMap<>();
+
+ private Node openNode(int x, int y, int z)
+ {
+ Node.Coordinate coordinate = new Node.Coordinate(x,y,z);
+ Node node = this.nodeMap.get(coordinate);
+
+ if (node == null)
+ {
+ node = new Node(coordinate);
+ this.nodeMap.put(coordinate, node);
+ }
+
+ return node;
+ }
+
+ @Getter
+ private LinkedList<Vec3> route = new LinkedList<>();
+
+ @Getter
+ private PriorityQueue<Node> open = new PriorityQueue<>(Comparator.comparing((Node a) -> a == null ? Float.MAX_VALUE : a.f).thenComparing(a -> a == null ? Float.MAX_VALUE : a.coordinate.x).thenComparing(a -> a == null ? Float.MAX_VALUE : a.coordinate.y).thenComparing(a -> a == null ? Float.MAX_VALUE : a.coordinate.z));
+
+ private int pfindIdx = 0;
+
+ public boolean pathfind(Vec3 from, long timeout) {
+ pfindIdx ++;
+ if (lastSx != (int)Math.round(from.xCoord * 2) || lastSy != (int)Math.round(from.yCoord*2) || lastSz != (int)Math.round(from.zCoord * 2))
+ open.clear();
+
+ this.lastSx = (int) Math.round(from.xCoord * 2);
+ this.lastSy = (int) Math.round(from.yCoord * 2);
+ this.lastSz = (int) Math.round(from.zCoord * 2);
+
+ Node startNode = openNode(dx, dy, dz);
+ Node goalNode = openNode(lastSx, lastSy, lastSz);
+ startNode.g = 0;
+ startNode.f = 0;
+ goalNode.g = Integer.MAX_VALUE; goalNode.f = Integer.MAX_VALUE;
+ if (goalNode.parent != null) {
+ LinkedList<Vec3> route = new LinkedList<>();
+ Node curr =goalNode;
+ while(curr.parent != null) {
+ route.addLast(new Vec3(curr.coordinate.x / 2.0, curr.coordinate.y / 2.0 + 0.1, curr.coordinate.z/ 2.0));
+ curr = curr.parent;
+ }
+ route.addLast(new Vec3(curr.coordinate.x / 2.0, curr.coordinate.y / 2.0 + 0.1, curr.coordinate.z/ 2.0));
+ this.route = route;
+ return true;
+ }
+ open.add(startNode);
+
+ long end = System.currentTimeMillis() + timeout;
+
+ while (!open.isEmpty()) {
+ if (System.currentTimeMillis() > end) {
+ return false;
+ }
+
+ Node n = open.poll();
+ if (n.lastVisited == pfindIdx) continue;
+ n.lastVisited = pfindIdx;
+
+ if (n == goalNode) {
+ // route = reconstructPath(startNode)
+ LinkedList<Vec3> route = new LinkedList<>();
+ Node curr =goalNode;
+ while(curr.parent != null) {
+ route.addLast(new Vec3(curr.coordinate.x / 2.0, curr.coordinate.y / 2.0 + 0.1, curr.coordinate.z/ 2.0));
+ curr = curr.parent;
+ }
+ route.addLast(new Vec3(curr.coordinate.x / 2.0, curr.coordinate.y / 2.0 + 0.1, curr.coordinate.z/ 2.0));
+ this.route = route;
+ return true;
+ }
+
+ for (EnumFacing value : EnumFacing.VALUES) {
+ Node neighbor = openNode(n.coordinate.x + value.getFrontOffsetX(), n.coordinate.y + value.getFrontOffsetY(), n.coordinate.z + value.getFrontOffsetZ());
+
+ // check blocked.
+ if (!((destinationBB.minX <= neighbor.coordinate.x && neighbor.coordinate.x <= destinationBB.maxX &&
+ destinationBB.minY <= neighbor.coordinate.y && neighbor.coordinate.y <= destinationBB.maxY &&
+ destinationBB.minZ <= neighbor.coordinate.z && neighbor.coordinate.z <= destinationBB.maxZ) // near destination
+ || !dungeonRoom.isBlocked(neighbor.coordinate.x, neighbor.coordinate.y, neighbor.coordinate.z))) { // not blocked
+ continue;
+ }
+
+ float gScore = n.g + 1; // altho it's sq, it should be fine
+ if (gScore < neighbor.g) {
+ neighbor.parent = n;
+ neighbor.g = gScore;
+ neighbor.f = gScore + distSq(goalNode.coordinate.x - neighbor.coordinate.x, goalNode.coordinate.y - neighbor.coordinate.y, goalNode.coordinate.z - neighbor.coordinate.z);
+ open.add(neighbor);
+ } else if (neighbor.lastVisited != pfindIdx) {
+ neighbor.f = gScore + distSq(goalNode.coordinate.x - neighbor.coordinate.x, goalNode.coordinate.y - neighbor.coordinate.y, goalNode.coordinate.z - neighbor.coordinate.z);
+ open.add(neighbor);
+ }
+ }
+ }
+ return true;
+ }
+
+ private int manhatten(int x, int y, int z) {return Math.abs(x)+ Math.abs(y)+ Math.abs(z);}
+ private float distSq(float x, float y, float z) {
+ return MathHelper.sqrt_float(x * x + y * y + z * z);
+ }
+
+ @RequiredArgsConstructor
+ @Data
+ public static final class Node {
+ @Data
+ @RequiredArgsConstructor
+ public static final class Coordinate {
+ private final int x, y, z;
+ }
+ private final Coordinate coordinate;
+
+ private float f = Float.MAX_VALUE, g = Float.MAX_VALUE;
+ private int lastVisited;
+
+ @EqualsAndHashCode.Exclude
+ private Node parent;
+
+ public static long makeHash(int x, int y, int z)
+ {
+ return y & 32767L | ((short)x & 32767L) << 16 | ((short)z & 32767L) << 32;
+ }
+ }
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/pathfinding/CachedWorld.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/pathfinding/CachedWorld.java
new file mode 100644
index 00000000..9d9644c6
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/pathfinding/CachedWorld.java
@@ -0,0 +1,85 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.pathfinding;
+
+import net.minecraft.block.state.IBlockState;
+import net.minecraft.tileentity.TileEntity;
+import net.minecraft.util.BlockPos;
+import net.minecraft.util.EnumFacing;
+import net.minecraft.world.*;
+import net.minecraft.world.chunk.IChunkProvider;
+
+public class CachedWorld extends World {
+ private ChunkCache chunkCache;
+
+ public CachedWorld(ChunkCache chunkCache) {
+ super(null, null, new WorldProviderSurface(), null, true);
+ this.chunkCache = chunkCache;
+ }
+
+ @Override
+ protected IChunkProvider createChunkProvider() {
+ return null;
+ }
+
+ @Override
+ protected int getRenderDistanceChunks() {
+ return 999;
+ }
+
+ @Override
+ public boolean extendedLevelsInChunkCache() {
+ return chunkCache.extendedLevelsInChunkCache();
+ }
+
+ @Override
+ public TileEntity getTileEntity(BlockPos pos) {
+ return chunkCache.getTileEntity(pos);
+ }
+
+ @Override
+ public int getCombinedLight(BlockPos pos, int lightValue) {
+ return chunkCache.getCombinedLight(pos, lightValue);
+ }
+
+ @Override
+ public IBlockState getBlockState(BlockPos pos) {
+ return chunkCache.getBlockState(pos);
+ }
+
+ @Override
+ public int getLightFor(EnumSkyBlock type, BlockPos pos) {
+ return chunkCache.getLightFor(type, pos);
+ }
+
+ @Override
+ public boolean isAirBlock(BlockPos pos) {
+ return chunkCache.isAirBlock(pos);
+ }
+
+ @Override
+ public int getStrongPower(BlockPos pos, EnumFacing direction) {
+ return chunkCache.getStrongPower(pos, direction);
+ }
+
+ @Override
+ public boolean isSideSolid(BlockPos pos, EnumFacing side, boolean _default) {
+ return chunkCache.isSideSolid(pos, side, _default);
+ }
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/pathfinding/JPSPathfinder.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/pathfinding/JPSPathfinder.java
new file mode 100644
index 00000000..0a4e1b7d
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/pathfinding/JPSPathfinder.java
@@ -0,0 +1,306 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.pathfinding;
+
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomfinder.DungeonRoom;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+import net.minecraft.util.*;
+import net.minecraft.world.World;
+
+import java.util.*;
+
+public class JPSPathfinder {
+ private final BlockPos min, max;
+ private final World world;
+
+ private Vec3 start;
+ private Vec3 destination;
+ private DungeonRoom dungeonRoom;
+
+ @Getter
+ private AxisAlignedBB destinationBB;
+
+ public JPSPathfinder(DungeonRoom dungeonRoom){
+ this.min = new BlockPos(dungeonRoom.getMinx(), 0, dungeonRoom.getMinz());
+ this.max = new BlockPos(dungeonRoom.getMaxx(), 255, dungeonRoom.getMaxz());
+
+ this.world = dungeonRoom.getCachedWorld();
+ this.dungeonRoom = dungeonRoom;
+ }
+
+ private IntHashMap<Node> nodeMap = new IntHashMap();
+
+ private Node openNode(int x, int y, int z)
+ {
+ int i = Node.makeHash(x, y, z);
+ Node node = this.nodeMap.lookup(i);
+
+ if (node == null)
+ {
+ node = new Node(x, y, z);
+ this.nodeMap.addKey(i, node);
+ }
+
+ return node;
+ }
+
+ @Getter
+ private LinkedList<Vec3> route = new LinkedList<>();
+
+ @Getter
+ private PriorityQueue<Node> open = new PriorityQueue<>(Comparator.comparing((Node a) -> a == null ? Float.MAX_VALUE : a.f).thenComparing(a -> a == null ? Float.MAX_VALUE : a.x).thenComparing(a -> a == null ? Float.MAX_VALUE : a.y).thenComparing(a -> a == null ? Float.MAX_VALUE : a.z));
+
+ private int tx, ty, tz;
+
+ private Node addNode(Node parent, Node jumpPt, boolean addToOpen) {
+ float ng = parent.g + distSq(jumpPt.x - parent.x, jumpPt.y - parent.y, jumpPt.z - parent.z);
+
+ if (ng < jumpPt.g) {
+ if (addToOpen)
+ open.remove(jumpPt);
+ jumpPt.g = ng;
+ jumpPt.h = jumpPt.h == -1 ? distSq(tx - jumpPt.x, ty - jumpPt.y, tz - jumpPt.z) : jumpPt.h;
+ jumpPt.f = jumpPt.h + jumpPt.g;
+ jumpPt.parent = parent;
+ if (addToOpen)
+ open.add(jumpPt);
+ }
+ return jumpPt;
+ }
+
+
+ long arr[];
+
+ public boolean pathfind(Vec3 from, Vec3 to, float within, long timeout) {
+ route.clear(); nodeMap.clearMap();
+
+ {
+ from = new Vec3(((int)(from.xCoord * 2)) / 2.0, ((int)(from.yCoord * 2)) / 2.0, ((int)(from.zCoord* 2)) / 2.0);
+ to = new Vec3(((int)(to.xCoord * 2)) / 2.0, ((int)(to.yCoord * 2)) / 2.0, ((int)(to.zCoord* 2)) / 2.0);
+ }
+
+ this.start = from; this.destination = to;
+ tx = (int)(to.xCoord * 2);
+ ty = (int)(to.yCoord * 2);
+ tz = (int)(to.zCoord * 2);
+
+ destinationBB = AxisAlignedBB.fromBounds((to.xCoord - within)* 2, (to.yCoord - within) * 2, (to.zCoord - within) * 2, (to.xCoord + within) * 2, (to.yCoord + within)* 2, (to.zCoord + within) *2);
+ open.clear();
+ Node start;
+ open.add(start = openNode((int)from.xCoord * 2 + 1, (int)from.yCoord * 2, (int)from.zCoord * 2+1));
+ start.g = 0; start.f = 0; start.h = (float) from.squareDistanceTo(to);
+
+ Node end = null; float minDist = Float.MAX_VALUE;
+ long forceEnd = System.currentTimeMillis() + timeout + 999999999L;
+ while(!open.isEmpty()) {
+ if (forceEnd < System.currentTimeMillis() && timeout != -1) break;
+ Node n = open.poll();
+ n.closed= true;
+ if (minDist > n.h) {
+ minDist = n.h;
+ end = n;
+ }
+ if (n.x > destinationBB.minX && n.x < destinationBB.maxX && n.y > destinationBB.minY && n.y < destinationBB.maxY && n.z > destinationBB.minZ && n.z < destinationBB.maxZ) {
+ break;
+ }
+
+ for (Node neighbor : getNeighbors(n.parent == null ? n : n.parent, n)) {
+ Node jumpPT = expand(n.x, n.y, n.z, neighbor.x - n.x, neighbor.y - n.y, neighbor.z - n.z);
+ if (jumpPT == null || jumpPT.closed) continue;
+
+ addNode(n, jumpPT, true);
+ }
+ }
+
+ if (end == null) return false;
+ Node p = end;
+ while (p != null) {
+ route.addLast(new Vec3(p.x / 2.0f, p.y / 2.0f + 0.1, p.z / 2.0f));
+ p = p.parent;
+ }
+
+
+ return true;
+ }
+
+ private float distSq(float x, float y, float z) {
+ return MathHelper.sqrt_float(x * x + y * y + z * z);
+ }
+
+ public Set<Node> getNeighbors(Node prevN, Node n) {
+// if (true) throw new RuntimeException("ah");
+ int dx = MathHelper.clamp_int(n.x - prevN.x, -1, 1);
+ int dy = MathHelper.clamp_int(n.y - prevN.y, -1, 1);
+ int dz = MathHelper.clamp_int(n.z - prevN.z, -1, 1);
+ int x = n.x, y = n.y, z = n.z;
+ int nx = n.x + dx, ny = n.y + dy, nz = n.z + dz;
+
+ Set<Node> nexts = new HashSet<>();
+ int determinant = Math.abs(dx) + Math.abs(dy) + Math.abs(dz);
+ if (determinant == 0) {
+ for (int i = -1; i <= 1; i++)
+ for (int j = -1; j <= 1; j++)
+ for (int k = -1; k <= 1; k++) {
+ if (i == 0 && j == 0 && k == 0) continue;
+ nexts.add(openNode(x+i, y+j, z+k));
+ }
+ } else if (determinant == 1) {
+ nexts.add(openNode(nx,ny,nz));
+ for (int i = -1; i<=1; i++) {
+ for (int j = - 1; j<=1; j++) {
+ if (i == 0 && j == 0) continue;
+ if (dx != 0 && dungeonRoom.isBlocked(x, y + i, z + j)) nexts.add(openNode(nx,y+i,z+j));
+ if (dy != 0 && dungeonRoom.isBlocked(x + i, y, z + j)) nexts.add(openNode(x+i,ny,z+j));
+ if (dz != 0 && dungeonRoom.isBlocked(x + i, y + j, z)) nexts.add(openNode(x+i,y+j,nz));
+ }
+ }
+ } else if (determinant == 2) {
+ if (dz != 0) nexts.add(openNode(x,y,nz));
+ if (dy != 0) nexts.add(openNode(x,ny,z));
+ if (dx != 0) nexts.add(openNode(nx,y,z));
+ nexts.add(openNode(nx,ny,nz));
+ if (dx == 0) {
+ if (dungeonRoom.isBlocked(x, y, z-dz)) {
+ nexts.add(openNode(x, ny, z-dz));
+ if (dungeonRoom.isBlocked(x+1, y, z-dz)) nexts.add(openNode(x+1, ny, z-dz));
+ if (dungeonRoom.isBlocked(x-1, y, z-dz)) nexts.add(openNode(x-1, ny, z-dz));
+ }
+ if (dungeonRoom.isBlocked(x, y-dy, z)) {
+ nexts.add(openNode(x, y-dy, nz));
+ if (dungeonRoom.isBlocked(x+1, y-dy, z)) nexts.add(openNode(x+1, y-dy, nz));
+ if (dungeonRoom.isBlocked(x-1, y-dy, z)) nexts.add(openNode(x+1, y-dy, nz));
+ }
+ } else if (dy == 0) {
+ if (dungeonRoom.isBlocked(x, y, z-dz)) {
+ nexts.add(openNode(nx, y, z-dz));
+ if (dungeonRoom.isBlocked(x, y+1, z-dz)) nexts.add(openNode(nx, y+1, z-dz));
+ if (dungeonRoom.isBlocked(x, y-1, z-dz)) nexts.add(openNode(nx, y-1, z-dz));
+ }
+ if (dungeonRoom.isBlocked(x-dx, y, z)) {
+ nexts.add(openNode(x-dx, y, nz));
+ if (dungeonRoom.isBlocked(x-dx, y+1, z)) nexts.add(openNode(x-dx, y+1, nz));
+ if (dungeonRoom.isBlocked(x-dx, y-1, z)) nexts.add(openNode(x-dx, y-1, nz));
+ }
+ } else if (dz == 0) {
+ if (dungeonRoom.isBlocked(x, y-dy, z)) {
+ nexts.add(openNode(nx, y-dy, z));
+ if (dungeonRoom.isBlocked(x, y-dy, z+1)) nexts.add(openNode(nx, y-dy, z+1));
+ if (dungeonRoom.isBlocked(x, y-dy, z-1)) nexts.add(openNode(nx, y-dy, z-1));
+ }
+ if (dungeonRoom.isBlocked(x-dx, y, z)) {
+ nexts.add(openNode(x-dx, ny, z));
+ if (dungeonRoom.isBlocked(x-dx, y, z+1)) nexts.add(openNode(x-dx, ny, z+1));
+ if (dungeonRoom.isBlocked(x-dx, y, z-1)) nexts.add(openNode(x-dx, ny, z-1));
+ }
+ }
+ } else if (determinant == 3) {
+ nexts.add(openNode(x,y,nz));
+ nexts.add(openNode(x,ny,z));
+ nexts.add(openNode(nx,y,z));
+ nexts.add(openNode(nx,y,nz));
+ nexts.add(openNode(x,ny,nz));
+ nexts.add(openNode(nx,ny,z));
+ nexts.add(openNode(nx,ny,nz));
+
+ if (dungeonRoom.isBlocked(x,y,z-dz)) {
+ nexts.add(openNode(x,ny,z-dz));
+ nexts.add(openNode(nx,ny,z-dz));
+ nexts.add(openNode(nx,y,z-dz));
+ }
+ if (dungeonRoom.isBlocked(x-dx,y,z)) {
+ nexts.add(openNode(x-dx,ny,nz));
+ nexts.add(openNode(x-dx,ny,z));
+ nexts.add(openNode(x-dx,y,nz));
+ }
+ if (dungeonRoom.isBlocked(x,y-dy,z)) {
+ nexts.add(openNode(x,y-dy,nz));
+ nexts.add(openNode(nx,y-dy,z));
+ nexts.add(openNode(nx,y-dy,nz));
+ }
+ }
+ return nexts;
+ }
+
+ public Node expand(int x, int y, int z, int dx, int dy, int dz) {
+ while(true) {
+ int nx = x + dx, ny = y + dy, nz = z + dz;
+ if (dungeonRoom.isBlocked(nx, ny, nz)) return null;
+
+ if (nx > destinationBB.minX && nx < destinationBB.maxX && ny > destinationBB.minY && ny < destinationBB.maxY && nz > destinationBB.minZ && nz < destinationBB.maxZ) return openNode(nx,ny,nz);
+
+ int determinant = Math.abs(dx) + Math.abs(dy) + Math.abs(dz);
+ if (determinant == 1) {
+ for (int i = -1; i<=1; i++) {
+ for (int j = - 1; j<=1; j++) {
+ if (i == 0 && j == 0) continue;
+ if (dx != 0 && dungeonRoom.isBlocked(nx, ny + i, nz + j) && !dungeonRoom.isBlocked(nx+dx, ny + i, nz + j)) return openNode(nx,ny,nz);
+ if (dy != 0 && dungeonRoom.isBlocked(nx + i, ny, nz + j) && !dungeonRoom.isBlocked(nx + i, ny+dy, nz + j)) return openNode(nx,ny,nz);
+ if (dz != 0 && dungeonRoom.isBlocked(nx + i, ny + j , nz) && !dungeonRoom.isBlocked(nx + i, ny + j , nz+dz)) return openNode(nx,ny,nz);
+ }
+ }
+ } else if (determinant == 2) {
+ for (EnumFacing value : EnumFacing.VALUES) {
+ if (value.getFrontOffsetX() == dx || value.getFrontOffsetY() == dy || value.getFrontOffsetZ() == dz) continue;
+ int tx = nx + value.getFrontOffsetX();
+ int ty = ny + value.getFrontOffsetY();
+ int tz = nz + value.getFrontOffsetZ();
+ if (dungeonRoom.isBlocked(tx, ty, tz)) return openNode(nx, ny, nz);
+ }
+ if (dx != 0 && expand(nx, ny, nz, dx, 0,0) != null) return openNode(nx,ny,nz);
+ if (dy != 0 && expand(nx, ny, nz, 0, dy,0) != null) return openNode(nx,ny,nz);
+ if (dz != 0 && expand(nx, ny, nz, 0, 0,dz) != null) return openNode(nx,ny,nz);
+ } else if (determinant == 3) {
+ if (dungeonRoom.isBlocked(x, ny, nz ) || dungeonRoom.isBlocked(nx, y , nz) || dungeonRoom.isBlocked(nx, ny, z)) return openNode(nx,ny,nz);
+ if (expand(nx, ny, nz, dx, 0, 0) != null ||
+ expand(nx, ny, nz, dx, dy, 0) != null ||
+ expand(nx, ny, nz, dx, 0, dz) != null ||
+ expand(nx, ny, nz, 0, dy, 0) != null ||
+ expand(nx, ny, nz, 0, dy, dz) != null ||
+ expand(nx, ny, nz, 0, 0, dz) != null) return openNode(nx,ny,nz);
+ }
+ x = nx; y = ny; z = nz;
+ }
+ }
+
+ @RequiredArgsConstructor
+ @Data
+ public static final class Node {
+ private final int x, y, z;
+
+ private float f, g = Float.MAX_VALUE, h = -1;
+ private boolean closed;
+
+ @EqualsAndHashCode.Exclude
+ private Node parent;
+
+ public static int makeHash(int x, int y, int z)
+ {
+ return y & 255 | (x & 32767) << 8 | (z & 32767) << 24 | (x < 0 ? Integer.MIN_VALUE : 0) | (z < 0 ? 32768 : 0);
+ }
+
+ public Node close() {
+ this.closed = true;
+ return this;
+ }
+
+ }
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/pathfinding/NodeProcessorDungeonRoom.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/pathfinding/NodeProcessorDungeonRoom.java
new file mode 100644
index 00000000..cdce6cf4
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/pathfinding/NodeProcessorDungeonRoom.java
@@ -0,0 +1,144 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.pathfinding;
+
+import com.google.common.collect.Sets;
+import kr.syeyoung.dungeonsguide.mod.DungeonsGuide;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomfinder.DungeonRoom;
+import net.minecraft.block.Block;
+import net.minecraft.block.state.IBlockState;
+import net.minecraft.entity.Entity;
+import net.minecraft.init.Blocks;
+import net.minecraft.pathfinding.PathPoint;
+import net.minecraft.util.BlockPos;
+import net.minecraft.util.EnumFacing;
+import net.minecraft.util.Vec3i;
+import net.minecraft.world.World;
+import net.minecraft.world.pathfinder.NodeProcessor;
+
+import java.util.Set;
+
+public class NodeProcessorDungeonRoom extends NodeProcessor {
+ private final DungeonRoom dungeonRoom;
+ private final BlockPos sub;
+
+ public NodeProcessorDungeonRoom(DungeonRoom dungeonRoom) {
+ this.dungeonRoom = dungeonRoom;
+ sub = dungeonRoom.getMax().subtract(dungeonRoom.getMin());
+ }
+
+ @Override
+ public PathPoint getPathPointTo(Entity entityIn) {
+ return openPoint((int) entityIn.posX - dungeonRoom.getMin().getX(), (int) entityIn.posY - dungeonRoom.getMin().getY(),
+ (int) entityIn.posZ - dungeonRoom.getMin().getZ());
+ }
+
+ @Override
+ public PathPoint getPathPointToCoords(Entity entityIn, double x, double y, double z) {
+ return openPoint((int) x - dungeonRoom.getMin().getX(), (int) y - dungeonRoom.getMin().getY(),
+ (int) z - dungeonRoom.getMin().getZ());
+ }
+
+ private static final EnumFacing[] values2 = new EnumFacing[] {
+ EnumFacing.DOWN, EnumFacing.NORTH, EnumFacing.SOUTH, EnumFacing.EAST, EnumFacing.WEST, EnumFacing.UP
+ };
+
+
+
+ @Override
+ public int findPathOptions(PathPoint[] pathOptions, Entity entityIn, PathPoint currentPoint, PathPoint targetPoint, float maxDistance) {
+
+ int i = 0;
+ for (EnumFacing ef : values2) {
+ Vec3i dir = ef.getDirectionVec();
+ int newX = currentPoint.xCoord + dir.getX();
+ int newY = currentPoint.yCoord + dir.getY();
+ int newZ = currentPoint.zCoord + dir.getZ();
+
+ if (newX < 0 || newZ < 0) continue;
+ if (newX > sub.getX() || newZ > sub.getZ()) continue;
+
+ BlockPos add1 = dungeonRoom.getMin().add(newX, newY, newZ);
+ World playerWorld = entityIn.getEntityWorld();
+
+ IBlockState curr = DungeonsGuide.getDungeonsGuide().getBlockCache().getBlockState(add1);
+
+
+ IBlockState up = DungeonsGuide.getDungeonsGuide().getBlockCache().getBlockState(dungeonRoom.getMin().add(newX, newY + 1, newZ));
+
+ if (isValidBlock(curr) && isValidBlock(up)) {
+ PathPoint pt = openPoint(newX, newY, newZ);
+ if (pt.visited) continue;
+ pathOptions[i++] = pt;
+ continue;
+ }
+
+ if (curr.getBlock() == Blocks.air) {
+ if (up.getBlock() == Blocks.stone_slab
+ || up.getBlock() == Blocks.wooden_slab
+ || up.getBlock() == Blocks.stone_slab2) {
+ IBlockState up2 = DungeonsGuide.getDungeonsGuide().getBlockCache().getBlockState(dungeonRoom.getMin().add(newX, newY - 1, newZ));
+ if (up2.getBlock() == Blocks.stone_slab
+ || up2.getBlock() == Blocks.wooden_slab
+ || up2.getBlock() == Blocks.stone_slab2) {
+ PathPoint pt = openPoint(newX, newY, newZ);
+ if (pt.visited) continue;
+ pathOptions[i++] = pt;
+ continue;
+ }
+ }
+ }
+
+ if (dir.getY() == 0
+ && curr.getBlock() == Blocks.iron_bars
+ && up.getBlock() == Blocks.air
+ && DungeonsGuide.getDungeonsGuide().getBlockCache().getBlockState(new BlockPos(currentPoint.xCoord, currentPoint.yCoord, currentPoint.zCoord)).getBlock() != Blocks.iron_bars) {
+
+ boolean theFlag = false;
+ if (dir.getZ() == 0) {
+ if (DungeonsGuide.getDungeonsGuide().getBlockCache().getBlockState(
+ add1.add(0, 0, 1)).getBlock() == Blocks.air ||
+ DungeonsGuide.getDungeonsGuide().getBlockCache().getBlockState(add1.add(0, 0, -1)).getBlock() == Blocks.air) {
+ theFlag = true;
+ }
+ } else if (dir.getX() == 0) {
+ if (DungeonsGuide.getDungeonsGuide().getBlockCache().getBlockState(add1.add(-1, 0, 0)).getBlock() == Blocks.air ||
+ DungeonsGuide.getDungeonsGuide().getBlockCache().getBlockState(add1.add(1, 0, 0)).getBlock() == Blocks.air) {
+ theFlag = true;
+ }
+ }
+ if (theFlag) {
+ PathPoint pt = openPoint(newX, newY, newZ);
+ if (pt.visited) continue;
+ pathOptions[i++] = pt;
+ }
+ }
+ }
+ return i;
+ }
+
+ public static final Set<Block> allowed = Sets.newHashSet(Blocks.air, Blocks.water, Blocks.lava, Blocks.flowing_water, Blocks.flowing_lava, Blocks.vine, Blocks.ladder
+ , Blocks.standing_sign, Blocks.wall_sign, Blocks.trapdoor, Blocks.iron_trapdoor, Blocks.wooden_button, Blocks.stone_button, Blocks.fire,
+ Blocks.torch, Blocks.rail, Blocks.golden_rail, Blocks.activator_rail, Blocks.detector_rail, Blocks.carpet, Blocks.redstone_torch);
+ public static final IBlockState preBuilt = Blocks.stone.getStateFromMeta(2);
+
+ public static boolean isValidBlock(IBlockState state) {
+ return state.equals(preBuilt) || allowed.contains(state.getBlock());
+ }
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/pathfinding/ThetaStar.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/pathfinding/ThetaStar.java
new file mode 100644
index 00000000..4a4cf786
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/pathfinding/ThetaStar.java
@@ -0,0 +1,209 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.pathfinding;
+
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomfinder.DungeonRoom;
+import lombok.*;
+import net.minecraft.util.*;
+import net.minecraft.world.World;
+
+import java.util.*;
+
+public class ThetaStar {
+ private final BlockPos min, max;
+ private final World world;
+
+ int lastSx, lastSy, lastSz;
+ final int dx, dy, dz;
+ private DungeonRoom dungeonRoom;
+
+ @Getter
+ private AxisAlignedBB destinationBB;
+
+ public ThetaStar(DungeonRoom dungeonRoom, Vec3 destination) {
+ this.min = new BlockPos(dungeonRoom.getMinx(), 0, dungeonRoom.getMinz());
+ this.max = new BlockPos(dungeonRoom.getMaxx(), 255, dungeonRoom.getMaxz());
+
+ this.world = dungeonRoom.getCachedWorld();
+ this.dungeonRoom = dungeonRoom;
+
+ this.dx = (int) (destination.xCoord * 2);
+ this.dy = (int) (destination.yCoord * 2);
+ this.dz = (int) (destination.zCoord * 2);
+ destinationBB = AxisAlignedBB.fromBounds(dx-2, dy-2, dz-2, dx+2, dy+2, dz+2);
+ }
+
+ private Map<Node.Coordinate, Node> nodeMap = new HashMap<>();
+
+ private Node openNode(int x, int y, int z)
+ {
+ Node.Coordinate coordinate = new Node.Coordinate(x,y,z);
+ Node node = this.nodeMap.get(coordinate);
+
+ if (node == null)
+ {
+ node = new Node(coordinate);
+ this.nodeMap.put(coordinate, node);
+ }
+
+ return node;
+ }
+
+ @Getter
+ private LinkedList<Vec3> route = new LinkedList<>();
+
+ @Getter
+ private PriorityQueue<Node> open = new PriorityQueue<>(Comparator.comparing((Node a) -> a == null ? Float.MAX_VALUE : a.f).thenComparing(a -> a == null ? Float.MAX_VALUE : a.coordinate.x).thenComparing(a -> a == null ? Float.MAX_VALUE : a.coordinate.y).thenComparing(a -> a == null ? Float.MAX_VALUE : a.coordinate.z));
+
+ private int pfindIdx = 0;
+
+ public boolean pathfind(Vec3 from, long timeout) {
+
+ pfindIdx ++;
+ if (lastSx != (int)Math.round(from.xCoord * 2) || lastSy != (int)Math.round(from.yCoord*2) || lastSz != (int)Math.round(from.zCoord * 2))
+ open.clear();
+
+ this.lastSx = (int) Math.round(from.xCoord * 2);
+ this.lastSy = (int) Math.round(from.yCoord * 2);
+ this.lastSz = (int) Math.round(from.zCoord * 2);
+ if (dungeonRoom.isBlocked(lastSx, lastSy, lastSz)) return false;
+
+ Node startNode = openNode(dx, dy, dz);
+ Node goalNode = openNode(lastSx, lastSy, lastSz);
+ startNode.g = 0;
+ startNode.f = 0;
+ goalNode.g = Integer.MAX_VALUE; goalNode.f = Integer.MAX_VALUE;
+ if (goalNode.parent != null) {
+ LinkedList<Vec3> route = new LinkedList<>();
+ Node curr =goalNode;
+ while(curr.parent != null) {
+ route.addLast(new Vec3(curr.coordinate.x / 2.0, curr.coordinate.y / 2.0 + 0.1, curr.coordinate.z/ 2.0));
+ curr = curr.parent;
+ }
+ route.addLast(new Vec3(curr.coordinate.x / 2.0, curr.coordinate.y / 2.0 + 0.1, curr.coordinate.z/ 2.0));
+ this.route = route;
+ return true;
+ }
+ open.add(startNode);
+
+ long end = System.currentTimeMillis() + timeout;
+
+ while (!open.isEmpty()) {
+ if (System.currentTimeMillis() > end) {
+ return false;
+ }
+ Node n = open.poll();
+ if (n.lastVisited == pfindIdx) continue;
+ n.lastVisited = pfindIdx;
+
+ if (n == goalNode) {
+ // route = reconstructPath(startNode)
+ LinkedList<Vec3> route = new LinkedList<>();
+ Node curr =goalNode;
+ while(curr.parent != null) {
+ route.addLast(new Vec3(curr.coordinate.x / 2.0, curr.coordinate.y / 2.0 + 0.1, curr.coordinate.z/ 2.0));
+ curr = curr.parent;
+ }
+ route.addLast(new Vec3(curr.coordinate.x / 2.0, curr.coordinate.y / 2.0 + 0.1, curr.coordinate.z/ 2.0));
+ this.route = route;
+ return true;
+ }
+
+ for (EnumFacing value : EnumFacing.VALUES) {
+ Node neighbor = openNode(n.coordinate.x + value.getFrontOffsetX(), n.coordinate.y + value.getFrontOffsetY(), n.coordinate.z + value.getFrontOffsetZ());
+
+ // check blocked.
+ if (!((destinationBB.minX <= neighbor.coordinate.x && neighbor.coordinate.x <= destinationBB.maxX &&
+ destinationBB.minY <= neighbor.coordinate.y && neighbor.coordinate.y <= destinationBB.maxY &&
+ destinationBB.minZ <= neighbor.coordinate.z && neighbor.coordinate.z <= destinationBB.maxZ) // near destination
+ || !dungeonRoom.isBlocked(neighbor.coordinate.x, neighbor.coordinate.y, neighbor.coordinate.z))) { // not blocked
+ continue;
+ }
+ if (neighbor.lastVisited == pfindIdx) continue;
+
+ boolean flag = false;
+ if (n. parent != null) {
+ float tempGScore = n.parent.g + distSq(n.parent.coordinate.x - neighbor.coordinate.x, n.parent.coordinate.y - neighbor.coordinate.y, n.parent.coordinate.z - neighbor.coordinate.z);
+ if (tempGScore < neighbor.g && lineofsight(n.parent, neighbor)) {
+ neighbor.parent = n.parent;
+ neighbor.g = tempGScore;
+ neighbor.f = tempGScore + distSq(goalNode.coordinate.x - neighbor.coordinate.x, goalNode.coordinate.y - neighbor.coordinate.y, goalNode.coordinate.z - neighbor.coordinate.z);
+ open.add(neighbor);
+ flag = true;
+ }
+ }
+ if (!flag) {
+ float gScore = n.g + 1; // altho it's sq, it should be fine
+ if (gScore < neighbor.g) {
+ neighbor.parent = n;
+ neighbor.g = gScore;
+ neighbor.f = gScore +distSq(goalNode.coordinate.x - neighbor.coordinate.x, goalNode.coordinate.y - neighbor.coordinate.y, goalNode.coordinate.z - neighbor.coordinate.z);
+ open.add(neighbor);
+ } else if (neighbor.lastVisited != pfindIdx) {
+ neighbor.f = neighbor.g + distSq(goalNode.coordinate.x - neighbor.coordinate.x, goalNode.coordinate.y - neighbor.coordinate.y, goalNode.coordinate.z - neighbor.coordinate.z);
+ open.add(neighbor);
+ }
+ }
+ }
+ }
+ return true;
+ }
+
+ private boolean lineofsight(Node a, Node b) {
+ if (a == null || b == null) return false;
+ float sx = a.coordinate.x, sy = a.coordinate.y, sz = a.coordinate.z;
+ int ex = b.coordinate.x, ey = b.coordinate.y, ez = b.coordinate.z;
+
+ float dx = ex - sx, dy = ey - sy, dz = ez - sz;
+ float len = distSq(dx, dy, dz);
+ dx /= len; dy /= len; dz /= len;
+
+ for (int d = 0; d <= len; d += 1) {
+ if (dungeonRoom.isBlocked(Math.round(sx), (int) Math.ceil(sy), Math.round(sz))) return false;
+ if (dungeonRoom.isBlocked(Math.round(sx)+1, (int) Math.ceil(sy), Math.round(sz)+1)) return false;
+ if (dungeonRoom.isBlocked(Math.round(sx)-1, (int) Math.ceil(sy), Math.round(sz)-1)) return false;
+ if (dungeonRoom.isBlocked(Math.round(sx)+1, (int) Math.ceil(sy), Math.round(sz)-1)) return false;
+ if (dungeonRoom.isBlocked(Math.round(sx)-1, (int) Math.ceil(sy), Math.round(sz)+1)) return false;
+ sx += dx; sy += dy; sz += dz;
+ }
+ return true;
+ }
+
+ private int manhatten(int x, int y, int z) {return Math.abs(x)+ Math.abs(y)+ Math.abs(z);}
+ private float distSq(float x, float y, float z) {
+ return MathHelper.sqrt_float(x * x + y * y + z * z);
+ }
+
+ @Data
+ public static final class Node {
+ @Data
+ public static final class Coordinate {
+ private final int x, y, z;
+ }
+
+ private final Coordinate coordinate;
+
+ private float f = Float.MAX_VALUE, g = Float.MAX_VALUE;
+ private int lastVisited;
+
+ @EqualsAndHashCode.Exclude
+ @ToString.Exclude
+ private Node parent;
+ }
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/EditingContext.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/EditingContext.java
new file mode 100755
index 00000000..8f5fec3f
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/EditingContext.java
@@ -0,0 +1,83 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.roomedit;
+
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomfinder.DungeonRoom;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomedit.gui.GuiDungeonRoomEdit;
+import lombok.Getter;
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.gui.GuiScreen;
+
+import java.util.Stack;
+
+public class EditingContext {
+
+ private static EditingContext editingContext;
+
+ public static void createEditingContext(DungeonRoom dungeonRoom) {
+ editingContext = new EditingContext(dungeonRoom);
+ }
+
+ public static EditingContext getEditingContext() {
+ return editingContext;
+ }
+
+ public static void endEditingSession() {
+ editingContext = null;
+ Minecraft.getMinecraft().displayGuiScreen(null);
+ }
+
+
+ private EditingContext(DungeonRoom dungeonRoom) {
+ this.room = dungeonRoom;
+ }
+
+ @Getter
+ private final DungeonRoom room;
+
+ @Getter
+ private final Stack<GuiScreen> guiStack = new Stack<GuiScreen>();
+
+ public boolean isEditingSecrets() {
+ return guiDungeonRoomEdit.isEditingSelected();
+ }
+ public void endEditing() {
+ guiDungeonRoomEdit.endEditing();
+ }
+
+ private GuiDungeonRoomEdit guiDungeonRoomEdit;
+ @Getter
+ private GuiScreen current;
+
+ public void openGui(GuiScreen gui) {
+ if (gui instanceof GuiDungeonRoomEdit) guiDungeonRoomEdit = (GuiDungeonRoomEdit) gui;
+ guiStack.push(current);
+ this.current = gui;
+ Minecraft.getMinecraft().displayGuiScreen(gui);
+ }
+
+ public void goBack() {
+ current = guiStack.pop();
+ Minecraft.getMinecraft().displayGuiScreen(current);
+ }
+
+ public void reopen() {
+ Minecraft.getMinecraft().displayGuiScreen(current);
+ }
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/Parameter.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/Parameter.java
new file mode 100755
index 00000000..850cbe11
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/Parameter.java
@@ -0,0 +1,39 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.roomedit;
+
+import lombok.Data;
+
+@Data
+public class Parameter {
+ private String name;
+ private Object previousData;
+ private Object newData;
+
+ public Parameter(String name, Object previousData, Object newData) {
+ this.name = name; this.previousData = previousData; this.newData = newData;
+ }
+
+ private Runnable onSetNewData;
+
+ public void setNewData(Object newData) {
+ this.newData = newData;
+ if (onSetNewData != null) onSetNewData.run();
+ }
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/gui/GuiDungeonAddSet.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/gui/GuiDungeonAddSet.java
new file mode 100755
index 00000000..4e4b5da4
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/gui/GuiDungeonAddSet.java
@@ -0,0 +1,136 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.roomedit.gui;
+
+import kr.syeyoung.dungeonsguide.dungeon.data.OffsetPoint;
+import kr.syeyoung.dungeonsguide.mod.gui.MGui;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomedit.EditingContext;
+import kr.syeyoung.dungeonsguide.mod.gui.elements.*;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomedit.valueedit.ValueEditOffsetPointSet;
+import kr.syeyoung.dungeonsguide.mod.utils.RenderUtils;
+import lombok.Getter;
+import net.minecraft.client.Minecraft;
+
+import java.awt.*;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+public class GuiDungeonAddSet extends MGui {
+
+ private final ValueEditOffsetPointSet valueEditOffsetPointSet;
+
+ private final MButton add;
+ private final MButton back;
+
+
+ @Getter
+ private final OffsetPoint start;
+ @Getter
+ private final OffsetPoint end;
+
+ public void onWorldRender(float partialTicks) {
+ for (OffsetPoint pos:getBlockPoses()) {
+ RenderUtils.highlightBlock(pos.getBlockPos(EditingContext.getEditingContext().getRoom()), new Color(0,255,255,50), partialTicks);
+ }
+ RenderUtils.highlightBlock(start.getBlockPos(EditingContext.getEditingContext().getRoom()), new Color(255,0,0,100), partialTicks);
+ RenderUtils.highlightBlock(end.getBlockPos(EditingContext.getEditingContext().getRoom()), new Color(0,255,0,100), partialTicks);
+ }
+
+ public List<OffsetPoint> getBlockPoses() {
+ int minX = Math.min(start.getX(), end.getX());
+ int minY = Math.min(start.getY(), end.getY());
+ int minZ = Math.min(start.getZ(), end.getZ());
+ int maxX = Math.max(start.getX(), end.getX());
+ int maxY = Math.max(start.getY(), end.getY());
+ int maxZ = Math.max(start.getZ(), end.getZ());
+
+ List<OffsetPoint> offsetPoints = new ArrayList<OffsetPoint>();
+ for (int z = minZ; z <= maxZ; z++) {
+ for (int x = minX; x <=maxX; x++) {
+ for (int y = maxY; y >= minY; y --) {
+ offsetPoints.add(new OffsetPoint(x,y,z));
+ }
+ }
+ }
+ return offsetPoints;
+ }
+
+ public void add() {
+ valueEditOffsetPointSet.addAll(getBlockPoses());
+ }
+
+ public GuiDungeonAddSet(final ValueEditOffsetPointSet processorParameterEditPane) {
+ this.valueEditOffsetPointSet = processorParameterEditPane;
+ getMainPanel().setBackgroundColor(new Color(17, 17, 17, 179));
+ {
+ start = new OffsetPoint(EditingContext.getEditingContext().getRoom(), Minecraft.getMinecraft().thePlayer.getPosition());
+ end = new OffsetPoint(EditingContext.getEditingContext().getRoom(), Minecraft.getMinecraft().thePlayer.getPosition());
+ }
+ {
+ MValue mValue = new MValue(start, Collections.emptyList());
+ mValue.setBounds(new Rectangle(0,0,150,20));
+ getMainPanel().add(mValue);
+ MValue mValue2 = new MValue(end,Collections.emptyList());
+ mValue2.setBounds(new Rectangle(0,20,150,20));
+ getMainPanel().add(mValue2);
+ }
+ {
+ add = new MButton() {
+ @Override
+ public void resize(int parentWidth, int parentHeight) {
+ setBounds(new Rectangle(0,parentHeight - 20, parentWidth / 2, 20));
+ }
+ };
+ add.setText("Add");
+ add.setBackgroundColor(Color.red);
+ add.setOnActionPerformed(new Runnable() {
+ @Override
+ public void run() {
+ add();
+ EditingContext.getEditingContext().goBack();
+ }
+ });
+
+ back = new MButton(){
+ @Override
+ public void resize(int parentWidth, int parentHeight) {
+ setBounds(new Rectangle(parentWidth / 2,parentHeight - 20, parentWidth / 2, 20));
+ }
+ };
+ back.setText("Go back");
+ back.setBackgroundColor(Color.green);
+ back.setOnActionPerformed(new Runnable() {
+ @Override
+ public void run() {
+ EditingContext.getEditingContext().goBack();
+ }
+ });
+ getMainPanel().add(add);
+ getMainPanel().add(back);
+ }
+ }
+
+ @Override
+ public void initGui() {
+ super.initGui();
+ // update bounds
+ getMainPanel().setBounds(new Rectangle(10, Math.min((Minecraft.getMinecraft().displayHeight - 300) / 2, Minecraft.getMinecraft().displayHeight),200,300));
+ }
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/gui/GuiDungeonParameterEdit.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/gui/GuiDungeonParameterEdit.java
new file mode 100755
index 00000000..0f2764de
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/gui/GuiDungeonParameterEdit.java
@@ -0,0 +1,173 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.roomedit.gui;
+
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomfinder.DungeonRoom;
+import kr.syeyoung.dungeonsguide.mod.gui.MGui;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomedit.EditingContext;
+import kr.syeyoung.dungeonsguide.mod.gui.MPanel;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomedit.Parameter;
+import kr.syeyoung.dungeonsguide.mod.gui.elements.*;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomedit.panes.DynamicEditor;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomedit.valueedit.ValueEdit;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomedit.valueedit.ValueEditCreator;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomedit.valueedit.ValueEditRegistry;
+import lombok.Getter;
+import net.minecraft.client.Minecraft;
+
+import java.awt.*;
+
+public class GuiDungeonParameterEdit extends MGui {
+
+ private final Parameter parameter;
+ private final DungeonRoom dungeonRoom;
+
+ private String classSelection;
+
+ private final MPanel currentValueEdit;
+
+ private final MButton save;
+ private final MButton delete;
+
+ @Getter
+ private ValueEdit valueEdit;
+
+ public GuiDungeonParameterEdit(final MParameter parameter2, final DynamicEditor processorParameterEditPane) {
+ dungeonRoom = EditingContext.getEditingContext().getRoom();
+ getMainPanel().setBackgroundColor(new Color(17, 17, 17, 179));
+ this.parameter = parameter2.getParameter();
+ {
+ MTextField mTextField = new MTextField() {
+ @Override
+ public void edit(String str) {
+ parameter.setName(str);
+ }
+ };
+ MLabelAndElement mLabelAndElement = new MLabelAndElement("Name", mTextField);
+
+ mTextField.setText(parameter.getName());
+ mLabelAndElement.setBounds(new Rectangle(0,0,200, 20));
+ getMainPanel().add(mLabelAndElement);
+ }
+ {
+ classSelection = parameter.getNewData() == null ?"null" : parameter.getNewData().getClass().getName();
+ final MStringSelectionButton mStringSelectionButton = new MStringSelectionButton(processorParameterEditPane.allowedClass(), classSelection) {
+ @Override
+ public void resize(int parentWidth, int parentHeight) {
+ setBounds(new Rectangle(0, 20, parentWidth,20));
+ }
+
+ @Override
+ public String selectionToDisplay(String selection) {
+ String[] split = selection.split("\\.");
+ return super.selectionToDisplay(split[split.length - 1]);
+ }
+ };
+
+ mStringSelectionButton.setOnUpdate(new Runnable() {
+ @Override
+ public void run() {
+ classSelection = mStringSelectionButton.getSelected();
+ updateClassSelection();
+ }
+ });
+ mStringSelectionButton.setBounds(new Rectangle(0,20,150,20));
+ getMainPanel().add(mStringSelectionButton);
+ }
+ {
+ currentValueEdit = new MPanel(){
+ @Override
+ public void resize(int parentWidth, int parentHeight) {
+ setBounds(new Rectangle(0, 40, parentWidth,parentHeight - 60));
+ }
+ };
+ getMainPanel().add(currentValueEdit);
+ }
+ {
+ delete = new MButton() {
+ @Override
+ public void resize(int parentWidth, int parentHeight) {
+ setBounds(new Rectangle(0,parentHeight - 20, parentWidth / 2, 20));
+ }
+ };
+ delete.setText("Delete");
+ delete.setBackgroundColor(Color.red);
+ delete.setOnActionPerformed(new Runnable() {
+ @Override
+ public void run() {
+ processorParameterEditPane.delete(parameter2);
+ EditingContext.getEditingContext().goBack();
+ }
+ });
+
+ save = new MButton(){
+ @Override
+ public void resize(int parentWidth, int parentHeight) {
+ setBounds(new Rectangle(parentWidth / 2,parentHeight - 20, parentWidth / 2, 20));
+ }
+ };
+ save.setText("Go back");
+ save.setBackgroundColor(Color.green);
+ save.setOnActionPerformed(new Runnable() {
+ @Override
+ public void run() {
+ EditingContext.getEditingContext().goBack();
+ }
+ });
+ getMainPanel().add(delete);
+ getMainPanel().add(save);
+ }
+ updateClassSelection();
+ }
+
+ public void updateClassSelection() {
+ currentValueEdit.getChildComponents().clear();
+
+ ValueEditCreator valueEditCreator = ValueEditRegistry.getValueEditMap(classSelection);
+
+ if (!classSelection.equals(parameter.getNewData() == null ?"null" :parameter.getNewData().getClass().getName())) {
+ parameter.setNewData(valueEditCreator.createDefaultValue(parameter));
+ parameter.setPreviousData(valueEditCreator.cloneObj(parameter.getNewData()));
+ }
+
+ MPanel valueEdit = (MPanel) valueEditCreator.createValueEdit(parameter);
+ if (valueEdit == null) {
+ MLabel valueEdit2 = new MLabel() {
+ @Override
+ public void resize(int parentWidth, int parentHeight) {
+ setBounds(new Rectangle(0, 0, parentWidth,20));
+ }
+ };
+ valueEdit2.setText("No Value Edit");
+ valueEdit2.setBounds(new Rectangle(0,0,150,20));
+ valueEdit = valueEdit2;
+ this.valueEdit = null;
+ } else{
+ this.valueEdit = (ValueEdit) valueEdit;
+ }
+ valueEdit.resize0(currentValueEdit.getBounds().width, currentValueEdit.getBounds().height);
+ currentValueEdit.add(valueEdit);
+ }
+ @Override
+ public void initGui() {
+ super.initGui();
+ // update bounds
+ getMainPanel().setBounds(new Rectangle(10, Math.min((Minecraft.getMinecraft().displayHeight - 300) / 2, Minecraft.getMinecraft().displayHeight),200,300));
+ }
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/gui/GuiDungeonRoomEdit.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/gui/GuiDungeonRoomEdit.java
new file mode 100755
index 00000000..181ff640
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/gui/GuiDungeonRoomEdit.java
@@ -0,0 +1,68 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.roomedit.gui;
+
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomfinder.DungeonRoom;
+import kr.syeyoung.dungeonsguide.mod.gui.MGui;
+import kr.syeyoung.dungeonsguide.mod.gui.elements.MTabbedPane;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomedit.panes.*;
+import lombok.Getter;
+import net.minecraft.client.Minecraft;
+
+import java.awt.*;
+
+public class GuiDungeonRoomEdit extends MGui {
+
+ private final DungeonRoom room;
+
+ private final MTabbedPane tabbedPane;
+ @Getter
+ private final SecretEditPane sep;
+
+ public GuiDungeonRoomEdit(DungeonRoom room) {
+ this.room = room;
+
+ MTabbedPane tabbedPane = new MTabbedPane();
+ getMainPanel().add(tabbedPane);
+ tabbedPane.setBackground2(new Color(17, 17, 17, 179));
+
+
+ tabbedPane.addTab("General", new GeneralEditPane(room));
+ tabbedPane.addTab("Match", new RoomDataDisplayPane(room));
+ tabbedPane.addTab("Secrets", sep = new SecretEditPane(room));
+ tabbedPane.addTab("Actions", new ActionDisplayPane(room));
+ tabbedPane.addTab("Test", new RoommatchingPane(room));
+ tabbedPane.addTab("Proc.Params", new ProcessorParameterEditPane(room));
+ this.tabbedPane = tabbedPane;
+ }
+
+ public boolean isEditingSelected() {
+ return "Secrets".equals(tabbedPane.getSelectedKey());
+ }
+ public void endEditing() {
+ tabbedPane.setSelectedKey("General");
+ }
+
+ @Override
+ public void initGui() {
+ super.initGui();
+ // update bounds
+ getMainPanel().setBounds(new Rectangle(Math.min((Minecraft.getMinecraft().displayWidth - 500) / 2, Minecraft.getMinecraft().displayWidth), Math.min((Minecraft.getMinecraft().displayHeight - 300) / 2, Minecraft.getMinecraft().displayHeight),500,300));
+ }
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/gui/GuiDungeonValueEdit.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/gui/GuiDungeonValueEdit.java
new file mode 100755
index 00000000..af4657f5
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/gui/GuiDungeonValueEdit.java
@@ -0,0 +1,127 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.roomedit.gui;
+
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomfinder.DungeonRoom;
+import kr.syeyoung.dungeonsguide.mod.gui.MGui;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomedit.EditingContext;
+import kr.syeyoung.dungeonsguide.mod.gui.MPanel;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomedit.Parameter;
+import kr.syeyoung.dungeonsguide.mod.gui.elements.*;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomedit.valueedit.ValueEdit;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomedit.valueedit.ValueEditCreator;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomedit.valueedit.ValueEditRegistry;
+import lombok.Getter;
+import net.minecraft.client.Minecraft;
+
+import java.awt.*;
+import java.util.List;
+
+public class GuiDungeonValueEdit extends MGui {
+ private DungeonRoom dungeonRoom;
+
+
+ private MPanel currentValueEdit;
+
+ private MButton save;
+
+ @Getter
+ private ValueEdit valueEdit;
+
+ private List<MPanel> addons;
+
+ private Object editingObj;
+
+ public GuiDungeonValueEdit(final Object object, final List<MPanel> addons) {
+ try {
+ dungeonRoom = EditingContext.getEditingContext().getRoom();
+ this.addons = addons;
+ this.editingObj = object;
+ getMainPanel().setBackgroundColor(new Color(17, 17, 17, 179));
+ {
+ currentValueEdit = new MPanel() {
+ @Override
+ public void resize(int parentWidth, int parentHeight) {
+ setBounds(new Rectangle(0, 0, parentWidth, parentHeight - 20 - addons.size() * 20));
+ }
+ };
+ getMainPanel().add(currentValueEdit);
+ }
+
+ for (MPanel addon : addons) {
+ getMainPanel().add(addon);
+ }
+ {
+ save = new MButton() {
+ @Override
+ public void resize(int parentWidth, int parentHeight) {
+ setBounds(new Rectangle(0, parentHeight - 20, parentWidth, 20));
+ }
+ };
+ save.setText("Go back");
+ save.setBackgroundColor(Color.green);
+ save.setOnActionPerformed(new Runnable() {
+ @Override
+ public void run() {
+ EditingContext.getEditingContext().goBack();
+ }
+ });
+ getMainPanel().add(save);
+ }
+ updateClassSelection();
+ } catch (Exception e){}
+ }
+
+ public void updateClassSelection() {
+ currentValueEdit.getChildComponents().clear();
+
+ ValueEditCreator valueEditCreator = ValueEditRegistry.getValueEditMap(editingObj == null ?"null":editingObj.getClass().getName());
+
+ MPanel valueEdit = (MPanel) valueEditCreator.createValueEdit(new Parameter("", editingObj, editingObj));
+ if (valueEdit == null) {
+ MLabel valueEdit2 = new MLabel() {
+ @Override
+ public void resize(int parentWidth, int parentHeight) {
+ setBounds(new Rectangle(0, 0, parentWidth,20));
+ }
+ };
+ valueEdit2.setText("No Value Edit");
+ valueEdit2.setBounds(new Rectangle(0,0,150,20));
+ valueEdit = valueEdit2;
+ this.valueEdit = null;
+ } else{
+ this.valueEdit = (ValueEdit) valueEdit;
+ }
+ valueEdit.resize0(currentValueEdit.getBounds().width, currentValueEdit.getBounds().height);
+ currentValueEdit.add(valueEdit);
+ }
+ @Override
+ public void initGui() {
+ super.initGui();
+ // update bounds
+ getMainPanel().setBounds(new Rectangle(10, Math.min((Minecraft.getMinecraft().displayHeight - 300) / 2, Minecraft.getMinecraft().displayHeight),200,300));
+
+
+ for (int i = 0; i < addons.size(); i++) {
+ addons.get(i).setBounds(new Rectangle(0, getMainPanel().getBounds().height - (i+1) * 20 - 20, getMainPanel().getBounds().width, 20));
+ }
+ save.setBounds(new Rectangle(0 ,getMainPanel().getBounds().height - 20, getMainPanel().getBounds().width, 20));
+ }
+
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/mechanicedit/ValueEditBreakableWall.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/mechanicedit/ValueEditBreakableWall.java
new file mode 100755
index 00000000..bcde40b9
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/mechanicedit/ValueEditBreakableWall.java
@@ -0,0 +1,143 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.roomedit.mechanicedit;
+
+import kr.syeyoung.dungeonsguide.dungeon.data.OffsetPoint;
+import kr.syeyoung.dungeonsguide.dungeon.data.OffsetPointSet;
+import kr.syeyoung.dungeonsguide.dungeon.mechanics.DungeonBreakableWall;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomedit.EditingContext;
+import kr.syeyoung.dungeonsguide.mod.gui.MPanel;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomedit.Parameter;
+import kr.syeyoung.dungeonsguide.mod.gui.elements.*;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomedit.valueedit.ValueEdit;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomedit.valueedit.ValueEditCreator;
+import kr.syeyoung.dungeonsguide.mod.utils.TextUtils;
+import net.minecraft.init.Blocks;
+
+import java.awt.*;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Collections;
+
+public class ValueEditBreakableWall extends MPanel implements ValueEdit<DungeonBreakableWall> {
+ private Parameter parameter;
+
+ // scroll pane
+ // just create
+ // add set
+ private final DungeonBreakableWall dungeonBreakableWall;
+
+ private final MLabel label;
+ private final MValue<OffsetPointSet> value;
+ private final MTextField preRequisite;
+ private final MLabelAndElement preRequisite2;
+ private final MButton updateOnlyAir;
+
+ public ValueEditBreakableWall(final Parameter parameter2) {
+ this.parameter = parameter2;
+ this.dungeonBreakableWall = (DungeonBreakableWall) parameter2.getNewData();
+
+
+ label = new MLabel();
+ label.setText("Wall Points");
+ label.setAlignment(MLabel.Alignment.LEFT);
+ add(label);
+
+ value = new MValue(dungeonBreakableWall.getSecretPoint(), Collections.emptyList());
+ add(value);
+
+ updateOnlyAir = new MButton();
+ updateOnlyAir.setText("Update Air");
+ updateOnlyAir.setBackgroundColor(Color.green);
+ updateOnlyAir.setForeground(Color.black);
+ updateOnlyAir.setBounds(new Rectangle(0,40,getBounds().width, 20));
+ add(updateOnlyAir);
+ updateOnlyAir.setOnActionPerformed(new Runnable() {
+ @Override
+ public void run() {
+ OffsetPointSet ofs = dungeonBreakableWall.getSecretPoint();
+ List<OffsetPoint> filtered = new ArrayList<OffsetPoint>();
+ for (OffsetPoint offsetPoint : ofs.getOffsetPointList()) {
+ if (offsetPoint.getBlock(EditingContext.getEditingContext().getRoom()) != Blocks.air) continue;
+ filtered.add(offsetPoint);
+ }
+ dungeonBreakableWall.getSecretPoint().setOffsetPointList(filtered);
+ }
+ });
+
+ preRequisite = new MTextField() {
+ @Override
+ public void edit(String str) {
+ dungeonBreakableWall.setPreRequisite(Arrays.asList(str.split(",")));
+ }
+ };
+ preRequisite.setText(TextUtils.join(dungeonBreakableWall.getPreRequisite(), ","));
+ preRequisite2 = new MLabelAndElement("Req.",preRequisite);
+ preRequisite2.setBounds(new Rectangle(0,60,getBounds().width,20));
+ add(preRequisite2);
+ }
+
+ @Override
+ public void onBoundsUpdate() {
+ label.setBounds(new Rectangle(0,0,getBounds().width, 20));
+ value.setBounds(new Rectangle(0,20,getBounds().width, 20));
+ updateOnlyAir.setBounds(new Rectangle(0,40,getBounds().width, 20));
+ preRequisite2.setBounds(new Rectangle(0,60,getBounds().width,20));
+ }
+
+ @Override
+ public void setParameter(Parameter parameter) {
+ this.parameter = parameter;
+ }
+
+ @Override
+ public void renderWorld(float partialTicks) {
+ dungeonBreakableWall.highlight(new Color(0,255,255,50), parameter.getName(), EditingContext.getEditingContext().getRoom(), partialTicks);
+ }
+
+ @Override
+ public void resize(int parentWidth, int parentHeight) {
+ this.setBounds(new Rectangle(0,0,parentWidth, parentHeight));
+ }
+
+ public static class Generator implements ValueEditCreator<ValueEditBreakableWall> {
+
+ @Override
+ public ValueEditBreakableWall createValueEdit(Parameter parameter) {
+ return new ValueEditBreakableWall(parameter);
+ }
+
+ @Override
+ public Object createDefaultValue(Parameter parameter) {
+ return new DungeonBreakableWall();
+ }
+
+ @Override
+ public Object cloneObj(Object object) {
+ try {
+ return ((DungeonBreakableWall)object).clone();
+ } catch (CloneNotSupportedException e) {
+ e.printStackTrace();
+ }
+ assert false;
+ return null;
+ }
+ }
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/mechanicedit/ValueEditDoor.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/mechanicedit/ValueEditDoor.java
new file mode 100755
index 00000000..b2a30bfb
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/mechanicedit/ValueEditDoor.java
@@ -0,0 +1,157 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.roomedit.mechanicedit;
+
+import kr.syeyoung.dungeonsguide.dungeon.data.OffsetPoint;
+import kr.syeyoung.dungeonsguide.dungeon.data.OffsetPointSet;
+import kr.syeyoung.dungeonsguide.dungeon.mechanics.DungeonDoor;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomedit.EditingContext;
+import kr.syeyoung.dungeonsguide.mod.gui.MPanel;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomedit.Parameter;
+import kr.syeyoung.dungeonsguide.mod.gui.elements.*;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomedit.valueedit.ValueEdit;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomedit.valueedit.ValueEditCreator;
+import kr.syeyoung.dungeonsguide.mod.utils.TextUtils;
+import net.minecraft.init.Blocks;
+
+import java.awt.*;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+public class ValueEditDoor extends MPanel implements ValueEdit<DungeonDoor> {
+ private Parameter parameter;
+
+ // scroll pane
+ // just create
+ // add set
+ private final DungeonDoor dungeonDoor;
+
+ private final MLabel label;
+ private final MValue<OffsetPointSet> value;
+ private final MTextField preRequisite;
+ private final MLabelAndElement preRequisite_par;
+ private final MTextField preRequisite2;
+ private final MLabelAndElement preRequisite2_par;
+ private final MButton updateOnlyAir;
+
+ public ValueEditDoor(final Parameter parameter2) {
+ this.parameter = parameter2;
+ this.dungeonDoor = (DungeonDoor) parameter2.getNewData();
+
+
+ label = new MLabel();
+ label.setText("Wall Points");
+ label.setAlignment(MLabel.Alignment.LEFT);
+ add(label);
+
+ value = new MValue(dungeonDoor.getSecretPoint(), Collections.emptyList());
+ add(value);
+
+ updateOnlyAir = new MButton();
+ updateOnlyAir.setText("Update Air");
+ updateOnlyAir.setBackgroundColor(Color.green);
+ updateOnlyAir.setForeground(Color.black);
+ updateOnlyAir.setBounds(new Rectangle(0,40,getBounds().width, 20));
+ add(updateOnlyAir);
+ updateOnlyAir.setOnActionPerformed(new Runnable() {
+ @Override
+ public void run() {
+ OffsetPointSet ofs = dungeonDoor.getSecretPoint();
+ List<OffsetPoint> filtered = new ArrayList<OffsetPoint>();
+ for (OffsetPoint offsetPoint : ofs.getOffsetPointList()) {
+ if (offsetPoint.getBlock(EditingContext.getEditingContext().getRoom()) != Blocks.air) continue;
+ filtered.add(offsetPoint);
+ }
+ dungeonDoor.getSecretPoint().setOffsetPointList(filtered);
+ }
+ });
+
+ preRequisite = new MTextField() {
+ @Override
+ public void edit(String str) {
+ dungeonDoor.setOpenPreRequisite(Arrays.asList(str.split(",")));
+ }
+ };
+ preRequisite.setText(TextUtils.join(dungeonDoor.getOpenPreRequisite(), ","));
+ preRequisite_par = new MLabelAndElement("Open Req.",preRequisite);
+ preRequisite_par.setBounds(new Rectangle(0,60,getBounds().width,20));
+ add(preRequisite_par);
+
+ preRequisite2 = new MTextField() {
+ @Override
+ public void edit(String str) {
+ dungeonDoor.setClosePreRequisite(Arrays.asList(str.split(",")));
+ }
+ };
+ preRequisite2.setText(TextUtils.join(dungeonDoor.getClosePreRequisite(), ","));
+ preRequisite2_par = new MLabelAndElement("Close Req.",preRequisite2);
+ preRequisite2_par.setBounds(new Rectangle(0,80,getBounds().width,20));
+ add(preRequisite2_par);
+ }
+
+ @Override
+ public void onBoundsUpdate() {
+ label.setBounds(new Rectangle(0,0,getBounds().width, 20));
+ value.setBounds(new Rectangle(0,20,getBounds().width, 20));
+ updateOnlyAir.setBounds(new Rectangle(0,40,getBounds().width, 20));
+ preRequisite_par.setBounds(new Rectangle(0,60,getBounds().width,20));
+ preRequisite2_par.setBounds(new Rectangle(0,80,getBounds().width,20));
+ }
+
+ @Override
+ public void setParameter(Parameter parameter) {
+ this.parameter = parameter;
+ }
+
+ @Override
+ public void renderWorld(float partialTicks) {
+ dungeonDoor.highlight(new Color(0,255,255,50), parameter.getName(), EditingContext.getEditingContext().getRoom(), partialTicks);
+ }
+
+ @Override
+ public void resize(int parentWidth, int parentHeight) {
+ this.setBounds(new Rectangle(0,0,parentWidth, parentHeight));
+ }
+
+ public static class Generator implements ValueEditCreator<ValueEditDoor> {
+
+ @Override
+ public ValueEditDoor createValueEdit(Parameter parameter) {
+ return new ValueEditDoor(parameter);
+ }
+
+ @Override
+ public Object createDefaultValue(Parameter parameter) {
+ return new DungeonDoor();
+ }
+
+ @Override
+ public Object cloneObj(Object object) {
+ try {
+ return ((DungeonDoor)object).clone();
+ } catch (CloneNotSupportedException e) {
+ e.printStackTrace();
+ }
+ assert false;
+ return null;
+ }
+ }
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/mechanicedit/ValueEditDummy.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/mechanicedit/ValueEditDummy.java
new file mode 100755
index 00000000..64808dda
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/mechanicedit/ValueEditDummy.java
@@ -0,0 +1,121 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.roomedit.mechanicedit;
+
+import kr.syeyoung.dungeonsguide.dungeon.data.OffsetPoint;
+import kr.syeyoung.dungeonsguide.dungeon.mechanics.DungeonDummy;
+import kr.syeyoung.dungeonsguide.mod.gui.MPanel;
+import kr.syeyoung.dungeonsguide.mod.gui.elements.MLabel;
+import kr.syeyoung.dungeonsguide.mod.gui.elements.MLabelAndElement;
+import kr.syeyoung.dungeonsguide.mod.gui.elements.MTextField;
+import kr.syeyoung.dungeonsguide.mod.gui.elements.MValue;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomedit.EditingContext;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomedit.Parameter;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomedit.valueedit.ValueEdit;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomedit.valueedit.ValueEditCreator;
+import kr.syeyoung.dungeonsguide.mod.utils.TextUtils;
+
+import java.awt.*;
+import java.util.Arrays;
+import java.util.Collections;
+
+public class ValueEditDummy extends MPanel implements ValueEdit<DungeonDummy> {
+ private Parameter parameter;
+
+ // scroll pane
+ // just create
+ // add set
+ private final DungeonDummy dungeonSecret;
+
+ private final MLabel label;
+ private final MValue<OffsetPoint> value;
+ private final MTextField preRequisite;
+ private final MLabelAndElement preRequisite2;
+
+ public ValueEditDummy(final Parameter parameter2) {
+ this.parameter = parameter2;
+ this.dungeonSecret = (DungeonDummy) parameter2.getNewData();
+
+
+ label = new MLabel();
+ label.setText("Dummy Point");
+ label.setAlignment(MLabel.Alignment.LEFT);
+ add(label);
+
+ value = new MValue(dungeonSecret.getSecretPoint(), Collections.emptyList());
+ add(value);
+
+ preRequisite = new MTextField() {
+ @Override
+ public void edit(String str) {
+ dungeonSecret.setPreRequisite(Arrays.asList(str.split(",")));
+ }
+ };
+ preRequisite.setText(TextUtils.join(dungeonSecret.getPreRequisite(), ","));
+ preRequisite2 = new MLabelAndElement("Req.",preRequisite);
+ preRequisite2.setBounds(new Rectangle(0,40,getBounds().width,20));
+ add(preRequisite2);
+ }
+
+ @Override
+ public void onBoundsUpdate() {
+ label.setBounds(new Rectangle(0,0,getBounds().width, 20));
+ value.setBounds(new Rectangle(0,20,getBounds().width, 20));
+ preRequisite2.setBounds(new Rectangle(0,40,getBounds().width,20));
+ }
+
+ @Override
+ public void setParameter(Parameter parameter) {
+ this.parameter = parameter;
+ }
+
+ @Override
+ public void renderWorld(float partialTicks) {
+ dungeonSecret.highlight(new Color(0,255,0,50), parameter.getName(), EditingContext.getEditingContext().getRoom(), partialTicks);
+ }
+
+ @Override
+ public void resize(int parentWidth, int parentHeight) {
+ this.setBounds(new Rectangle(0,0,parentWidth, parentHeight));
+ }
+
+ public static class Generator implements ValueEditCreator<ValueEditDummy> {
+
+ @Override
+ public ValueEditDummy createValueEdit(Parameter parameter) {
+ return new ValueEditDummy(parameter);
+ }
+
+ @Override
+ public Object createDefaultValue(Parameter parameter) {
+ return new DungeonDummy();
+ }
+
+ @Override
+ public Object cloneObj(Object object) {
+ try {
+ return ((DungeonDummy)object).clone();
+ } catch (CloneNotSupportedException e) {
+ e.printStackTrace();
+ }
+ assert false;
+ return null;
+ }
+ }
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/mechanicedit/ValueEditFairySoul.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/mechanicedit/ValueEditFairySoul.java
new file mode 100755
index 00000000..3bd69eb9
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/mechanicedit/ValueEditFairySoul.java
@@ -0,0 +1,118 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.roomedit.mechanicedit;
+
+import kr.syeyoung.dungeonsguide.dungeon.data.OffsetPoint;
+import kr.syeyoung.dungeonsguide.dungeon.mechanics.DungeonFairySoul;
+import kr.syeyoung.dungeonsguide.mod.gui.MPanel;
+import kr.syeyoung.dungeonsguide.mod.gui.elements.*;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomedit.EditingContext;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomedit.Parameter;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomedit.valueedit.ValueEdit;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomedit.valueedit.ValueEditCreator;
+import kr.syeyoung.dungeonsguide.mod.utils.TextUtils;
+
+import java.awt.*;
+import java.util.Arrays;
+import java.util.Collections;
+
+public class ValueEditFairySoul extends MPanel implements ValueEdit<DungeonFairySoul> {
+ private Parameter parameter;
+
+ // scroll pane
+ // just create
+ // add set
+ private final DungeonFairySoul dungeonSecret;
+
+ private final MLabel label;
+ private final MValue<OffsetPoint> value;
+ private final MTextField preRequisite;
+ private final MLabelAndElement preRequisite2;
+
+ public ValueEditFairySoul(final Parameter parameter2) {
+ this.parameter = parameter2;
+ this.dungeonSecret = (DungeonFairySoul) parameter2.getNewData();
+
+
+ label = new MLabel();
+ label.setText("FairySoul Point");
+ label.setAlignment(MLabel.Alignment.LEFT);
+ add(label);
+
+ value = new MValue(dungeonSecret.getSecretPoint(), Collections.emptyList());
+ add(value);
+
+ preRequisite = new MTextField() {
+ @Override
+ public void edit(String str) {
+ dungeonSecret.setPreRequisite(Arrays.asList(str.split(",")));
+ }
+ };
+ preRequisite.setText(TextUtils.join(dungeonSecret.getPreRequisite(), ","));
+ preRequisite2 = new MLabelAndElement("Req.",preRequisite);
+ preRequisite2.setBounds(new Rectangle(0,40,getBounds().width,20));
+ add(preRequisite2);
+ }
+
+ @Override
+ public void onBoundsUpdate() {
+ label.setBounds(new Rectangle(0,0,getBounds().width, 20));
+ value.setBounds(new Rectangle(0,20,getBounds().width, 20));
+ preRequisite2.setBounds(new Rectangle(0,40,getBounds().width,20));
+ }
+
+ @Override
+ public void setParameter(Parameter parameter) {
+ this.parameter = parameter;
+ }
+
+ @Override
+ public void renderWorld(float partialTicks) {
+ dungeonSecret.highlight(new Color(0,255,0,50), parameter.getName(), EditingContext.getEditingContext().getRoom(), partialTicks);
+ }
+
+ @Override
+ public void resize(int parentWidth, int parentHeight) {
+ this.setBounds(new Rectangle(0,0,parentWidth, parentHeight));
+ }
+
+ public static class Generator implements ValueEditCreator<ValueEditFairySoul> {
+
+ @Override
+ public ValueEditFairySoul createValueEdit(Parameter parameter) {
+ return new ValueEditFairySoul(parameter);
+ }
+
+ @Override
+ public Object createDefaultValue(Parameter parameter) {
+ return new DungeonFairySoul();
+ }
+
+ @Override
+ public Object cloneObj(Object object) {
+ try {
+ return ((DungeonFairySoul)object).clone();
+ } catch (CloneNotSupportedException e) {
+ e.printStackTrace();
+ }
+ assert false;
+ return null;
+ }
+ }
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/mechanicedit/ValueEditJournal.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/mechanicedit/ValueEditJournal.java
new file mode 100755
index 00000000..1123050e
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/mechanicedit/ValueEditJournal.java
@@ -0,0 +1,122 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.roomedit.mechanicedit;
+
+import kr.syeyoung.dungeonsguide.dungeon.data.OffsetPoint;
+import kr.syeyoung.dungeonsguide.dungeon.mechanics.DungeonJournal;
+import kr.syeyoung.dungeonsguide.mod.gui.MPanel;
+import kr.syeyoung.dungeonsguide.mod.gui.elements.MLabel;
+import kr.syeyoung.dungeonsguide.mod.gui.elements.MLabelAndElement;
+import kr.syeyoung.dungeonsguide.mod.gui.elements.MTextField;
+import kr.syeyoung.dungeonsguide.mod.gui.elements.MValue;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomedit.EditingContext;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomedit.Parameter;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomedit.valueedit.ValueEdit;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomedit.valueedit.ValueEditCreator;
+import kr.syeyoung.dungeonsguide.mod.utils.TextUtils;
+
+import java.awt.*;
+import java.util.Arrays;
+import java.util.Collections;
+
+
+public class ValueEditJournal extends MPanel implements ValueEdit<DungeonJournal> {
+ private Parameter parameter;
+
+ // scroll pane
+ // just create
+ // add set
+ private final DungeonJournal dungeonSecret;
+
+ private final MLabel label;
+ private final MValue<OffsetPoint> value;
+ private final MTextField preRequisite;
+ private final MLabelAndElement preRequisite2;
+
+ public ValueEditJournal(final Parameter parameter2) {
+ this.parameter = parameter2;
+ this.dungeonSecret = (DungeonJournal) parameter2.getNewData();
+
+
+ label = new MLabel();
+ label.setText("Journal Point");
+ label.setAlignment(MLabel.Alignment.LEFT);
+ add(label);
+
+ value = new MValue(dungeonSecret.getSecretPoint(), Collections.emptyList());
+ add(value);
+
+ preRequisite = new MTextField() {
+ @Override
+ public void edit(String str) {
+ dungeonSecret.setPreRequisite(Arrays.asList(str.split(",")));
+ }
+ };
+ preRequisite.setText(TextUtils.join(dungeonSecret.getPreRequisite(), ","));
+ preRequisite2 = new MLabelAndElement("Req.",preRequisite);
+ preRequisite2.setBounds(new Rectangle(0,40,getBounds().width,20));
+ add(preRequisite2);
+ }
+
+ @Override
+ public void onBoundsUpdate() {
+ label.setBounds(new Rectangle(0,0,getBounds().width, 20));
+ value.setBounds(new Rectangle(0,20,getBounds().width, 20));
+ preRequisite2.setBounds(new Rectangle(0,40,getBounds().width,20));
+ }
+
+ @Override
+ public void setParameter(Parameter parameter) {
+ this.parameter = parameter;
+ }
+
+ @Override
+ public void renderWorld(float partialTicks) {
+ dungeonSecret.highlight(new Color(0,255,0,50), parameter.getName(), EditingContext.getEditingContext().getRoom(), partialTicks);
+ }
+
+ @Override
+ public void resize(int parentWidth, int parentHeight) {
+ this.setBounds(new Rectangle(0,0,parentWidth, parentHeight));
+ }
+
+ public static class Generator implements ValueEditCreator<ValueEditJournal> {
+
+ @Override
+ public ValueEditJournal createValueEdit(Parameter parameter) {
+ return new ValueEditJournal(parameter);
+ }
+
+ @Override
+ public Object createDefaultValue(Parameter parameter) {
+ return new DungeonJournal();
+ }
+
+ @Override
+ public Object cloneObj(Object object) {
+ try {
+ return ((DungeonJournal)object).clone();
+ } catch (CloneNotSupportedException e) {
+ e.printStackTrace();
+ }
+ assert false;
+ return null;
+ }
+ }
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/mechanicedit/ValueEditLever.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/mechanicedit/ValueEditLever.java
new file mode 100755
index 00000000..080be185
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/mechanicedit/ValueEditLever.java
@@ -0,0 +1,133 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.roomedit.mechanicedit;
+
+import kr.syeyoung.dungeonsguide.dungeon.data.OffsetPoint;
+import kr.syeyoung.dungeonsguide.dungeon.mechanics.DungeonLever;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomedit.EditingContext;
+import kr.syeyoung.dungeonsguide.mod.gui.MPanel;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomedit.Parameter;
+import kr.syeyoung.dungeonsguide.mod.gui.elements.*;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomedit.valueedit.ValueEdit;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomedit.valueedit.ValueEditCreator;
+import kr.syeyoung.dungeonsguide.mod.utils.TextUtils;
+
+import java.awt.*;
+import java.util.Arrays;
+import java.util.Collections;
+
+public class ValueEditLever extends MPanel implements ValueEdit<DungeonLever> {
+ private Parameter parameter;
+
+ // scroll pane
+ // just create
+ // add set
+ private final DungeonLever dungeonLever;
+
+ private final MLabel label;
+ private final MValue<OffsetPoint> value;
+ private final MTextField preRequisite;
+ private final MLabelAndElement preRequisite2;
+ private final MTextField target;
+ private final MLabelAndElement target2;
+
+ public ValueEditLever(final Parameter parameter2) {
+ this.parameter = parameter2;
+ this.dungeonLever = (DungeonLever) parameter2.getNewData();
+
+
+ label = new MLabel();
+ label.setText("Secret Point");
+ label.setAlignment(MLabel.Alignment.LEFT);
+ add(label);
+
+ value = new MValue(dungeonLever.getLeverPoint(), Collections.emptyList());
+ add(value);
+
+ preRequisite = new MTextField() {
+ @Override
+ public void edit(String str) {
+ dungeonLever.setPreRequisite(Arrays.asList(str.split(",")));
+ }
+ };
+ preRequisite.setText(TextUtils.join(dungeonLever.getPreRequisite(), ","));
+ preRequisite2 = new MLabelAndElement("Req.",preRequisite);
+ preRequisite2.setBounds(new Rectangle(0,40,getBounds().width,20));
+ add(preRequisite2);
+
+
+ target = new MTextField() {
+ @Override
+ public void edit(String str) {
+ dungeonLever.setTriggering(str);
+ }
+ };
+ target.setText(dungeonLever.getTriggering());
+ target2 = new MLabelAndElement("Target",target);
+ target2.setBounds(new Rectangle(0,60,getBounds().width,20));
+ add(target2);
+ }
+
+ @Override
+ public void onBoundsUpdate() {
+ label.setBounds(new Rectangle(0,0,getBounds().width, 20));
+ value.setBounds(new Rectangle(0,20,getBounds().width, 20));
+ preRequisite2.setBounds(new Rectangle(0,40,getBounds().width,20));
+ target2.setBounds(new Rectangle(0,60,getBounds().width,20));
+ }
+
+ @Override
+ public void setParameter(Parameter parameter) {
+ this.parameter = parameter;
+ }
+
+ @Override
+ public void renderWorld(float partialTicks) {
+ dungeonLever.highlight(new Color(0,255,0,50), parameter.getName(), EditingContext.getEditingContext().getRoom(), partialTicks);
+ }
+
+ @Override
+ public void resize(int parentWidth, int parentHeight) {
+ this.setBounds(new Rectangle(0,0,parentWidth, parentHeight));
+ }
+
+ public static class Generator implements ValueEditCreator<ValueEditLever> {
+
+ @Override
+ public ValueEditLever createValueEdit(Parameter parameter) {
+ return new ValueEditLever(parameter);
+ }
+
+ @Override
+ public Object createDefaultValue(Parameter parameter) {
+ return new DungeonLever();
+ }
+
+ @Override
+ public Object cloneObj(Object object) {
+ try {
+ return ((DungeonLever)object).clone();
+ } catch (CloneNotSupportedException e) {
+ e.printStackTrace();
+ }
+ assert false;
+ return null;
+ }
+ }
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/mechanicedit/ValueEditNPC.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/mechanicedit/ValueEditNPC.java
new file mode 100755
index 00000000..20608f8e
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/mechanicedit/ValueEditNPC.java
@@ -0,0 +1,121 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.roomedit.mechanicedit;
+
+import kr.syeyoung.dungeonsguide.dungeon.data.OffsetPoint;
+import kr.syeyoung.dungeonsguide.dungeon.mechanics.DungeonNPC;
+import kr.syeyoung.dungeonsguide.mod.gui.MPanel;
+import kr.syeyoung.dungeonsguide.mod.gui.elements.MLabel;
+import kr.syeyoung.dungeonsguide.mod.gui.elements.MLabelAndElement;
+import kr.syeyoung.dungeonsguide.mod.gui.elements.MTextField;
+import kr.syeyoung.dungeonsguide.mod.gui.elements.MValue;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomedit.EditingContext;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomedit.Parameter;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomedit.valueedit.ValueEdit;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomedit.valueedit.ValueEditCreator;
+import kr.syeyoung.dungeonsguide.mod.utils.TextUtils;
+
+import java.awt.*;
+import java.util.Arrays;
+import java.util.Collections;
+
+public class ValueEditNPC extends MPanel implements ValueEdit<DungeonNPC> {
+ private Parameter parameter;
+
+ // scroll pane
+ // just create
+ // add set
+ private final DungeonNPC dungeonSecret;
+
+ private final MLabel label;
+ private final MValue<OffsetPoint> value;
+ private final MTextField preRequisite;
+ private final MLabelAndElement preRequisite2;
+
+ public ValueEditNPC(final Parameter parameter2) {
+ this.parameter = parameter2;
+ this.dungeonSecret = (DungeonNPC) parameter2.getNewData();
+
+
+ label = new MLabel();
+ label.setText("NPC Point");
+ label.setAlignment(MLabel.Alignment.LEFT);
+ add(label);
+
+ value = new MValue(dungeonSecret.getSecretPoint(), Collections.emptyList());
+ add(value);
+
+ preRequisite = new MTextField() {
+ @Override
+ public void edit(String str) {
+ dungeonSecret.setPreRequisite(Arrays.asList(str.split(",")));
+ }
+ };
+ preRequisite.setText(TextUtils.join(dungeonSecret.getPreRequisite(), ","));
+ preRequisite2 = new MLabelAndElement("Req.",preRequisite);
+ preRequisite2.setBounds(new Rectangle(0,40,getBounds().width,20));
+ add(preRequisite2);
+ }
+
+ @Override
+ public void onBoundsUpdate() {
+ label.setBounds(new Rectangle(0,0,getBounds().width, 20));
+ value.setBounds(new Rectangle(0,20,getBounds().width, 20));
+ preRequisite2.setBounds(new Rectangle(0,40,getBounds().width,20));
+ }
+
+ @Override
+ public void setParameter(Parameter parameter) {
+ this.parameter = parameter;
+ }
+
+ @Override
+ public void renderWorld(float partialTicks) {
+ dungeonSecret.highlight(new Color(0,255,0,50), parameter.getName(), EditingContext.getEditingContext().getRoom(), partialTicks);
+ }
+
+ @Override
+ public void resize(int parentWidth, int parentHeight) {
+ this.setBounds(new Rectangle(0,0,parentWidth, parentHeight));
+ }
+
+ public static class Generator implements ValueEditCreator<ValueEditNPC> {
+
+ @Override
+ public ValueEditNPC createValueEdit(Parameter parameter) {
+ return new ValueEditNPC(parameter);
+ }
+
+ @Override
+ public Object createDefaultValue(Parameter parameter) {
+ return new DungeonNPC();
+ }
+
+ @Override
+ public Object cloneObj(Object object) {
+ try {
+ return ((DungeonNPC)object).clone();
+ } catch (CloneNotSupportedException e) {
+ e.printStackTrace();
+ }
+ assert false;
+ return null;
+ }
+ }
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/mechanicedit/ValueEditOnewayDoor.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/mechanicedit/ValueEditOnewayDoor.java
new file mode 100755
index 00000000..ffeba48d
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/mechanicedit/ValueEditOnewayDoor.java
@@ -0,0 +1,143 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.roomedit.mechanicedit;
+
+import kr.syeyoung.dungeonsguide.dungeon.data.OffsetPoint;
+import kr.syeyoung.dungeonsguide.dungeon.data.OffsetPointSet;
+import kr.syeyoung.dungeonsguide.dungeon.mechanics.DungeonOnewayDoor;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomedit.EditingContext;
+import kr.syeyoung.dungeonsguide.mod.gui.MPanel;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomedit.Parameter;
+import kr.syeyoung.dungeonsguide.mod.gui.elements.*;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomedit.valueedit.ValueEdit;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomedit.valueedit.ValueEditCreator;
+import kr.syeyoung.dungeonsguide.mod.utils.TextUtils;
+import net.minecraft.init.Blocks;
+
+import java.awt.*;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+public class ValueEditOnewayDoor extends MPanel implements ValueEdit<DungeonOnewayDoor> {
+ private Parameter parameter;
+
+ // scroll pane
+ // just create
+ // add set
+ private final DungeonOnewayDoor dungeonDoor;
+
+ private final MLabel label;
+ private final MValue<OffsetPointSet> value;
+ private final MTextField preRequisite;
+ private final MLabelAndElement preRequisite2;
+ private final MButton updateOnlyAir;
+
+ public ValueEditOnewayDoor(final Parameter parameter2) {
+ this.parameter = parameter2;
+ this.dungeonDoor = (DungeonOnewayDoor) parameter2.getNewData();
+
+
+ label = new MLabel();
+ label.setText("Wall Points");
+ label.setAlignment(MLabel.Alignment.LEFT);
+ add(label);
+
+ value = new MValue(dungeonDoor.getSecretPoint(), Collections.emptyList());
+ add(value);
+
+ updateOnlyAir = new MButton();
+ updateOnlyAir.setText("Update Air");
+ updateOnlyAir.setBackgroundColor(Color.green);
+ updateOnlyAir.setForeground(Color.black);
+ updateOnlyAir.setBounds(new Rectangle(0,40,getBounds().width, 20));
+ add(updateOnlyAir);
+ updateOnlyAir.setOnActionPerformed(new Runnable() {
+ @Override
+ public void run() {
+ OffsetPointSet ofs = dungeonDoor.getSecretPoint();
+ List<OffsetPoint> filtered = new ArrayList<OffsetPoint>();
+ for (OffsetPoint offsetPoint : ofs.getOffsetPointList()) {
+ if (offsetPoint.getBlock(EditingContext.getEditingContext().getRoom()) != Blocks.air) continue;
+ filtered.add(offsetPoint);
+ }
+ dungeonDoor.getSecretPoint().setOffsetPointList(filtered);
+ }
+ });
+
+ preRequisite = new MTextField() {
+ @Override
+ public void edit(String str) {
+ dungeonDoor.setPreRequisite(Arrays.asList(str.split(",")));
+ }
+ };
+ preRequisite.setText(TextUtils.join(dungeonDoor.getPreRequisite(), ","));
+ preRequisite2 = new MLabelAndElement("Req.",preRequisite);
+ preRequisite2.setBounds(new Rectangle(0,60,getBounds().width,20));
+ add(preRequisite2);
+ }
+
+ @Override
+ public void onBoundsUpdate() {
+ label.setBounds(new Rectangle(0,0,getBounds().width, 20));
+ value.setBounds(new Rectangle(0,20,getBounds().width, 20));
+ updateOnlyAir.setBounds(new Rectangle(0,40,getBounds().width, 20));
+ preRequisite2.setBounds(new Rectangle(0,60,getBounds().width,20));
+ }
+
+ @Override
+ public void setParameter(Parameter parameter) {
+ this.parameter = parameter;
+ }
+
+ @Override
+ public void renderWorld(float partialTicks) {
+ dungeonDoor.highlight(new Color(0,255,255,50), parameter.getName(), EditingContext.getEditingContext().getRoom(), partialTicks);
+ }
+
+ @Override
+ public void resize(int parentWidth, int parentHeight) {
+ this.setBounds(new Rectangle(0,0,parentWidth, parentHeight));
+ }
+
+ public static class Generator implements ValueEditCreator<ValueEditOnewayDoor> {
+
+ @Override
+ public ValueEditOnewayDoor createValueEdit(Parameter parameter) {
+ return new ValueEditOnewayDoor(parameter);
+ }
+
+ @Override
+ public Object createDefaultValue(Parameter parameter) {
+ return new DungeonOnewayDoor();
+ }
+
+ @Override
+ public Object cloneObj(Object object) {
+ try {
+ return ((DungeonOnewayDoor)object).clone();
+ } catch (CloneNotSupportedException e) {
+ e.printStackTrace();
+ }
+ assert false;
+ return null;
+ }
+ }
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/mechanicedit/ValueEditOnewayLever.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/mechanicedit/ValueEditOnewayLever.java
new file mode 100755
index 00000000..a315b736
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/mechanicedit/ValueEditOnewayLever.java
@@ -0,0 +1,137 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.roomedit.mechanicedit;
+
+import kr.syeyoung.dungeonsguide.dungeon.data.OffsetPoint;
+import kr.syeyoung.dungeonsguide.dungeon.mechanics.DungeonOnewayLever;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomedit.EditingContext;
+import kr.syeyoung.dungeonsguide.mod.gui.MPanel;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomedit.Parameter;
+import kr.syeyoung.dungeonsguide.mod.gui.elements.MLabel;
+import kr.syeyoung.dungeonsguide.mod.gui.elements.MLabelAndElement;
+import kr.syeyoung.dungeonsguide.mod.gui.elements.MTextField;
+import kr.syeyoung.dungeonsguide.mod.gui.elements.MValue;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomedit.valueedit.ValueEdit;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomedit.valueedit.ValueEditCreator;
+import kr.syeyoung.dungeonsguide.mod.utils.TextUtils;
+
+import java.awt.*;
+import java.util.Arrays;
+import java.util.Collections;
+
+public class ValueEditOnewayLever extends MPanel implements ValueEdit<DungeonOnewayLever> {
+ private Parameter parameter;
+
+ // scroll pane
+ // just create
+ // add set
+ private final DungeonOnewayLever dungeonLever;
+
+ private final MLabel label;
+ private final MValue<OffsetPoint> value;
+ private final MTextField preRequisite;
+ private final MLabelAndElement preRequisite2;
+ private final MTextField target;
+ private final MLabelAndElement target2;
+
+
+ public ValueEditOnewayLever(final Parameter parameter2) {
+ this.parameter = parameter2;
+ this.dungeonLever = (DungeonOnewayLever) parameter2.getNewData();
+
+
+ label = new MLabel();
+ label.setText("Secret Point");
+ label.setAlignment(MLabel.Alignment.LEFT);
+ add(label);
+
+ value = new MValue(dungeonLever.getLeverPoint(), Collections.emptyList());
+ add(value);
+
+ preRequisite = new MTextField() {
+ @Override
+ public void edit(String str) {
+ dungeonLever.setPreRequisite(Arrays.asList(str.split(",")));
+ }
+ };
+ preRequisite.setText(TextUtils.join(dungeonLever.getPreRequisite(), ","));
+ preRequisite2 = new MLabelAndElement("Req.",preRequisite);
+ preRequisite2.setBounds(new Rectangle(0,40,getBounds().width,20));
+ add(preRequisite2);
+
+
+ target = new MTextField() {
+ @Override
+ public void edit(String str) {
+ dungeonLever.setTriggering(str);
+ }
+ };
+ target.setText(dungeonLever.getTriggering());
+ target2 = new MLabelAndElement("Target",target);
+ target2.setBounds(new Rectangle(0,60,getBounds().width,20));
+ add(target2);
+ }
+
+ @Override
+ public void onBoundsUpdate() {
+ label.setBounds(new Rectangle(0,0,getBounds().width, 20));
+ value.setBounds(new Rectangle(0,20,getBounds().width, 20));
+ preRequisite2.setBounds(new Rectangle(0,40,getBounds().width,20));
+ target2.setBounds(new Rectangle(0,60,getBounds().width,20));
+ }
+
+ @Override
+ public void setParameter(Parameter parameter) {
+ this.parameter = parameter;
+ }
+
+ @Override
+ public void renderWorld(float partialTicks) {
+ dungeonLever.highlight(new Color(0,255,0,50), parameter.getName(), EditingContext.getEditingContext().getRoom(), partialTicks);
+ }
+
+ @Override
+ public void resize(int parentWidth, int parentHeight) {
+ this.setBounds(new Rectangle(0,0,parentWidth, parentHeight));
+ }
+
+ public static class Generator implements ValueEditCreator<ValueEditOnewayLever> {
+
+ @Override
+ public ValueEditOnewayLever createValueEdit(Parameter parameter) {
+ return new ValueEditOnewayLever(parameter);
+ }
+
+ @Override
+ public Object createDefaultValue(Parameter parameter) {
+ return new DungeonOnewayLever();
+ }
+
+ @Override
+ public Object cloneObj(Object object) {
+ try {
+ return ((DungeonOnewayLever)object).clone();
+ } catch (CloneNotSupportedException e) {
+ e.printStackTrace();
+ }
+ assert false;
+ return null;
+ }
+ }
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/mechanicedit/ValueEditPressurePlate.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/mechanicedit/ValueEditPressurePlate.java
new file mode 100755
index 00000000..dac3d196
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/mechanicedit/ValueEditPressurePlate.java
@@ -0,0 +1,136 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.roomedit.mechanicedit;
+
+import kr.syeyoung.dungeonsguide.dungeon.data.OffsetPoint;
+import kr.syeyoung.dungeonsguide.dungeon.mechanics.DungeonPressurePlate;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomedit.EditingContext;
+import kr.syeyoung.dungeonsguide.mod.gui.MPanel;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomedit.Parameter;
+import kr.syeyoung.dungeonsguide.mod.gui.elements.MLabel;
+import kr.syeyoung.dungeonsguide.mod.gui.elements.MLabelAndElement;
+import kr.syeyoung.dungeonsguide.mod.gui.elements.MTextField;
+import kr.syeyoung.dungeonsguide.mod.gui.elements.MValue;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomedit.valueedit.ValueEdit;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomedit.valueedit.ValueEditCreator;
+import kr.syeyoung.dungeonsguide.mod.utils.TextUtils;
+import java.awt.*;
+import java.util.Arrays;
+import java.util.Collections;
+
+public class ValueEditPressurePlate extends MPanel implements ValueEdit<DungeonPressurePlate> {
+ private Parameter parameter;
+
+ // scroll pane
+ // just create
+ // add set
+ private final DungeonPressurePlate dungeonPressureplate;
+
+ private final MLabel label;
+ private final MValue<OffsetPoint> value;
+ private final MTextField preRequisite;
+ private final MLabelAndElement preRequisite2;
+ private final MTextField target;
+ private final MLabelAndElement target2;
+
+
+ public ValueEditPressurePlate(final Parameter parameter2) {
+ this.parameter = parameter2;
+ this.dungeonPressureplate = (DungeonPressurePlate) parameter2.getNewData();
+
+
+ label = new MLabel();
+ label.setText("Secret Point");
+ label.setAlignment(MLabel.Alignment.LEFT);
+ add(label);
+
+ value = new MValue(dungeonPressureplate.getPlatePoint(), Collections.emptyList());
+ add(value);
+
+ preRequisite = new MTextField() {
+ @Override
+ public void edit(String str) {
+ dungeonPressureplate.setPreRequisite(Arrays.asList(str.split(",")));
+ }
+ };
+ preRequisite.setText(TextUtils.join(dungeonPressureplate.getPreRequisite(), ","));
+ preRequisite2 = new MLabelAndElement("Req.",preRequisite);
+ preRequisite2.setBounds(new Rectangle(0,40,getBounds().width,20));
+ add(preRequisite2);
+
+
+ target = new MTextField() {
+ @Override
+ public void edit(String str) {
+ dungeonPressureplate.setTriggering(str);
+ }
+ };
+ target.setText(dungeonPressureplate.getTriggering());
+ target2 = new MLabelAndElement("Target",target);
+ target2.setBounds(new Rectangle(0,60,getBounds().width,20));
+ add(target2);
+ }
+
+ @Override
+ public void onBoundsUpdate() {
+ label.setBounds(new Rectangle(0,0,getBounds().width, 20));
+ value.setBounds(new Rectangle(0,20,getBounds().width, 20));
+ preRequisite2.setBounds(new Rectangle(0,40,getBounds().width,20));
+ target2.setBounds(new Rectangle(0,60,getBounds().width,20));
+ }
+
+ @Override
+ public void setParameter(Parameter parameter) {
+ this.parameter = parameter;
+ }
+
+ @Override
+ public void renderWorld(float partialTicks) {
+ dungeonPressureplate.highlight(new Color(0,255,0,50), parameter.getName(), EditingContext.getEditingContext().getRoom(), partialTicks);
+ }
+
+ @Override
+ public void resize(int parentWidth, int parentHeight) {
+ this.setBounds(new Rectangle(0,0,parentWidth, parentHeight));
+ }
+
+ public static class Generator implements ValueEditCreator<ValueEditPressurePlate> {
+
+ @Override
+ public ValueEditPressurePlate createValueEdit(Parameter parameter) {
+ return new ValueEditPressurePlate(parameter);
+ }
+
+ @Override
+ public Object createDefaultValue(Parameter parameter) {
+ return new DungeonPressurePlate();
+ }
+
+ @Override
+ public Object cloneObj(Object object) {
+ try {
+ return ((DungeonPressurePlate)object).clone();
+ } catch (CloneNotSupportedException e) {
+ e.printStackTrace();
+ }
+ assert false;
+ return null;
+ }
+ }
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/mechanicedit/ValueEditSecret.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/mechanicedit/ValueEditSecret.java
new file mode 100755
index 00000000..165105aa
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/mechanicedit/ValueEditSecret.java
@@ -0,0 +1,129 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.roomedit.mechanicedit;
+
+import kr.syeyoung.dungeonsguide.dungeon.data.OffsetPoint;
+import kr.syeyoung.dungeonsguide.dungeon.mechanics.DungeonSecret;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomedit.EditingContext;
+import kr.syeyoung.dungeonsguide.mod.gui.MPanel;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomedit.Parameter;
+import kr.syeyoung.dungeonsguide.mod.gui.elements.*;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomedit.valueedit.ValueEdit;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomedit.valueedit.ValueEditCreator;
+import kr.syeyoung.dungeonsguide.mod.utils.TextUtils;
+
+import java.awt.*;
+import java.util.Arrays;
+import java.util.Collections;
+
+public class ValueEditSecret extends MPanel implements ValueEdit<DungeonSecret> {
+ private Parameter parameter;
+
+ // scroll pane
+ // just create
+ // add set
+ private final DungeonSecret dungeonSecret;
+
+ private final MLabel label;
+ private final MValue<OffsetPoint> value;
+ private final MStringSelectionButton selectionButton;
+ private final MTextField preRequisite;
+ private final MLabelAndElement preRequisite2;
+
+ public ValueEditSecret(final Parameter parameter2) {
+ this.parameter = parameter2;
+ this.dungeonSecret = (DungeonSecret) parameter2.getNewData();
+
+
+ label = new MLabel();
+ label.setText("Secret Point");
+ label.setAlignment(MLabel.Alignment.LEFT);
+ add(label);
+
+ value = new MValue(dungeonSecret.getSecretPoint(), Collections.emptyList());
+ add(value);
+
+ selectionButton = new MStringSelectionButton(Arrays.asList("CHEST", "BAT", "ITEM_DROP", "ESSENCE"), dungeonSecret.getSecretType().name());
+ selectionButton.setOnUpdate(new Runnable() {
+ @Override
+ public void run() {
+ dungeonSecret.setSecretType(DungeonSecret.SecretType.valueOf(selectionButton.getSelected()));
+ }
+ });
+ add(selectionButton);
+
+ preRequisite = new MTextField() {
+ @Override
+ public void edit(String str) {
+ dungeonSecret.setPreRequisite(Arrays.asList(str.split(",")));
+ }
+ };
+ preRequisite.setText(TextUtils.join(dungeonSecret.getPreRequisite(), ","));
+ preRequisite2 = new MLabelAndElement("Req.",preRequisite);
+ preRequisite2.setBounds(new Rectangle(0,60,getBounds().width,20));
+ add(preRequisite2);
+ }
+
+ @Override
+ public void onBoundsUpdate() {
+ label.setBounds(new Rectangle(0,0,getBounds().width, 20));
+ value.setBounds(new Rectangle(0,20,getBounds().width, 20));
+ selectionButton.setBounds(new Rectangle(0,40,getBounds().width, 20));
+ preRequisite2.setBounds(new Rectangle(0,60,getBounds().width,20));
+ }
+
+ @Override
+ public void setParameter(Parameter parameter) {
+ this.parameter = parameter;
+ }
+
+ @Override
+ public void renderWorld(float partialTicks) {
+ dungeonSecret.highlight(new Color(0,255,0,50), parameter.getName(), EditingContext.getEditingContext().getRoom(), partialTicks);
+ }
+
+ @Override
+ public void resize(int parentWidth, int parentHeight) {
+ this.setBounds(new Rectangle(0,0,parentWidth, parentHeight));
+ }
+
+ public static class Generator implements ValueEditCreator<ValueEditSecret> {
+
+ @Override
+ public ValueEditSecret createValueEdit(Parameter parameter) {
+ return new ValueEditSecret(parameter);
+ }
+
+ @Override
+ public Object createDefaultValue(Parameter parameter) {
+ return new DungeonSecret();
+ }
+
+ @Override
+ public Object cloneObj(Object object) {
+ try {
+ return ((DungeonSecret)object).clone();
+ } catch (CloneNotSupportedException e) {
+ e.printStackTrace();
+ }
+ assert false;
+ return null;
+ }
+ }
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/mechanicedit/ValueEditTomb.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/mechanicedit/ValueEditTomb.java
new file mode 100755
index 00000000..2604b873
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/mechanicedit/ValueEditTomb.java
@@ -0,0 +1,118 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.roomedit.mechanicedit;
+
+import kr.syeyoung.dungeonsguide.dungeon.data.OffsetPointSet;
+import kr.syeyoung.dungeonsguide.dungeon.mechanics.DungeonTomb;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomedit.EditingContext;
+import kr.syeyoung.dungeonsguide.mod.gui.MPanel;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomedit.Parameter;
+import kr.syeyoung.dungeonsguide.mod.gui.elements.*;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomedit.valueedit.ValueEdit;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomedit.valueedit.ValueEditCreator;
+import kr.syeyoung.dungeonsguide.mod.utils.TextUtils;
+
+import java.awt.*;
+import java.util.Arrays;
+import java.util.Collections;
+
+public class ValueEditTomb extends MPanel implements ValueEdit<DungeonTomb> {
+ private Parameter parameter;
+
+ // scroll pane
+ // just create
+ // add set
+ private final DungeonTomb dungeonTomb;
+
+ private final MLabel label;
+ private final MValue<OffsetPointSet> value;
+ private final MTextField preRequisite;
+ private final MLabelAndElement preRequisite2;
+
+ public ValueEditTomb(final Parameter parameter2) {
+ this.parameter = parameter2;
+ this.dungeonTomb = (DungeonTomb) parameter2.getNewData();
+
+
+ label = new MLabel();
+ label.setText("Tomb Points");
+ label.setAlignment(MLabel.Alignment.LEFT);
+ add(label);
+
+ value = new MValue(dungeonTomb.getSecretPoint(), Collections.emptyList());
+ add(value);
+
+ preRequisite = new MTextField() {
+ @Override
+ public void edit(String str) {
+ dungeonTomb.setPreRequisite(Arrays.asList(str.split(",")));
+ }
+ };
+ preRequisite.setText(TextUtils.join(dungeonTomb.getPreRequisite(), ","));
+ preRequisite2 = new MLabelAndElement("Req.",preRequisite);
+ preRequisite2.setBounds(new Rectangle(0,40,getBounds().width,20));
+ add(preRequisite2);
+ }
+
+ @Override
+ public void onBoundsUpdate() {
+ label.setBounds(new Rectangle(0,0,getBounds().width, 20));
+ value.setBounds(new Rectangle(0,20,getBounds().width, 20));
+ preRequisite2.setBounds(new Rectangle(0,40,getBounds().width,20));
+ }
+
+ @Override
+ public void setParameter(Parameter parameter) {
+ this.parameter = parameter;
+ }
+
+ @Override
+ public void renderWorld(float partialTicks) {
+ dungeonTomb.highlight(new Color(0,255,255,50), parameter.getName(), EditingContext.getEditingContext().getRoom(), partialTicks);
+ }
+
+ @Override
+ public void resize(int parentWidth, int parentHeight) {
+ this.setBounds(new Rectangle(0,0,parentWidth, parentHeight));
+ }
+
+ public static class Generator implements ValueEditCreator<ValueEditTomb> {
+
+ @Override
+ public ValueEditTomb createValueEdit(Parameter parameter) {
+ return new ValueEditTomb(parameter);
+ }
+
+ @Override
+ public Object createDefaultValue(Parameter parameter) {
+ return new DungeonTomb();
+ }
+
+ @Override
+ public Object cloneObj(Object object) {
+ try {
+ return ((DungeonTomb)object).clone();
+ } catch (CloneNotSupportedException e) {
+ e.printStackTrace();
+ }
+ assert false;
+ return null;
+ }
+ }
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/panes/ActionDisplayPane.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/panes/ActionDisplayPane.java
new file mode 100755
index 00000000..2c886ac9
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/panes/ActionDisplayPane.java
@@ -0,0 +1,82 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.roomedit.panes;
+
+import kr.syeyoung.dungeonsguide.mod.dungeon.actions.ActionChangeState;
+import kr.syeyoung.dungeonsguide.mod.dungeon.actions.tree.ActionTree;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomfinder.DungeonRoom;
+import kr.syeyoung.dungeonsguide.mod.gui.MPanel;
+import kr.syeyoung.dungeonsguide.mod.gui.elements.*;
+
+import java.awt.*;
+
+public class ActionDisplayPane extends MPanel {
+ private final DungeonRoom dungeonRoom;
+
+ private ActionTreeDisplayPane displayPane;
+
+ private final MTextField textField;
+ private final MButton calculate;
+ public ActionDisplayPane(final DungeonRoom dungeonRoom) {
+ this.dungeonRoom = dungeonRoom;
+
+ {
+ textField = new MTextField();
+ textField.setBounds(new Rectangle(0,0,getBounds().width - 100, 20));
+ add(textField);
+ }
+ {
+ calculate = new MButton();
+ calculate.setBounds(new Rectangle(getBounds().width - 100,0,100, 20));
+ calculate.setText("calculate");
+ calculate.setOnActionPerformed(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ remove(displayPane);
+
+ String text = textField.getText();
+ String target = text.split(":")[0];
+ String state = text.split(":")[1];
+ ActionChangeState actionChangeState = new ActionChangeState(target, state);
+ ActionTree tree= ActionTree.buildActionTree(actionChangeState, dungeonRoom);
+
+ displayPane = new ActionTreeDisplayPane(dungeonRoom, tree);
+ displayPane.setBounds(new Rectangle(0,25,getBounds().width,getBounds().height-25));
+ add(displayPane);
+ } catch (Throwable t) {
+ t.printStackTrace();
+ }
+ }
+ });
+ add(calculate);
+ }
+ }
+
+ @Override
+ public void resize(int parentWidth, int parentHeight) {
+ this.setBounds(new Rectangle(5,5,parentWidth-10,parentHeight-10));
+ }
+
+ @Override
+ public void onBoundsUpdate() {
+ textField.setBounds(new Rectangle(0,0,getBounds().width - 100, 20));
+ calculate.setBounds(new Rectangle(getBounds().width - 100,0,100, 20));
+ }
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/panes/ActionTreeDisplayPane.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/panes/ActionTreeDisplayPane.java
new file mode 100755
index 00000000..bcc75a98
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/panes/ActionTreeDisplayPane.java
@@ -0,0 +1,216 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.roomedit.panes;
+
+import kr.syeyoung.dungeonsguide.mod.dungeon.actions.AbstractAction;
+import kr.syeyoung.dungeonsguide.mod.dungeon.actions.tree.ActionTree;
+import kr.syeyoung.dungeonsguide.mod.dungeon.actions.tree.ActionTreeUtil;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomfinder.DungeonRoom;
+import kr.syeyoung.dungeonsguide.mod.gui.MPanel;
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.gui.FontRenderer;
+import net.minecraft.client.gui.Gui;
+import net.minecraft.client.gui.ScaledResolution;
+import net.minecraft.client.renderer.GlStateManager;
+import org.lwjgl.opengl.GL11;
+
+import java.awt.*;
+import java.util.*;
+import java.util.List;
+
+public class ActionTreeDisplayPane extends MPanel {
+
+ private int offsetX = 0;
+ private int offsetY = 0;
+
+ private float scale;
+
+ private final DungeonRoom dungeonRoom;
+ private final ActionTree tree;
+ private List<AbstractAction> linearified;
+ public ActionTreeDisplayPane(DungeonRoom dungeonRoom, ActionTree tree) {
+ this.dungeonRoom = dungeonRoom;
+ this.tree = tree;
+ try {
+ this.linearified = ActionTreeUtil.linearifyActionTree(tree);
+ } catch (Exception e) {
+ linearified = new ArrayList<AbstractAction>();
+ e.printStackTrace();
+ }
+ scale = 1.0f;
+ }
+
+ @Override
+ public void render(int absMousex, int absMousey, int relMousex0, int relMousey0, float partialTicks, Rectangle clip) {
+ ScaledResolution sr = new ScaledResolution(Minecraft.getMinecraft());
+
+ FontRenderer fr = Minecraft.getMinecraft().fontRendererObj;
+
+ GlStateManager.pushMatrix();
+ GlStateManager.translate(offsetX, offsetY, 0);
+ GlStateManager.scale(scale,scale,1);
+ int x = renderTree(tree, 5, 5, Minecraft.getMinecraft().fontRendererObj, null, new HashMap<ActionTree, Point>());
+ renderLinearified(linearified, x, 5, fr);
+ GlStateManager.popMatrix();
+ }
+
+ public int renderTree(ActionTree actionTree, int x, int y, FontRenderer fr, Point drawLineFrom, HashMap<ActionTree, Point> drawmPoints) {
+ if (drawmPoints.containsKey(actionTree)) {
+ // recursive, fu
+ Point pt = drawmPoints.get(actionTree);
+
+ GlStateManager.pushMatrix();
+
+ GlStateManager.enableBlend();
+ GlStateManager.disableDepth();
+ GlStateManager.disableTexture2D();
+ GlStateManager.blendFunc(770, 771);
+ GlStateManager.enableBlend();
+ GL11.glLineWidth(1);
+ GlStateManager.color(1, 0, 0, 1);
+ GL11.glBegin(2);
+ GL11.glVertex2d(drawLineFrom.x, drawLineFrom.y);
+ GL11.glVertex2d(pt.x, pt.y);
+ GL11.glEnd();
+ GlStateManager.disableBlend();
+ GlStateManager.enableTexture2D();
+ GlStateManager.enableDepth();
+ GlStateManager.disableBlend();
+ GlStateManager.popMatrix();
+
+ return 0;
+ }
+
+ Dimension dim = renderAction(actionTree.getCurrent(), x, y, fr);
+ if (drawLineFrom != null) {
+ GlStateManager.pushMatrix();
+
+
+ GlStateManager.enableBlend();
+ GlStateManager.disableDepth();
+ GlStateManager.disableTexture2D();
+ GlStateManager.blendFunc(770, 771);
+ GlStateManager.enableBlend();
+ GL11.glLineWidth(1);
+ GlStateManager.color(1, 1, 1, 1);
+ GL11.glBegin(2);
+ GL11.glVertex2d(drawLineFrom.x, drawLineFrom.y);
+ GL11.glVertex2d(x + dim.width / 2, y);
+ GL11.glEnd();
+ GlStateManager.disableBlend();
+ GlStateManager.enableTexture2D();
+ GlStateManager.enableDepth();
+ GlStateManager.disableBlend();
+ GlStateManager.popMatrix();
+
+ }
+ Point pt = new Point(x + dim.width / 2, y + dim.height);
+
+ drawmPoints.put(actionTree, new Point(x + dim.width / 2, y + dim.height / 2));
+ int xOff = 0;
+ for (ActionTree tree:actionTree.getChildren()) {
+ xOff += renderTree(tree, x + xOff, y + dim.height + 10, fr, pt, drawmPoints) + 10;
+ }
+ return Math.max(xOff, dim.width);
+ }
+
+ public void renderLinearified(List<AbstractAction> actions, int x, int y, FontRenderer fr) {
+ Point lastPt = null;
+ int y2 = y;
+
+ for (AbstractAction action : actions) {
+ Dimension dim = renderAction(action, x, y2, fr);
+ if (lastPt != null) {
+ GlStateManager.pushMatrix();
+
+
+ GlStateManager.enableBlend();
+ GlStateManager.disableDepth();
+ GlStateManager.disableTexture2D();
+ GlStateManager.blendFunc(770, 771);
+ GlStateManager.enableBlend();
+ GL11.glLineWidth(1);
+ GlStateManager.color(1, 1, 1, 1);
+ GL11.glBegin(2);
+ GL11.glVertex2d(lastPt.x, lastPt.y);
+ GL11.glVertex2d(x + dim.width / 2, y2);
+ GL11.glEnd();
+ GlStateManager.disableBlend();
+ GlStateManager.enableTexture2D();
+ GlStateManager.enableDepth();
+ GlStateManager.disableBlend();
+ GlStateManager.popMatrix();
+
+ }
+ lastPt = new Point(x + dim.width / 2, y2 + dim.height);
+
+ y2 += dim.height + 10;
+ }
+ }
+
+ public Dimension renderAction(AbstractAction action, int x, int y, FontRenderer fr) {
+ String[] lines = action.toString().split("\n");
+ int maxWidth = 0;
+ for (String line : lines) {
+ if (fr.getStringWidth(line) > maxWidth) maxWidth= fr.getStringWidth(line);
+ }
+ int offset = 2;
+ int height = (fr.FONT_HEIGHT + offset) * lines.length;
+
+ Gui.drawRect(x,y,x + maxWidth +10, y + height + 10, 0xff000000);
+ Gui.drawRect(x+1,y+1,x + maxWidth +8, y + height + 8, 0xff4d4d4d);
+ for (int i = 0; i < lines.length; i++) {
+ fr.drawString(lines[i], x + 5, y + 5 + i*(fr.FONT_HEIGHT + offset), 0xffffffff);
+ }
+
+ return new Dimension(maxWidth + 10, height + 10);
+ }
+
+ @Override
+ public void resize(int parentWidth, int parentHeight) {
+ this.setBounds(new Rectangle(0,25,parentWidth,parentHeight-25));
+ }
+
+
+ private int lastX;
+ private int lastY;
+ @Override
+ public void mouseClicked(int absMouseX, int absMouseY, int relMouseX, int relMouseY, int mouseButton) {
+ lastX = absMouseX;
+ lastY = absMouseY;
+ }
+
+ @Override
+ public void mouseClickMove(int absMouseX, int absMouseY, int relMouseX, int relMouseY, int clickedMouseButton, long timeSinceLastClick) {
+ int dX = absMouseX - lastX;
+ int dY = absMouseY - lastY;
+ offsetX += dX;
+ offsetY += dY;
+ lastX = absMouseX;
+ lastY = absMouseY;
+ }
+
+ @Override
+ public void mouseScrolled0(int absMouseX, int absMouseY, int relMouseX0, int relMouseY0, int scrollAmount) {
+ if (scrollAmount > 0) scale += 0.1;
+ if (scrollAmount < 0) scale -= 0.1;
+
+ if (scale < 0) scale = 0.1f;
+ }
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/panes/DynamicEditor.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/panes/DynamicEditor.java
new file mode 100755
index 00000000..5be67660
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/panes/DynamicEditor.java
@@ -0,0 +1,29 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.roomedit.panes;
+
+import kr.syeyoung.dungeonsguide.mod.gui.elements.MParameter;
+
+import java.util.List;
+
+public interface DynamicEditor {
+ void delete(MParameter parameter);
+
+ List<String> allowedClass();
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/panes/GeneralEditPane.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/panes/GeneralEditPane.java
new file mode 100755
index 00000000..a60797e8
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/panes/GeneralEditPane.java
@@ -0,0 +1,286 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.roomedit.panes;
+
+import kr.syeyoung.dungeonsguide.mod.DungeonsGuide;
+import kr.syeyoung.dungeonsguide.Main;
+import kr.syeyoung.dungeonsguide.mod.chat.ChatTransmitter;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomedit.EditingContext;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomfinder.DungeonRoom;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomfinder.DungeonRoomInfoRegistry;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.ProcessorFactory;
+import kr.syeyoung.dungeonsguide.mod.gui.MPanel;
+import kr.syeyoung.dungeonsguide.mod.gui.elements.*;
+import net.minecraft.block.Block;
+import net.minecraft.block.state.IBlockState;
+import net.minecraft.nbt.NBTTagCompound;
+import net.minecraft.nbt.NBTTagList;
+import net.minecraft.tileentity.TileEntity;
+import net.minecraft.util.BlockPos;
+import net.minecraft.util.ChatComponentText;
+
+import java.awt.*;
+import java.io.*;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.UUID;
+import java.util.zip.GZIPOutputStream;
+
+public class GeneralEditPane extends MPanel {
+ private final DungeonRoom dungeonRoom;
+
+ private final MLabelAndElement uuid;
+ private final MLabelAndElement name;
+ private final MLabelAndElement secrets;
+
+ private final MLabelAndElement shape;
+ private final MLabelAndElement rotation;
+ private final MLabelAndElement shape2;
+
+ private MButton save;
+ private final MButton end;
+ private final MButton schematic;
+
+ private final MLabelAndElement roomProcessor;
+
+ public GeneralEditPane(final DungeonRoom dungeonRoom) {
+ this.dungeonRoom = dungeonRoom;
+ {
+ MLabel la;
+ uuid = new MLabelAndElement("Room UUID: ", la = new MLabel());
+ la.setText(dungeonRoom.getDungeonRoomInfo().getUuid().toString());
+ uuid.setBounds(new Rectangle(0,0,getBounds().width, 20));
+ add(uuid);
+ }
+ {
+ MTextField la = new MTextField() {
+ @Override
+ public void edit(String str) {
+ dungeonRoom.getDungeonRoomInfo().setName(str);
+ }
+ };
+ name = new MLabelAndElement("Room Name: ", la);
+ la.setText(dungeonRoom.getDungeonRoomInfo().getName());
+ name.setBounds(new Rectangle(0,20,getBounds().width, 20));
+ add(name);
+ }
+ {
+ final MIntegerSelectionButton la = new MIntegerSelectionButton(dungeonRoom.getDungeonRoomInfo().getTotalSecrets());
+ la.setOnUpdate(new Runnable() {
+ @Override
+ public void run() {
+ dungeonRoom.getDungeonRoomInfo().setTotalSecrets(la.getData());
+ }
+ });
+ secrets = new MLabelAndElement("Room Secrets: ", la);
+ secrets.setBounds(new Rectangle(0,40,getBounds().width, 20));
+ add(secrets);
+ }
+
+ {
+ MLabel la;
+ shape = new MLabelAndElement("Room Shape: ", la = new MLabel());
+ la.setText(dungeonRoom.getDungeonRoomInfo().getShape()+"");
+ shape.setBounds(new Rectangle(0,60,getBounds().width, 20));
+ add(shape);
+ }
+
+ {
+ MLabel la;
+ rotation = new MLabelAndElement("Found Room Rotation: ", la = new MLabel());
+ la.setText(dungeonRoom.getRoomMatcher().getRotation()+"");
+ rotation.setBounds(new Rectangle(0,80,getBounds().width, 20));
+ add(rotation);
+ }
+ {
+ MLabel la;
+ shape2 = new MLabelAndElement("Found Room Shape: ", la = new MLabel());
+ la.setText(dungeonRoom.getShape()+"");
+ shape2.setBounds(new Rectangle(0,100,getBounds().width, 20));
+ add(shape2);
+ }
+ {
+ final MStringSelectionButton mStringSelectionButton = new MStringSelectionButton(new ArrayList<String>(ProcessorFactory.getProcessors()), dungeonRoom.getDungeonRoomInfo().getProcessorId());
+ roomProcessor = new MLabelAndElement("Room Processor: ", mStringSelectionButton);
+ roomProcessor.setBounds(new Rectangle(0,120,getBounds().width, 20));
+ add(roomProcessor);
+
+ mStringSelectionButton.setOnUpdate(new Runnable() {
+ @Override
+ public void run() {
+ dungeonRoom.getDungeonRoomInfo().setProcessorId(mStringSelectionButton.getSelected());
+ dungeonRoom.updateRoomProcessor();
+ }
+ });
+ }
+ {
+ end = new MButton();
+ end.setText("End Editing Session");
+ end.setOnActionPerformed(new Runnable() {
+ @Override
+ public void run() {
+ EditingContext.endEditingSession();
+ }
+ });
+ end.setBackgroundColor(Color.green);
+ end.setBounds(new Rectangle(0,140,getBounds().width, 20));
+ add(end);
+ }
+ {
+ schematic = new MButton();
+ schematic.setText("Save Schematic");
+ schematic.setOnActionPerformed(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ NBTTagCompound nbtTagCompound2 = createNBT();
+
+ File f=new File(Main.getConfigDir(), "schematics/"+
+ dungeonRoom.getDungeonRoomInfo().getName()+"-"+dungeonRoom.getDungeonRoomInfo().getUuid().toString()+"-"+ UUID.randomUUID()+".schematic");
+
+ Method method = null;
+ try {
+ method = NBTTagCompound.class.getDeclaredMethod("write", DataOutput.class);
+ method.setAccessible(true);
+ } catch (NoSuchMethodException e) {
+ e.printStackTrace();
+ return;
+ }
+ FileOutputStream fos = new FileOutputStream(f);
+ DataOutputStream dataoutputstream = new DataOutputStream(new BufferedOutputStream(new GZIPOutputStream(fos)));
+
+ try
+ {
+ dataoutputstream.writeByte(nbtTagCompound2.getId());
+
+ dataoutputstream.writeUTF("Schematic");
+ method.invoke(nbtTagCompound2, dataoutputstream);
+ }
+ finally
+ {
+ dataoutputstream.close();
+ }
+ ChatTransmitter.addToQueue(new ChatComponentText("§eDungeons Guide §7:: §fSaved to "+f.getName()));
+ } catch (Throwable e) {
+ e.printStackTrace();
+ }
+
+ }
+ });
+ schematic.setBackgroundColor(Color.orange);
+ schematic.setBounds(new Rectangle(0,180,getBounds().width, 20));
+ add(schematic);
+ }
+ {
+ if (dungeonRoom.getDungeonRoomInfo().isRegistered()) return;
+ save = new MButton();
+ save.setText("Save RoomData");
+ save.setOnActionPerformed(new Runnable() {
+ @Override
+ public void run() {
+ DungeonRoomInfoRegistry.register(dungeonRoom.getDungeonRoomInfo());
+ remove(save);
+ }
+ });
+ save.setBackgroundColor(Color.green);
+ save.setBounds(new Rectangle(0,10,getBounds().width, 20));
+ add(save);
+ }
+ }
+
+ @Override
+ public void resize(int parentWidth, int parentHeight) {
+ this.setBounds(new Rectangle(5,5,parentWidth-10,parentHeight-10));
+ }
+
+ @Override
+ public void onBoundsUpdate() {
+ if (save != null)
+ save.setBounds(new Rectangle(0,160,getBounds().width, 20));
+ end.setBounds(new Rectangle(1,140,getBounds().width-2, 20));
+ if (schematic != null)
+ schematic.setBounds(new Rectangle(0,180,getBounds().width, 20));
+ }
+
+ private NBTTagCompound createNBT() {
+ NBTTagCompound compound = new NBTTagCompound();
+ compound.setShort("Width", (short) (dungeonRoom.getMax().getX() - dungeonRoom.getMin().getX() + 1));
+ compound.setShort("Height", (short) 255);
+ compound.setShort("Length", (short) (dungeonRoom.getMax().getZ() - dungeonRoom.getMin().getZ() + 1));
+ int size =compound.getShort("Width") * compound.getShort("Height") * compound.getShort("Length");
+
+ byte[] blocks = new byte[size];
+ byte[] meta = new byte[size];
+ byte[] extra = new byte[size];
+ byte[] extranibble = new byte[(int) Math.ceil(size / 2.0)];
+
+ boolean extraEx = false;
+ NBTTagList tileEntitiesList = new NBTTagList();
+ for (int x = 0; x < compound.getShort("Width"); x++) {
+ for (int y = 0; y < compound.getShort("Height"); y++) {
+ for (int z = 0; z < compound.getShort("Length"); z++) {
+ int index = x + (y * compound.getShort("Length") + z) * compound.getShort("Width");
+ BlockPos pos = dungeonRoom.getRelativeBlockPosAt(x,y - 70,z);
+ IBlockState blockState = DungeonsGuide.getDungeonsGuide().getBlockCache().getBlockState(pos);
+ boolean acc = dungeonRoom.canAccessRelative(x,z);
+ int id = Block.getIdFromBlock(blockState.getBlock());
+ blocks[index] = acc ? (byte) id : 0;
+ meta[index] = acc ? (byte) blockState.getBlock().getMetaFromState(blockState) : 0;
+ if ((extra[index] = (byte) ((acc ? id : 0) >> 8)) > 0) {
+ extraEx = true;
+ }
+
+ if (blockState.getBlock().hasTileEntity(blockState)) {
+ TileEntity tileEntity = dungeonRoom.getContext().getWorld().getTileEntity(pos);
+ try {
+ final NBTTagCompound tileEntityCompound = new NBTTagCompound();
+ tileEntity.writeToNBT(tileEntityCompound);
+ tileEntitiesList.appendTag(tileEntityCompound);
+ } catch (final Exception e) {
+ final BlockPos tePos = tileEntity.getPos();
+
+ blocks[index] = (byte) 7;
+ meta[index] = 0;
+ extra[index] = 0;
+ }
+ }
+ }
+ }
+ }
+ for (int i = 0; i < extranibble.length; i++) {
+ if (i * 2 + 1 < extra.length) {
+ extranibble[i] = (byte) ((extra[i * 2 + 0] << 4) | extra[i * 2 + 1]);
+ } else {
+ extranibble[i] = (byte) (extra[i * 2 + 0] << 4);
+ }
+ }
+
+
+ compound.setByteArray("Blocks", blocks);
+ compound.setByteArray("Data", meta);
+ compound.setString("Materials", "Alpha");
+ if (extraEx) {
+ compound.setByteArray("AddBlocks", extranibble);
+ }
+ compound.setTag("Entities", new NBTTagList());
+ compound.setTag("TileEntities", tileEntitiesList);
+
+ return compound;
+ }
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/panes/ProcessorParameterEditPane.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/panes/ProcessorParameterEditPane.java
new file mode 100755
index 00000000..5b907fb7
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/panes/ProcessorParameterEditPane.java
@@ -0,0 +1,144 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.roomedit.panes;
+
+import kr.syeyoung.dungeonsguide.dungeon.data.DungeonRoomInfo;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomfinder.DungeonRoom;
+import kr.syeyoung.dungeonsguide.mod.gui.MPanel;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomedit.Parameter;
+import kr.syeyoung.dungeonsguide.mod.gui.elements.MButton;
+import kr.syeyoung.dungeonsguide.mod.gui.elements.MParameter;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomedit.valueedit.ValueEditCreator;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomedit.valueedit.ValueEditRegistry;
+
+import java.awt.*;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+
+public class ProcessorParameterEditPane extends MPanel implements DynamicEditor {
+ private final DungeonRoom dungeonRoom;
+
+ private MButton save;
+ private MButton create;
+ private final List<MParameter> parameters = new ArrayList<MParameter>();
+
+ public ProcessorParameterEditPane(DungeonRoom dungeonRoom) {
+ this.dungeonRoom = dungeonRoom;
+ buildElements();
+ }
+
+ public void buildElements() {
+ {
+ create = new MButton();
+ create.setText("Create New Parameter");
+ create.setBackgroundColor(Color.cyan);
+ create.setBounds(new Rectangle(0,0,100,20));
+ create.setOnActionPerformed(new Runnable() {
+ @Override
+ public void run() {
+ MParameter parameter;
+ parameters.add(parameter = new MParameter(new Parameter(UUID.randomUUID().toString(), null, null), ProcessorParameterEditPane.this));
+ parameter.setParent(ProcessorParameterEditPane.this);
+ parameter.setBounds(new Rectangle(0,0,getBounds().width, 20));
+ }
+ });
+
+ save = new MButton();
+ save.setText("Save");
+ save.setBackgroundColor(Color.green);
+ save.setBounds(new Rectangle(0,0,100,20));
+ save.setOnActionPerformed(new Runnable() {
+ @Override
+ public void run() {
+ DungeonRoomInfo dungeonRoomInfo = dungeonRoom.getDungeonRoomInfo();
+ dungeonRoomInfo.getProperties().clear();
+
+ for (MParameter parameter : parameters) {
+ Parameter real = parameter.getParameter();
+
+ ValueEditCreator vec = ValueEditRegistry.getValueEditMap(real.getNewData() == null ? "null" :real.getNewData().getClass().getName());
+
+ real.setPreviousData(vec.cloneObj(real.getNewData()));
+ dungeonRoomInfo.getProperties().put(real.getName(), real.getNewData());
+ }
+ }
+ });
+ create.setParent(this); save.setParent(this);
+ }
+ {
+ for (Map.Entry<String, Object> en : dungeonRoom.getDungeonRoomInfo().getProperties().entrySet()) {
+ ValueEditCreator vec = ValueEditRegistry.getValueEditMap(en.getValue() == null ? "null" :en.getValue().getClass().getName());
+
+ MParameter mParameter = new MParameter(new Parameter(en.getKey(), vec.cloneObj(en.getValue()), vec.cloneObj(en.getValue())), this);
+ mParameter.setBounds(new Rectangle(0,0,getBounds().width,20));
+ parameters.add(mParameter);
+ mParameter.setParent(this);
+ }
+ }
+ }
+
+ @Override
+ public void onBoundsUpdate() {
+ for (MPanel panel :getChildComponents()){
+ panel.setSize(new Dimension(getBounds().width, 20));
+ }
+ }
+ @Override
+ public void resize(int parentWidth, int parentHeight) {
+ this.setBounds(new Rectangle(5,5,parentWidth-10,parentHeight-10));
+ }
+
+
+ public void delete(MParameter parameter) {
+ parameters.remove(parameter);
+ }
+
+ @Override
+ public List<String> allowedClass() {
+ return ValueEditRegistry.getClassesSupported();
+ }
+
+
+ @Override
+ public List<MPanel> getChildComponents() {
+ ArrayList<MPanel> panels = new ArrayList<MPanel>(parameters);
+ panels.add(create);
+ panels.add(save);
+ return panels;
+ }
+
+ private int offsetY = 0;
+ @Override
+ public void render(int absMousex, int absMousey, int relMousex0, int relMousey0, float partialTicks, Rectangle scissor) {
+ int heights = 0;
+ for (MPanel panel:getChildComponents()) {
+ panel.setPosition(new Point(0, -offsetY + heights));
+ heights += panel.getBounds().height;
+ }
+ }
+
+ @Override
+ public void mouseScrolled(int absMouseX, int absMouseY, int relMouseX0, int relMouseY0, int scrollAmount) {
+ if (scrollAmount > 0) offsetY -= 20;
+ else if (scrollAmount < 0) offsetY += 20;
+ if (offsetY < 0) offsetY = 0;
+ }
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/panes/RoomDataDisplayPane.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/panes/RoomDataDisplayPane.java
new file mode 100755
index 00000000..f2ae85c3
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/panes/RoomDataDisplayPane.java
@@ -0,0 +1,126 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.roomedit.panes;
+
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomfinder.DungeonRoom;
+import kr.syeyoung.dungeonsguide.mod.gui.MPanel;
+import net.minecraft.block.Block;
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.gui.FontRenderer;
+import net.minecraft.client.gui.Gui;
+import net.minecraft.client.gui.ScaledResolution;
+import net.minecraft.item.Item;
+import net.minecraft.item.ItemStack;
+
+import java.awt.*;
+
+public class RoomDataDisplayPane extends MPanel {
+
+ private int offsetX = 0;
+ private int offsetY = 0;
+
+ private int selectedX = -1;
+ private int selectedY = -1;
+
+ private final DungeonRoom dungeonRoom;
+ public RoomDataDisplayPane(DungeonRoom dungeonRoom) {
+ this.dungeonRoom = dungeonRoom;
+ }
+
+ @Override
+ public void render(int absMousex, int absMousey, int relMousex0, int relMousey0, float partialTicks, Rectangle clip) {
+ ScaledResolution sr = new ScaledResolution(Minecraft.getMinecraft());
+
+ FontRenderer fr = Minecraft.getMinecraft().fontRendererObj;
+
+ int[][] blocks = dungeonRoom.getDungeonRoomInfo().getBlocks();
+ // draw Axis;
+ Gui.drawRect(0,0,10,10,0x77777777);
+ clip(clip.x + 10, clip.y, clip.width - 10, 10);
+ Gui.drawRect(0,0,getBounds().width, getBounds().height, 0x77777777);
+ for (int x = 0; x < blocks[0].length; x++) {
+ fr.drawString(x+"", x * 16 +10 + offsetX, 0, 0xFFFFFFFF);
+ }
+ clip(clip.x, clip.y +10, 10, clip.height-10);
+ Gui.drawRect(0,0,getBounds().width, getBounds().height, 0x77777777);
+ for (int z = 0; z < blocks.length; z++) {
+ fr.drawString(z+"", 2, z * 16 + 10 + offsetY, 0xFFFFFFFF);
+ }
+
+ int hoverX = (relMousex0 - offsetX - 10) / 16;
+ int hoverY = (relMousey0 - offsetY - 10) / 16;
+ // draw Content
+ clip(clip.x + 10, clip.y +10, clip.width - 10, clip.height - 10);
+ for (int z = 0; z < blocks.length; z++) {
+ for (int x = 0; x < blocks[z].length; x++) {
+ int data = blocks[z][x];
+ if (z == selectedY && x == selectedX){
+ Gui.drawRect(x *16 +10+offsetX, z *16 +10 + offsetY, x *16 +26 +offsetX, z *16 +26 + offsetY, 0xAA707070);
+ } else if (z == hoverY && x == hoverX) {
+ Gui.drawRect(x *16 +10+offsetX, z *16 +10 + offsetY, x *16 +26 +offsetX, z *16 +26 + offsetY, 0xAA505050);
+ }
+
+
+ if (data == -1) fr.drawString("X", x *16 +10 + offsetX, z *16 +10 + offsetY,0xFFFFFF);
+ else drawItemStack(new ItemStack(Item.getItemFromBlock(Block.getBlockById(data)), 1), x * 16 +10 + offsetX, z *16 +10 + offsetY);
+ }
+ }
+
+ }
+ private void drawItemStack(ItemStack stack, int x, int y)
+ {
+ Minecraft.getMinecraft().getRenderItem().renderItemAndEffectIntoGUI(stack, x, y);
+ }
+
+ @Override
+ public void resize(int parentWidth, int parentHeight) {
+ this.setBounds(new Rectangle(5,5,parentWidth-10,parentHeight-10));
+ }
+
+ @Override
+ public void keyPressed(char typedChar, int keyCode) {
+ int[][] blocks = dungeonRoom.getDungeonRoomInfo().getBlocks();
+ if (selectedX != -1 && selectedY != -1 && selectedY < blocks.length && selectedX < blocks[0].length) {
+ dungeonRoom.getDungeonRoomInfo().getBlocks()[selectedY][selectedX] = -1;
+ }
+ }
+
+ private int lastX;
+ private int lastY;
+ @Override
+ public void mouseClicked(int absMouseX, int absMouseY, int relMouseX, int relMouseY, int mouseButton) {
+ lastX = absMouseX;
+ lastY = absMouseY;
+
+ if (lastAbsClip.contains(absMouseX, absMouseY)) {
+ selectedX = (relMouseX - offsetX - 10) / 16;
+ selectedY = (relMouseY - offsetY - 10) / 16;
+ }
+ }
+
+ @Override
+ public void mouseClickMove(int absMouseX, int absMouseY, int relMouseX, int relMouseY, int clickedMouseButton, long timeSinceLastClick) {
+ int dX = absMouseX - lastX;
+ int dY = absMouseY - lastY;
+ offsetX += dX;
+ offsetY += dY;
+ lastX = absMouseX;
+ lastY = absMouseY;
+ }
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/panes/RoomMatchDisplayPane.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/panes/RoomMatchDisplayPane.java
new file mode 100755
index 00000000..b7023c4b
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/panes/RoomMatchDisplayPane.java
@@ -0,0 +1,152 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.roomedit.panes;
+
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomfinder.DungeonRoom;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomfinder.DungeonRoomInfoRegistry;
+import kr.syeyoung.dungeonsguide.mod.gui.MPanel;
+import kr.syeyoung.dungeonsguide.mod.gui.elements.MTooltip;
+import kr.syeyoung.dungeonsguide.mod.gui.elements.MTooltipText;
+import kr.syeyoung.dungeonsguide.mod.utils.ArrayUtils;
+import net.minecraft.block.Block;
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.gui.FontRenderer;
+import net.minecraft.client.gui.Gui;
+import net.minecraft.client.gui.ScaledResolution;
+import net.minecraft.item.Item;
+import net.minecraft.item.ItemStack;
+
+import java.awt.*;
+import java.util.Arrays;
+import java.util.UUID;
+
+public class RoomMatchDisplayPane extends MPanel {
+
+ private int offsetX = 0;
+ private int offsetY = 0;
+
+ private final DungeonRoom dungeonRoom;
+
+ private final int[][] currentBlocks;
+ private int[][] targetBlocks;
+ public RoomMatchDisplayPane(DungeonRoom dungeonRoom, UUID uid, int rotation) {
+ this.dungeonRoom = dungeonRoom;
+
+ currentBlocks = dungeonRoom.getRoomMatcher().createNew().getBlocks();
+ targetBlocks = DungeonRoomInfoRegistry.getByUUID(uid).getBlocks();
+ for (int i = 0; i < rotation; i++)
+ targetBlocks = ArrayUtils.rotateCounterClockwise(targetBlocks);
+ }
+
+ MTooltip mTooltip;
+ int lastTooltipX = -1, lastTooltipZ = -1;
+
+ @Override
+ public void render(int absMousex, int absMousey, int relMousex0, int relMousey0, float partialTicks, Rectangle clip) {
+ ScaledResolution sr = new ScaledResolution(Minecraft.getMinecraft());
+
+ FontRenderer fr = Minecraft.getMinecraft().fontRendererObj;
+
+ int height = Math.max(currentBlocks.length, targetBlocks.length);
+ int width = Math.max(currentBlocks[0].length, targetBlocks[0].length);
+
+ // draw Axis;
+ Gui.drawRect(0,0,10,10,0x77777777);
+ clip(clip.x + 10, clip.y, clip.width - 10, 10);
+ Gui.drawRect(0,0,getBounds().width, getBounds().height, 0x77777777);
+ for (int x = 0; x < width; x++) {
+ fr.drawString(x+"", x * 16 +10 + offsetX, 0, 0xFFFFFFFF);
+ }
+ clip(clip.x, clip.y +10, 10, clip.height-10);
+ Gui.drawRect(0,0,getBounds().width, getBounds().height, 0x77777777);
+ for (int z = 0; z < height; z++) {
+ fr.drawString(z+"", 2, z * 16 + 10 + offsetY, 0xFFFFFFFF);
+ }
+
+ int hoverX = (relMousex0 - offsetX - 10) / 16;
+ int hoverY = (relMousey0 - offsetY - 10) / 16;
+ // draw Content
+ clip(clip.x + 10, clip.y +10, clip.width - 10, clip.height - 10);
+ boolean tooltiped=false;
+ for (int z = 0; z < height; z++) {
+ for (int x = 0; x < width; x++) {
+ int data1;
+ try { data1 = currentBlocks[z][x]; } catch (Exception e) {
+ data1 = -2;
+ }
+ int data2;
+ try { data2 = targetBlocks[z][x]; } catch (Exception e) {
+ data2 = -2;
+ }
+
+ if (z == hoverY && x == hoverX) {
+ Gui.drawRect(x *16 +10+offsetX, z *16 +10 + offsetY, x *16 +26 +offsetX, z *16 +26 + offsetY, 0xAA505050);
+ }
+
+ if (data1 == data2) drawItemStack(new ItemStack(Item.getItemFromBlock(Block.getBlockById(data1)), 1), x * 16 +10 + offsetX, z *16 +10 + offsetY);
+ else if (data2 == -1 || data1 == -1) {
+ drawItemStack(new ItemStack(Item.getItemFromBlock(Block.getBlockById(data1 == -1 ? data2 : data1)), 1), x * 16 +10 + offsetX, z *16 +10 + offsetY);
+ fr.drawString("S", x *16 +10 + offsetX, z *16 +10 + offsetY,0xFFFFFF00);
+ } else {
+ fr.drawString("N", x *16 +10 + offsetX, z *16 +10 + offsetY,0xFFFF0000);
+ }
+ if (z == hoverY && x == hoverX) {
+ tooltiped = true;
+ if (lastTooltipX != x || lastTooltipZ != z){
+ if (mTooltip != null) mTooltip.close();
+ mTooltip = new MTooltipText(Arrays.asList("Expected "+data2 +" But found "+data1));
+ mTooltip.open(this);
+ }
+ }
+ }
+ }
+ if (!tooltiped && mTooltip != null) {
+ mTooltip.close();
+ mTooltip = null;
+ }
+
+ }
+ private void drawItemStack(ItemStack stack, int x, int y)
+ {
+ Minecraft.getMinecraft().getRenderItem().renderItemAndEffectIntoGUI(stack, x, y);
+ }
+
+ @Override
+ public void resize(int parentWidth, int parentHeight) {
+ this.setBounds(new Rectangle(5,5,parentWidth-10,parentHeight-10));
+ }
+
+ private int lastX;
+ private int lastY;
+ @Override
+ public void mouseClicked(int absMouseX, int absMouseY, int relMouseX, int relMouseY, int mouseButton) {
+ lastX = absMouseX;
+ lastY = absMouseY;
+ }
+
+ @Override
+ public void mouseClickMove(int absMouseX, int absMouseY, int relMouseX, int relMouseY, int clickedMouseButton, long timeSinceLastClick) {
+ int dX = absMouseX - lastX;
+ int dY = absMouseY - lastY;
+ offsetX += dX;
+ offsetY += dY;
+ lastX = absMouseX;
+ lastY = absMouseY;
+ }
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/panes/RoommatchingPane.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/panes/RoommatchingPane.java
new file mode 100755
index 00000000..964c450b
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/panes/RoommatchingPane.java
@@ -0,0 +1,84 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.roomedit.panes;
+
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomfinder.DungeonRoom;
+import kr.syeyoung.dungeonsguide.mod.gui.MPanel;
+import kr.syeyoung.dungeonsguide.mod.gui.elements.MButton;
+import kr.syeyoung.dungeonsguide.mod.gui.elements.MTextField;
+
+import java.awt.*;
+import java.util.UUID;
+
+public class RoommatchingPane extends MPanel {
+ private final DungeonRoom dungeonRoom;
+
+ private RoomMatchDisplayPane displayPane;
+
+ private final MTextField textField;
+ private final MButton calculate;
+ public RoommatchingPane(final DungeonRoom dungeonRoom) {
+ this.dungeonRoom = dungeonRoom;
+
+ {
+ textField = new MTextField();
+ textField.setBounds(new Rectangle(0,0,getBounds().width - 100, 20));
+ add(textField);
+ }
+ {
+ calculate = new MButton();
+ calculate.setBounds(new Rectangle(getBounds().width - 100,0,100, 20));
+ calculate.setText("match");
+ calculate.setOnActionPerformed(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ remove(displayPane);
+
+ String text = textField.getText();
+ String target = text.split(":")[0];
+ String state = text.split(":")[1];
+
+ UUID uid = UUID.fromString(target);
+ int rotation = Integer.parseInt(state) % 4;
+
+
+ displayPane = new RoomMatchDisplayPane(dungeonRoom, uid, rotation);
+ displayPane.setBounds(new Rectangle(0,25,getBounds().width,getBounds().height-25));
+ add(displayPane);
+ } catch (Throwable t) {
+ t.printStackTrace();
+ }
+ }
+ });
+ add(calculate);
+ }
+ }
+
+ @Override
+ public void resize(int parentWidth, int parentHeight) {
+ this.setBounds(new Rectangle(5,5,parentWidth-10,parentHeight-10));
+ }
+
+ @Override
+ public void onBoundsUpdate() {
+ textField.setBounds(new Rectangle(0,0,getBounds().width - 100, 20));
+ calculate.setBounds(new Rectangle(getBounds().width - 100,0,100, 20));
+ }
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/panes/SecretEditPane.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/panes/SecretEditPane.java
new file mode 100755
index 00000000..5c52e770
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/panes/SecretEditPane.java
@@ -0,0 +1,156 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.roomedit.panes;
+
+import kr.syeyoung.dungeonsguide.dungeon.data.DungeonRoomInfo;
+import kr.syeyoung.dungeonsguide.dungeon.mechanics.dunegonmechanic.DungeonMechanic;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomfinder.DungeonRoom;
+import kr.syeyoung.dungeonsguide.mod.gui.MPanel;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomedit.Parameter;
+import kr.syeyoung.dungeonsguide.mod.gui.elements.MButton;
+import kr.syeyoung.dungeonsguide.mod.gui.elements.MParameter;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomedit.valueedit.ValueEditCreator;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomedit.valueedit.ValueEditRegistry;
+
+import java.awt.*;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+
+public class SecretEditPane extends MPanel implements DynamicEditor {
+ private final DungeonRoom dungeonRoom;
+
+ private MButton save;
+ private MButton create;
+ private final List<MParameter> parameters = new ArrayList<MParameter>();
+
+ private final List<String> allowedClasses = new ArrayList<String>();
+
+ public SecretEditPane(DungeonRoom dungeonRoom) {
+ this.dungeonRoom = dungeonRoom;
+ buildElements();
+
+ for (String clazz : ValueEditRegistry.getClassesSupported()) {
+ if (clazz.contains("mechanics") || clazz.equals("null")) {
+ allowedClasses.add(clazz);
+ }
+ }
+ }
+
+ public void createNewMechanic(String uid, DungeonMechanic data) {
+ MParameter parameter;
+ parameters.add(parameter = new MParameter(new Parameter(uid, data, data), SecretEditPane.this));
+ parameter.setBounds(new Rectangle(0,0,getBounds().width, 20));
+ parameter.setParent(SecretEditPane.this);
+ }
+
+ public void buildElements() {
+ {
+ create = new MButton();
+ create.setText("Create New Mechanic");
+ create.setBackgroundColor(Color.cyan);
+ create.setBounds(new Rectangle(0,0,100,20));
+ create.setOnActionPerformed(new Runnable() {
+ @Override
+ public void run() {
+ createNewMechanic(UUID.randomUUID().toString(), null);
+ }
+ });
+
+ save = new MButton();
+ save.setText("Save");
+ save.setBackgroundColor(Color.green);
+ save.setBounds(new Rectangle(0,0,100,20));
+ save.setOnActionPerformed(new Runnable() {
+ @Override
+ public void run() {
+ DungeonRoomInfo dungeonRoomInfo = dungeonRoom.getDungeonRoomInfo();
+ dungeonRoomInfo.getMechanics().clear();
+
+ for (MParameter parameter : parameters) {
+ Parameter real = parameter.getParameter();
+
+ ValueEditCreator vec = ValueEditRegistry.getValueEditMap(real.getNewData() == null ? "null" :real.getNewData().getClass().getName());
+
+ real.setPreviousData(vec.cloneObj(real.getNewData()));
+ dungeonRoomInfo.getMechanics().put(real.getName(), (DungeonMechanic) real.getNewData());
+ }
+ }
+ });
+ create.setParent(this); save.setParent(this);
+ }
+ {
+ for (Map.Entry<String, DungeonMechanic> en : dungeonRoom.getDungeonRoomInfo().getMechanics().entrySet()) {
+ ValueEditCreator vec = ValueEditRegistry.getValueEditMap(en.getValue() == null ? "null" :en.getValue().getClass().getName());
+
+ MParameter mParameter = new MParameter(new Parameter(en.getKey(), vec.cloneObj(en.getValue()), vec.cloneObj(en.getValue())), this);
+ mParameter.setBounds(new Rectangle(0,0,getBounds().width,20));
+ parameters.add(mParameter);
+ mParameter.setParent(this);
+ }
+ }
+ }
+
+ @Override
+ public void onBoundsUpdate() {
+ for (MPanel panel :getChildComponents()){
+ panel.setSize(new Dimension(getBounds().width, 20));
+ }
+ }
+ @Override
+ public void resize(int parentWidth, int parentHeight) {
+ this.setBounds(new Rectangle(5,5,parentWidth-10,parentHeight-10));
+ }
+
+
+ public void delete(MParameter parameter) {
+ parameters.remove(parameter);
+ }
+
+ @Override
+ public List<String> allowedClass() {
+ return allowedClasses;
+ }
+
+ @Override
+ public List<MPanel> getChildComponents() {
+ ArrayList<MPanel> panels = new ArrayList<MPanel>(parameters);
+ panels.add(create);
+ panels.add(save);
+ return panels;
+ }
+
+ private int offsetY = 0;
+ @Override
+ public void render(int absMousex, int absMousey, int relMousex0, int relMousey0, float partialTicks, Rectangle scissor) {
+ int heights = 0;
+ for (MPanel panel:getChildComponents()) {
+ panel.setPosition(new Point(0, -offsetY + heights));
+ heights += panel.getBounds().height;
+ }
+ }
+
+ @Override
+ public void mouseScrolled(int absMouseX, int absMouseY, int relMouseX0, int relMouseY0, int scrollAmount) {
+ if (scrollAmount > 0) offsetY -= 20;
+ else if (scrollAmount < 0) offsetY += 20;
+ if (offsetY < 0) offsetY = 0;
+ }
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/valueedit/ValueEdit.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/valueedit/ValueEdit.java
new file mode 100755
index 00000000..d52094de
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/valueedit/ValueEdit.java
@@ -0,0 +1,27 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.roomedit.valueedit;
+
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomedit.Parameter;
+
+public interface ValueEdit<T extends Object> {
+ void setParameter(Parameter parameter);
+
+ void renderWorld(float partialTicks);
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/valueedit/ValueEditAColor.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/valueedit/ValueEditAColor.java
new file mode 100755
index 00000000..c42fa423
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/valueedit/ValueEditAColor.java
@@ -0,0 +1,339 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.roomedit.valueedit;
+
+import kr.syeyoung.dungeonsguide.mod.config.types.AColor;
+import kr.syeyoung.dungeonsguide.mod.gui.MPanel;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomedit.Parameter;
+import kr.syeyoung.dungeonsguide.mod.gui.elements.MColor;
+import kr.syeyoung.dungeonsguide.mod.gui.elements.MFloatSelectionButton;
+import kr.syeyoung.dungeonsguide.mod.gui.elements.MLabelAndElement;
+import net.minecraft.client.renderer.GlStateManager;
+import net.minecraft.client.renderer.Tessellator;
+import net.minecraft.client.renderer.WorldRenderer;
+import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
+import net.minecraft.util.MathHelper;
+import org.lwjgl.opengl.GL11;
+
+import java.awt.*;
+
+public class ValueEditAColor extends MPanel implements ValueEdit<AColor> {
+ private Parameter parameter;
+ private final MFloatSelectionButton h;
+ private final MFloatSelectionButton s;
+ private final MFloatSelectionButton v;
+ private final MFloatSelectionButton a;
+
+
+ @Override
+ public void renderWorld(float partialTicks) {
+
+ }
+ public ValueEditAColor(final Parameter parameter2) {
+ this.parameter = parameter2;
+ {
+ MColor color = new MColor() {
+ @Override
+ public Color getColor() {
+ return (Color) parameter2.getPreviousData();
+ }
+ };
+ MLabelAndElement mLabelAndElement = new MLabelAndElement("Prev",color);
+ mLabelAndElement.setBounds(new Rectangle(0,0,getBounds().width,20));
+ add(mLabelAndElement);
+ }
+ {
+ MColor color = new MColor() {
+ @Override
+ public Color getColor() {
+ return (Color) parameter2.getNewData();
+ }
+ };
+ MLabelAndElement mLabelAndElement = new MLabelAndElement("New",color);
+ mLabelAndElement.setBounds(new Rectangle(0,20,getBounds().width,20));
+ add(mLabelAndElement);
+ }
+
+ Color color = (Color) parameter2.getNewData();
+ Color.RGBtoHSB(color.getRed(), color.getGreen(), color.getBlue(), hsv);
+ alpha = color.getAlpha() / 255.0f;
+
+ {
+ h = new MFloatSelectionButton(hsv[0] * 360);
+ h.setOnUpdate(new Runnable() {
+ @Override
+ public void run() {
+ hsv[0] = h.getData() / 360;
+ update();
+ }
+ });
+ MLabelAndElement mLabelAndElement = new MLabelAndElement("H", h);
+ mLabelAndElement.setBounds(new Rectangle(0,20,getBounds().width,20));
+ add(mLabelAndElement);
+ }
+ {
+ s = new MFloatSelectionButton(hsv[1] * 100);
+ s.setOnUpdate(new Runnable() {
+ @Override
+ public void run() {
+ hsv[1] = s.getData() / 100;
+ update();
+ }
+ });
+ MLabelAndElement mLabelAndElement = new MLabelAndElement("S", s);
+ mLabelAndElement.setBounds(new Rectangle(0,20,getBounds().width,20));
+ add(mLabelAndElement);
+ }
+ {
+ v = new MFloatSelectionButton(hsv[2] * 100);
+ v.setOnUpdate(new Runnable() {
+ @Override
+ public void run() {
+ hsv[2] = v.getData() / 100;
+ update();
+ }
+ });
+ MLabelAndElement mLabelAndElement = new MLabelAndElement("V", v);
+ mLabelAndElement.setBounds(new Rectangle(0,20,getBounds().width,20));
+ add(mLabelAndElement);
+ }
+ {
+ a = new MFloatSelectionButton(alpha * 100);
+ a.setOnUpdate(new Runnable() {
+ @Override
+ public void run() {
+ alpha = a.getData() / 100;
+ update();
+ }
+ });
+ MLabelAndElement mLabelAndElement = new MLabelAndElement("A", a);
+ mLabelAndElement.setBounds(new Rectangle(0,20,getBounds().width,20));
+ add(mLabelAndElement);
+ }
+ }
+
+ private final float[] hsv = new float[3];
+ private float alpha = 0;
+
+ public void update() {
+ if (hsv[2] > 1) hsv[2] = 1;
+ if (hsv[2] < 0) hsv[2] = 0;
+ if (hsv[1] > 1) hsv[1] = 1;
+ if (hsv[1] < 0) hsv[1] = 0;
+ parameter.setNewData(new AColor(Color.HSBtoRGB(hsv[0], hsv[1], hsv[2]) & 0xffffff | (MathHelper.clamp_int((int)(alpha * 255), 0, 255) << 24), true ));
+ h.setData((float) Math.floor(hsv[0] * 360));
+ s.setData((float) Math.floor(hsv[1] * 100));
+ v.setData((float) Math.floor(hsv[2] * 100));
+ a.setData((float) Math.floor(alpha * 100));
+ h.updateSelected();
+ s.updateSelected();
+ v.updateSelected();
+ a.updateSelected();
+ }
+ @Override
+ public void render(int absMousex, int absMousey, int relMousex0, int relMousey0, float partialTicks, Rectangle scissor) {
+ // draw CoolRect
+ int width = getBounds().width - 60;
+ Tessellator tessellator = Tessellator.getInstance();
+ WorldRenderer worldrenderer = tessellator.getWorldRenderer();
+ int shademodel = GL11.glGetInteger(GL11.GL_SHADE_MODEL);
+ GlStateManager.shadeModel(GL11.GL_SMOOTH);
+ GlStateManager.enableBlend();
+ GlStateManager.disableDepth();
+ GlStateManager.disableTexture2D();
+ GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
+
+// worldrenderer.begin(GL11.GL_TRIANGLES, DefaultVertexFormats.POSITION_COLOR);
+
+ int rgb = Color.HSBtoRGB(hsv[0], hsv[1], 1);
+ float r = (rgb >> 16 & 255) / 255.0f;
+ float g = (rgb >> 8 & 255) / 255.0f;
+ float b = (rgb & 255) / 255.0f;
+ GL11.glBegin(GL11.GL_TRIANGLES);
+ GlStateManager.color(0,0,0,alpha);GL11.glVertex3i(25+width ,45, 0);
+ GlStateManager.color(0,0,0,alpha);GL11.glVertex3i(10+width , 45, 0);
+ GlStateManager.color(r,g,b,alpha);GL11.glVertex3i(25+width , 45+width, 0);
+
+ GlStateManager.color(0,0,0,alpha); GL11.glVertex3i(10+width , 45, 0);
+ GlStateManager.color(r,g,b,alpha);GL11.glVertex3i(10+width , 45 + width, 0);
+ GlStateManager.color(r,g,b,alpha);GL11.glVertex3i(25+width , 45+width, 0);
+ GL11.glEnd();
+ rgb = Color.HSBtoRGB(hsv[0], hsv[1], hsv[2]);
+ r = (rgb >> 16 & 255) / 255.0f;
+ g = (rgb >> 8 & 255) / 255.0f;
+ b = (rgb & 255) / 255.0f;
+ GL11.glBegin(GL11.GL_TRIANGLES);
+ GlStateManager.color(r,g,b,0);GL11.glVertex3i(50+width ,45, 0);
+ GlStateManager.color(r,g,b,0);GL11.glVertex3i(35+width , 45, 0);
+ GlStateManager.color(r,g,b,1);GL11.glVertex3i(50+width , 45+width, 0);
+
+// GlStateManager.color(r,g,b,0); GL11.glVertex3i(35+width , 45, 0);
+// GlStateManager.color(r,g,b,1);GL11.glVertex3i(35+width , 45 + width, 0);
+// GlStateManager.color(r,g,b,1);GL11.glVertex3i(50+width , 45+width, 0);
+ GL11.glEnd();
+
+
+ float radius = width/2f;
+ float cx = 5 + radius;
+ float cy = 45 + radius;
+
+ GL11.glBegin(GL11.GL_TRIANGLE_FAN);
+ GlStateManager.color(1,1,1,alpha);
+ GL11.glVertex3f(cx,cy,0);
+ for (int i = 0; i <= 360; i++) {
+ float rad = 3.141592653f * i / 180;
+ int rgb2 = Color.HSBtoRGB(i / 360f, 1, hsv[2]);
+ float r2 = (rgb2 >> 16 & 255) / 255.0f;
+ float g2 = (rgb2 >> 8 & 255) / 255.0f;
+ float b2 = (rgb2 & 255) / 255.0f;
+ GlStateManager.color(r2,g2,b2, alpha);
+ GL11.glVertex3f(MathHelper.sin(rad) * radius + cx, MathHelper.cos(rad) * radius + cy, 0);
+ }
+ GL11.glEnd();
+ GlStateManager.shadeModel(shademodel);
+
+ GlStateManager.color(1,1,1,1);
+ worldrenderer.begin(GL11.GL_LINE_LOOP, DefaultVertexFormats.POSITION);
+ float rad2 = 2 * 3.141592653f * hsv[0] ;
+ float x = 5 + radius + (MathHelper.sin(rad2)) * hsv[1] * radius;
+ float y = 45 + radius + (MathHelper.cos(rad2))* hsv[1] * radius;
+ for (int i = 0; i < 100; i++) {
+ float rad = 2 * 3.141592653f * (i / 100f);
+ worldrenderer.pos(MathHelper.sin(rad) * 2 + x, MathHelper.cos(rad) * 2 + y, 0).endVertex();
+ }
+ tessellator.draw();
+
+ worldrenderer.begin(GL11.GL_LINES, DefaultVertexFormats.POSITION);
+ worldrenderer.pos(8+width, 45 + (hsv[2]) * width, 0.5).endVertex();
+ worldrenderer.pos(27+width, 45 + (hsv[2]) * width, 0.5).endVertex();
+ tessellator.draw();
+
+ worldrenderer.begin(GL11.GL_LINES, DefaultVertexFormats.POSITION);
+ worldrenderer.pos(33+width, 45 + (alpha) * width, 0.5).endVertex();
+ worldrenderer.pos(52+width, 45 + (alpha) * width, 0.5).endVertex();
+ tessellator.draw();
+
+ GlStateManager.enableTexture2D();
+ GlStateManager.disableBlend();
+ GlStateManager.color(1,1,1,1);
+ GlStateManager.color(1,1,1,1);
+ }
+ private int selected = 0;
+
+ @Override
+ public void mouseClicked(int absMouseX, int absMouseY, int relMouseX, int relMouseY, int mouseButton) {
+ int width = getBounds().width - 60;
+ float radius = width / 2f;
+ float circleX = 5 + radius;
+ float circleY = 45 + radius;
+ selected = 0;
+ {
+ // check circle
+ float dx = relMouseX - circleX;
+ float dy = circleY - relMouseY;
+ if (dx * dx + dy * dy <= radius * radius) {
+ double theta = (MathHelper.atan2(dy, dx) / Math.PI * 180 + 90) % 360;
+ hsv[0] = (float) theta / 360f;
+ hsv[1] = MathHelper.sqrt_float(dx * dx + dy * dy) / radius;
+ selected = 1;
+ }
+ }
+ {
+ if (10+width <= relMouseX && relMouseX <= 25 + width &&
+ 45 <= relMouseY && relMouseY <= 45 + width) {
+ hsv[2] = (relMouseY - 45) / (float)width;
+ selected = 2;
+ }
+ }
+ {
+ if (35+width <= relMouseX && relMouseX <= 50 + width &&
+ 45 <= relMouseY && relMouseY <= 45 + width) {
+ alpha = (relMouseY - 45) / (float)width;
+ selected = 3;
+ }
+ }
+ update();
+ }
+
+ @Override
+ public void mouseClickMove(int absMouseX, int absMouseY, int relMouseX, int relMouseY, int clickedMouseButton, long timeSinceLastClick) {
+ int width = getBounds().width - 60;
+ float radius = width / 2f;
+ float circleX = 5 + radius;
+ float circleY = 45 + radius;
+ {
+ // check circle
+ float dx = relMouseX - circleX;
+ float dy = circleY - relMouseY;
+ if (selected == 1) {
+ double theta = (MathHelper.atan2(dy, dx) / Math.PI * 180 + 90) % 360;
+ hsv[0] = (float) theta / 360f;
+ hsv[1] = MathHelper.clamp_float(MathHelper.sqrt_float(dx * dx + dy * dy) / radius, 0, 1);
+ }
+ }
+ {
+ if (selected == 2) {
+ hsv[2] = MathHelper.clamp_float((relMouseY - 45) / (float)width, 0, 1);
+ }
+ if (selected == 3) {
+ alpha = MathHelper.clamp_float((relMouseY - 45) / (float)width, 0, 1);
+ }
+ }
+ update();
+ }
+
+ @Override
+ public void onBoundsUpdate() {
+ int cnt = 0;
+ for (MPanel panel :getChildComponents()){
+ panel.setSize(new Dimension(getBounds().width, 20)); cnt++;
+ if (cnt > 2) {
+ panel.setPosition(new Point(0, getBounds().width + (cnt - 3) * 20));
+ }
+ }
+ }
+
+ @Override
+ public void setParameter(Parameter parameter) {
+ this.parameter = parameter;
+ }
+
+ @Override
+ public void resize(int parentWidth, int parentHeight) {
+ this.setBounds(new Rectangle(0,0,parentWidth, parentHeight));
+ }
+
+ public static class Generator implements ValueEditCreator<ValueEditAColor> {
+
+ @Override
+ public ValueEditAColor createValueEdit(Parameter parameter) {
+ return new ValueEditAColor(parameter);
+ }
+
+ @Override
+ public Object createDefaultValue(Parameter parameter) {
+ return new AColor(255,0,0,255);
+ }
+
+ @Override
+ public Object cloneObj(Object object) {
+ return object;
+ }
+ }
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/valueedit/ValueEditBoolean.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/valueedit/ValueEditBoolean.java
new file mode 100755
index 00000000..639afc20
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/valueedit/ValueEditBoolean.java
@@ -0,0 +1,101 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.roomedit.valueedit;
+
+import kr.syeyoung.dungeonsguide.mod.gui.MPanel;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomedit.Parameter;
+import kr.syeyoung.dungeonsguide.mod.gui.elements.MLabel;
+import kr.syeyoung.dungeonsguide.mod.gui.elements.MLabelAndElement;
+import kr.syeyoung.dungeonsguide.mod.gui.elements.MStringSelectionButton;
+
+import java.awt.*;
+import java.util.Arrays;
+
+public class ValueEditBoolean extends MPanel implements ValueEdit<Boolean> {
+ private Parameter parameter;
+
+
+ public ValueEditBoolean(Parameter parameter2) {
+ this.parameter = parameter2;
+ {
+ MLabel label = new MLabel() {
+ @Override
+ public String getText() {
+ return parameter.getPreviousData().toString();
+ }
+ };
+ MLabelAndElement mLabelAndElement = new MLabelAndElement("Prev",label);
+ mLabelAndElement.setBounds(new Rectangle(0,0,getBounds().width,20));
+ add(mLabelAndElement);
+ }
+ {
+ boolean newData = (Boolean) parameter.getNewData();
+ final MStringSelectionButton textField = new MStringSelectionButton(Arrays.asList("true", "false"), Boolean.toString(newData));
+ textField.setOnUpdate(new Runnable() {
+ @Override
+ public void run() {
+ parameter.setNewData(Boolean.valueOf(textField.getSelected()));
+ }
+ });
+ MLabelAndElement mLabelAndElement = new MLabelAndElement("New",textField);
+ mLabelAndElement.setBounds(new Rectangle(0,20,getBounds().width,20));
+ add(mLabelAndElement);
+ }
+ }
+
+ @Override
+ public void onBoundsUpdate() {
+ for (MPanel panel :getChildComponents()){
+ panel.setSize(new Dimension(getBounds().width, 20));
+ }
+ }
+
+ @Override
+ public void setParameter(Parameter parameter) {
+ this.parameter = parameter;
+ }
+
+ @Override
+ public void renderWorld(float partialTicks) {
+
+ }
+
+ @Override
+ public void resize(int parentWidth, int parentHeight) {
+ this.setBounds(new Rectangle(0,0,parentWidth, parentHeight));
+ }
+
+ public static class Generator implements ValueEditCreator<ValueEditBoolean> {
+
+ @Override
+ public ValueEditBoolean createValueEdit(Parameter parameter) {
+ return new ValueEditBoolean(parameter);
+ }
+
+ @Override
+ public Object createDefaultValue(Parameter parameter) {
+ return true;
+ }
+
+ @Override
+ public Object cloneObj(Object object) {
+ return object;
+ }
+ }
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/valueedit/ValueEditColor.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/valueedit/ValueEditColor.java
new file mode 100755
index 00000000..5ef977a1
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/valueedit/ValueEditColor.java
@@ -0,0 +1,287 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.roomedit.valueedit;
+
+import kr.syeyoung.dungeonsguide.mod.gui.MPanel;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomedit.Parameter;
+import kr.syeyoung.dungeonsguide.mod.gui.elements.*;
+import net.minecraft.client.renderer.GlStateManager;
+import net.minecraft.client.renderer.Tessellator;
+import net.minecraft.client.renderer.WorldRenderer;
+import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
+import net.minecraft.util.MathHelper;
+import org.lwjgl.opengl.GL11;
+
+import java.awt.*;
+
+public class ValueEditColor extends MPanel implements ValueEdit<Color> {
+ private Parameter parameter;
+ private final MFloatSelectionButton h;
+ private final MFloatSelectionButton s;
+ private final MFloatSelectionButton v;
+
+
+ @Override
+ public void renderWorld(float partialTicks) {
+
+ }
+ public ValueEditColor(final Parameter parameter2) {
+ this.parameter = parameter2;
+ {
+ MColor color = new MColor() {
+ @Override
+ public Color getColor() {
+ return (Color) parameter2.getPreviousData();
+ }
+ };
+ MLabelAndElement mLabelAndElement = new MLabelAndElement("Prev",color);
+ mLabelAndElement.setBounds(new Rectangle(0,0,getBounds().width,20));
+ add(mLabelAndElement);
+ }
+ {
+ MColor color = new MColor() {
+ @Override
+ public Color getColor() {
+ return (Color) parameter2.getNewData();
+ }
+ };
+ MLabelAndElement mLabelAndElement = new MLabelAndElement("New",color);
+ mLabelAndElement.setBounds(new Rectangle(0,20,getBounds().width,20));
+ add(mLabelAndElement);
+ }
+
+ Color color = (Color) parameter2.getNewData();
+ Color.RGBtoHSB(color.getRed(), color.getGreen(), color.getBlue(), hsv);
+
+ {
+ h = new MFloatSelectionButton(hsv[0] * 360);
+ h.setOnUpdate(new Runnable() {
+ @Override
+ public void run() {
+ hsv[0] = h.getData() / 360;
+ update();
+ }
+ });
+ MLabelAndElement mLabelAndElement = new MLabelAndElement("H", h);
+ mLabelAndElement.setBounds(new Rectangle(0,20,getBounds().width,20));
+ add(mLabelAndElement);
+ }
+ {
+ s = new MFloatSelectionButton(hsv[1] * 100);
+ s.setOnUpdate(new Runnable() {
+ @Override
+ public void run() {
+ hsv[1] = s.getData() / 100;
+ update();
+ }
+ });
+ MLabelAndElement mLabelAndElement = new MLabelAndElement("S", s);
+ mLabelAndElement.setBounds(new Rectangle(0,20,getBounds().width,20));
+ add(mLabelAndElement);
+ }
+ {
+ v = new MFloatSelectionButton(hsv[2] * 100);
+ v.setOnUpdate(new Runnable() {
+ @Override
+ public void run() {
+ hsv[2] = v.getData() / 100;
+ update();
+ }
+ });
+ MLabelAndElement mLabelAndElement = new MLabelAndElement("V", v);
+ mLabelAndElement.setBounds(new Rectangle(0,20,getBounds().width,20));
+ add(mLabelAndElement);
+ }
+ }
+
+ private final float[] hsv = new float[3];
+
+ public void update() {
+ if (hsv[2] > 1) hsv[2] = 1;
+ if (hsv[2] < 0) hsv[2] = 0;
+ if (hsv[1] > 1) hsv[1] = 1;
+ if (hsv[1] < 0) hsv[1] = 0;
+ parameter.setNewData(new Color(Color.HSBtoRGB(hsv[0], hsv[1], hsv[2])));
+ h.setData((float) Math.floor(hsv[0] * 360));
+ s.setData((float) Math.floor(hsv[1] * 100));
+ v.setData((float) Math.floor(hsv[2] * 100));
+ h.updateSelected();
+ s.updateSelected();
+ v.updateSelected();
+ }
+ @Override
+ public void render(int absMousex, int absMousey, int relMousex0, int relMousey0, float partialTicks, Rectangle scissor) {
+ // draw CoolRect
+ int width = getBounds().width - 30;
+ Tessellator tessellator = Tessellator.getInstance();
+ WorldRenderer worldrenderer = tessellator.getWorldRenderer();
+ int shademodel = GL11.glGetInteger(GL11.GL_SHADE_MODEL);
+ GlStateManager.shadeModel(GL11.GL_SMOOTH);
+ GlStateManager.enableBlend();
+ GlStateManager.disableTexture2D();
+ GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
+// worldrenderer.begin(GL11.GL_TRIANGLES, DefaultVertexFormats.POSITION_COLOR);
+
+ int rgb = Color.HSBtoRGB(hsv[0], hsv[1], 1);
+ float r = (rgb >> 16 & 255) / 255.0f;
+ float g = (rgb >> 8 & 255) / 255.0f;
+ float b = (rgb & 255) / 255.0f;
+ GL11.glBegin(GL11.GL_TRIANGLES);
+ GlStateManager.color(0,0,0,1);GL11.glVertex3i(25+width ,45, 0);
+ GlStateManager.color(0,0,0,1);GL11.glVertex3i(10+width , 45, 0);
+ GlStateManager.color(r,g,b,1);GL11.glVertex3i(25+width , 45+width, 0);
+
+ GlStateManager.color(0,0,0,1); GL11.glVertex3i(10+width , 45, 0);
+ GlStateManager.color(r,g,b,1);GL11.glVertex3i(10+width , 45 + width, 0);
+ GlStateManager.color(r,g,b,1);GL11.glVertex3i(25+width , 45+width, 0);
+ GL11.glEnd();
+
+ float radius = width/2f;
+ float cx = 5 + radius;
+ float cy = 45 + radius;
+
+ GL11.glBegin(GL11.GL_TRIANGLE_FAN);
+ GlStateManager.color(1,1,1,1);
+ GL11.glVertex3f(cx,cy,0);
+ for (int i = 0; i <= 360; i++) {
+ float rad = 3.141592653f * i / 180;
+ int rgb2 = Color.HSBtoRGB(i / 360f, 1, hsv[2]);
+ float r2 = (rgb2 >> 16 & 255) / 255.0f;
+ float g2 = (rgb2 >> 8 & 255) / 255.0f;
+ float b2 = (rgb2 & 255) / 255.0f;
+ GlStateManager.color(r2,g2,b2, 1);
+ GL11.glVertex3f(MathHelper.sin(rad) * radius + cx, MathHelper.cos(rad) * radius + cy, 0);
+ }
+ GL11.glEnd();
+ GlStateManager.shadeModel(shademodel);
+
+ GlStateManager.color(1,1,1,1);
+ worldrenderer.begin(GL11.GL_LINE_LOOP, DefaultVertexFormats.POSITION);
+ float rad2 = 2 * 3.141592653f * hsv[0] ;
+ float x = 5 + radius + (MathHelper.sin(rad2)) * hsv[1] * radius;
+ float y = 45 + radius + (MathHelper.cos(rad2))* hsv[1] * radius;
+ for (int i = 0; i < 100; i++) {
+ float rad = 2 * 3.141592653f * (i / 100f);
+ worldrenderer.pos(MathHelper.sin(rad) * 2 + x, MathHelper.cos(rad) * 2 + y, 0).endVertex();
+ }
+ tessellator.draw();
+
+ worldrenderer.begin(GL11.GL_LINES, DefaultVertexFormats.POSITION);
+ worldrenderer.pos(8+width, 45 + (hsv[2]) * width, 0.5).endVertex();
+ worldrenderer.pos(27+width, 45 + (hsv[2]) * width, 0.5).endVertex();
+ tessellator.draw();
+
+ GlStateManager.enableTexture2D();
+ GlStateManager.disableBlend();
+ GlStateManager.color(1,1,1,1);
+ GlStateManager.color(1,1,1,1);
+ }
+ private int selected = 0;
+
+ @Override
+ public void mouseClicked(int absMouseX, int absMouseY, int relMouseX, int relMouseY, int mouseButton) {
+ int width = getBounds().width - 30;
+ float radius = width / 2f;
+ float circleX = 5 + radius;
+ float circleY = 45 + radius;
+ selected = 0;
+ {
+ // check circle
+ float dx = relMouseX - circleX;
+ float dy = circleY - relMouseY;
+ if (dx * dx + dy * dy <= radius * radius) {
+ double theta = (MathHelper.atan2(dy, dx) / Math.PI * 180 + 90) % 360;
+ hsv[0] = (float) theta / 360f;
+ hsv[1] = MathHelper.sqrt_float(dx * dx + dy * dy) / radius;
+ selected = 1;
+ }
+ }
+ {
+ if (10+width <= relMouseX && relMouseX <= 25 + width &&
+ 45 <= relMouseY && relMouseY <= 45 + width) {
+ hsv[2] = (relMouseY - 45) / (float)width;
+ selected = 2;
+ }
+ }
+ update();
+ }
+
+ @Override
+ public void mouseClickMove(int absMouseX, int absMouseY, int relMouseX, int relMouseY, int clickedMouseButton, long timeSinceLastClick) {
+ int width = getBounds().width - 30;
+ float radius = width / 2f;
+ float circleX = 5 + radius;
+ float circleY = 45 + radius;
+ {
+ // check circle
+ float dx = relMouseX - circleX;
+ float dy = circleY - relMouseY;
+ if (selected == 1) {
+ double theta = (MathHelper.atan2(dy, dx) / Math.PI * 180 + 90) % 360;
+ hsv[0] = (float) theta / 360f;
+ hsv[1] = MathHelper.clamp_float(MathHelper.sqrt_float(dx * dx + dy * dy) / radius, 0, 1);
+ }
+ }
+ {
+ if (selected == 2) {
+ hsv[2] = MathHelper.clamp_float((relMouseY - 45) / (float)width, 0, 1);
+ }
+ }
+ update();
+ }
+
+ @Override
+ public void onBoundsUpdate() {
+ int cnt = 0;
+ for (MPanel panel :getChildComponents()){
+ panel.setSize(new Dimension(getBounds().width, 20)); cnt++;
+ if (cnt > 2) {
+ panel.setPosition(new Point(0, getBounds().width + (cnt - 2) * 20));
+ }
+ }
+ }
+
+ @Override
+ public void setParameter(Parameter parameter) {
+ this.parameter = parameter;
+ }
+
+ @Override
+ public void resize(int parentWidth, int parentHeight) {
+ this.setBounds(new Rectangle(0,0,parentWidth, parentHeight));
+ }
+
+ public static class Generator implements ValueEditCreator<ValueEditColor> {
+
+ @Override
+ public ValueEditColor createValueEdit(Parameter parameter) {
+ return new ValueEditColor(parameter);
+ }
+
+ @Override
+ public Object createDefaultValue(Parameter parameter) {
+ return Color.red;
+ }
+
+ @Override
+ public Object cloneObj(Object object) {
+ return object;
+ }
+ }
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/valueedit/ValueEditCreator.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/valueedit/ValueEditCreator.java
new file mode 100755
index 00000000..5d37040b
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/valueedit/ValueEditCreator.java
@@ -0,0 +1,29 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.roomedit.valueedit;
+
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomedit.Parameter;
+
+public interface ValueEditCreator<T extends ValueEdit> {
+ T createValueEdit(Parameter parameter);
+
+ Object createDefaultValue(Parameter parameter);
+
+ Object cloneObj(Object object);
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/valueedit/ValueEditFloat.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/valueedit/ValueEditFloat.java
new file mode 100755
index 00000000..e44adab1
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/valueedit/ValueEditFloat.java
@@ -0,0 +1,99 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.roomedit.valueedit;
+
+import kr.syeyoung.dungeonsguide.mod.gui.MPanel;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomedit.Parameter;
+import kr.syeyoung.dungeonsguide.mod.gui.elements.MFloatSelectionButton;
+import kr.syeyoung.dungeonsguide.mod.gui.elements.MLabel;
+import kr.syeyoung.dungeonsguide.mod.gui.elements.MLabelAndElement;
+
+import java.awt.*;
+
+public class ValueEditFloat extends MPanel implements ValueEdit<Float> {
+ private Parameter parameter;
+
+
+ @Override
+ public void renderWorld(float partialTicks) {
+
+ }
+ public ValueEditFloat(final Parameter parameter2) {
+ this.parameter = parameter2;
+ {
+ MLabel label = new MLabel() {
+ @Override
+ public String getText() {
+ return parameter.getPreviousData().toString();
+ }
+ };
+ MLabelAndElement mLabelAndElement = new MLabelAndElement("Prev",label);
+ mLabelAndElement.setBounds(new Rectangle(0,0,getBounds().width,20));
+ add(mLabelAndElement);
+ }
+ {
+ float newData = (Float) parameter.getNewData();
+ final MFloatSelectionButton textField = new MFloatSelectionButton(newData);
+ textField.setOnUpdate(new Runnable() {
+ @Override
+ public void run() {
+ parameter.setNewData(textField.getData());
+ }
+ });
+ MLabelAndElement mLabelAndElement = new MLabelAndElement("New",textField);
+ mLabelAndElement.setBounds(new Rectangle(0,20,getBounds().width,20));
+ add(mLabelAndElement);
+ }
+ }
+
+ @Override
+ public void onBoundsUpdate() {
+ for (MPanel panel :getChildComponents()){
+ panel.setSize(new Dimension(getBounds().width, 20));
+ }
+ }
+
+ @Override
+ public void setParameter(Parameter parameter) {
+ this.parameter = parameter;
+ }
+
+ @Override
+ public void resize(int parentWidth, int parentHeight) {
+ this.setBounds(new Rectangle(0,0,parentWidth, parentHeight));
+ }
+
+ public static class Generator implements ValueEditCreator<ValueEditFloat> {
+
+ @Override
+ public ValueEditFloat createValueEdit(Parameter parameter) {
+ return new ValueEditFloat(parameter);
+ }
+
+ @Override
+ public Object createDefaultValue(Parameter parameter) {
+ return 0.0f;
+ }
+
+ @Override
+ public Object cloneObj(Object object) {
+ return object;
+ }
+ }
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/valueedit/ValueEditInteger.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/valueedit/ValueEditInteger.java
new file mode 100755
index 00000000..4b93a30d
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/valueedit/ValueEditInteger.java
@@ -0,0 +1,99 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.roomedit.valueedit;
+
+import kr.syeyoung.dungeonsguide.mod.gui.MPanel;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomedit.Parameter;
+import kr.syeyoung.dungeonsguide.mod.gui.elements.MIntegerSelectionButton;
+import kr.syeyoung.dungeonsguide.mod.gui.elements.MLabel;
+import kr.syeyoung.dungeonsguide.mod.gui.elements.MLabelAndElement;
+
+import java.awt.*;
+
+public class ValueEditInteger extends MPanel implements ValueEdit<Integer> {
+ private Parameter parameter;
+
+
+ @Override
+ public void renderWorld(float partialTicks) {
+
+ }
+ public ValueEditInteger(final Parameter parameter2) {
+ this.parameter = parameter2;
+ {
+ MLabel label = new MLabel() {
+ @Override
+ public String getText() {
+ return parameter.getPreviousData().toString();
+ }
+ };
+ MLabelAndElement mLabelAndElement = new MLabelAndElement("Prev",label);
+ mLabelAndElement.setBounds(new Rectangle(0,0,getBounds().width,20));
+ add(mLabelAndElement);
+ }
+ {
+ int newData = (Integer) parameter.getNewData();
+ final MIntegerSelectionButton textField = new MIntegerSelectionButton(newData);
+ textField.setOnUpdate(new Runnable() {
+ @Override
+ public void run() {
+ parameter.setNewData(textField.getData());
+ }
+ });
+ MLabelAndElement mLabelAndElement = new MLabelAndElement("New",textField);
+ mLabelAndElement.setBounds(new Rectangle(0,20,getBounds().width,20));
+ add(mLabelAndElement);
+ }
+ }
+
+ @Override
+ public void onBoundsUpdate() {
+ for (MPanel panel :getChildComponents()){
+ panel.setSize(new Dimension(getBounds().width, 20));
+ }
+ }
+
+ @Override
+ public void setParameter(Parameter parameter) {
+ this.parameter = parameter;
+ }
+
+ @Override
+ public void resize(int parentWidth, int parentHeight) {
+ this.setBounds(new Rectangle(0,0,parentWidth, parentHeight));
+ }
+
+ public static class Generator implements ValueEditCreator<ValueEditInteger> {
+
+ @Override
+ public ValueEditInteger createValueEdit(Parameter parameter) {
+ return new ValueEditInteger(parameter);
+ }
+
+ @Override
+ public Object createDefaultValue(Parameter parameter) {
+ return 0;
+ }
+
+ @Override
+ public Object cloneObj(Object object) {
+ return object;
+ }
+ }
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/valueedit/ValueEditNull.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/valueedit/ValueEditNull.java
new file mode 100755
index 00000000..0868470e
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/valueedit/ValueEditNull.java
@@ -0,0 +1,38 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.roomedit.valueedit;
+
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomedit.Parameter;
+
+public class ValueEditNull implements ValueEditCreator {
+ @Override
+ public ValueEdit createValueEdit(Parameter parameter) {
+ return null;
+ }
+
+ @Override
+ public Cloneable createDefaultValue(Parameter parameter) {
+ return null;
+ }
+
+ @Override
+ public Object cloneObj(Object object) {
+ return null;
+ }
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/valueedit/ValueEditOffsetPoint.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/valueedit/ValueEditOffsetPoint.java
new file mode 100755
index 00000000..813ac68a
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/valueedit/ValueEditOffsetPoint.java
@@ -0,0 +1,163 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.roomedit.valueedit;
+
+import kr.syeyoung.dungeonsguide.dungeon.data.OffsetPoint;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomedit.EditingContext;
+import kr.syeyoung.dungeonsguide.mod.gui.MPanel;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomedit.Parameter;
+import kr.syeyoung.dungeonsguide.mod.gui.elements.*;
+import kr.syeyoung.dungeonsguide.mod.utils.RenderUtils;
+import net.minecraft.block.Block;
+import net.minecraft.client.Minecraft;
+import net.minecraft.entity.player.EntityPlayer;
+import net.minecraft.util.BlockPos;
+import java.awt.*;
+
+public class ValueEditOffsetPoint extends MPanel implements ValueEdit<String> {
+ private Parameter parameter;
+
+ @Override
+ public void renderWorld(float partialTicks) {
+ RenderUtils.highlightBlock(((OffsetPoint)parameter.getPreviousData()).getBlockPos(EditingContext.getEditingContext().getRoom()), new Color(255,0,0,150), partialTicks);
+ RenderUtils.highlightBlock(((OffsetPoint)parameter.getNewData()).getBlockPos(EditingContext.getEditingContext().getRoom()), new Color(0,255,0,150), partialTicks);
+ }
+
+ public ValueEditOffsetPoint(final Parameter parameter2) {
+ this.parameter = parameter2;
+ {
+ MLabel label = new MLabel() {
+ @Override
+ public String getText() {
+ return parameter.getPreviousData().toString();
+ }
+ };
+ MLabelAndElement mLabelAndElement = new MLabelAndElement("Prev",label);
+ mLabelAndElement.setBounds(new Rectangle(0,0,getBounds().width,20));
+ add(mLabelAndElement);
+ }
+ OffsetPoint newData = (OffsetPoint) parameter.getNewData();
+ {
+ final MIntegerSelectionButton textField = new MIntegerSelectionButton(newData.getX());
+ textField.setOnUpdate(new Runnable() {
+ @Override
+ public void run() {
+ ((OffsetPoint) parameter.getNewData()).setX(textField.getData());
+ }
+ });
+ MLabelAndElement mLabelAndElement = new MLabelAndElement("x",textField);
+ mLabelAndElement.setBounds(new Rectangle(0,20,getBounds().width,20));
+ add(mLabelAndElement);
+ }
+ {
+ final MIntegerSelectionButton textField = new MIntegerSelectionButton(newData.getY());
+ textField.setOnUpdate(new Runnable() {
+ @Override
+ public void run() {
+ ((OffsetPoint) parameter.getNewData()).setY(textField.getData());
+ }
+ });
+ MLabelAndElement mLabelAndElement = new MLabelAndElement("y",textField);
+ mLabelAndElement.setBounds(new Rectangle(0,40,getBounds().width,20));
+ add(mLabelAndElement);
+ }
+ {
+ final MIntegerSelectionButton textField = new MIntegerSelectionButton(newData.getZ());
+ textField.setOnUpdate(new Runnable() {
+ @Override
+ public void run() {
+ ((OffsetPoint) parameter.getNewData()).setZ(textField.getData());
+ }
+ });
+ MLabelAndElement mLabelAndElement = new MLabelAndElement("z",textField);
+ mLabelAndElement.setBounds(new Rectangle(0,60,getBounds().width,20));
+ add(mLabelAndElement);
+ }
+ {
+ final MLabel setToHEre = new MLabel() {
+ @Override
+ public String getText() {
+ OffsetPoint offsetPoint = (OffsetPoint) parameter.getNewData();
+ return Block.getIdFromBlock(offsetPoint.getBlock(EditingContext.getEditingContext().getRoom())) +
+ ":" + offsetPoint.getData(EditingContext.getEditingContext().getRoom());
+ }
+ };
+ MLabelAndElement mLabelAndElement = new MLabelAndElement("newPt",setToHEre);
+ mLabelAndElement.setBounds(new Rectangle(0,80,getBounds().width,20));
+ add(mLabelAndElement);
+ }
+ {
+ final MButton setToHEre2 = new MButton();
+ setToHEre2.setText("Set to here");
+ setToHEre2.setBackgroundColor(Color.green);
+ setToHEre2.setOnActionPerformed(new Runnable() {
+ @Override
+ public void run() {
+ EntityPlayer player = Minecraft.getMinecraft().thePlayer;
+ BlockPos pos = new BlockPos(player.posX, player.posY, player.posZ);
+ ((OffsetPoint)parameter2.getNewData()).setPosInWorld(EditingContext.getEditingContext().getRoom(),pos );
+ }
+ });
+ MLabelAndElement mLabelAndElement = new MLabelAndElement("set",setToHEre2);
+ mLabelAndElement.setBounds(new Rectangle(0,100,getBounds().width,20));
+ add(mLabelAndElement);
+ }
+ }
+
+ @Override
+ public void onBoundsUpdate() {
+ for (MPanel panel :getChildComponents()){
+ panel.setSize(new Dimension(getBounds().width, 20));
+ }
+ }
+
+ @Override
+ public void setParameter(Parameter parameter) {
+ this.parameter = parameter;
+ }
+
+ @Override
+ public void resize(int parentWidth, int parentHeight) {
+ this.setBounds(new Rectangle(0,0,parentWidth, parentHeight));
+ }
+
+ public static class Generator implements ValueEditCreator<ValueEditOffsetPoint> {
+
+ @Override
+ public ValueEditOffsetPoint createValueEdit(Parameter parameter) {
+ return new ValueEditOffsetPoint(parameter);
+ }
+
+ @Override
+ public Object createDefaultValue(Parameter parameter) {
+ return new OffsetPoint(EditingContext.getEditingContext().getRoom(), Minecraft.getMinecraft().thePlayer.getPosition());
+ }
+
+ @Override
+ public Object cloneObj(Object object) {
+ try {
+ return ((OffsetPoint)object).clone();
+ } catch (CloneNotSupportedException e) {
+ e.printStackTrace();
+ }
+ assert false;
+ return null;
+ }
+ }
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/valueedit/ValueEditOffsetPointSet.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/valueedit/ValueEditOffsetPointSet.java
new file mode 100755
index 00000000..cd6351bd
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/valueedit/ValueEditOffsetPointSet.java
@@ -0,0 +1,250 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.roomedit.valueedit;
+
+import kr.syeyoung.dungeonsguide.dungeon.data.OffsetPoint;
+import kr.syeyoung.dungeonsguide.dungeon.data.OffsetPointSet;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomedit.EditingContext;
+import kr.syeyoung.dungeonsguide.mod.gui.MPanel;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomedit.Parameter;
+import kr.syeyoung.dungeonsguide.mod.gui.elements.MButton;
+import kr.syeyoung.dungeonsguide.mod.gui.elements.MValue;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomedit.gui.GuiDungeonAddSet;
+import kr.syeyoung.dungeonsguide.mod.utils.RenderUtils;
+import lombok.Getter;
+import net.minecraft.client.Minecraft;
+
+import java.awt.*;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+public class ValueEditOffsetPointSet extends MPanel implements ValueEdit<OffsetPointSet> {
+ private Parameter parameter;
+
+ // scroll pane
+ // just create
+ // add set
+
+ private final MPanel scroll;
+ @Getter
+ private final List<MPanel> MParameters = new ArrayList<MPanel>();
+
+ private final MButton add;
+ private final MButton addSet;
+
+ public void delete(OffsetPoint offsetPoint) {
+ ((OffsetPointSet)parameter.getNewData()).getOffsetPointList().remove(offsetPoint);
+ Iterator<MPanel> iterator = MParameters.iterator();
+ while (iterator.hasNext()) {
+ MValue panel = (MValue) iterator.next();
+ if (panel.getData() == offsetPoint) {
+ iterator.remove();
+ break;
+ }
+ }
+
+ }
+
+ public ValueEditOffsetPointSet(final Parameter parameter2) {
+ this.parameter = parameter2;
+ {
+ scroll = new MPanel() {
+ private int offsetY = 0;
+
+ @Override
+ public List<MPanel> getChildComponents() {
+ return MParameters;
+ }
+
+ @Override
+ public void render(int absMousex, int absMousey, int relMousex0, int relMousey0, float partialTicks, Rectangle scissor) {
+ int heights = 0;
+ for (MPanel panel:getChildComponents()) {
+ panel.setPosition(new Point(0, -offsetY + heights));
+ heights += panel.getBounds().height;
+ }
+ }
+
+ @Override
+ public boolean mouseClicked0(int absMouseX, int absMouseY, int relMouseX0, int relMouseY0, int mouseButton) {
+ if (!getBounds().contains(relMouseX0, relMouseY0)) {
+ return false;
+ }
+
+ int relMousex = relMouseX0 - getBounds().x;
+ int relMousey = relMouseY0 - getBounds().y;
+
+ boolean noClip = true;
+ boolean focusedOverall = false;
+ for (MPanel childComponent : getChildComponents()) {
+ if (childComponent.mouseClicked0(absMouseX, absMouseY, relMousex, relMousey, mouseButton)) {
+ noClip = false;
+ focusedOverall = true;
+ }
+ }
+
+ if (getBounds().contains(relMouseX0, relMouseY0) && noClip) {
+ isFocused = true;
+ focusedOverall = true;
+ } else {
+ isFocused = false;
+ }
+
+ mouseClicked(absMouseX, absMouseY, relMousex, relMousey, mouseButton);
+ return focusedOverall;
+ }
+
+ @Override
+ public void onBoundsUpdate() {
+ for (MPanel panel :getChildComponents()){
+ panel.setSize(new Dimension(getBounds().width, 20));
+ }
+ }
+ @Override
+ public void resize(int parentWidth, int parentHeight) {
+ this.setBounds(new Rectangle(5,5,parentWidth-10,parentHeight-10));
+ }
+
+ @Override
+ public void mouseScrolled(int absMouseX, int absMouseY, int relMouseX0, int relMouseY0, int scrollAmount) {
+ if (new Rectangle(new Point(0,0), getSize()).contains(relMouseX0, relMouseY0)) {
+ if (scrollAmount >0) offsetY += 20;
+ else if (scrollAmount < 0) offsetY -= 20;
+ if (offsetY <0) offsetY = 0;
+ }
+ }
+ };
+ scroll.setBounds(new Rectangle(0,0,getBounds().width, getBounds().height-20));
+ add(scroll);
+ }
+
+ {
+ add = new MButton() {
+ @Override
+ public void resize(int parentWidth, int parentHeight) {
+ setBounds(new Rectangle(0,parentHeight - 20, parentWidth / 2, 20));
+ }
+ };
+ add.setText("Add");
+ add.setBackgroundColor(Color.green);
+ add.setOnActionPerformed(new Runnable() {
+ @Override
+ public void run() {
+ OffsetPoint offsetPoint = new OffsetPoint(EditingContext.getEditingContext().getRoom(), Minecraft.getMinecraft().thePlayer.getPosition());
+ MValue mValue;
+ MParameters.add(mValue = new MValue(offsetPoint, buildAddonsFor(offsetPoint)));
+ ((OffsetPointSet)parameter.getNewData()).getOffsetPointList().add(offsetPoint);
+ mValue.setSize(new Dimension(getBounds().width, 20));
+ }
+ });
+
+ addSet = new MButton(){
+ @Override
+ public void resize(int parentWidth, int parentHeight) {
+ setBounds(new Rectangle(parentWidth / 2,parentHeight - 20, parentWidth / 2, 20));
+ }
+ };
+ addSet.setText("Add Set");
+ addSet.setBackgroundColor(Color.cyan);
+ addSet.setOnActionPerformed(new Runnable() {
+ @Override
+ public void run() {
+ EditingContext.getEditingContext().openGui(new GuiDungeonAddSet(ValueEditOffsetPointSet.this));
+ }
+ });
+ add(add);
+ add(addSet);
+ }
+ for (OffsetPoint offsetPoint : ((OffsetPointSet)parameter.getNewData()).getOffsetPointList()) {
+ MParameters.add(new MValue(offsetPoint, buildAddonsFor(offsetPoint)));
+ }
+ }
+
+ public List<MPanel> buildAddonsFor(final OffsetPoint offsetPoint) {
+ ArrayList<MPanel> panels = new ArrayList<MPanel>();
+ MButton mButton = new MButton();
+ mButton.setText("Delete");
+ mButton.setForeground(Color.white);
+ mButton.setBackgroundColor(Color.red);
+ mButton.setOnActionPerformed(new Runnable() {
+ @Override
+ public void run() {
+ delete(offsetPoint);
+ }
+ });
+ panels.add(mButton);
+ return panels;
+ }
+
+ @Override
+ public void onBoundsUpdate() {
+ scroll.setBounds(new Rectangle(0,0,getBounds().width, getBounds().height-20));
+ add.setBounds(new Rectangle(0,getBounds().height-20,getBounds().width / 2, 20));
+ addSet.setBounds(new Rectangle(getBounds().width / 2,getBounds().height-20,getBounds().width / 2, 20));
+ }
+
+ @Override
+ public void setParameter(Parameter parameter) {
+ this.parameter = parameter;
+ }
+
+ @Override
+ public void renderWorld(float partialTicks) {
+ for (OffsetPoint offsetPoint :((OffsetPointSet)parameter.getNewData()).getOffsetPointList()) {
+ RenderUtils.highlightBlock(offsetPoint.getBlockPos(EditingContext.getEditingContext().getRoom()), new Color(0,255,255,50), partialTicks);
+ }
+ }
+
+ @Override
+ public void resize(int parentWidth, int parentHeight) {
+ this.setBounds(new Rectangle(0,0,parentWidth, parentHeight));
+ }
+
+ public void addAll(List<OffsetPoint> blockPoses) {
+ ((OffsetPointSet)parameter.getNewData()).getOffsetPointList().addAll(blockPoses);
+ for (OffsetPoint blockPose : blockPoses) {
+ MParameters.add(new MValue(blockPose, buildAddonsFor(blockPose)));
+ }
+ }
+
+ public static class Generator implements ValueEditCreator<ValueEditOffsetPointSet> {
+
+ @Override
+ public ValueEditOffsetPointSet createValueEdit(Parameter parameter) {
+ return new ValueEditOffsetPointSet(parameter);
+ }
+
+ @Override
+ public Object createDefaultValue(Parameter parameter) {
+ return new OffsetPointSet();
+ }
+
+ @Override
+ public Object cloneObj(Object object) {
+ try {
+ return ((OffsetPointSet)object).clone();
+ } catch (CloneNotSupportedException e) {
+ e.printStackTrace();
+ }
+ assert false;
+ return null;
+ }
+ }
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/valueedit/ValueEditRegistry.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/valueedit/ValueEditRegistry.java
new file mode 100755
index 00000000..af368f2c
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/valueedit/ValueEditRegistry.java
@@ -0,0 +1,70 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.roomedit.valueedit;
+
+import kr.syeyoung.dungeonsguide.mod.config.types.AColor;
+import kr.syeyoung.dungeonsguide.dungeon.data.OffsetPoint;
+import kr.syeyoung.dungeonsguide.dungeon.data.OffsetPointSet;
+import kr.syeyoung.dungeonsguide.dungeon.mechanics.*;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomedit.mechanicedit.*;
+
+import java.awt.*;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class ValueEditRegistry {
+ private static final Map<String, ValueEditCreator> valueEditMap = new HashMap<String, ValueEditCreator>();
+
+ public static ValueEditCreator getValueEditMap(String className) {
+ return valueEditMap.get(className);
+ }
+
+ public static List<String> getClassesSupported() {
+ return new ArrayList<String>(valueEditMap.keySet());
+ }
+
+ static {
+ valueEditMap.put("null", new ValueEditNull());
+ valueEditMap.put(String.class.getName(), new ValueEditString.Generator());
+ valueEditMap.put(Boolean.class.getName(), new ValueEditBoolean.Generator());
+ valueEditMap.put(Integer.class.getName(), new ValueEditInteger.Generator());
+ valueEditMap.put(Float.class.getName(), new ValueEditFloat.Generator());
+ valueEditMap.put(OffsetPoint.class.getName(), new ValueEditOffsetPoint.Generator());
+ valueEditMap.put(OffsetPointSet.class.getName(), new ValueEditOffsetPointSet.Generator());
+ valueEditMap.put(Color.class.getName(), new ValueEditColor.Generator());
+ valueEditMap.put(AColor.class.getName(), new ValueEditAColor.Generator());
+
+
+ valueEditMap.put(DungeonSecret.class.getName(), new ValueEditSecret.Generator());
+ valueEditMap.put(DungeonFairySoul.class.getName(), new ValueEditFairySoul.Generator());
+ valueEditMap.put(DungeonNPC.class.getName(), new ValueEditNPC.Generator());
+ valueEditMap.put(DungeonTomb.class.getName(), new ValueEditTomb.Generator());
+ valueEditMap.put(DungeonBreakableWall.class.getName(), new ValueEditBreakableWall.Generator());
+ valueEditMap.put(DungeonJournal.class.getName(), new ValueEditJournal.Generator());
+ valueEditMap.put(DungeonDummy.class.getName(), new ValueEditDummy.Generator());
+
+ valueEditMap.put(DungeonPressurePlate.class.getName(), new ValueEditPressurePlate.Generator());
+ valueEditMap.put(DungeonOnewayLever.class.getName(), new ValueEditOnewayLever.Generator());
+ valueEditMap.put(DungeonLever.class.getName(), new ValueEditLever.Generator());
+ valueEditMap.put(DungeonDoor.class.getName(), new ValueEditDoor.Generator());
+ valueEditMap.put(DungeonOnewayDoor.class.getName(), new ValueEditOnewayDoor.Generator());
+ }
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/valueedit/ValueEditString.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/valueedit/ValueEditString.java
new file mode 100755
index 00000000..0d2b3697
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomedit/valueedit/ValueEditString.java
@@ -0,0 +1,99 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.roomedit.valueedit;
+
+import kr.syeyoung.dungeonsguide.mod.gui.MPanel;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomedit.Parameter;
+import kr.syeyoung.dungeonsguide.mod.gui.elements.MLabel;
+import kr.syeyoung.dungeonsguide.mod.gui.elements.MLabelAndElement;
+import kr.syeyoung.dungeonsguide.mod.gui.elements.MTextField;
+
+import java.awt.*;
+
+public class ValueEditString extends MPanel implements ValueEdit<String> {
+ private Parameter parameter;
+
+ @Override
+ public void renderWorld(float partialTicks) {
+
+ }
+
+ public ValueEditString(Parameter parameter2) {
+ this.parameter = parameter2;
+ {
+ MLabel label = new MLabel() {
+ @Override
+ public String getText() {
+ return parameter.getPreviousData().toString();
+ }
+ };
+ MLabelAndElement mLabelAndElement = new MLabelAndElement("Prev",label);
+ mLabelAndElement.setBounds(new Rectangle(0,0,getBounds().width,20));
+ add(mLabelAndElement);
+ }
+ {
+ String newData = (String) parameter.getNewData();
+ MTextField textField = new MTextField() {
+ @Override
+ public void edit(String str) {
+ parameter.setNewData(str);
+ }
+ };
+ textField.setText(newData);
+ MLabelAndElement mLabelAndElement = new MLabelAndElement("New",textField);
+ mLabelAndElement.setBounds(new Rectangle(0,20,getBounds().width,20));
+ add(mLabelAndElement);
+ }
+ }
+
+ @Override
+ public void onBoundsUpdate() {
+ for (MPanel panel :getChildComponents()){
+ panel.setSize(new Dimension(getBounds().width, 20));
+ }
+ }
+
+ @Override
+ public void setParameter(Parameter parameter) {
+ this.parameter = parameter;
+ }
+
+ @Override
+ public void resize(int parentWidth, int parentHeight) {
+ this.setBounds(new Rectangle(0,0,parentWidth, parentHeight));
+ }
+
+ public static class Generator implements ValueEditCreator<ValueEditString> {
+
+ @Override
+ public ValueEditString createValueEdit(Parameter parameter) {
+ return new ValueEditString(parameter);
+ }
+
+ @Override
+ public Object createDefaultValue(Parameter parameter) {
+ return "default";
+ }
+
+ @Override
+ public Object cloneObj(Object object) {
+ return object;
+ }
+ }
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomfinder/DungeonRoom.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomfinder/DungeonRoom.java
new file mode 100755
index 00000000..5834d67e
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomfinder/DungeonRoom.java
@@ -0,0 +1,381 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.roomfinder;
+
+import com.google.common.collect.Sets;
+import kr.syeyoung.dungeonsguide.mod.dungeon.DungeonContext;
+import kr.syeyoung.dungeonsguide.mod.dungeon.MapProcessor;
+import kr.syeyoung.dungeonsguide.dungeon.data.DungeonRoomInfo;
+import kr.syeyoung.dungeonsguide.mod.dungeon.doorfinder.DungeonDoor;
+import kr.syeyoung.dungeonsguide.mod.dungeon.doorfinder.EDungeonDoorType;
+import kr.syeyoung.dungeonsguide.mod.dungeon.events.impl.DungeonStateChangeEvent;
+import kr.syeyoung.dungeonsguide.dungeon.mechanics.dunegonmechanic.DungeonMechanic;
+import kr.syeyoung.dungeonsguide.dungeon.mechanics.DungeonRoomDoor;
+import kr.syeyoung.dungeonsguide.mod.dungeon.pathfinding.*;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomedit.EditingContext;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.ProcessorFactory;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.RoomProcessor;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.RoomProcessorGenerator;
+import kr.syeyoung.dungeonsguide.mod.features.FeatureRegistry;
+import kr.syeyoung.dungeonsguide.mod.features.impl.secret.FeaturePathfindStrategy;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.Setter;
+import net.minecraft.block.Block;
+import net.minecraft.block.state.IBlockState;
+import net.minecraft.entity.Entity;
+import net.minecraft.pathfinding.PathEntity;
+import net.minecraft.pathfinding.PathFinder;
+import net.minecraft.pathfinding.PathPoint;
+import net.minecraft.util.*;
+import net.minecraft.world.ChunkCache;
+import net.minecraft.world.IBlockAccess;
+import net.minecraft.world.World;
+
+import javax.vecmath.Vector2d;
+import java.awt.*;
+import java.util.List;
+import java.util.*;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.TimeUnit;
+
+@Getter
+public class DungeonRoom {
+ private final List<Point> unitPoints;
+ private final short shape;
+ private final byte color;
+
+ private final BlockPos min;
+ private final BlockPos max;
+ private final Point minRoomPt;
+
+ private final DungeonContext context;
+
+ private final List<DungeonDoor> doors = new ArrayList<>();
+
+ private DungeonRoomInfo dungeonRoomInfo;
+
+ private final int unitWidth; // X
+ private final int unitHeight; // Z
+
+ @Setter
+ private int totalSecrets = -1;
+ private RoomState currentState = RoomState.DISCOVERED;
+
+ private Map<String, DungeonMechanic> cached = null;
+
+ @Getter
+ private final World cachedWorld;
+ public Map<String, DungeonMechanic> getMechanics() {
+ if (cached == null || EditingContext.getEditingContext() != null) {
+ cached = new HashMap<>(dungeonRoomInfo.getMechanics());
+ int index = 0;
+ for (DungeonDoor door : doors) {
+ if (door.getType().isExist()) cached.put((door.getType().getName())+"-"+(++index), new DungeonRoomDoor(this, door));
+ }
+ }
+ return cached;
+ }
+
+ public void setCurrentState(RoomState currentState) {
+ context.createEvent(new DungeonStateChangeEvent(unitPoints.get(0), dungeonRoomInfo.getName(), this.currentState, currentState));
+ this.currentState = currentState;
+ }
+
+ private final Map<BlockPos, AStarFineGrid> activeBetterAStar = new HashMap<>();
+ private final Map<BlockPos, AStarCornerCut> activeBetterAStarCornerCut = new HashMap<>();
+ private final Map<BlockPos, ThetaStar> activeThetaStar = new HashMap<>();
+
+ public ScheduledFuture<List<Vec3>> createEntityPathTo(IBlockAccess blockaccess, Entity entityIn, BlockPos targetPos, float dist, int timeout) {
+ FeaturePathfindStrategy.PathfindStrategy pathfindStrategy = FeatureRegistry.SECRET_PATHFIND_STRATEGY.getPathfindStrat();
+ if (pathfindStrategy == FeaturePathfindStrategy.PathfindStrategy.JPS_LEGACY) {
+ return asyncPathFinder.schedule(() -> {
+ BlockPos min = new BlockPos(getMin().getX(), 0, getMin().getZ());
+ BlockPos max= new BlockPos(getMax().getX(), 255, getMax().getZ());
+ JPSPathfinder pathFinder = new JPSPathfinder(this);
+ pathFinder.pathfind(entityIn.getPositionVector(), new Vec3(targetPos).addVector(0.5, 0.5, 0.5), 1.5f,timeout);
+ return pathFinder.getRoute();
+ }, 0, TimeUnit.MILLISECONDS);
+ } else if (pathfindStrategy == FeaturePathfindStrategy.PathfindStrategy.A_STAR_FINE_GRID) {
+ return asyncPathFinder.schedule(() -> {
+ AStarFineGrid pathFinder =
+ activeBetterAStar.computeIfAbsent(targetPos, (pos) -> new AStarFineGrid(this, new Vec3(pos.getX(), pos.getY(), pos.getZ()).addVector(0.5, 0.5, 0.5)));
+ pathFinder.pathfind(entityIn.getPositionVector(),timeout);
+ return pathFinder.getRoute();
+ }, 0, TimeUnit.MILLISECONDS);
+ }else if (pathfindStrategy == FeaturePathfindStrategy.PathfindStrategy.A_STAR_DIAGONAL) {
+ return asyncPathFinder.schedule(() -> {
+ AStarCornerCut pathFinder =
+ activeBetterAStarCornerCut.computeIfAbsent(targetPos, (pos) -> new AStarCornerCut(this, new Vec3(pos.getX(), pos.getY(), pos.getZ()).addVector(0.5, 0.5, 0.5)));
+ pathFinder.pathfind(entityIn.getPositionVector(),timeout);
+ return pathFinder.getRoute();
+ }, 0, TimeUnit.MILLISECONDS);
+ } else if (pathfindStrategy == FeaturePathfindStrategy.PathfindStrategy.THETA_STAR) {
+ return asyncPathFinder.schedule(() -> {
+ ThetaStar pathFinder =
+ activeThetaStar.computeIfAbsent(targetPos, (pos) -> new ThetaStar(this, new Vec3(pos.getX(), pos.getY(), pos.getZ()).addVector(0.5, 0.5, 0.5)));
+ pathFinder.pathfind(entityIn.getPositionVector(),timeout);
+ return pathFinder.getRoute();
+ }, 0, TimeUnit.MILLISECONDS);
+ } else {
+ return asyncPathFinder.schedule(() -> {
+ PathFinder pathFinder = new PathFinder(nodeProcessorDungeonRoom);
+ PathEntity latest = pathFinder.createEntityPathTo(blockaccess, entityIn, targetPos, dist);
+ if (latest != null) {
+ List<Vec3> poses = new ArrayList<>();
+ for (int i = 0; i < latest.getCurrentPathLength(); i++) {
+ PathPoint pathPoint = latest.getPathPointFromIndex(i);
+ poses.add(new Vec3(getMin().add(pathPoint.xCoord, pathPoint.yCoord, pathPoint.zCoord)).addVector(0.5,0.5,0.5));
+ }
+ return poses;
+ }
+ return new ArrayList<>();
+ }, 0, TimeUnit.MILLISECONDS);
+ }
+ }
+
+ private static final ScheduledExecutorService asyncPathFinder = Executors.newScheduledThreadPool(4);
+ @Getter
+ private final NodeProcessorDungeonRoom nodeProcessorDungeonRoom;
+
+ @Getter
+ private final Map<String, Object> roomContext = new HashMap<>();
+
+ @AllArgsConstructor
+ @Getter
+ public enum RoomState {
+ DISCOVERED(0), COMPLETE_WITHOUT_SECRETS(0), FINISHED(0), FAILED(-14);
+ private final int scoreModifier;
+ }
+
+ private RoomProcessor roomProcessor;
+
+ public DungeonRoom(List<Point> points, short shape, byte color, BlockPos min, BlockPos max, DungeonContext context, Set<Tuple<Vector2d, EDungeonDoorType>> doorsAndStates) {
+ this.unitPoints = points;
+ this.shape = shape;
+ this.color = color;
+ this.min = min;
+ this.max = max;
+ this.context = context;
+
+ minRoomPt = new Point(Integer.MAX_VALUE, Integer.MAX_VALUE);
+ for (Point pt : unitPoints) {
+ if (pt.x < minRoomPt.x) minRoomPt.x = pt.x;
+ if (pt.y < minRoomPt.y) minRoomPt.y = pt.y;
+ }
+ unitWidth = (int) Math.ceil(max.getX() - min.getX() / 32.0);
+ unitHeight = (int) Math.ceil(max.getZ() - min.getZ() / 32.0);
+
+
+ ChunkCache chunkCache = new ChunkCache(getContext().getWorld(), min.add(-3, 0, -3), max.add(3,0,3), 0);
+ this.cachedWorld = new CachedWorld(chunkCache);
+
+
+
+ minx = min.getX() * 2; miny = 0; minz = min.getZ() * 2;
+ maxx = max.getX() * 2 + 2; maxy = 255 * 2 + 2; maxz = max.getZ() * 2 + 2;
+
+ lenx = maxx - minx;
+ leny = maxy - miny;
+ lenz = maxz - minz;
+ arr = new long[lenx *leny * lenz * 2 / 8];;
+
+ buildDoors(doorsAndStates);
+ buildRoom();
+ nodeProcessorDungeonRoom = new NodeProcessorDungeonRoom(this);
+ updateRoomProcessor();
+
+
+ }
+
+ private static final Set<Vector2d> directions = Sets.newHashSet(new Vector2d(0,16), new Vector2d(0, -16), new Vector2d(16, 0), new Vector2d(-16 , 0));
+
+ private void buildDoors(Set<Tuple<Vector2d, EDungeonDoorType>> doorsAndStates) {
+ Set<Tuple<BlockPos, EDungeonDoorType>> positions = new HashSet<>();
+ BlockPos pos = context.getMapProcessor().roomPointToWorldPoint(minRoomPt).add(16,0,16);
+ for (Tuple<Vector2d, EDungeonDoorType> doorsAndState : doorsAndStates) {
+ Vector2d vector2d = doorsAndState.getFirst();
+ BlockPos neu = pos.add(vector2d.x * 32, 0, vector2d.y * 32);
+ positions.add(new Tuple<>(neu, doorsAndState.getSecond()));
+ }
+
+ for (Tuple<BlockPos, EDungeonDoorType> door : positions) {
+ doors.add(new DungeonDoor(context.getWorld(), door.getFirst(), door.getSecond()));
+ }
+ }
+
+ private RoomMatcher roomMatcher = null;
+ private void buildRoom() {
+ if (roomMatcher == null)
+ roomMatcher = new RoomMatcher(this);
+ DungeonRoomInfo dungeonRoomInfo = roomMatcher.match();
+ if (dungeonRoomInfo == null) {
+ dungeonRoomInfo = roomMatcher.createNew();
+ if (color == 18) dungeonRoomInfo.setProcessorId("bossroom");
+ }
+ this.dungeonRoomInfo = dungeonRoomInfo;
+ totalSecrets = dungeonRoomInfo.getTotalSecrets();
+ }
+
+ public void updateRoomProcessor() {
+ RoomProcessorGenerator roomProcessorGenerator = ProcessorFactory.getRoomProcessorGenerator(dungeonRoomInfo.getProcessorId());
+ if (roomProcessorGenerator == null) this.roomProcessor = null;
+ else this.roomProcessor = roomProcessorGenerator.createNew(this);
+ }
+
+ public Block getAbsoluteBlockAt(int x, int y, int z) {
+ // validate x y z's
+ BlockPos pos = new BlockPos(x,y,z);
+ if (canAccessAbsolute(pos)) {
+ return cachedWorld.getBlockState(pos).getBlock();
+ }
+ return null;
+ }
+
+ public Block getRelativeBlockAt(int x, int y, int z) {
+ // validate x y z's
+ if (canAccessRelative(x,z)) {
+ BlockPos pos = new BlockPos(x,y,z).add(min.getX(),min.getY(),min.getZ());
+ return cachedWorld.getBlockState(pos).getBlock();
+ }
+ return null;
+ }
+
+ public BlockPos getRelativeBlockPosAt(int x, int y, int z) {
+ BlockPos pos = new BlockPos(x,y,z).add(min.getX(),min.getY(),min.getZ());
+ return pos;
+ }
+
+ public int getRelativeBlockDataAt(int x, int y, int z) {
+ // validate x y z's
+ if (canAccessRelative(x,z)) {
+ BlockPos pos = new BlockPos(x,y,z).add(min.getX(),min.getY(),min.getZ());
+ IBlockState iBlockState = cachedWorld.getBlockState(pos);
+ return iBlockState.getBlock().getMetaFromState(iBlockState);
+ }
+ return -1;
+ }
+
+ public int getAbsoluteBlockDataAt(int x, int y, int z) {
+ // validate x y z's
+ BlockPos pos = new BlockPos(x,y,z);
+ if (canAccessAbsolute(pos)) {
+ IBlockState iBlockState = cachedWorld.getBlockState(pos);
+ return iBlockState.getBlock().getMetaFromState(iBlockState);
+ }
+ return -1;
+ }
+
+ public boolean canAccessAbsolute(BlockPos pos) {
+ MapProcessor mapProcessor = this.context.getMapProcessor();
+ Point roomPt = mapProcessor.worldPointToRoomPoint(pos);
+ roomPt.translate(-minRoomPt.x, -minRoomPt.y);
+
+ return (shape >>(roomPt.y *4 +roomPt.x) & 0x1) > 0;
+ }
+ public boolean canAccessRelative(int x, int z) {
+ return x>= 0 && z >= 0 && (shape >>((z/32) *4 +(x/32)) & 0x1) > 0;
+ }
+
+
+
+ long[] arr;
+ // These values are doubled
+ private final int minx;
+ private final int miny;
+ private final int minz;
+ private final int maxx;
+ private final int maxy;
+ private final int maxz;
+ private final int lenx, leny, lenz;
+ private static final float playerWidth = 0.3f;
+ public boolean isBlocked(int x,int y, int z) {
+ if (x < minx || z < minz || x >= maxx || z >= maxz || y < miny || y >= maxy) return true;
+ int dx = x - minx, dy = y - miny, dz = z - minz;
+ int bitIdx = dx * leny * lenz + dy * lenz + dz;
+ int location = bitIdx / 4;
+ int bitStart = (2 * (bitIdx % 4));
+ long theBit = arr[location];
+ if (((theBit >> bitStart) & 0x2) > 0) return ((theBit >> bitStart) & 1) > 0;
+ float wX = x / 2.0f, wY = y / 2.0f, wZ = z / 2.0f;
+
+
+ AxisAlignedBB bb = AxisAlignedBB.fromBounds(wX - playerWidth, wY, wZ - playerWidth, wX + playerWidth, wY + 1.9f, wZ + playerWidth);
+
+ int i = MathHelper.floor_double(bb.minX);
+ int j = MathHelper.floor_double(bb.maxX + 1.0D);
+ int k = MathHelper.floor_double(bb.minY);
+ int l = MathHelper.floor_double(bb.maxY + 1.0D);
+ int i1 = MathHelper.floor_double(bb.minZ);
+ int j1 = MathHelper.floor_double(bb.maxZ + 1.0D);
+ BlockPos.MutableBlockPos blockPos = new BlockPos.MutableBlockPos();
+
+ List<AxisAlignedBB> list = new ArrayList<>();
+ for (int k1 = i; k1 < j; ++k1) {
+ for (int l1 = i1; l1 < j1; ++l1) {
+ for (int i2 = k - 1; i2 < l; ++i2) {
+ blockPos.set(k1, i2, l1);
+ IBlockState iblockstate1 = cachedWorld.getBlockState(blockPos);
+ Block b = iblockstate1.getBlock();
+ if (!b.getMaterial().blocksMovement())continue;
+ if (b.isFullCube() && i2 == k-1) continue;
+ if (iblockstate1.equals( NodeProcessorDungeonRoom.preBuilt)) continue;
+ if (b.isFullCube()) {
+ theBit |= (3L << bitStart);
+ arr[location] = theBit;
+ return true;
+ }
+ try {
+ b.addCollisionBoxesToList(cachedWorld, blockPos, iblockstate1, bb, list, null);
+ } catch (Exception e) {
+ return true;
+ }
+ if (list.size() > 0) {
+ theBit |= (3L << bitStart);
+ arr[location] = theBit;
+ return true;
+ }
+ }
+ }
+ }
+ theBit |= 2L << bitStart;
+ arr[location] = theBit;
+ return false;
+ }
+
+
+ public void resetBlock(BlockPos pos) {
+ for (int x = -1; x <= 1; x++) {
+ for (int y = -1; y <= 1; y++) {
+ for (int z = -1; z <= 1; z++) {
+ resetBlock(pos.getX()*2 + x, pos.getY()*2 + y, pos.getZ()*2 + z);
+ }
+ }
+ }
+ }
+ private void resetBlock(int x, int y, int z) {
+ if (x < minx || z < minz || x >= maxx || z >= maxz || y < miny || y >= maxy) return;
+ int dx = x - minx, dy = y - miny, dz = z - minz;
+ int bitIdx = dx * leny * lenz + dy * lenz + dz;
+ int location = bitIdx / 4;
+ arr[location] = 0;
+ }
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomfinder/DungeonRoomInfoRegistry.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomfinder/DungeonRoomInfoRegistry.java
new file mode 100755
index 00000000..72000d38
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomfinder/DungeonRoomInfoRegistry.java
@@ -0,0 +1,163 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.roomfinder;
+
+import com.google.common.io.Files;
+import com.google.gson.Gson;
+import kr.syeyoung.dungeonsguide.Main;
+import kr.syeyoung.dungeonsguide.dungeon.data.DungeonRoomInfo;
+import lombok.Getter;
+import net.minecraft.client.Minecraft;
+import org.apache.commons.io.IOUtils;
+import org.jetbrains.annotations.NotNull;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.NoSuchPaddingException;
+import java.io.*;
+import java.nio.charset.Charset;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.util.*;
+
+public class DungeonRoomInfoRegistry {
+ @Getter
+ private static final List<DungeonRoomInfo> registered = new ArrayList<DungeonRoomInfo>();
+ private static final Map<Short, List<DungeonRoomInfo>> shapeMap = new HashMap<Short, List<DungeonRoomInfo>>();
+ private static final Map<UUID, DungeonRoomInfo> uuidMap = new HashMap<UUID, DungeonRoomInfo>();
+
+ static Gson gson = new Gson();
+
+ public static void register(@NotNull DungeonRoomInfo dungeonRoomInfo) {
+
+// System.out.println("Loading room: " + dungeonRoomInfo.getUuid());
+//
+// File file = new File(Main.getConfigDir() + "/" + "rooms" + "/" + dungeonRoomInfo.getUuid() + ".json");
+// if(!file.exists()){
+// try {
+// FileUtils.writeStringToFile(file, gson.toJson(dungeonRoomInfo));
+// } catch (IOException e) {
+// throw new RuntimeException(e);
+// }
+// }
+
+
+
+ if (uuidMap.containsKey(dungeonRoomInfo.getUuid())) {
+ DungeonRoomInfo dri1 = uuidMap.get(dungeonRoomInfo.getUuid());
+ registered.remove(dri1);
+ shapeMap.get(dri1.getShape()).remove(dri1);
+ uuidMap.remove(dri1.getUuid());
+ }
+ dungeonRoomInfo.setRegistered(true);
+ registered.add(dungeonRoomInfo);
+ uuidMap.put(dungeonRoomInfo.getUuid(), dungeonRoomInfo);
+ List<DungeonRoomInfo> roomInfos = shapeMap.get(dungeonRoomInfo.getShape());
+ if (roomInfos == null) {
+ roomInfos = new ArrayList<>();
+ }
+ roomInfos.add(dungeonRoomInfo);
+ shapeMap.put(dungeonRoomInfo.getShape(), roomInfos);
+ }
+
+
+ public static List<DungeonRoomInfo> getByShape(Short shape) {
+ List<DungeonRoomInfo> dungeonRoomInfos = shapeMap.get(shape);
+ return dungeonRoomInfos == null ? Collections.emptyList() : dungeonRoomInfos;
+ }
+
+ public static DungeonRoomInfo getByUUID(UUID uid) {
+ return uuidMap.get(uid);
+ }
+
+ public static void unregister(DungeonRoomInfo dungeonRoomInfo) {
+ if (!dungeonRoomInfo.isRegistered()) throw new IllegalStateException("what tha fak? that is not registered one");
+ if (!uuidMap.containsKey(dungeonRoomInfo.getUuid())) throw new IllegalStateException("what tha fak? that is not registered one, but you desperately wanted to trick this program");
+ dungeonRoomInfo.setRegistered(false);
+ registered.remove(dungeonRoomInfo);
+ shapeMap.get(dungeonRoomInfo.getShape()).remove(dungeonRoomInfo);
+ uuidMap.remove(dungeonRoomInfo.getUuid());
+ }
+
+ public static void saveAll(File dir) {
+ dir.mkdirs();
+ boolean isDev = Minecraft.getMinecraft().getSession().getPlayerID().replace("-","").equals("e686fe0aab804a71ac7011dc8c2b534c");
+ StringBuilder nameidstring = new StringBuilder("name,uuid,processsor,secrets");
+ StringBuilder ids = new StringBuilder();
+ for (DungeonRoomInfo dungeonRoomInfo : registered) {
+ try {
+ if (!dungeonRoomInfo.isUserMade() && !isDev) continue;
+ FileOutputStream fos = new FileOutputStream(new File(dir, dungeonRoomInfo.getUuid().toString() + ".roomdata"));
+ ObjectOutputStream oos = new ObjectOutputStream(fos);
+ oos.writeObject(dungeonRoomInfo);
+ oos.flush();
+ oos.close();
+
+ nameidstring.append("\n").append(dungeonRoomInfo.getName()).append(",").append(dungeonRoomInfo.getUuid()).append(",").append(dungeonRoomInfo.getProcessorId()).append(",").append(dungeonRoomInfo.getTotalSecrets());
+ ids.append("roomdata/").append(dungeonRoomInfo.getUuid()).append(".roomdata\n");
+ } catch (Exception e) {e.printStackTrace();}
+ }
+
+ try {
+ Files.write(nameidstring.toString(), new File(dir, "roomidmapping.csv"), Charset.defaultCharset());
+ Files.write(ids.toString(), new File(dir, "datas.txt"), Charset.defaultCharset());
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ public static void loadAll(File dir) throws BadPaddingException, InvalidAlgorithmParameterException, NoSuchAlgorithmException, IOException, IllegalBlockSizeException, NoSuchPaddingException, InvalidKeyException {
+ registered.clear();
+ shapeMap.clear();
+ uuidMap.clear();
+ try {
+ List<String> lines = IOUtils.readLines(Main.class.getResourceAsStream("/roomdata/datas.txt"));
+ for (String name : lines) {
+ if (!name.endsWith(".roomdata")) continue;
+ try {
+ InputStream fis = Main.class.getResourceAsStream("/"+name);
+ ObjectInputStream ois = new ObjectInputStream(fis);
+ DungeonRoomInfo dri = (DungeonRoomInfo) ois.readObject();
+ ois.close();
+ fis.close();
+ register(dri);
+ } catch (Exception e) {
+ System.out.println(name);
+ e.printStackTrace();
+ }
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ for (File f : dir.listFiles()) {
+ if (!f.getName().endsWith(".roomdata")) continue;
+ try {
+ InputStream fis = new FileInputStream(f);
+ ObjectInputStream ois = new ObjectInputStream(fis);
+ DungeonRoomInfo dri = (DungeonRoomInfo) ois.readObject();
+ ois.close();
+ fis.close();
+ register(dri);
+ } catch (Exception e) {
+ System.out.println(f.getName());e.printStackTrace();}
+ }
+ }
+
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomfinder/RoomMatcher.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomfinder/RoomMatcher.java
new file mode 100755
index 00000000..994a19d8
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomfinder/RoomMatcher.java
@@ -0,0 +1,145 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.roomfinder;
+
+import kr.syeyoung.dungeonsguide.mod.chat.ChatTransmitter;
+import kr.syeyoung.dungeonsguide.dungeon.data.DungeonRoomInfo;
+import kr.syeyoung.dungeonsguide.mod.utils.ArrayUtils;
+import kr.syeyoung.dungeonsguide.mod.utils.ShortUtils;
+import lombok.Getter;
+import net.minecraft.block.Block;
+import net.minecraft.init.Blocks;
+import net.minecraft.util.ChatComponentText;
+
+import java.util.List;
+
+public class RoomMatcher {
+ private final DungeonRoom dungeonRoom;
+ @Getter
+ private DungeonRoomInfo match;
+ @Getter
+ private int rotation; // how much the "found room" has to rotate clockwise to match the given dungeon room info. !
+ private boolean triedMatch = false;
+
+
+ public RoomMatcher(DungeonRoom dungeonRoom) {
+ this.dungeonRoom = dungeonRoom;
+ }
+
+ public DungeonRoomInfo match() {
+ if (triedMatch) return match;
+
+ int zz = dungeonRoom.getMax().getZ() - dungeonRoom.getMin().getZ() + 1;
+ int xx = dungeonRoom.getMax().getX() - dungeonRoom.getMin().getX() + 1;
+ for (int z = 0; z < zz; z ++) {
+ for (int x = 0; x < xx; x++) {
+ if (x % 8 == 0 && z % 8 == 0 && dungeonRoom.getContext().getWorld().getChunkFromBlockCoords(dungeonRoom.getRelativeBlockPosAt(x, 0, z)).isEmpty()) {
+ ChatTransmitter.sendDebugChat(new ChatComponentText("Chunk Not loaded in Room Matcher"));
+ }
+ }
+ }
+
+ triedMatch = true;
+ int lowestcost = 10;
+ int lowestRot = 0;
+ DungeonRoomInfo bestMatch = null;
+ for (int rotation = 0; rotation < 4; rotation++) {
+ short shape = dungeonRoom.getShape();
+ for (int j = 0; j<rotation; j++)
+ shape = ShortUtils.rotateClockwise(shape);
+ shape = ShortUtils.topLeftifyInt(shape);
+
+ List<DungeonRoomInfo> roomInfoList = DungeonRoomInfoRegistry.getByShape(shape);
+ for (DungeonRoomInfo roomInfo : roomInfoList) {
+ int cost = tryMatching(roomInfo, rotation);
+ if (cost == 0) {
+ match = roomInfo;
+ this.rotation = rotation;
+ return match;
+ }
+ if (cost < lowestcost) {
+ lowestcost = cost;
+ bestMatch = roomInfo;
+ lowestRot = rotation;
+ }
+ }
+ }
+ match = bestMatch;
+ this.rotation = lowestRot;
+ return bestMatch;
+ }
+
+ private int tryMatching(DungeonRoomInfo dungeonRoomInfo, int rotation) {
+ if (dungeonRoomInfo.getColor() != dungeonRoom.getColor()) return Integer.MAX_VALUE;
+
+ int[][] res = dungeonRoomInfo.getBlocks();
+ for (int i = 0; i < rotation; i++)
+ res = ArrayUtils.rotateCounterClockwise(res);
+
+ int wrongs = 0;
+ for (int z = 0; z < res.length; z ++) {
+ for (int x = 0; x < res[0].length; x++) {
+ int data = res[z][x];
+ if (data == -1) continue;
+ Block b = dungeonRoom.getRelativeBlockAt(x,0,z);
+
+ if (b == null || Block.getIdFromBlock(b) != data) {
+ wrongs++;
+
+ if (wrongs > 10) return wrongs;
+ }
+ }
+ }
+ return wrongs;
+ }
+
+ private static final int offset = 3;
+ public DungeonRoomInfo createNew() {
+ DungeonRoomInfo roomInfo = new DungeonRoomInfo(dungeonRoom.getShape(), dungeonRoom.getColor());
+
+ int maxX = dungeonRoom.getMax().getX();
+ int maxZ = dungeonRoom.getMax().getZ();
+ int minX = dungeonRoom.getMin().getX();
+ int minZ = dungeonRoom.getMin().getZ();
+ int[][] data = new int[dungeonRoom.getMax().getZ() - dungeonRoom.getMin().getZ() +2][dungeonRoom.getMax().getX() - dungeonRoom.getMin().getX() + 2];
+
+ for (int z = 0; z < data.length; z++) {
+ for (int x = 0; x < data[0].length; x++) {
+ if (!(dungeonRoom.canAccessRelative(x + offset, z + offset)
+ && dungeonRoom.canAccessRelative(x - offset -1 , z - offset-1)
+ && dungeonRoom.canAccessRelative(x + offset , z - offset-1)
+ && dungeonRoom.canAccessRelative(x - offset -1 , z + offset))) {
+ data[z][x] = -1;
+ continue;
+ }
+
+ Block b = dungeonRoom.getRelativeBlockAt(x,0,z);
+ if (b == null || b == Blocks.chest || b == Blocks.trapped_chest) {
+ data[z][x] = -1;
+ } else {
+ data[z][x] = Block.getIdFromBlock(b);
+ }
+ }
+ }
+
+ roomInfo.setBlocks(data);
+ roomInfo.setUserMade(true);
+ return roomInfo;
+ }
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/GeneralRoomProcessor.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/GeneralRoomProcessor.java
new file mode 100755
index 00000000..22cdb20c
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/GeneralRoomProcessor.java
@@ -0,0 +1,448 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor;
+
+import kr.syeyoung.dungeonsguide.mod.DungeonsGuide;
+import kr.syeyoung.dungeonsguide.mod.chat.ChatTransmitter;
+import kr.syeyoung.dungeonsguide.mod.dungeon.DungeonContext;
+import kr.syeyoung.dungeonsguide.mod.dungeon.DungeonActionContext;
+import kr.syeyoung.dungeonsguide.mod.dungeon.actions.ActionComplete;
+import kr.syeyoung.dungeonsguide.mod.dungeon.actions.ActionMove;
+import kr.syeyoung.dungeonsguide.mod.dungeon.actions.ActionMoveNearestAir;
+import kr.syeyoung.dungeonsguide.mod.dungeon.actions.tree.ActionRoute;
+import kr.syeyoung.dungeonsguide.mod.dungeon.actions.tree.ActionRouteProperties;
+import kr.syeyoung.dungeonsguide.dungeon.data.OffsetPoint;
+import kr.syeyoung.dungeonsguide.dungeon.mechanics.dunegonmechanic.DungeonMechanic;
+import kr.syeyoung.dungeonsguide.dungeon.mechanics.DungeonRoomDoor;
+import kr.syeyoung.dungeonsguide.dungeon.mechanics.DungeonSecret;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomfinder.DungeonRoom;
+import kr.syeyoung.dungeonsguide.mod.events.impl.BlockUpdateEvent;
+import kr.syeyoung.dungeonsguide.mod.events.impl.KeyBindPressedEvent;
+import kr.syeyoung.dungeonsguide.mod.events.impl.PlayerInteractEntityEvent;
+import kr.syeyoung.dungeonsguide.mod.features.FeatureRegistry;
+import kr.syeyoung.dungeonsguide.mod.dungeon.pathfinding.NodeProcessorDungeonRoom;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomedit.EditingContext;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomedit.gui.GuiDungeonAddSet;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomedit.gui.GuiDungeonRoomEdit;
+import kr.syeyoung.dungeonsguide.mod.utils.VectorUtils;
+import lombok.Getter;
+import lombok.Setter;
+import net.minecraft.block.state.IBlockState;
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.gui.FontRenderer;
+import net.minecraft.client.gui.GuiScreen;
+import net.minecraft.client.gui.ScaledResolution;
+import net.minecraft.client.renderer.GlStateManager;
+import net.minecraft.entity.Entity;
+import net.minecraft.entity.item.EntityArmorStand;
+import net.minecraft.entity.passive.EntityBat;
+import net.minecraft.init.Blocks;
+import net.minecraft.init.Items;
+import net.minecraft.util.*;
+import net.minecraftforge.client.event.GuiScreenEvent;
+import net.minecraftforge.event.entity.living.LivingDeathEvent;
+import net.minecraftforge.event.entity.living.LivingEvent;
+import net.minecraftforge.event.entity.player.PlayerInteractEvent;
+import org.lwjgl.opengl.GL11;
+import org.lwjgl.opengl.GL14;
+
+import java.awt.*;
+import java.util.*;
+
+public class GeneralRoomProcessor implements RoomProcessor {
+
+ @Getter
+ @Setter
+ private DungeonRoom dungeonRoom;
+ public GeneralRoomProcessor(DungeonRoom dungeonRoom) {
+ this.dungeonRoom = dungeonRoom;
+ }
+ private boolean ticked = false;
+
+
+ @Override
+ public void tick() {
+ if (!ticked && FeatureRegistry.SECRET_AUTO_START.isEnabled()) {
+ searchForNextTarget();
+ }else if (!ticked && FeatureRegistry.SECRET_PATHFIND_ALL.isEnabled()) {
+ for (Map.Entry<String, DungeonMechanic> value : getDungeonRoom().getDungeonRoomInfo().getMechanics().entrySet()) {
+ if (value.getValue() instanceof DungeonSecret && ((DungeonSecret) value.getValue()).getSecretStatus(dungeonRoom) != DungeonSecret.SecretStatus.FOUND) {
+ DungeonSecret dungeonSecret = (DungeonSecret) value.getValue();
+ if (FeatureRegistry.SECRET_PATHFIND_ALL.isBat() && dungeonSecret.getSecretType() == DungeonSecret.SecretType.BAT)
+ pathfind(value.getKey(), "found", FeatureRegistry.SECRET_LINE_PROPERTIES_PATHFINDALL_BAT.getRouteProperties());
+ if (FeatureRegistry.SECRET_PATHFIND_ALL.isChest() && dungeonSecret.getSecretType() == DungeonSecret.SecretType.CHEST)
+ pathfind(value.getKey(), "found", FeatureRegistry.SECRET_LINE_PROPERTIES_PATHFINDALL_CHEST.getRouteProperties());
+ if (FeatureRegistry.SECRET_PATHFIND_ALL.isEssence() && dungeonSecret.getSecretType() == DungeonSecret.SecretType.ESSENCE)
+ pathfind(value.getKey(), "found", FeatureRegistry.SECRET_LINE_PROPERTIES_PATHFINDALL_ESSENCE.getRouteProperties());
+ if (FeatureRegistry.SECRET_PATHFIND_ALL.isItemdrop() && dungeonSecret.getSecretType() == DungeonSecret.SecretType.ITEM_DROP)
+ pathfind(value.getKey(), "found", FeatureRegistry.SECRET_LINE_PROPERTIES_PATHFINDALL_ITEM_DROP.getRouteProperties());
+ }
+ }
+ } else if (!ticked && FeatureRegistry.SECRET_BLOOD_RUSH.isEnabled()) {
+ for (Map.Entry<String, DungeonMechanic> value : getDungeonRoom().getMechanics().entrySet()) {
+ if (value.getValue() instanceof DungeonRoomDoor) {
+ DungeonRoomDoor dungeonDoor = (DungeonRoomDoor) value.getValue();
+ if (dungeonDoor.getDoorfinder().getType().isHeadToBlood()) {
+ pathfind(value.getKey(), "navigate", FeatureRegistry.SECRET_BLOOD_RUSH_LINE_PROPERTIES.getRouteProperties());
+ }
+ }
+ }
+ }
+ ticked = true;
+
+ Set<String> toRemove = new HashSet<>();
+ path.entrySet().forEach(a -> {
+ a.getValue().onTick();
+ if (a.getValue().getCurrentAction() instanceof ActionComplete)
+ toRemove.add(a.getKey());
+ });
+ toRemove.forEach(path::remove);
+
+
+ for (DungeonMechanic value : dungeonRoom.getMechanics().values()) {
+ if (value instanceof DungeonSecret) ((DungeonSecret) value).tick(dungeonRoom);
+ }
+
+ if (toRemove.contains("AUTO-BROWSE") && FeatureRegistry.SECRET_AUTO_BROWSE_NEXT.isEnabled()) {
+ searchForNextTarget();
+ }
+ }
+ private final Set<String> visited = new HashSet<String>();
+
+ public void searchForNextTarget() {
+ if (getDungeonRoom().getCurrentState() == DungeonRoom.RoomState.FINISHED) {
+ cancelAll();
+ return;
+ }
+
+ BlockPos pos = Minecraft.getMinecraft().thePlayer.getPosition();
+
+ double lowestCost = 99999999999999.0;
+ Map.Entry<String, DungeonMechanic> lowestWeightMechanic = null;
+ for (Map.Entry<String, DungeonMechanic> mech: dungeonRoom.getMechanics().entrySet()) {
+ if (!(mech.getValue() instanceof DungeonSecret)) continue;
+ if (visited.contains(mech.getKey())) continue;
+ if (((DungeonSecret) mech.getValue()).getSecretStatus(getDungeonRoom()) != DungeonSecret.SecretStatus.FOUND) {
+ double cost = 0;
+ if (((DungeonSecret) mech.getValue()).getSecretType() == DungeonSecret.SecretType.BAT &&
+ ((DungeonSecret) mech.getValue()).getPreRequisite().size() == 0) {
+ cost += -100000000;
+ }
+ if (mech.getValue().getRepresentingPoint(getDungeonRoom()) == null) continue;
+ BlockPos blockpos = mech.getValue().getRepresentingPoint(getDungeonRoom()).getBlockPos(getDungeonRoom());
+
+ cost += blockpos.distanceSq(pos);
+ cost += ((DungeonSecret) mech.getValue()).getPreRequisite().size() * 100;
+
+ if (cost < lowestCost) {
+ lowestCost = cost;
+ lowestWeightMechanic = mech;
+ }
+ }
+ }
+ if (lowestWeightMechanic != null) {
+ visited.add(lowestWeightMechanic.getKey());
+ pathfind("AUTO-BROWSE", lowestWeightMechanic.getKey(), "found", FeatureRegistry.SECRET_LINE_PROPERTIES_AUTOPATHFIND.getRouteProperties());
+ } else {
+ visited.clear();
+ }
+ }
+
+ @Override
+ public void drawScreen(float partialTicks) {
+ path.values().forEach(a -> {
+ a.onRenderScreen(partialTicks);
+ });
+
+ if (FeatureRegistry.ADVANCED_ROOMEDIT.isEnabled() && FeatureRegistry.DEBUG.isEnabled()) {
+ FontRenderer fr = Minecraft.getMinecraft().fontRendererObj;
+
+ if (Minecraft.getMinecraft().objectMouseOver == null) return;
+ Entity en = Minecraft.getMinecraft().objectMouseOver.entityHit;
+ if (en == null) return;
+
+ ScaledResolution sr = new ScaledResolution(Minecraft.getMinecraft());
+ if (DungeonActionContext.getSpawnLocation().containsKey(en.getEntityId())) {
+ GlStateManager.enableBlend();
+ GL14.glBlendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA);
+ GlStateManager.tryBlendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA);
+ fr.drawString("Spawned at " + DungeonActionContext.getSpawnLocation().get(en.getEntityId()), sr.getScaledWidth() / 2, sr.getScaledHeight() / 2, 0xFFFFFFFF);
+ }
+ }
+ }
+
+ @Override
+ public void drawWorld(float partialTicks) {
+ if (FeatureRegistry.DEBUG.isEnabled() && (EditingContext.getEditingContext() != null && EditingContext.getEditingContext().getCurrent() instanceof GuiDungeonRoomEdit)) {
+ for (Map.Entry<String, DungeonMechanic> value : dungeonRoom.getMechanics().entrySet()) {
+ if (value.getValue() == null) continue;
+ value.getValue().highlight(new Color(0,255,255,50), value.getKey(), dungeonRoom, partialTicks);
+ }
+ }
+
+
+ ActionRoute finalSmallest = getBestFit(partialTicks);
+ path.values().forEach(a -> {
+ a.onRenderWorld(partialTicks, finalSmallest == a);
+ });
+ }
+
+ private ActionRoute getBestFit(float partialTicks) {
+
+ ActionRoute smallest = null;
+ double smallestTan = 0.002;
+ for (ActionRoute value : path.values()) {
+ BlockPos target;
+ if (value.getCurrentAction() instanceof ActionMove) {
+ target = ((ActionMove) value.getCurrentAction()).getTarget().getBlockPos(dungeonRoom);
+ } else if (value.getCurrentAction() instanceof ActionMoveNearestAir) {
+ target = ((ActionMoveNearestAir) value.getCurrentAction()).getTarget().getBlockPos(dungeonRoom);
+ } else if (value.getCurrent() >= 1 && value.getActions().get(value.getCurrent()-1) instanceof ActionMove) {
+ target = ((ActionMove)value.getActions().get(value.getCurrent()-1)).getTarget().getBlockPos(dungeonRoom);
+ } else if (value.getCurrent() >= 1 && value.getActions().get(value.getCurrent()-1) instanceof ActionMoveNearestAir) {
+ target = ((ActionMoveNearestAir)value.getActions().get(value.getCurrent()-1)).getTarget().getBlockPos(dungeonRoom);
+ } else continue;
+
+ if (value.getActionRouteProperties().getLineRefreshRate() != -1 && value.getActionRouteProperties().isPathfind() && !FeatureRegistry.SECRET_FREEZE_LINES.isEnabled()) continue;
+
+ Entity e = Minecraft.getMinecraft().getRenderViewEntity();
+
+ double vectorV = VectorUtils.distSquared(e.getLook(partialTicks), e.getPositionEyes(partialTicks), new Vec3(target).addVector(0.5,0.5,0.5));
+
+ if (vectorV < smallestTan) {
+ smallest = value;
+ smallestTan = vectorV;
+ }
+ }
+ return smallest;
+ }
+
+ @Override
+ public void chatReceived(IChatComponent chat) {
+ if (lastChest != null && chat.getFormattedText().equals("§r§cThis chest has already been searched!§r")) {
+ getDungeonRoom().getRoomContext().put("c-"+lastChest.toString(), 2);
+ lastChest = null;
+ }
+ }
+
+ private int stack = 0;
+ private long secrets2 = 0;
+ @Override
+ public void actionbarReceived(IChatComponent chat) {
+ if (!DungeonsGuide.getDungeonsGuide().getSkyblockStatus().isOnDungeon()) return;
+ if (dungeonRoom.getTotalSecrets() == -1) {
+ ChatTransmitter.sendDebugChat(new ChatComponentText(chat.getFormattedText().replace('§', '&') + " - received"));
+ }
+ if (!chat.getFormattedText().contains("/")) return;
+ BlockPos pos = Minecraft.getMinecraft().thePlayer.getPosition();
+
+ DungeonContext context = DungeonsGuide.getDungeonsGuide().getDungeonFacade().getContext();
+ Point pt1 = context.getMapProcessor().worldPointToRoomPoint(pos.add(2, 0, 2));
+ Point pt2 = context.getMapProcessor().worldPointToRoomPoint(pos.add(-2, 0, -2));
+ if (!pt1.equals(pt2)) {
+ stack = 0;
+ secrets2 = -1;
+ return;
+ }
+ BlockPos pos2 = dungeonRoom.getMin().add(5, 0, 5);
+
+ String text = chat.getFormattedText();
+ int secretsIndex = text.indexOf("Secrets");
+ int secrets = 0;
+ if (secretsIndex != -1) {
+ int theindex = 0;
+ for (int i = secretsIndex; i >= 0; i--) {
+ if (text.startsWith("§7", i)) {
+ theindex = i;
+ }
+ }
+ String it = text.substring(theindex + 2, secretsIndex - 1);
+
+ secrets = Integer.parseInt(it.split("/")[1]);
+ }
+
+ if (secrets2 == secrets) stack++;
+ else {
+ stack = 0;
+ secrets2 = secrets;
+ }
+
+ if (stack == 4 && dungeonRoom.getTotalSecrets() != secrets) {
+ dungeonRoom.setTotalSecrets(secrets);
+ if (FeatureRegistry.DUNGEON_INTERMODCOMM.isEnabled())
+ Minecraft.getMinecraft().thePlayer.sendChatMessage("/pchat $DG-Comm " + pos2.getX() + "/" + pos2.getZ() + " " + secrets);
+ }
+ }
+
+ @Override
+ public boolean readGlobalChat() {
+ return false;
+ }
+
+ @Getter
+ private Map<String, ActionRoute> path = new HashMap<>();
+
+ public ActionRoute getPath(String id){
+ return path.get(id);
+ }
+
+ public String pathfind(String mechanic, String state, ActionRouteProperties actionRouteProperties) {
+ String str = UUID.randomUUID().toString();
+ pathfind(str, mechanic, state, actionRouteProperties);
+ return str;
+ }
+ public void pathfind(String id, String mechanic, String state, ActionRouteProperties actionRouteProperties) {
+ path.put(id, new ActionRoute(getDungeonRoom(), mechanic, state, actionRouteProperties));
+ }
+ public void cancelAll() {
+ path.clear();
+ }
+ public void cancel(String id) {
+ path.remove(id);
+ }
+
+ @Override
+ public void onPostGuiRender(GuiScreenEvent.DrawScreenEvent.Post event) {
+
+ }
+
+ @Override
+ public void onEntityUpdate(LivingEvent.LivingUpdateEvent updateEvent) {
+ if (updateEvent.entityLiving instanceof EntityArmorStand &&
+ updateEvent.entityLiving.getName() != null &&
+ updateEvent.entityLiving.getName().contains("Mimic") &&
+ !dungeonRoom.getContext().isGotMimic()) {
+ dungeonRoom.getContext().setGotMimic(true);
+// Minecraft.getMinecraft().thePlayer.sendChatMessage("/pc $DG-Mimic");
+ }
+ }
+
+ @Override
+ public void onKeybindPress(KeyBindPressedEvent keyInputEvent) {
+ if (FeatureRegistry.SECRET_NEXT_KEY.isEnabled() && FeatureRegistry.SECRET_NEXT_KEY.<Integer>getParameter("key").getValue() == keyInputEvent.getKey()) {
+ searchForNextTarget();
+ } else if (FeatureRegistry.SECRET_CREATE_REFRESH_LINE.getKeybind() == keyInputEvent.getKey() && FeatureRegistry.SECRET_CREATE_REFRESH_LINE.isEnabled()) {
+ ActionRoute actionRoute = getBestFit(0);
+ // actually do force refresh because of force freeze pathfind
+ if (actionRoute.getCurrentAction() instanceof ActionMove) {
+ ActionMove ac = (ActionMove) actionRoute.getCurrentAction();
+ ac.forceRefresh(getDungeonRoom());
+ } else if (actionRoute.getCurrentAction() instanceof ActionMoveNearestAir) {
+ ActionMoveNearestAir ac = (ActionMoveNearestAir) actionRoute.getCurrentAction();
+ ac.forceRefresh(getDungeonRoom());
+ } else if (actionRoute.getCurrent() >= 1 && actionRoute.getActions().get(actionRoute.getCurrent()-1) instanceof ActionMove) {
+ ((ActionMove)actionRoute.getActions().get(actionRoute.getCurrent()-1)).forceRefresh(dungeonRoom);
+ } else if (actionRoute.getCurrent() >= 1 && actionRoute.getActions().get(actionRoute.getCurrent()-1) instanceof ActionMoveNearestAir) {
+ ((ActionMoveNearestAir)actionRoute.getActions().get(actionRoute.getCurrent()-1)).forceRefresh(dungeonRoom);
+ }
+
+ if (FeatureRegistry.SECRET_CREATE_REFRESH_LINE.isPathfind() && !actionRoute.getActionRouteProperties().isPathfind()) {
+ actionRoute.getActionRouteProperties().setPathfind(true);
+ actionRoute.getActionRouteProperties().setLineRefreshRate(FeatureRegistry.SECRET_CREATE_REFRESH_LINE.getRefreshRate());
+ }
+ }
+ }
+
+ @Override
+ public void onInteract(PlayerInteractEntityEvent event) {
+ path.values().forEach(a -> {
+ a.onLivingInteract(event);
+ });
+ }
+
+ private boolean last = false;
+ private BlockPos lastChest;
+ @Override
+ public void onInteractBlock(PlayerInteractEvent event) {
+ path.values().forEach(a -> {
+ a.onPlayerInteract(event);
+ });
+
+ if (event.pos != null) {
+ IBlockState iBlockState = event.world.getBlockState(event.pos);
+ if (iBlockState.getBlock() == Blocks.chest || iBlockState.getBlock() == Blocks.trapped_chest)
+ lastChest = event.pos;
+ }
+
+ if (event.entityPlayer.getHeldItem() != null &&
+ event.entityPlayer.getHeldItem().getItem() == Items.stick &&
+ FeatureRegistry.ADVANCED_ROOMEDIT.isEnabled() &&
+ FeatureRegistry.DEBUG.isEnabled()) {
+ EditingContext ec = EditingContext.getEditingContext();
+ if (ec == null) return;
+ if (!(ec.getCurrent() instanceof GuiDungeonAddSet)) return;
+ GuiDungeonAddSet gdas = (GuiDungeonAddSet) ec.getCurrent();
+ if (event.action == PlayerInteractEvent.Action.RIGHT_CLICK_BLOCK) {
+ if (last)
+ gdas.getEnd().setPosInWorld(getDungeonRoom(), event.pos);
+ else
+ gdas.getStart().setPosInWorld(getDungeonRoom(), event.pos);
+
+ last = !last;
+ }
+ }
+ }
+
+ @Override
+ public void onEntityDeath(LivingDeathEvent deathEvent) {
+ path.values().forEach(a -> {
+ a.onLivingDeath(deathEvent);
+ });
+ if (EditingContext.getEditingContext() != null && EditingContext.getEditingContext().getRoom() == getDungeonRoom()) {
+ if (deathEvent.entity instanceof EntityBat) {
+ for (GuiScreen screen : EditingContext.getEditingContext().getGuiStack()) {
+ if (screen instanceof GuiDungeonRoomEdit) {
+ DungeonSecret secret = new DungeonSecret();
+ secret.setSecretType(DungeonSecret.SecretType.BAT);
+ secret.setSecretPoint(new OffsetPoint(dungeonRoom,
+ DungeonActionContext.getSpawnLocation().get(deathEvent.entity.getEntityId())
+ ));
+ ((GuiDungeonRoomEdit) screen).getSep().createNewMechanic("BAT-"+ UUID.randomUUID(),
+ secret);
+ return;
+ }
+ }
+ if (EditingContext.getEditingContext().getCurrent() instanceof GuiDungeonRoomEdit) {
+ DungeonSecret secret = new DungeonSecret();
+ secret.setSecretType(DungeonSecret.SecretType.BAT);
+ secret.setSecretPoint(new OffsetPoint(dungeonRoom,
+ DungeonActionContext.getSpawnLocation().get(deathEvent.entity.getEntityId())
+ ));
+ ((GuiDungeonRoomEdit) EditingContext.getEditingContext().getCurrent()).getSep().createNewMechanic("BAT-"+ UUID.randomUUID(),
+ secret);
+ }
+ }
+ }
+ }
+ @Override
+ public void onBlockUpdate(BlockUpdateEvent blockUpdateEvent) {
+ for (Tuple<BlockPos, IBlockState> updatedBlock : blockUpdateEvent.getUpdatedBlocks()) {
+ if (updatedBlock.getSecond().equals(NodeProcessorDungeonRoom.preBuilt)) continue;
+ dungeonRoom.resetBlock(updatedBlock.getFirst());
+ }
+ }
+
+ public static class Generator implements RoomProcessorGenerator<GeneralRoomProcessor> {
+ @Override
+ public GeneralRoomProcessor createNew(DungeonRoom dungeonRoom) {
+ GeneralRoomProcessor defaultRoomProcessor = new GeneralRoomProcessor(dungeonRoom);
+ return defaultRoomProcessor;
+ }
+ }
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/ProcessorFactory.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/ProcessorFactory.java
new file mode 100755
index 00000000..1c61a45d
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/ProcessorFactory.java
@@ -0,0 +1,65 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor;
+
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.bombdefuse.RoomProcessorBombDefuseSolver;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.boxpuzzle.RoomProcessorBoxSolver;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.icefill.RoomProcessorIcePath2;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.waterpuzzle.RoomProcessorWaterPuzzle;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+public class ProcessorFactory {
+ private static final Map<String, RoomProcessorGenerator> map = new HashMap<>();
+
+ public static RoomProcessorGenerator getRoomProcessorGenerator(String processorId) {
+ return map.get(processorId);
+ }
+
+ public static void registerRoomProcessor(String processorId, RoomProcessorGenerator generator) {
+ map.put(processorId, generator);
+ }
+
+ public static Set<String> getProcessors() {
+ return map.keySet();
+ }
+
+ static {
+ registerRoomProcessor("default", new GeneralRoomProcessor.Generator());
+ registerRoomProcessor("button_5", new RoomProcessorButtonSolver.Generator());
+ registerRoomProcessor("puzzle_water_solver", new RoomProcessorWaterPuzzle.Generator());
+ registerRoomProcessor("puzzle_teleport_solver", new RoomProcessorTeleportMazeSolver.Generator());
+ registerRoomProcessor("puzzle_riddle_solver", new RoomProcessorRiddle.Generator());
+ registerRoomProcessor("puzzle_creeper_solver", new RoomProcessorCreeperSolver.Generator());
+ registerRoomProcessor("puzzle_tictactoe_solver", new RoomProcessorTicTacToeSolver.Generator());
+
+ registerRoomProcessor("puzzle_blaze_solver", new RoomProcessorBlazeSolver.Generator());
+
+
+ registerRoomProcessor("puzzle_silverfish", new RoomProcessorIcePath.Generator()); // done
+ registerRoomProcessor("puzzle_icefill", new RoomProcessorIcePath2.Generator());
+ registerRoomProcessor("puzzle_box", new RoomProcessorBoxSolver.Generator());
+ registerRoomProcessor("puzzle_trivia", new RoomProcessorTrivia.Generator());
+ registerRoomProcessor("puzzle_bombdefuse", new RoomProcessorBombDefuseSolver.Generator());
+
+ registerRoomProcessor("bossroom", new RoomProcessorRedRoom.Generator());
+ }
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/RoomProcessor.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/RoomProcessor.java
new file mode 100755
index 00000000..96b9fb72
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/RoomProcessor.java
@@ -0,0 +1,49 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor;
+
+import kr.syeyoung.dungeonsguide.mod.events.impl.BlockUpdateEvent;
+import kr.syeyoung.dungeonsguide.mod.events.impl.KeyBindPressedEvent;
+import kr.syeyoung.dungeonsguide.mod.events.impl.PlayerInteractEntityEvent;
+import net.minecraft.util.IChatComponent;
+import net.minecraftforge.client.event.GuiScreenEvent;
+import net.minecraftforge.event.entity.living.LivingDeathEvent;
+import net.minecraftforge.event.entity.living.LivingEvent;
+import net.minecraftforge.event.entity.player.PlayerInteractEvent;
+
+public interface RoomProcessor {
+ void tick();
+ void drawScreen(float partialTicks);
+ void drawWorld(float partialTicks);
+ void chatReceived(IChatComponent chat);
+ void actionbarReceived(IChatComponent chat);
+
+ boolean readGlobalChat();
+
+ void onPostGuiRender(GuiScreenEvent.DrawScreenEvent.Post event);
+ void onEntityUpdate(LivingEvent.LivingUpdateEvent updateEvent);
+ void onEntityDeath(LivingDeathEvent deathEvent);
+
+ void onKeybindPress(KeyBindPressedEvent keyInputEvent);
+
+ void onInteract(PlayerInteractEntityEvent event);
+ void onInteractBlock(PlayerInteractEvent event);
+
+ void onBlockUpdate(BlockUpdateEvent blockUpdateEvent);
+} \ No newline at end of file
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/RoomProcessorBlazeSolver.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/RoomProcessorBlazeSolver.java
new file mode 100755
index 00000000..f36fd71b
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/RoomProcessorBlazeSolver.java
@@ -0,0 +1,201 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor;
+
+import kr.syeyoung.dungeonsguide.mod.config.types.AColor;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomfinder.DungeonRoom;
+import kr.syeyoung.dungeonsguide.mod.features.FeatureRegistry;
+import kr.syeyoung.dungeonsguide.mod.utils.RenderUtils;
+import kr.syeyoung.dungeonsguide.mod.utils.TextUtils;
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.renderer.GlStateManager;
+import net.minecraft.entity.Entity;
+import net.minecraft.entity.item.EntityArmorStand;
+import net.minecraft.entity.monster.EntityBlaze;
+import net.minecraft.util.*;
+import net.minecraft.world.World;
+import org.lwjgl.opengl.GL11;
+
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.List;
+
+public class RoomProcessorBlazeSolver extends GeneralRoomProcessor {
+
+ private boolean highToLow = false;
+
+ private List<EntityArmorStand> entityList = new ArrayList<EntityArmorStand>();
+ private List<EntityBlaze> blazeList = new ArrayList<>();
+ private EntityArmorStand next;
+ private EntityBlaze nextBlaze, theoneafterit;
+ public RoomProcessorBlazeSolver(DungeonRoom dungeonRoom) {
+ super(dungeonRoom);
+ Object highToLow = dungeonRoom.getDungeonRoomInfo().getProperties().get("order");
+ if (highToLow == null) this.highToLow = false;
+ else this.highToLow = (Boolean) highToLow;
+ }
+
+ @Override
+ public void tick() {
+ super.tick();
+
+ DungeonRoom dungeonRoom = getDungeonRoom();
+ World w = dungeonRoom.getContext().getWorld();
+ final BlockPos low = dungeonRoom.getMin();
+ final BlockPos high = dungeonRoom.getMax();
+ entityList = new ArrayList<EntityArmorStand>(w.getEntities(EntityArmorStand.class, input -> {
+ BlockPos pos = input.getPosition();
+ return low.getX() < pos.getX() && pos.getX() < high.getX()
+ && low.getZ() < pos.getZ() && pos.getZ() < high.getZ() && input.getName().toLowerCase().contains("blaze");
+ }));
+ blazeList = new ArrayList<EntityBlaze>(w.getEntities(EntityBlaze.class, input -> {
+ BlockPos pos = input.getPosition();
+ return low.getX() < pos.getX() && pos.getX() < high.getX()
+ && low.getZ() < pos.getZ() && pos.getZ() < high.getZ();
+ }));
+
+ Comparator<EntityArmorStand> comparator = Comparator.comparingInt(a -> {
+ String name = a.getName();
+ String colorGone = TextUtils.stripColor(name);
+ String health2 = TextUtils.keepIntegerCharactersOnly(colorGone.split("/")[1]);
+ try {
+ return Integer.parseInt(health2);
+ } catch (Exception e) {return -1;}
+ });
+ if (highToLow) {
+ entityList.sort(comparator.reversed());
+ } else {
+ entityList.sort(comparator);
+ }
+
+ if (entityList.size() > 0) {
+ next = entityList.get(0);
+ nextBlaze = blazeList.stream().min(Comparator.comparingDouble(e -> e.getDistanceSqToEntity(next))).orElse(null);
+ } else {
+ next = null;
+ nextBlaze = null;
+ }
+ if (entityList.size() > 1) {
+ EntityArmorStand thenextone = entityList.get(1);
+ theoneafterit = blazeList.stream().min(Comparator.comparingDouble(e -> e.getDistanceSqToEntity(thenextone))).orElse(null);
+ } else {
+ theoneafterit = null;
+ }
+ }
+
+
+ @Override
+ public void drawWorld(float partialTicks) {
+ super.drawWorld(partialTicks);
+ if (!FeatureRegistry.SOLVER_BLAZE.isEnabled()) return;
+ if (next == null) return;
+ Vec3 pos = next.getPositionEyes(partialTicks);
+ RenderUtils.drawTextAtWorld("NEXT", (float)pos.xCoord, (float)pos.yCoord, (float)pos.zCoord, 0xFFFF0000, 0.5f, true, false, partialTicks);
+
+ Entity viewing_from = Minecraft.getMinecraft().getRenderViewEntity();
+
+ double x_fix = viewing_from.lastTickPosX + ((viewing_from.posX - viewing_from.lastTickPosX) * partialTicks);
+ double y_fix = viewing_from.lastTickPosY + ((viewing_from.posY - viewing_from.lastTickPosY) * partialTicks);
+ double z_fix = viewing_from.lastTickPosZ + ((viewing_from.posZ - viewing_from.lastTickPosZ) * partialTicks);
+
+
+ for (EntityBlaze entity : blazeList) {
+ GlStateManager.pushMatrix();
+ float f = entity.prevRotationYaw + (entity.rotationYaw - entity.prevRotationYaw) * partialTicks;
+ double x = entity.prevPosX + (entity.posX - entity.prevPosX) * partialTicks;
+ double y = entity.prevPosY + (entity.posY - entity.prevPosY) * partialTicks;
+ double z = entity.prevPosZ + (entity.posZ - entity.prevPosZ) * partialTicks;
+
+
+ GL11.glEnable(GL11.GL_STENCIL_TEST);
+ GL11.glClearStencil(0);
+ GlStateManager.disableDepth();
+ GL11.glClear(GL11.GL_STENCIL_BUFFER_BIT);
+
+ GL11.glStencilMask(0xFF);
+ GL11.glStencilFunc(GL11.GL_ALWAYS, 1, 0xFF);
+ GL11.glStencilOp(GL11.GL_KEEP, GL11.GL_REPLACE, GL11.GL_REPLACE);
+
+ GlStateManager.pushMatrix();
+
+ GlStateManager.translate(-x_fix, -y_fix, -z_fix);
+
+ GlStateManager.colorMask(false, false, false, false);
+ Minecraft.getMinecraft().getRenderManager().doRenderEntity(entity, x,y,z,f,partialTicks, true);
+ GlStateManager.colorMask(true, true, true, true);
+
+ GlStateManager.popMatrix();
+
+
+ GL11.glStencilFunc(GL11.GL_EQUAL, 1, 0xFF);
+ GL11.glStencilOp(GL11.GL_KEEP, GL11.GL_KEEP, GL11.GL_KEEP);
+
+// Gui.drawRect(-9999,-9999, 9999, 9999, 0xFFFFFFFF);
+
+ boolean border = true;
+
+ RenderUtils.highlightBox(entity, AxisAlignedBB.fromBounds(-0.8,0, -0.8, 0.8, 2, 0.8), FeatureRegistry.SOLVER_BLAZE.getBlazeColor(), partialTicks, false);
+ if (entity == theoneafterit) {
+ RenderUtils.highlightBox(entity, AxisAlignedBB.fromBounds(-0.8,0, -0.8, 0.8, 2, 0.8), FeatureRegistry.SOLVER_BLAZE.getNextUpBlazeColor(), partialTicks, false);
+ } else if (entity == nextBlaze)
+ RenderUtils.highlightBox(entity, AxisAlignedBB.fromBounds(-0.8,0, -0.8, 0.8, 2, 0.8), FeatureRegistry.SOLVER_BLAZE.getNextBlazeColor(), partialTicks, false);
+
+ GlStateManager.color(1,1,1,1);
+
+
+ if (FeatureRegistry.SOLVER_BLAZE.<AColor>getParameter("blazeborder").getValue().getAlpha() > 0x10) {
+ GL11.glStencilFunc(GL11.GL_NOTEQUAL, 3, 0x01);
+ GL11.glStencilOp(GL11.GL_KEEP, GL11.GL_REPLACE, GL11.GL_REPLACE);
+ GlStateManager.pushMatrix();
+
+ GlStateManager.translate(-x_fix, -y_fix, -z_fix);
+ GlStateManager.translate(x, y + 0.7, z);
+ GlStateManager.scale(1.1f, 1.1f, 1.1f);
+
+ GlStateManager.colorMask(false, false, false, false);
+ Minecraft.getMinecraft().getRenderManager().doRenderEntity(entity, 0, -0.7, 0, f, partialTicks, true);
+ GlStateManager.colorMask(true, true, true, true);
+
+ GlStateManager.popMatrix();
+
+
+
+ GL11.glStencilFunc(GL11.GL_EQUAL, 3, 0xFF);
+ GL11.glStencilOp(GL11.GL_KEEP, GL11.GL_KEEP, GL11.GL_KEEP);
+
+ RenderUtils.highlightBox(entity, AxisAlignedBB.fromBounds(-1, 0, -1, 1, 2, 1), FeatureRegistry.SOLVER_BLAZE.<AColor>getParameter("blazeborder").getValue(), partialTicks, false);
+
+
+ }
+ GL11.glDisable(GL11.GL_STENCIL_TEST);
+ GlStateManager.enableDepth();
+ GlStateManager.popMatrix();
+ }
+ }
+
+
+
+ public static class Generator implements RoomProcessorGenerator<RoomProcessorBlazeSolver> {
+ @Override
+ public RoomProcessorBlazeSolver createNew(DungeonRoom dungeonRoom) {
+ RoomProcessorBlazeSolver defaultRoomProcessor = new RoomProcessorBlazeSolver(dungeonRoom);
+ return defaultRoomProcessor;
+ }
+ }
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/RoomProcessorButtonSolver.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/RoomProcessorButtonSolver.java
new file mode 100644
index 00000000..709922a0
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/RoomProcessorButtonSolver.java
@@ -0,0 +1,132 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor;
+
+import kr.syeyoung.dungeonsguide.dungeon.data.OffsetPointSet;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomfinder.DungeonRoom;
+import kr.syeyoung.dungeonsguide.mod.utils.RenderUtils;
+import net.minecraft.client.Minecraft;
+import net.minecraft.util.BlockPos;
+import net.minecraft.util.IChatComponent;
+import net.minecraftforge.event.entity.player.PlayerInteractEvent;
+
+import java.awt.*;
+import java.util.Arrays;
+
+public class RoomProcessorButtonSolver extends GeneralRoomProcessor {
+ public RoomProcessorButtonSolver(DungeonRoom dungeonRoom) {
+ super(dungeonRoom);
+
+ OffsetPointSet ops = (OffsetPointSet) dungeonRoom.getDungeonRoomInfo().getProperties().get("buttons");
+ if (ops == null) {
+ bugged = true;
+ return;
+ }
+
+ buttons = new BlockPos[12];
+ woods = new BlockPos[12];
+ for (int i = 0; i < ops.getOffsetPointList().size(); i++) {
+ buttons[i] = ops.getOffsetPointList().get(i).getBlockPos(dungeonRoom);
+ woods[i] = buttons[i].add(0,-1,0);
+ }
+ }
+
+ private boolean bugged;
+
+ private BlockPos[] buttons;
+ private BlockPos[] woods;
+
+ private long clicked;
+ private int clickedButton = -1;
+
+ private final int[] result = new int[12];
+
+ @Override
+ public void onInteractBlock(PlayerInteractEvent event) {
+ super.onInteractBlock(event);
+ if (bugged) return;
+
+ if (event.action != PlayerInteractEvent.Action.RIGHT_CLICK_BLOCK) return;
+ for (int i = 0; i < buttons.length; i++) {
+ if (event.pos.equals(buttons[i])) {
+ clicked = System.currentTimeMillis();
+ clickedButton = i;
+ return;
+ }
+ }
+ }
+
+ @Override
+ public void chatReceived(IChatComponent chat) {
+ super.chatReceived(chat);
+ if (bugged) return;
+
+ if (clickedButton == -1) return;
+ if (clicked + 500 < System.currentTimeMillis()) return;
+
+ String msg = chat.getFormattedText();
+ if (msg.equals("§r§cThis button doesn't seem to do anything...§r")) {
+ result[clickedButton] = -1;
+ clickedButton = -1;
+ } else if (msg.equals("§r§aThis button seems connected to something§r")) {
+ Arrays.fill(result, -1);
+ if (clickedButton % 4 != 0) result[clickedButton - 1] = 1;
+ if (clickedButton % 4 != 3) result[clickedButton + 1] = 1;
+ clickedButton = -1;
+ } else if (msg.equals("§r§aClick! you Hear the sound of a door opening§r")) {
+ Arrays.fill(result, -1);
+ result[clickedButton] = 2;
+ clickedButton = -1;
+ } else if (msg.equals("§r§aWrong button, looks like the system reset!§r")) {
+ Arrays.fill(result, 0);
+ clickedButton = -1;
+ }
+ }
+
+ @Override
+ public void drawWorld(float partialTicks) {
+ super.drawWorld(partialTicks);
+ if (bugged) return;
+ if (Minecraft.getMinecraft().thePlayer.getPosition().distanceSq(woods[6]) > 100) return;
+
+
+ for (int i = 0; i < woods.length; i++) {
+ int data = result[i];
+ BlockPos pos = woods[i];
+
+ if (data == 0) {
+ RenderUtils.highlightBlock(pos, new Color(0, 255, 255, 50), partialTicks, false);
+ } else if (data == -1) {
+ RenderUtils.highlightBlock(pos, new Color(255, 0, 0, 50), partialTicks, false);
+ } else if (data == 1) {
+ RenderUtils.highlightBlock(pos, new Color(0, 255, 0, 50), partialTicks, false);
+ } else if (data == 2) {
+ RenderUtils.highlightBlock(pos, new Color(0, 255, 0, 100), partialTicks, false);
+ }
+ }
+ }
+
+ public static class Generator implements RoomProcessorGenerator<RoomProcessorButtonSolver> {
+ @Override
+ public RoomProcessorButtonSolver createNew(DungeonRoom dungeonRoom) {
+ RoomProcessorButtonSolver defaultRoomProcessor = new RoomProcessorButtonSolver(dungeonRoom);
+ return defaultRoomProcessor;
+ }
+ }
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/RoomProcessorCreeperSolver.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/RoomProcessorCreeperSolver.java
new file mode 100755
index 00000000..b2c236c8
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/RoomProcessorCreeperSolver.java
@@ -0,0 +1,148 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor;
+
+import kr.syeyoung.dungeonsguide.mod.DungeonsGuide;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomfinder.DungeonRoom;
+import kr.syeyoung.dungeonsguide.mod.features.FeatureRegistry;
+import kr.syeyoung.dungeonsguide.mod.utils.RenderUtils;
+import net.minecraft.block.Block;
+import net.minecraft.init.Blocks;
+import net.minecraft.util.AxisAlignedBB;
+import net.minecraft.util.BlockPos;
+import net.minecraft.util.EnumFacing;
+import net.minecraft.util.Vec3;
+import net.minecraft.world.World;
+
+import java.awt.*;
+import java.util.ArrayList;
+import java.util.List;
+
+public class RoomProcessorCreeperSolver extends GeneralRoomProcessor {
+
+ private final List<BlockPos[]> poses = new ArrayList<BlockPos[]>();
+
+ private final boolean bugged = false;
+
+ public RoomProcessorCreeperSolver(DungeonRoom dungeonRoom) {
+ super(dungeonRoom);
+
+ findCreeperAndDoPoses();
+ }
+
+ private boolean check(AxisAlignedBB axis, Vec3 vec) {
+ if (vec == null) return false;
+ return axis.isVecInside(vec);
+ }
+
+ private void findCreeperAndDoPoses() {
+ World w = getDungeonRoom().getContext().getWorld();
+ List<BlockPos> prismarines = new ArrayList<BlockPos>();
+ final BlockPos low = getDungeonRoom().getMin().add(0,-2,0);
+ final BlockPos high = getDungeonRoom().getMax().add(0,20,0);
+ final AxisAlignedBB axis = AxisAlignedBB.fromBounds(
+ low.getX() + 17, low.getY() + 7, low.getZ() + 17,
+ low.getX() + 16, low.getY() + 10.5, low.getZ() + 16
+ );
+
+ for (BlockPos pos : BlockPos.getAllInBox(low, high)) {
+ Block b = DungeonsGuide.getDungeonsGuide().getBlockCache().getBlockState(pos).getBlock();
+ if (b == Blocks.prismarine || b == Blocks.sea_lantern) {
+ for (EnumFacing face:EnumFacing.VALUES) {
+ if (w.getBlockState(pos.offset(face)).getBlock() == Blocks.air) {
+ prismarines.add(pos);
+ break;
+ }
+ }
+ }
+ }
+ double offset = 0.1;
+
+ while (prismarines.size() > 1) {
+ BlockPos first = prismarines.get(0);
+ BlockPos highestMatch = null;
+ int highestDist = 0;
+ label: for (int i = 1; i < prismarines.size(); i++) {
+ BlockPos second = prismarines.get(i);
+
+ if (second.distanceSq(first) < highestDist) continue;
+
+ Vec3 startLoc = new Vec3(first).addVector(0.5,0.5,0.5);
+ Vec3 dest = new Vec3(second).addVector(0.5,0.5,0.5);
+ if (check(axis, startLoc.getIntermediateWithYValue(dest, axis.minY+offset)) ||
+ check(axis, startLoc.getIntermediateWithYValue(dest, axis.maxY-offset)) ||
+ check(axis, startLoc.getIntermediateWithXValue(dest, axis.minX+offset)) ||
+ check(axis, startLoc.getIntermediateWithXValue(dest, axis.maxX-offset)) ||
+ check(axis, startLoc.getIntermediateWithZValue(dest, axis.minZ+offset)) ||
+ check(axis, startLoc.getIntermediateWithZValue(dest, axis.maxZ-offset))) {
+ highestDist = (int) second.distanceSq(first);
+ highestMatch = second;
+ }
+
+ }
+
+
+ if (highestMatch == null) {
+ prismarines.remove(first);
+ } else {
+ prismarines.remove(first);
+ prismarines.remove(highestMatch);
+ poses.add(new BlockPos[] {first, highestMatch});
+ }
+ }
+ }
+
+ @Override
+ public void tick() {
+ super.tick();
+ if (bugged) {
+ findCreeperAndDoPoses();
+ }
+ }
+
+ private static final Color[] colors = new Color[] {Color.red, Color.orange, Color.green, Color.cyan, Color.blue, Color.pink, Color.yellow, Color.darkGray, Color.lightGray};
+ @Override
+ public void drawWorld(float partialTicks) {
+ super.drawWorld(partialTicks);
+ if (!FeatureRegistry.SOLVER_CREEPER.isEnabled()) return;
+ World w = getDungeonRoom().getContext().getWorld();
+ for (int i = 0; i < poses.size(); i++) {
+ BlockPos[] poset = poses.get(i);
+ Color color = colors[i % colors.length];
+ boolean oneIsConnected = w.getChunkFromBlockCoords(poset[0]).getBlock(poset[0]) != Blocks.sea_lantern &&
+ w.getChunkFromBlockCoords(poset[1]).getBlock(poset[1]) != Blocks.sea_lantern;
+ RenderUtils.drawLine(new Vec3(poset[0].getX() +0.5, poset[0].getY() +0.5, poset[0].getZ()+0.5),
+ new Vec3(poset[1].getX() +0.5, poset[1].getY() +0.5, poset[1].getZ()+0.5), oneIsConnected ? new Color(0,0,0,50) : color, partialTicks, true);
+ }
+ final BlockPos low = getDungeonRoom().getMin();
+ final AxisAlignedBB axis = AxisAlignedBB.fromBounds(
+ low.getX() + 17, low.getY() + 5, low.getZ() + 17,
+ low.getX() + 16, low.getY() + 8.5, low.getZ() + 16
+ );
+ RenderUtils.highlightBox(axis, new Color(0x4400FF00, true), partialTicks, false);
+ }
+
+ public static class Generator implements RoomProcessorGenerator<RoomProcessorCreeperSolver> {
+ @Override
+ public RoomProcessorCreeperSolver createNew(DungeonRoom dungeonRoom) {
+ RoomProcessorCreeperSolver defaultRoomProcessor = new RoomProcessorCreeperSolver(dungeonRoom);
+ return defaultRoomProcessor;
+ }
+ }
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/RoomProcessorGenerator.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/RoomProcessorGenerator.java
new file mode 100755
index 00000000..969424d9
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/RoomProcessorGenerator.java
@@ -0,0 +1,25 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor;
+
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomfinder.DungeonRoom;
+
+public interface RoomProcessorGenerator<T extends RoomProcessor> {
+ T createNew(DungeonRoom dungeonRoom);
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/RoomProcessorIcePath.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/RoomProcessorIcePath.java
new file mode 100755
index 00000000..df902858
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/RoomProcessorIcePath.java
@@ -0,0 +1,234 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor;
+
+import com.google.common.base.Predicate;
+import kr.syeyoung.dungeonsguide.dungeon.data.OffsetPoint;
+import kr.syeyoung.dungeonsguide.dungeon.data.OffsetPointSet;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomfinder.DungeonRoom;
+import kr.syeyoung.dungeonsguide.mod.features.FeatureRegistry;
+import kr.syeyoung.dungeonsguide.mod.utils.RenderUtils;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import net.minecraft.entity.Entity;
+import net.minecraft.entity.monster.EntitySilverfish;
+import net.minecraft.init.Blocks;
+import net.minecraft.util.BlockPos;
+import org.jetbrains.annotations.Nullable;
+
+import java.awt.*;
+import java.util.*;
+import java.util.List;
+
+public class RoomProcessorIcePath extends GeneralRoomProcessor {
+
+ private int[][] map;
+ private OffsetPoint[][] map2;
+ private final Set<OffsetPoint> endNode = new HashSet<OffsetPoint>();
+
+ private final List<BlockPos> solution = new ArrayList<BlockPos>();
+
+ private BlockPos lastSilverfishLoc;
+ private int sameTick;
+
+ private Entity silverfish;
+
+ private boolean err;
+
+ public RoomProcessorIcePath(DungeonRoom dungeonRoom) {
+ super(dungeonRoom);
+ findSilverFishanddoStuff();
+ }
+
+ public void findSilverFishanddoStuff() {
+ final BlockPos low = getDungeonRoom().getMin();
+ final BlockPos high = getDungeonRoom().getMax();
+ List<EntitySilverfish> silverfishs = getDungeonRoom().getContext().getWorld().getEntities(EntitySilverfish.class, new Predicate<EntitySilverfish>() {
+ @Override
+ public boolean apply(@Nullable EntitySilverfish input) {
+ if (input.isInvisible()) return false;
+ BlockPos pos = input.getPosition();
+ return low.getX() < pos.getX() && pos.getX() < high.getX()
+ && low.getZ() < pos.getZ() && pos.getZ() < high.getZ();
+ }
+ });
+
+ if (!silverfishs.isEmpty()) silverfish = silverfishs.get(0);
+ if (silverfishs.isEmpty()) {
+ err = true;
+ return;
+ }
+ try {
+ buildMap();
+ err = false;
+ } catch (Exception e) {
+ e.printStackTrace();
+ err = true;
+ return;
+ }
+ }
+
+ private void buildMap() {
+ int width = (Integer) getDungeonRoom().getDungeonRoomInfo().getProperties().get("width");
+ int height = (Integer) getDungeonRoom().getDungeonRoomInfo().getProperties().get("height");
+ OffsetPointSet ops = (OffsetPointSet) getDungeonRoom().getDungeonRoomInfo().getProperties().get("board");
+ OffsetPointSet endNodes = (OffsetPointSet) getDungeonRoom().getDungeonRoomInfo().getProperties().get("endnodes");
+ map2 = new OffsetPoint[width][height];
+ map = new int[width][height];
+ for (int y = 0; y < height; y ++) {
+ for (int x =0; x < width; x++) {
+ OffsetPoint op = ops.getOffsetPointList().get(y * width + x);
+ map2[y][x] = op;
+ map[y][x] = op.getBlock(getDungeonRoom()) == Blocks.air ? 0 : 1;
+ }
+ }
+ endNode.addAll(endNodes.getOffsetPointList());
+ }
+
+ public void tick() {
+ super.tick();
+ if (err || silverfish.isDead) {
+ findSilverFishanddoStuff();
+ if (err) return;
+ }
+ if (silverfish.getPosition().equals(lastSilverfishLoc)) {
+ if (sameTick < 10) {
+ sameTick ++;
+ return;
+ } else if (sameTick == 10) {
+ sameTick ++;
+ Point silverfish = getPointOfSilverFishOnMap(this.silverfish.getPosition());
+ List<Point> tempSol = solve(map, silverfish.x, silverfish.y, new Predicate<Point>() {
+ @Override
+ public boolean apply(@Nullable Point input) {
+ return endNode.contains(map2[input.y][input.x]);
+ }
+ });
+ {
+ solution.clear();
+ for (Point point : tempSol) {
+ solution.add(map2[point.y][point.x].getBlockPos(getDungeonRoom()));
+ }
+ }
+
+ }
+ } else {
+ sameTick = 0;
+ }
+
+ lastSilverfishLoc = silverfish.getPosition();
+ }
+
+
+ @Override
+ public void drawWorld(float partialTicks) {
+ super.drawWorld(partialTicks);
+ if (!FeatureRegistry.SOLVER_SILVERFISH.isEnabled()) return;
+ if (!err)
+ RenderUtils.drawLines(solution, FeatureRegistry.SOLVER_SILVERFISH.getLineColor(),FeatureRegistry.SOLVER_SILVERFISH.getLineWidth(), partialTicks, true);
+ }
+
+ public Point getPointOfSilverFishOnMap(BlockPos blockPos) {
+ for (int y = 0; y < map.length; y ++) {
+ for (int x = 0; x < map[0].length; x++) {
+ if (map2[y][x].getBlockPos(getDungeonRoom()).equals(blockPos))
+ return new Point(x,y);
+ }
+ }
+ return null;
+ }
+
+
+ // Taken from https://stackoverflow.com/a/55271133 and modified to suit our needs
+ // Answer by ofekp (https://stackoverflow.com/users/4295037/ofekp)
+ public static List<Point> solve(int[][] board, int startX, int startY, Predicate<Point> finishLinePredicate) {
+ Point startPoint = new Point(startX, startY);
+
+ LinkedList<Point> queue = new LinkedList<Point>();
+ Point[][] boardSearch = new Point[board.length][board[0].length];
+
+ queue.addLast(new Point(startX, startY));
+ boardSearch[startY][startX] = startPoint;
+
+ while (queue.size() != 0) {
+ Point currPos = queue.pollFirst();
+ for (Direction dir : Direction.values()) {
+ Point nextPos = move(board, boardSearch, currPos, dir);
+ if (nextPos != null) {
+ queue.addLast(nextPos);
+ boardSearch[nextPos.y][nextPos.x] = new Point(currPos.x, currPos.y);
+ if (finishLinePredicate.apply(nextPos)) {
+ List<Point> route = new ArrayList<Point>();
+ Point tmp = currPos;
+ route.add(nextPos);
+ route.add(currPos);
+ while (tmp != startPoint) {
+ tmp = boardSearch[tmp.y][tmp.x];
+ route.add(tmp);
+ }
+ return route;
+ }
+ }
+ }
+ }
+ return Collections.emptyList();
+ }
+
+ public static Point move(int[][] board, Point[][] boardSearch, Point currPos, Direction dir) {
+ int x = currPos.x;
+ int y = currPos.y;
+
+ int diffX = dir.dx;
+ int diffY = dir.dy;
+
+ int i = 1;
+ while (x + i * diffX >= 0 && x + i * diffX < board[0].length
+ && y + i * diffY >= 0 && y + i * diffY < board.length
+ && board[y + i * diffY][x + i * diffX] != 1) {
+ i++;
+ }
+ i--;
+
+ if (boardSearch[y + i * diffY][x + i * diffX] != null) {
+ return null;
+ }
+
+ return new Point(x + i * diffX, y + i * diffY);
+ }
+
+ @Getter
+ @AllArgsConstructor
+ public enum Direction {
+ LEFT(-1,0),
+ RIGHT(1,0),
+ UP(0,-1),
+ DOWN(0,1);
+
+ int dx, dy;
+ }
+
+
+ public static class Generator implements RoomProcessorGenerator<RoomProcessorIcePath> {
+ @Override
+ public RoomProcessorIcePath createNew(DungeonRoom dungeonRoom) {
+ RoomProcessorIcePath defaultRoomProcessor = new RoomProcessorIcePath(dungeonRoom);
+ return defaultRoomProcessor;
+ }
+ }
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/RoomProcessorRedRoom.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/RoomProcessorRedRoom.java
new file mode 100644
index 00000000..d171c928
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/RoomProcessorRedRoom.java
@@ -0,0 +1,121 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor;
+
+import kr.syeyoung.dungeonsguide.dungeon.data.OffsetPoint;
+import kr.syeyoung.dungeonsguide.mod.dungeon.doorfinder.DungeonDoor;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomfinder.DungeonRoom;
+import kr.syeyoung.dungeonsguide.mod.features.FeatureRegistry;
+import kr.syeyoung.dungeonsguide.mod.features.impl.boss.FeatureWarningOnPortal;
+import kr.syeyoung.dungeonsguide.mod.features.text.StyledTextRenderer;
+import kr.syeyoung.dungeonsguide.mod.utils.RenderUtils;
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.renderer.GlStateManager;
+import net.minecraft.client.renderer.entity.RenderManager;
+import net.minecraft.util.BlockPos;
+import net.minecraft.util.MathHelper;
+import net.minecraft.util.Vec3;
+import org.lwjgl.opengl.GL11;
+
+import javax.vecmath.Vector3f;
+
+public class RoomProcessorRedRoom extends GeneralRoomProcessor {
+ public RoomProcessorRedRoom(DungeonRoom dungeonRoom) {
+ super(dungeonRoom);
+ BlockPos basePt = dungeonRoom.getMin().add(dungeonRoom.getMax());
+ this.basePt = new Vec3(basePt.getX() / 2.0f, basePt.getY() / 2.0f, basePt.getZ() / 2.0f);
+ }
+
+ Vec3 basePt;
+ int dir = 0;
+
+ @Override
+ public void tick() {
+ BlockPos basePt = getDungeonRoom().getMin().add(getDungeonRoom().getMax());
+ this.basePt = new Vec3(basePt.getX() / 2.0f, basePt.getY() / 2.0f + 4, basePt.getZ() / 2.0f);
+ DungeonDoor real = null;
+ for (DungeonDoor door : getDungeonRoom().getDoors()) {
+ if (door.getType().isExist()) {
+ real = door;break;
+ }
+ }
+ if (real != null) {
+ OffsetPoint offsetPoint = new OffsetPoint(getDungeonRoom(), real.getPosition());
+ offsetPoint = new OffsetPoint(33- offsetPoint.getX(), offsetPoint.getY(), 33 - offsetPoint.getZ());
+ BlockPos opposite =offsetPoint.getBlockPos(getDungeonRoom());
+ BlockPos dir = new BlockPos(real.getPosition().subtract(opposite));
+ dir = new BlockPos(MathHelper.clamp_int(dir.getX() / 10, -1, 1), 0, MathHelper.clamp_int(dir.getZ() / 10, -1, 1));
+
+ this.basePt = new Vec3(opposite.add(dir.getX() * 6 + dir.getZ(), 3, dir.getZ() * 6 - dir.getX()));
+
+ if (dir.getX() > 0) this.dir = 270;
+ else if (dir.getX() < 0) this.dir = 90;
+ else if (dir.getZ() < 0) this.dir = 0;
+ else if (dir.getZ() > 0) this.dir = 180;
+ else this.dir = Integer.MIN_VALUE;
+ } else {
+ dir = Integer.MIN_VALUE;
+ }
+ }
+
+ @Override
+ public void drawWorld(float partialTicks) {
+ super.drawWorld(partialTicks);
+ if (!FeatureRegistry.BOSSFIGHT_WARNING_ON_PORTAL.isEnabled()) return;
+
+
+ FeatureWarningOnPortal featureWarningOnPortal = FeatureRegistry.BOSSFIGHT_WARNING_ON_PORTAL;
+ {
+ RenderManager renderManager = Minecraft.getMinecraft().getRenderManager();
+
+ Vector3f renderPos = RenderUtils.getRenderPos((float)basePt.xCoord,(float) basePt.yCoord, (float)basePt.zCoord, partialTicks);
+
+ GlStateManager.color(1f, 1f, 1f, 0.5f);
+ GlStateManager.pushMatrix();
+ GlStateManager.translate(renderPos.x, renderPos.y, renderPos.z);
+ if (dir == Integer.MIN_VALUE)
+ GlStateManager.rotate(-renderManager.playerViewY, 0.0f, 1.0f, 0.0f);
+ else
+ GlStateManager.rotate(dir, 0.0f, 1.0f, 0.0f);
+ GlStateManager.scale(-0.05f, -0.05f, 0.05f);
+ GlStateManager.disableLighting();
+ GlStateManager.depthMask(false); GL11.glDisable(GL11.GL_DEPTH_TEST);
+ GlStateManager.disableDepth();
+ GlStateManager.enableBlend();
+ GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
+
+
+ StyledTextRenderer.drawTextWithStylesAssociated(featureWarningOnPortal.getText(), 0, 0,0, featureWarningOnPortal.getStylesMap(), StyledTextRenderer.Alignment.LEFT);
+
+ GlStateManager.color(1.0f, 1.0f, 1.0f, 1.0f);
+ GlStateManager.depthMask(true);
+ GlStateManager.enableDepth();
+ GlStateManager.popMatrix();
+ }
+ }
+
+
+ public static class Generator implements RoomProcessorGenerator<RoomProcessorRedRoom> {
+ @Override
+ public RoomProcessorRedRoom createNew(DungeonRoom dungeonRoom) {
+ RoomProcessorRedRoom defaultRoomProcessor = new RoomProcessorRedRoom(dungeonRoom);
+ return defaultRoomProcessor;
+ }
+ }
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/RoomProcessorRiddle.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/RoomProcessorRiddle.java
new file mode 100755
index 00000000..f7a0b65f
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/RoomProcessorRiddle.java
@@ -0,0 +1,121 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor;
+
+import com.google.common.base.Predicate;
+import kr.syeyoung.dungeonsguide.mod.chat.ChatTransmitter;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomfinder.DungeonRoom;
+import kr.syeyoung.dungeonsguide.mod.features.FeatureRegistry;
+import kr.syeyoung.dungeonsguide.mod.utils.RenderUtils;
+import kr.syeyoung.dungeonsguide.mod.utils.TextUtils;
+import net.minecraft.block.Block;
+import net.minecraft.entity.item.EntityArmorStand;
+import net.minecraft.init.Blocks;
+import net.minecraft.util.AxisAlignedBB;
+import net.minecraft.util.BlockPos;
+import net.minecraft.util.ChatComponentText;
+import net.minecraft.util.IChatComponent;
+import net.minecraft.world.World;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.regex.Pattern;
+
+public class RoomProcessorRiddle extends GeneralRoomProcessor {
+
+ public RoomProcessorRiddle(DungeonRoom dungeonRoom) {
+ super(dungeonRoom);
+ }
+
+ private static final List<Pattern> patternList = Arrays.asList(
+ Pattern.compile("My chest doesn't have the reward. We are all telling the truth.*"),
+ Pattern.compile("The reward isn't in any of our chests.*"),
+ Pattern.compile("The reward is not in my chest!.*"),
+ Pattern.compile("At least one of them is lying, and the reward is not in .+'s chest.*"),
+ Pattern.compile("Both of them are telling the truth. Also,.+has the reward in their chest.*"),
+ Pattern.compile("My chest has the reward and I'm telling the truth.*")
+ );
+
+ @Override
+ public void chatReceived(IChatComponent chat) {
+ super.chatReceived(chat);
+ if (!FeatureRegistry.SOLVER_RIDDLE.isEnabled()) return;
+ String ch2 = chat.getUnformattedText();
+ if (!ch2.startsWith("§e[NPC] ")) {
+ return;
+ }
+ String watsaid = TextUtils.stripColor(ch2.split(":")[1]).trim();
+ boolean foundMatch = false;
+ for (Pattern p:patternList) {
+ if (p.matcher(watsaid).matches()) {
+ foundMatch = true;
+ break;
+ }
+ }
+ if (foundMatch) {
+ ChatTransmitter.addToQueue(new ChatComponentText("§eDungeons Guide §7:: §eRiddle §7:: "+ch2.split(":")[0].trim()+" §fhas the reward!"));
+ final String name = TextUtils.stripColor(ch2.split(":")[0]).replace("[NPC] ","").trim();
+ final BlockPos low = getDungeonRoom().getMin();
+ final BlockPos high = getDungeonRoom().getMax();
+ World w = getDungeonRoom().getContext().getWorld();
+ List<EntityArmorStand> armor = w.getEntities(EntityArmorStand.class, new Predicate<EntityArmorStand>() {
+ @Override
+ public boolean apply(@Nullable EntityArmorStand input) {
+ BlockPos pos = input.getPosition();
+ return low.getX() < pos.getX() && pos.getX() < high.getX()
+ && low.getZ() < pos.getZ() && pos.getZ() < high.getZ() && TextUtils.stripColor(input.getName()).equalsIgnoreCase(name);
+ }
+ });
+
+ if (armor != null) {
+ this.chest = null;
+ BlockPos pos = armor.get(0).getPosition();
+ for (BlockPos allInBox : BlockPos.getAllInBox(pos.add(-1, 0, -1), pos.add(1, 0, 1))) {
+ Block b = w.getChunkFromBlockCoords(allInBox).getBlock(allInBox);
+
+ if ((b == Blocks.chest || b == Blocks.trapped_chest)&& allInBox.distanceSq(pos) == 1 ) {
+ this.chest = allInBox;
+ return;
+ }
+ }
+ }
+
+ }
+ }
+
+ BlockPos chest;
+
+ @Override
+ public void drawWorld(float partialTicks) {
+ super.drawWorld(partialTicks);
+ if (!FeatureRegistry.SOLVER_RIDDLE.isEnabled()) return;
+ if (chest != null) {
+ RenderUtils.highlightBoxAColor(AxisAlignedBB.fromBounds(chest.getX(), chest.getY(), chest.getZ(), chest.getX()+1, chest.getY() + 1, chest.getZ() + 1), FeatureRegistry.SOLVER_RIDDLE.getTargetColor(), partialTicks, true);
+ }
+ }
+
+ public static class Generator implements RoomProcessorGenerator<RoomProcessorRiddle> {
+ @Override
+ public RoomProcessorRiddle createNew(DungeonRoom dungeonRoom) {
+ RoomProcessorRiddle defaultRoomProcessor = new RoomProcessorRiddle(dungeonRoom);
+ return defaultRoomProcessor;
+ }
+ }
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/RoomProcessorTeleportMazeSolver.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/RoomProcessorTeleportMazeSolver.java
new file mode 100755
index 00000000..30f1d385
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/RoomProcessorTeleportMazeSolver.java
@@ -0,0 +1,145 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor;
+
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomfinder.DungeonRoom;
+import kr.syeyoung.dungeonsguide.mod.features.FeatureRegistry;
+import kr.syeyoung.dungeonsguide.mod.utils.RenderUtils;
+import net.minecraft.block.Block;
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.entity.EntityPlayerSP;
+import net.minecraft.init.Blocks;
+import net.minecraft.util.AxisAlignedBB;
+import net.minecraft.util.BlockPos;
+import net.minecraft.util.Vec3;
+import net.minecraft.world.World;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class RoomProcessorTeleportMazeSolver extends GeneralRoomProcessor {
+ @Nullable
+ private BlockPos lastPlayerLocation;
+
+ public RoomProcessorTeleportMazeSolver(DungeonRoom dungeonRoom) {
+ super(dungeonRoom);
+ yLevel = dungeonRoom.getMin().getY() - 1;
+ }
+
+ private final List<BlockPos> visitedPortals = new ArrayList<BlockPos>();
+
+ private int yLevel = 0;
+ private double slope1, slope2;
+ private double posX1, posZ1, posX2, posZ2;
+ private int times=0 ;
+
+ private double intersectionX, intersectionZ;
+ private BlockPos intersection;
+
+ @Override
+ public void tick() {
+ super.tick();
+
+
+
+ World w = getDungeonRoom().getContext().getWorld();
+ EntityPlayerSP entityPlayerSP = Minecraft.getMinecraft().thePlayer;
+ BlockPos pos2 = new BlockPos(Math.floor(entityPlayerSP.posX), Math.floor(entityPlayerSP.posY), Math.floor(entityPlayerSP.posZ));
+ Block b = w.getChunkFromBlockCoords(pos2).getBlock(pos2);
+ Vec3 lookVec = entityPlayerSP.getLookVec();
+
+ if (times % 4 == 1) {
+ posX1 = entityPlayerSP.posX;
+ posZ1 = entityPlayerSP.posZ;
+ slope1 = lookVec.zCoord / lookVec.xCoord;
+ times ++;
+ } else if (times % 4 == 3) {
+ posX2 = entityPlayerSP.posX;
+ posZ2 = entityPlayerSP.posZ;
+ slope2 = lookVec.zCoord / lookVec.xCoord;
+
+ double yInt1 = posZ1 - posX1 * slope1;
+ double yInt2 = posZ2 - posX2 * slope2;
+
+ intersectionX = (yInt2 - yInt1) / (slope1 - slope2);
+ intersectionZ = (slope1 * intersectionX + yInt1);
+ intersection = new BlockPos((int) intersectionX, yLevel, (int) intersectionZ);
+ times++;
+ }
+
+ if (b == Blocks.stone_slab || b == Blocks.stone_slab2) {
+ boolean teleport = false;
+ if (lastPlayerLocation != null && lastPlayerLocation.distanceSq(pos2) < 3) {
+ return;
+ }
+ for (BlockPos allInBox : BlockPos.getAllInBox(lastPlayerLocation, pos2)) {
+ if (w.getChunkFromBlockCoords(allInBox).getBlock(allInBox) == Blocks.iron_bars) {
+ teleport = true;
+ break;
+ }
+ }
+
+ if (teleport) {
+ if (times % 4 == 0) {
+ times ++;
+ } else if (times % 4 == 2){
+ times++;
+ }
+
+ for (BlockPos allInBox : BlockPos.getAllInBox(pos2.add(-1, 0, -1), pos2.add(1, 0, 1))) {
+ if (w.getChunkFromBlockCoords(allInBox).getBlock(allInBox) == Blocks.end_portal_frame) {
+ if (!visitedPortals.contains(allInBox))
+ visitedPortals.add(allInBox);
+ break;
+ }
+ }
+ for (BlockPos allInBox : BlockPos.getAllInBox(lastPlayerLocation.add(-1, -1, -1), lastPlayerLocation.add(1, 1, 1))) {
+ if (w.getChunkFromBlockCoords(allInBox).getBlock(allInBox) == Blocks.end_portal_frame) {
+ if (!visitedPortals.contains(allInBox))
+ visitedPortals.add(allInBox);
+ break;
+ }
+ }
+ }
+ }
+
+ lastPlayerLocation = pos2;
+ }
+
+ @Override
+ public void drawWorld(float partialTicks) {
+ super.drawWorld(partialTicks);
+ if (!FeatureRegistry.SOLVER_TELEPORT.isEnabled()) return;
+ for (BlockPos bpos:visitedPortals) {
+ RenderUtils.highlightBoxAColor( AxisAlignedBB.fromBounds(bpos.getX(), bpos.getY(), bpos.getZ(), bpos.getX()+1, bpos.getY() + 1, bpos.getZ() + 1), FeatureRegistry.SOLVER_TELEPORT.getTargetColor2(), partialTicks, true);
+ }
+
+ if (intersection != null) {
+ RenderUtils.highlightBoxAColor( AxisAlignedBB.fromBounds(intersection.getX(), intersection.getY(), intersection.getZ(), intersection.getX()+1, intersection.getY() + 1, intersection.getZ() + 1), FeatureRegistry.SOLVER_TELEPORT.getTargetColor(), partialTicks, false);
+ }
+ }
+ public static class Generator implements RoomProcessorGenerator<RoomProcessorTeleportMazeSolver> {
+ @Override
+ public RoomProcessorTeleportMazeSolver createNew(DungeonRoom dungeonRoom) {
+ RoomProcessorTeleportMazeSolver defaultRoomProcessor = new RoomProcessorTeleportMazeSolver(dungeonRoom);
+ return defaultRoomProcessor;
+ }
+ }
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/RoomProcessorTicTacToeSolver.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/RoomProcessorTicTacToeSolver.java
new file mode 100755
index 00000000..9ee8c215
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/RoomProcessorTicTacToeSolver.java
@@ -0,0 +1,214 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor;
+
+import kr.syeyoung.dungeonsguide.dungeon.data.OffsetPoint;
+import kr.syeyoung.dungeonsguide.dungeon.data.OffsetPointSet;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomfinder.DungeonRoom;
+import kr.syeyoung.dungeonsguide.mod.features.FeatureRegistry;
+import kr.syeyoung.dungeonsguide.mod.utils.RenderUtils;
+import net.minecraft.block.Block;
+import net.minecraft.entity.item.EntityItemFrame;
+import net.minecraft.init.Blocks;
+import net.minecraft.item.ItemMap;
+import net.minecraft.item.ItemStack;
+import net.minecraft.util.AxisAlignedBB;
+import net.minecraft.util.BlockPos;
+import net.minecraft.world.World;
+import net.minecraft.world.storage.MapData;
+
+import java.util.List;
+
+public class RoomProcessorTicTacToeSolver extends GeneralRoomProcessor {
+
+ private final OffsetPointSet board;
+ private byte[][] lastBoard;
+ public RoomProcessorTicTacToeSolver(DungeonRoom dungeonRoom) {
+ super(dungeonRoom);
+
+ board = (OffsetPointSet) dungeonRoom.getDungeonRoomInfo().getProperties().get("board");
+ }
+
+ // -1 com, 1 pla, 0 emp
+ private byte[][] buildBoardState() {
+ byte[][] board = new byte[3][3];
+ World w= getDungeonRoom().getContext().getWorld();
+ for (int x = 0; x < 3; x++) {
+ for (int y = 0; y < 3; y++) {
+ OffsetPoint op = this.board.getOffsetPointList().get(x * 3 + y);
+ BlockPos bpos = op.getBlockPos(getDungeonRoom());
+ Block b = w.getChunkFromBlockCoords(bpos).getBlock(bpos);
+ if (b == Blocks.stone_button) {
+ board[y][x] = 0;
+ } else if (b == Blocks.air){
+ AxisAlignedBB abab = AxisAlignedBB.fromBounds(bpos.getX() , bpos.getY(), bpos.getZ(), bpos.getX() +1, bpos.getY() +1, bpos.getZ() +1);
+ List<EntityItemFrame> frames = getDungeonRoom().getContext().getWorld().getEntitiesWithinAABB(EntityItemFrame.class, abab);
+ if (frames.isEmpty()) board[y][x] = 0;
+ else {
+ ItemStack displayedItem = frames.get(0).getDisplayedItem();
+ if (displayedItem == null || displayedItem.getItem() == null || !displayedItem.getItem().isMap()) {
+ board[y][x] = 0;
+ continue;
+ }
+ MapData mapData = ((ItemMap)displayedItem.getItem()).getMapData(displayedItem, w);
+ byte center = mapData.colors[64 * 128+64];
+ if (center == 114)
+ board[y][x] = -1;
+ else
+ board[y][x] = 1;
+ }
+ }
+ }
+ }
+ return board;
+ }
+
+ private byte checkWinner(byte[][] board) {
+ for (int y = 0; y <3; y++) {
+ byte potentialWinner = board[y][0];
+ if (potentialWinner == 0) continue;
+ boolean found = false;
+ for (int x = 0; x < 3; x++) {
+ if (potentialWinner != board[y][x]) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ return potentialWinner;
+ }
+ }
+ for (int x = 0; x <3; x++) {
+ byte potentialWinner = board[0][x];
+ if (potentialWinner == 0) continue;
+ boolean found = false;
+ for (int y = 0; y < 3; y++) {
+ if (potentialWinner != board[y][x]) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ return potentialWinner;
+ }
+ }
+ if (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[0][0] != 0) {
+ return board[0][0];
+ }
+ if (board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[0][2] != 0) {
+ return board[0][2];
+ }
+ return 0;
+ }
+
+ private int chosePos = -1;
+ private int minimax(byte[][] board, byte player) {
+ byte winner = checkWinner(board);
+ if (winner != 0) {
+ return winner * player;
+ }
+
+ int move = -1;
+ int score = -2;
+ for (int i = 0; i < 9; i++) {
+ if (board[i % 3][i / 3] == 0) {
+ byte[][] cloned = new byte[3][];
+ for(int k = 0; k < 3; k++)
+ cloned[k] = board[k].clone();
+
+ cloned[i % 3][i/3] = player;
+ int scoreForMove = -minimax(cloned, (byte) -player);
+ if (scoreForMove > score) {
+ score = scoreForMove;
+ move = i;
+ }
+ }
+ }
+ chosePos = move;
+ if (move == -1) {
+ return 0;
+ }
+
+ return score;
+ }
+
+ private boolean gameEnded = false;
+
+ @Override
+ public void tick() {
+ super.tick();
+ if (board == null) return;
+ if (gameEnded) return;
+ byte[][] board = buildBoardState();
+ if (checkWinner(board) != 0) {
+ gameEnded = true;
+ return;
+ }
+ if (lastBoard != null) {
+ boolean yesdoit = false;
+ label:
+ for (int y = 0; y < 3; y++)
+ for (int x = 0; x < 3; x++)
+ if (board[y][x] != lastBoard[y][x]) {
+ yesdoit = true;
+ break label;
+ }
+ if (!yesdoit) return;
+ }
+ lastBoard = board;
+
+ minimax(board, (byte) 1);
+ if (chosePos == -1) {
+ gameEnded = true;
+ return;
+ }
+ }
+
+ @Override
+ public void drawWorld(float partialTicks) {
+ super.drawWorld(partialTicks);
+ if (!FeatureRegistry.SOLVER_TICTACTOE.isEnabled()) return;
+ if (chosePos != -1) {
+ BlockPos block = board.getOffsetPointList().get(chosePos).getBlockPos(getDungeonRoom());
+ boolean whoseturn = false; // false => hype true => me
+ if (lastBoard != null) {
+ int ones = 0;
+ int negativeones = 0;
+ for (byte[] bytes : lastBoard) {
+ for (byte aByte : bytes) {
+ if (aByte == 1) ones++;
+ else if (aByte == -1) negativeones++;
+ }
+ }
+ whoseturn = ones < negativeones;
+ }
+ RenderUtils.highlightBoxAColor(AxisAlignedBB.fromBounds(block.getX(), block.getY(), block.getZ(), block.getX()+1, block.getY() + 1, block.getZ() + 1),
+ whoseturn ? FeatureRegistry.SOLVER_TICTACTOE.getTargetColor()
+ : FeatureRegistry.SOLVER_TICTACTOE.getTargetColor2(), partialTicks, true);
+ }
+ }
+
+ public static class Generator implements RoomProcessorGenerator<RoomProcessorTicTacToeSolver> {
+ @Override
+ public RoomProcessorTicTacToeSolver createNew(DungeonRoom dungeonRoom) {
+ RoomProcessorTicTacToeSolver defaultRoomProcessor = new RoomProcessorTicTacToeSolver(dungeonRoom);
+ return defaultRoomProcessor;
+ }
+ }
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/RoomProcessorTrivia.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/RoomProcessorTrivia.java
new file mode 100755
index 00000000..b7956122
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/RoomProcessorTrivia.java
@@ -0,0 +1,165 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor;
+
+import kr.syeyoung.dungeonsguide.mod.chat.ChatTransmitter;
+import kr.syeyoung.dungeonsguide.dungeon.data.OffsetPoint;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomfinder.DungeonRoom;
+import kr.syeyoung.dungeonsguide.mod.features.FeatureRegistry;
+import kr.syeyoung.dungeonsguide.mod.utils.RenderUtils;
+import kr.syeyoung.dungeonsguide.mod.utils.SkyblockUtils;
+import kr.syeyoung.dungeonsguide.mod.utils.TextUtils;
+import kr.syeyoung.dungeonsguide.mod.wsresource.StaticResourceCache;
+import net.minecraft.util.AxisAlignedBB;
+import net.minecraft.util.BlockPos;
+import net.minecraft.util.ChatComponentText;
+import net.minecraft.util.IChatComponent;
+import org.apache.commons.lang3.math.NumberUtils;
+import org.json.JSONObject;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class RoomProcessorTrivia extends GeneralRoomProcessor {
+
+ public RoomProcessorTrivia(DungeonRoom dungeonRoom) {
+ super(dungeonRoom);
+ }
+
+
+ private final List<String> questionDialog = new ArrayList<String>();
+ private boolean questionDialogStart = false;
+
+ private boolean parseDialog = false;
+ @Override
+ public void chatReceived(IChatComponent chat) {
+ super.chatReceived(chat);
+ if (!FeatureRegistry.SOLVER_KAHOOT.isEnabled()) return;
+ String ch2 = chat.getUnformattedText();
+ if (parseDialog) {
+ parseDialog = false;
+ parseDialog();
+ }
+ if (chat.getFormattedText().contains("§r§6§lQuestion ")) {
+ questionDialogStart = true;
+ questionDialog.clear();
+ }
+ if (questionDialogStart && (chat.getFormattedText().startsWith("§r§r§r") || chat.getFormattedText().startsWith("§r§r§r") || chat.getFormattedText().trim().startsWith("§r§6 "))) {
+ questionDialog.add(chat.getFormattedText());
+ }
+
+ if (chat.getFormattedText().contains("§r§6 ⓒ")) {
+ questionDialogStart = false;
+ parseDialog = true;
+ }
+ }
+ public static final Pattern anwerPattern = Pattern.compile("§r§6 . §a(.+)§r");
+ private void parseDialog() {
+ String question = TextUtils.stripColor(questionDialog.get(1)).trim();
+ String answerA = getAnswer(questionDialog.get(2));
+ String answerB = getAnswer(questionDialog.get(3));
+ String answerC = getAnswer(questionDialog.get(4));
+ match(question, answerA, answerB, answerC);
+
+ }
+ String correctAnswer;
+
+
+ private String getAnswer(String answerString) {
+ Matcher matcher = anwerPattern.matcher(answerString.trim());
+ if (!matcher.matches()) return "";
+ return matcher.group(1);
+ }
+ private void match(String question, String a, String b, String c) {
+ StaticResourceCache.INSTANCE.getResource(StaticResourceCache.TRIVIA_ANSWERS).thenAccept(value -> {
+ JSONObject answersJSON = new JSONObject(value.getValue());
+
+ String semi_answers = answersJSON.getString(question.toLowerCase().trim());
+ String theRealAnswer;
+ if (semi_answers == null) theRealAnswer = null;
+ else {
+ semi_answers = takeCareOfPlaceHolders(semi_answers);
+ String[] answers = semi_answers.split(",");
+ if (match(answers, a)) theRealAnswer = "A";
+ else if (match(answers, b)) theRealAnswer = "B";
+ else if (match(answers, c)) theRealAnswer = "C";
+ else theRealAnswer = semi_answers;
+ }
+ if (theRealAnswer == null)
+ ChatTransmitter.addToQueue(new ChatComponentText("§eDungeons Guide §7:: §eTrivia §7:: §cCouldn't determine the answer! (no question found)"));
+ else if (theRealAnswer.length() >1)
+ ChatTransmitter.addToQueue(new ChatComponentText("§eDungeons Guide §7:: §eTrivia §7:: §cCouldn't determine the answer! ("+theRealAnswer+")"));
+ else
+ ChatTransmitter.addToQueue(new ChatComponentText("§eDungeons Guide §7:: §eTrivia §7:: "+theRealAnswer+"§f is the correct answer!"));
+ correctAnswer = theRealAnswer;
+ });
+ }
+
+ private String takeCareOfPlaceHolders(String input) {
+ String str = input;
+ if (str.contains("$year")) {
+ ChatTransmitter.addToQueue(new ChatComponentText("§eDungeons Guide §fuses §eInventiveTalent§7(https://github.com/InventivetalentDev)§e's Skyblock Api §fto fetch current skyblock year!"));
+ try {
+ str = str.replace("$year", SkyblockUtils.getSkyblockYear()+"");
+ } catch (IOException e) {
+ str = str.replace("$year", "Couldn't determine current skyblock year :: "+e.getMessage());
+ }
+ }
+ return str;
+ }
+ private boolean match(String[] match, String match2) {
+ for (String s : match) {
+ if (NumberUtils.isNumber(s)) {
+ if (match2.toLowerCase().contains(s)) return true;
+ } else {
+ if (match2.equalsIgnoreCase(s)) return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public void drawWorld(float partialTicks) {
+ super.drawWorld(partialTicks);
+ if (!FeatureRegistry.SOLVER_KAHOOT.isEnabled()) return;
+ if (correctAnswer == null) return;
+
+ OffsetPoint op = (OffsetPoint) getDungeonRoom().getDungeonRoomInfo().getProperties().get(correctAnswer);
+ if (op != null) {
+ BlockPos solution = op.getBlockPos(getDungeonRoom());
+ RenderUtils.highlightBoxAColor(AxisAlignedBB.fromBounds(solution.getX(), solution.getY(), solution.getZ(), solution.getX()+1, solution.getY() + 1, solution.getZ() + 1), FeatureRegistry.SOLVER_KAHOOT.getTargetColor(), partialTicks, false);
+ }
+ }
+
+ public static class Generator implements RoomProcessorGenerator<RoomProcessorTrivia> {
+ @Override
+ public RoomProcessorTrivia createNew(DungeonRoom dungeonRoom) {
+ RoomProcessorTrivia defaultRoomProcessor = new RoomProcessorTrivia(dungeonRoom);
+ return defaultRoomProcessor;
+ }
+ }
+
+ @Override
+ public boolean readGlobalChat() {
+ return true;
+ }
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bombdefuse/RoomProcessorBombDefuseSolver.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bombdefuse/RoomProcessorBombDefuseSolver.java
new file mode 100644
index 00000000..d3d7ae3b
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bombdefuse/RoomProcessorBombDefuseSolver.java
@@ -0,0 +1,441 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.bombdefuse;
+
+import kr.syeyoung.dungeonsguide.mod.chat.ChatTransmitter;
+import kr.syeyoung.dungeonsguide.dungeon.data.OffsetPoint;
+import kr.syeyoung.dungeonsguide.dungeon.data.OffsetPointSet;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomfinder.DungeonRoom;
+import kr.syeyoung.dungeonsguide.mod.events.impl.KeyBindPressedEvent;
+import kr.syeyoung.dungeonsguide.mod.events.impl.PlayerInteractEntityEvent;
+import kr.syeyoung.dungeonsguide.mod.features.FeatureRegistry;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.GeneralRoomProcessor;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.RoomProcessorGenerator;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.bombdefuse.chambers.BDChamber;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.bombdefuse.chambers.BombDefuseChamberGenerator;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.bombdefuse.chambers.DummyDefuseChamberProcessor;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.bombdefuse.chambers.arrow.ArrowProcessorMatcher;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.bombdefuse.chambers.bugged.ImpossibleMatcher;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.bombdefuse.chambers.color.ColorProcessorMatcher;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.bombdefuse.chambers.creeper.CreeperProcessorMatcher;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.bombdefuse.chambers.goldenpath.GoldenPathProcessorMatcher;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.bombdefuse.chambers.maze.MazeProcessorMatcher;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.bombdefuse.chambers.number.NumberProcessorMatcher;
+import kr.syeyoung.dungeonsguide.mod.utils.RenderUtils;
+import kr.syeyoung.dungeonsguide.mod.utils.TextUtils;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.Getter;
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.gui.FontRenderer;
+import net.minecraft.nbt.CompressedStreamTools;
+import net.minecraft.nbt.NBTTagCompound;
+import net.minecraft.util.BlockPos;
+import net.minecraft.util.ChatComponentText;
+import net.minecraft.util.IChatComponent;
+import net.minecraftforge.client.event.GuiScreenEvent;
+import net.minecraftforge.event.entity.living.LivingEvent;
+import net.minecraftforge.event.entity.player.PlayerInteractEvent;
+import org.apache.commons.codec.binary.Base64;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+public class RoomProcessorBombDefuseSolver extends GeneralRoomProcessor {
+
+ @Getter
+ private final List<ChamberSet> chambers = new ArrayList<ChamberSet>();
+ @Getter
+ private OffsetPointSet doors;
+
+ private static final List<BombDefuseChamberGenerator> chamberGenerators = new ArrayList<BombDefuseChamberGenerator>();
+ {
+ chamberGenerators.add(new ArrowProcessorMatcher());
+ chamberGenerators.add(new ColorProcessorMatcher());
+ chamberGenerators.add(new CreeperProcessorMatcher());
+ chamberGenerators.add(new NumberProcessorMatcher());
+ chamberGenerators.add(new GoldenPathProcessorMatcher());
+ chamberGenerators.add(new MazeProcessorMatcher());
+ chamberGenerators.add(new ImpossibleMatcher());
+ }
+
+ private boolean bugged = false;
+ private boolean maze = false;
+ private boolean impossible = false;
+
+ public RoomProcessorBombDefuseSolver(DungeonRoom dungeonRoom) {
+ super(dungeonRoom);
+ if (!FeatureRegistry.SOLVER_BOMBDEFUSE.isEnabled()) {
+ bugged = true;
+ return;
+ }
+ chambers.add(new ChamberSet(
+ buildChamber((OffsetPointSet) dungeonRoom.getDungeonRoomInfo().getProperties().get("L1"), 1, true),
+ buildChamber((OffsetPointSet) dungeonRoom.getDungeonRoomInfo().getProperties().get("R1"), 1, true), null
+ ));
+ chambers.add(new ChamberSet(
+ buildChamber((OffsetPointSet) dungeonRoom.getDungeonRoomInfo().getProperties().get("L2"), 2, true),
+ buildChamber((OffsetPointSet) dungeonRoom.getDungeonRoomInfo().getProperties().get("R2"), 2, true), null
+ ));
+ chambers.add(new ChamberSet(
+ buildChamber((OffsetPointSet) dungeonRoom.getDungeonRoomInfo().getProperties().get("L3"), 3, true),
+ buildChamber((OffsetPointSet) dungeonRoom.getDungeonRoomInfo().getProperties().get("R3"), 3, true), null
+ ));
+ chambers.add(new ChamberSet(
+ buildChamber((OffsetPointSet) dungeonRoom.getDungeonRoomInfo().getProperties().get("L4"), 4, true),
+ buildChamber((OffsetPointSet) dungeonRoom.getDungeonRoomInfo().getProperties().get("R4"), 4, true), null
+ ));
+ doors = (OffsetPointSet) dungeonRoom.getDungeonRoomInfo().getProperties().get("Door");
+ if (doors == null) {bugged = true; return;}
+ for (ChamberSet set:chambers) {
+ if (set.getLeft().getChamberBlocks() == null) {
+ bugged = true;
+ return;
+ }
+ if (set.getRight().getChamberBlocks() == null) {
+ bugged = true;
+ return;
+ }
+ }
+
+ for (ChamberSet set:chambers) {
+ if (set.getLeft().getChamberBlocks() == null) {
+ bugged = true;
+ return;
+ }
+ if (set.getRight().getChamberBlocks() == null) {
+ bugged = true;
+ return;
+ }
+ }
+
+ for (ChamberSet set:chambers) {
+ for (BombDefuseChamberGenerator bdcg:chamberGenerators) {
+ if (bdcg.match(set.getLeft(), set.getRight())) {
+ set.setChamberGen(bdcg);
+ set.getLeft().setProcessor(bdcg.createLeft(set.getLeft(), this));
+ set.getRight().setProcessor(bdcg.createRight(set.getRight(), this));
+ if (bdcg instanceof ImpossibleMatcher) impossible=true;
+ if (bdcg instanceof MazeProcessorMatcher) maze = true;
+ break;
+ }
+ }
+ if (set.getChamberGen() == null) {
+ set.setChamberGen(null);
+ set.getLeft().setProcessor(new DummyDefuseChamberProcessor(this, set.getLeft()));
+ set.getRight().setProcessor(new DummyDefuseChamberProcessor(this, set.getRight()));
+ }
+ }
+
+ OffsetPoint warning1 = (OffsetPoint) dungeonRoom.getDungeonRoomInfo().getProperties().get("Warning");
+ if (warning1 != null) warning = warning1.getBlockPos(dungeonRoom);
+ }
+
+ public BDChamber buildChamber(OffsetPointSet ops, int level, boolean left) {
+ return new BDChamber(getDungeonRoom(), ops, left, level, null);
+ }
+ BlockPos warning;
+
+
+ public void communicate(NBTTagCompound compound) {
+ if (bugged) return;
+ try {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ DataOutputStream w = new DataOutputStream(baos);
+ CompressedStreamTools.writeCompressed(compound, w);
+ w.flush();
+ byte[] bytes = baos.toByteArray();
+ String str = Base64.encodeBase64String(bytes);
+ Minecraft.getMinecraft().thePlayer.sendChatMessage("/pc $DG-BD " +str);
+
+ for (ChamberSet ch:chambers) {
+ if (ch.getLeft() != null && ch.getLeft().getProcessor() != null)
+ ch.getLeft().getProcessor().onDataRecieve(compound);
+ if (ch.getRight() != null && ch.getRight().getProcessor() != null)
+ ch.getRight().getProcessor().onDataRecieve(compound);
+ }
+ } catch (IOException e2) {
+ e2.printStackTrace();
+ ChatTransmitter.sendDebugChat(new ChatComponentText("Failed to send Bomb Defuse Chat"));
+ }
+ }
+
+ @Override
+ public void chatReceived(IChatComponent component) {
+ super.chatReceived(component);
+ if (bugged) return;
+ for (ChamberSet ch:chambers) {
+ if (ch.getLeft() != null && ch.getLeft().getProcessor() != null)
+ ch.getLeft().getProcessor().chatReceived(component);
+ if (ch.getRight() != null && ch.getRight().getProcessor() != null)
+ ch.getRight().getProcessor().chatReceived(component);
+ }
+
+ if (component.getFormattedText().contains("$DG-BD ")) {
+ try {
+ String data = component.getFormattedText().substring(component.getFormattedText().indexOf("$DG-BD"));
+ String actual = TextUtils.stripColor(data).trim().split(" ")[1];
+ byte[] data2 = Base64.decodeBase64(actual);
+ NBTTagCompound compound = CompressedStreamTools.readCompressed(new ByteArrayInputStream(data2));
+
+ for (ChamberSet ch:chambers) {
+ if (ch.getLeft() != null && ch.getLeft().getProcessor() != null)
+ ch.getLeft().getProcessor().onDataRecieve(compound);
+ if (ch.getRight() != null && ch.getRight().getProcessor() != null)
+ ch.getRight().getProcessor().onDataRecieve(compound);
+ }
+ } catch (Throwable t) {
+ t.printStackTrace();
+ ChatTransmitter.sendDebugChat(new ChatComponentText("Failed to analyze Bomb Defuse Chat"));
+ }
+ }
+ }
+
+
+ @Override
+ public void tick() {
+ super.tick();
+ if (bugged) return;
+ BlockPos player = Minecraft.getMinecraft().thePlayer.getPosition();
+ OffsetPoint offsetPoint = new OffsetPoint(getDungeonRoom(), new BlockPos(player.getX(), 68, player.getZ()));
+ for (ChamberSet ch:chambers) {
+ if (ch.getLeft() != null && ch.getLeft().getProcessor() != null) {
+ if (ch.getLeft().getChamberBlocks().getOffsetPointList().contains(offsetPoint)) {
+ ch.getLeft().getProcessor().tick();
+ }
+ }
+ if (ch.getRight() != null && ch.getRight().getProcessor() != null) {
+ if (ch.getRight().getChamberBlocks().getOffsetPointList().contains(offsetPoint)) {
+ ch.getRight().getProcessor().tick();
+ }
+ }
+ }
+ }
+
+
+ @Override
+ public void drawScreen(float partialTicks) {
+ super.drawScreen(partialTicks);
+ if (bugged) return;
+ BlockPos player = Minecraft.getMinecraft().thePlayer.getPosition();
+ OffsetPoint offsetPoint = new OffsetPoint(getDungeonRoom(), new BlockPos(player.getX(), 68, player.getZ()));
+ if (FeatureRegistry.DEBUG.isEnabled()) {
+ for (ChamberSet ch : chambers) {
+ if (ch.getChamberGen() == null) continue;
+ if (ch.getLeft() != null && ch.getLeft().getProcessor() != null) {
+ if (ch.getLeft().getChamberBlocks().getOffsetPointList().contains(offsetPoint)) {
+ ch.getLeft().getProcessor().drawScreen(partialTicks);
+
+ FontRenderer fr = Minecraft.getMinecraft().fontRendererObj;
+ String str = "Current: " + ch.getChamberGen().getName() + " Specific: " + ch.getLeft().getProcessor().getName();
+ fr.drawString(str, 0, 0, 0xFFFFFFFF);
+ }
+ }
+ if (ch.getRight() != null && ch.getRight().getProcessor() != null) {
+ if (ch.getRight().getChamberBlocks().getOffsetPointList().contains(offsetPoint)) {
+ ch.getRight().getProcessor().drawScreen(partialTicks);
+
+ FontRenderer fr = Minecraft.getMinecraft().fontRendererObj;
+ if (ch.getChamberGen() == null || ch.getRight().getProcessor() == null) continue;
+ String str = "Current: " + ch.getChamberGen().getName() + " Specific: " + ch.getRight().getProcessor().getName();
+ fr.drawString(str, 0, 0, 0xFFFFFFFF);
+ }
+ }
+ }
+ }
+ }
+
+ @Override
+ public void drawWorld(float partialTicks) {
+ super.drawWorld(partialTicks);
+ if (bugged) return;
+
+ OffsetPoint offsetPoint = new OffsetPoint(getDungeonRoom(), new BlockPos((int)Minecraft.getMinecraft().thePlayer.posX, 68, (int)Minecraft.getMinecraft().thePlayer.posZ));
+ boolean found = false;
+ for (ChamberSet ch:chambers) {
+ if (ch.getLeft() != null && ch.getLeft().getProcessor() != null) {
+ if (ch.getLeft().getChamberBlocks().getOffsetPointList().contains(offsetPoint)) {
+ found = true;
+ ch.getLeft().getProcessor().drawWorld(partialTicks);
+ }
+ }
+ if (ch.getRight() != null && ch.getRight().getProcessor() != null) {
+ if (ch.getRight().getChamberBlocks().getOffsetPointList().contains(offsetPoint)) {
+ found = true;
+ ch.getRight().getProcessor().drawWorld(partialTicks);
+ }
+ }
+ }
+
+ if ((maze || impossible) && warning != null && !found) {
+ if (impossible) {
+ RenderUtils.drawTextAtWorld("Warning: This Bomb Defuse is bugged and Impossible" , warning.getX()+ 0.5f, warning.getY(), warning.getZ()+ 0.5f, 0xFF00FF00, 0.03F, false, false, partialTicks);
+ } else {
+ RenderUtils.drawTextAtWorld("Warning: This Bomb Defuse must be done with 2 people (maze)" , warning.getX()+ 0.5f, warning.getY(), warning.getZ()+ 0.5f, 0xFF00FF00, 0.03F, false, false, partialTicks);
+ }
+ }
+ if (warning != null && !found) {
+ for (int i = 0; i < 4; i++) {
+ BombDefuseChamberGenerator bdcg = chambers.get(i).getChamberGen();
+ RenderUtils.drawTextAtWorld((i + 1) + ". " + (bdcg == null ? "null" : bdcg.getName()), warning.getX() + 0.5f, warning.getY() - ((i + 1) * 0.3f), warning.getZ() + 0.5f, 0xFF00FF00, 0.03F, false, false, partialTicks);
+ }
+ }
+ }
+
+ @Override
+ public void actionbarReceived(IChatComponent chat) {
+ super.actionbarReceived(chat);
+ if (bugged) return;
+
+ for (ChamberSet ch:chambers) {
+ if (ch.getLeft() != null && ch.getLeft().getProcessor() != null)
+ ch.getLeft().getProcessor().actionbarReceived(chat);
+ if (ch.getRight() != null && ch.getRight().getProcessor() != null)
+ ch.getRight().getProcessor().actionbarReceived(chat);
+ }
+ }
+
+ @Override
+ public void onPostGuiRender(GuiScreenEvent.DrawScreenEvent.Post event) {
+ super.onPostGuiRender(event);
+ if (bugged) return;
+
+ BlockPos player = Minecraft.getMinecraft().thePlayer.getPosition();
+ OffsetPoint offsetPoint = new OffsetPoint(getDungeonRoom(), new BlockPos(player.getX(), 68, player.getZ()));
+ for (ChamberSet ch:chambers) {
+ if (ch.getLeft() != null && ch.getLeft().getProcessor() != null) {
+ if (ch.getLeft().getChamberBlocks().getOffsetPointList().contains(offsetPoint)) {
+ ch.getLeft().getProcessor().onPostGuiRender(event);
+ }
+ }
+ if (ch.getRight() != null && ch.getRight().getProcessor() != null) {
+ if (ch.getRight().getChamberBlocks().getOffsetPointList().contains(offsetPoint)) {
+ ch.getRight().getProcessor().onPostGuiRender(event);
+ }
+ }
+ }
+ }
+
+ @Override
+ public void onEntityUpdate(LivingEvent.LivingUpdateEvent updateEvent) {
+ super.onEntityUpdate(updateEvent);
+ if (bugged) return;
+
+ BlockPos player = Minecraft.getMinecraft().thePlayer.getPosition();
+ OffsetPoint offsetPoint = new OffsetPoint(getDungeonRoom(), new BlockPos(player.getX(), 68, player.getZ()));
+ for (ChamberSet ch:chambers) {
+ if (ch.getLeft() != null && ch.getLeft().getProcessor() != null) {
+ if (ch.getLeft().getChamberBlocks().getOffsetPointList().contains(offsetPoint)) {
+ ch.getLeft().getProcessor().onEntityUpdate(updateEvent);
+ }
+ }
+ if (ch.getRight() != null && ch.getRight().getProcessor() != null) {
+// if (ch.getRight().getChamberBlocks().getOffsetPointList().contains(offsetPoint)) {
+ ch.getRight().getProcessor().onEntityUpdate(updateEvent);
+// }
+ }
+ }
+ }
+
+ @Override
+ public void onKeybindPress(KeyBindPressedEvent keyInputEvent) {
+ super.onKeybindPress(keyInputEvent);
+ if (bugged) return;
+
+ BlockPos player = Minecraft.getMinecraft().thePlayer.getPosition();
+ OffsetPoint offsetPoint = new OffsetPoint(getDungeonRoom(), new BlockPos(player.getX(), 68, player.getZ()));
+ for (ChamberSet ch:chambers) {
+ if (ch.getLeft() != null && ch.getLeft().getProcessor() != null) {
+ if (ch.getLeft().getChamberBlocks().getOffsetPointList().contains(offsetPoint)) {
+ ch.getLeft().getProcessor().onKeybindPress(keyInputEvent);
+ }
+ }
+ if (ch.getRight() != null && ch.getRight().getProcessor() != null) {
+ if (ch.getRight().getChamberBlocks().getOffsetPointList().contains(offsetPoint)) {
+ ch.getRight().getProcessor().onKeybindPress(keyInputEvent);
+ }
+ }
+ }
+ }
+
+ @Override
+ public void onInteract(PlayerInteractEntityEvent event) {
+ super.onInteract(event);
+ if (bugged) return;
+
+ BlockPos player = Minecraft.getMinecraft().thePlayer.getPosition();
+ OffsetPoint offsetPoint = new OffsetPoint(getDungeonRoom(), new BlockPos(player.getX(), 68, player.getZ()));
+ for (ChamberSet ch:chambers) {
+ if (ch.getLeft() != null && ch.getLeft().getProcessor() != null) {
+ if (ch.getLeft().getChamberBlocks().getOffsetPointList().contains(offsetPoint)) {
+ ch.getLeft().getProcessor().onInteract(event);
+ }
+ }
+ if (ch.getRight() != null && ch.getRight().getProcessor() != null) {
+ if (ch.getRight().getChamberBlocks().getOffsetPointList().contains(offsetPoint)) {
+ ch.getRight().getProcessor().onInteract(event);
+ }
+ }
+ }
+ }
+
+ @Override
+ public void onInteractBlock(PlayerInteractEvent event) {
+ super.onInteractBlock(event);
+ if (bugged) return;
+
+ BlockPos player = Minecraft.getMinecraft().thePlayer.getPosition();
+ OffsetPoint offsetPoint = new OffsetPoint(getDungeonRoom(), new BlockPos(player.getX(), 68, player.getZ()));
+ for (ChamberSet ch:chambers) {
+ if (ch.getLeft() != null && ch.getLeft().getProcessor() != null) {
+ if (ch.getLeft().getChamberBlocks().getOffsetPointList().contains(offsetPoint)) {
+ ch.getLeft().getProcessor().onInteractBlock(event);
+ }
+ }
+ if (ch.getRight() != null && ch.getRight().getProcessor() != null) {
+ if (ch.getRight().getChamberBlocks().getOffsetPointList().contains(offsetPoint)) {
+ ch.getRight().getProcessor().onInteractBlock(event);
+ }
+ }
+ }
+ }
+
+ @Override public boolean readGlobalChat() { return true; }
+
+ @Data
+ @AllArgsConstructor
+ public static class ChamberSet {
+ private BDChamber left;
+ private BDChamber right;
+ private BombDefuseChamberGenerator chamberGen;
+ }
+
+
+ public static class Generator implements RoomProcessorGenerator<RoomProcessorBombDefuseSolver> {
+ @Override
+ public RoomProcessorBombDefuseSolver createNew(DungeonRoom dungeonRoom) {
+ RoomProcessorBombDefuseSolver defaultRoomProcessor = new RoomProcessorBombDefuseSolver(dungeonRoom);
+ return defaultRoomProcessor;
+ }
+ }
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bombdefuse/chambers/BDChamber.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bombdefuse/chambers/BDChamber.java
new file mode 100644
index 00000000..2dc754b1
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bombdefuse/chambers/BDChamber.java
@@ -0,0 +1,83 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.bombdefuse.chambers;
+
+import com.google.common.base.Predicate;
+import kr.syeyoung.dungeonsguide.mod.DungeonsGuide;
+import kr.syeyoung.dungeonsguide.dungeon.data.OffsetPoint;
+import kr.syeyoung.dungeonsguide.dungeon.data.OffsetPointSet;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomfinder.DungeonRoom;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import net.minecraft.block.state.IBlockState;
+import net.minecraft.entity.Entity;
+import net.minecraft.util.BlockPos;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.List;
+
+@AllArgsConstructor
+@Data
+public class BDChamber {
+ private DungeonRoom room;
+ private OffsetPointSet chamberBlocks;
+
+ private boolean isLeft;
+ private int level;
+
+ private ChamberProcessor processor;
+
+ // for whatever's sake, 6: z, 9: x. Starts from botoom right, left, then up
+
+ public OffsetPoint getOffsetPoint(int x, int z) {
+ return chamberBlocks.getOffsetPointList().get(z * 9 + x);
+ }
+
+ public BlockPos getBlockPos(int x, int y, int z) {
+ return getOffsetPoint(x,z).getBlockPos(room).add(0,y,0);
+ }
+
+ public IBlockState getBlock(int x, int y, int z) {
+ BlockPos pos = getBlockPos(x,y,z);
+ return DungeonsGuide.getDungeonsGuide().getBlockCache().getBlockState(pos);
+ }
+
+ public boolean isWithinAbsolute(int x, int y, int z) {
+ return isWithinAbsolute(new BlockPos(x,68,z));
+ }
+ public boolean isWithinAbsolute(BlockPos pos) {
+ return chamberBlocks.getOffsetPointList().contains(new OffsetPoint(room, new BlockPos(pos.getX(), 68, pos.getZ())));
+ }
+
+
+ public <T extends Entity> T getEntityAt(Class<T> entity, int x, int y, int z) {
+ final BlockPos pos = getBlockPos(x,y,z);
+ return getEntityAt(entity, pos);
+ }
+ public <T extends Entity> T getEntityAt(Class<T> entity, final BlockPos pos) {
+ List<T> entities = room.getContext().getWorld().getEntities(entity, new Predicate<T>() {
+ @Override
+ public boolean apply(@Nullable T input) {
+ return input.getPosition().equals(pos);
+ }
+ });
+ if (entities.size() == 0) return null;
+ return entities.get(0);
+ }
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bombdefuse/chambers/BombDefuseChamberGenerator.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bombdefuse/chambers/BombDefuseChamberGenerator.java
new file mode 100644
index 00000000..8c43ca36
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bombdefuse/chambers/BombDefuseChamberGenerator.java
@@ -0,0 +1,30 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.bombdefuse.chambers;
+
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.bombdefuse.RoomProcessorBombDefuseSolver;
+
+public interface BombDefuseChamberGenerator {
+ boolean match(BDChamber left, BDChamber right);
+
+ String getName();
+
+ ChamberProcessor createLeft(BDChamber left, RoomProcessorBombDefuseSolver solver);
+ ChamberProcessor createRight(BDChamber right, RoomProcessorBombDefuseSolver solver);
+} \ No newline at end of file
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bombdefuse/chambers/ChamberProcessor.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bombdefuse/chambers/ChamberProcessor.java
new file mode 100644
index 00000000..c4d63f42
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bombdefuse/chambers/ChamberProcessor.java
@@ -0,0 +1,27 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.bombdefuse.chambers;
+
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.RoomProcessor;
+import net.minecraft.nbt.NBTTagCompound;
+
+public interface ChamberProcessor extends RoomProcessor {
+ void onDataRecieve(NBTTagCompound compound);
+ String getName();
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bombdefuse/chambers/DummyDefuseChamberProcessor.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bombdefuse/chambers/DummyDefuseChamberProcessor.java
new file mode 100644
index 00000000..d7056dbf
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bombdefuse/chambers/DummyDefuseChamberProcessor.java
@@ -0,0 +1,32 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.bombdefuse.chambers;
+
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.bombdefuse.RoomProcessorBombDefuseSolver;
+
+public class DummyDefuseChamberProcessor extends GeneralDefuseChamberProcessor {
+ public DummyDefuseChamberProcessor(RoomProcessorBombDefuseSolver solver, BDChamber chamber) {
+ super(solver, chamber);
+ }
+
+ @Override
+ public String getName() {
+ return "dummy";
+ }
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bombdefuse/chambers/GeneralDefuseChamberProcessor.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bombdefuse/chambers/GeneralDefuseChamberProcessor.java
new file mode 100644
index 00000000..0040bc4f
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bombdefuse/chambers/GeneralDefuseChamberProcessor.java
@@ -0,0 +1,137 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.bombdefuse.chambers;
+
+import kr.syeyoung.dungeonsguide.mod.events.impl.BlockUpdateEvent;
+import kr.syeyoung.dungeonsguide.mod.events.impl.KeyBindPressedEvent;
+import kr.syeyoung.dungeonsguide.mod.events.impl.PlayerInteractEntityEvent;
+import kr.syeyoung.dungeonsguide.mod.features.FeatureRegistry;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.bombdefuse.RoomProcessorBombDefuseSolver;
+import lombok.Getter;
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.gui.FontRenderer;
+import net.minecraft.client.gui.ScaledResolution;
+import net.minecraft.client.renderer.GlStateManager;
+import net.minecraft.client.settings.GameSettings;
+import net.minecraft.nbt.NBTTagCompound;
+import net.minecraft.util.IChatComponent;
+import net.minecraftforge.client.event.GuiScreenEvent;
+import net.minecraftforge.event.entity.living.LivingDeathEvent;
+import net.minecraftforge.event.entity.living.LivingEvent;
+import net.minecraftforge.event.entity.player.PlayerInteractEvent;
+import org.lwjgl.opengl.GL11;
+import org.lwjgl.opengl.GL14;
+
+@Getter
+public abstract class GeneralDefuseChamberProcessor implements ChamberProcessor{
+ private final RoomProcessorBombDefuseSolver solver;
+ private final BDChamber chamber;
+
+ public GeneralDefuseChamberProcessor(RoomProcessorBombDefuseSolver solver, BDChamber chamber) {
+ this.solver = solver;
+ this.chamber = chamber;
+ }
+
+
+ @Override
+ public void onDataRecieve(NBTTagCompound compound) {
+
+ }
+
+ @Override
+ public void tick() {
+
+ }
+
+ @Override
+ public void drawScreen(float partialTicks) {
+
+ }
+
+ @Override
+ public void drawWorld(float partialTicks) {
+
+ }
+
+ @Override
+ public void chatReceived(IChatComponent chat) {
+
+ }
+
+ @Override
+ public void onEntityDeath(LivingDeathEvent deathEvent) {
+
+ }
+
+ @Override
+ public void actionbarReceived(IChatComponent chat) {
+
+ }
+ @Override
+ public void onBlockUpdate(BlockUpdateEvent blockUpdateEvent) {
+
+ }
+
+ @Override
+ public boolean readGlobalChat() {
+ return false;
+ }
+
+ @Override
+ public void onPostGuiRender(GuiScreenEvent.DrawScreenEvent.Post event) {
+
+ }
+
+ @Override
+ public void onEntityUpdate(LivingEvent.LivingUpdateEvent updateEvent) {
+
+ }
+
+ protected void drawPressKey() {
+ FontRenderer fr = Minecraft.getMinecraft().fontRendererObj;
+ ScaledResolution sr = new ScaledResolution(Minecraft.getMinecraft());
+ String str = "Press "+ GameSettings.getKeyDisplayString(FeatureRegistry.SOLVER_BOMBDEFUSE.<Integer>getParameter("key").getValue()) + " to save and send solution";
+ GlStateManager.enableBlend();
+ GL14.glBlendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA);
+ GlStateManager.tryBlendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA);
+ fr.drawString(str, (sr.getScaledWidth() - fr.getStringWidth(str)) / 2, (sr.getScaledHeight() - fr.FONT_HEIGHT) / 2, 0xFFFFFFFF);
+ }
+
+ @Override
+ public void onKeybindPress(KeyBindPressedEvent keyInputEvent) {
+ if (keyInputEvent.getKey() == FeatureRegistry.SOLVER_BOMBDEFUSE.<Integer>getParameter("key").getValue()) {
+ if (!getChamber().isWithinAbsolute(Minecraft.getMinecraft().thePlayer.getPosition())) {
+ return;
+ }
+ onSendData();
+ }
+ }
+
+ @Override
+ public void onInteract(PlayerInteractEntityEvent event) {
+
+ }
+
+ @Override
+ public void onInteractBlock(PlayerInteractEvent event) {
+
+ }
+
+ public void onSendData() {}
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bombdefuse/chambers/arrow/ArrowLeftProcessor.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bombdefuse/chambers/arrow/ArrowLeftProcessor.java
new file mode 100644
index 00000000..94b4f78d
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bombdefuse/chambers/arrow/ArrowLeftProcessor.java
@@ -0,0 +1,138 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.bombdefuse.chambers.arrow;
+
+import com.google.common.collect.BiMap;
+import com.google.common.collect.HashBiMap;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.bombdefuse.RoomProcessorBombDefuseSolver;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.bombdefuse.chambers.BDChamber;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.bombdefuse.chambers.GeneralDefuseChamberProcessor;
+import kr.syeyoung.dungeonsguide.mod.utils.RenderUtils;
+import net.minecraft.entity.item.EntityArmorStand;
+import net.minecraft.item.ItemStack;
+import net.minecraft.nbt.NBTTagCompound;
+import net.minecraft.nbt.NBTTagList;
+import net.minecraft.util.BlockPos;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class ArrowLeftProcessor extends GeneralDefuseChamberProcessor {
+ public ArrowLeftProcessor(RoomProcessorBombDefuseSolver solver, BDChamber chamber) {
+ super(solver, chamber);
+
+ for (int i = 0; i < 9; i++) {
+ grid[i] = chamber.getBlockPos(7,1 + (i / 3),1 + (i % 3));
+ }
+ }
+
+ @Override
+ public String getName() {
+ return "arrowLeft";
+ }
+
+
+ private int answer = -1;
+ private final int[] answers = new int[9];
+ private final BlockPos[] grid = new BlockPos[9];
+ @Override
+ public void tick() {
+ super.tick();
+ if (answer != -1) return;
+ for (int i = 0; i < 9; i++)
+ answers[i] = match(getChamber().getEntityAt(EntityArmorStand.class, grid[i].add(0, -1, 0)));
+
+ answer = 0;
+ for (int i =0; i < 9; i++) {
+ answer = answer * 10 + answers[i];
+ }
+ }
+
+ @Override
+ public void drawScreen(float partialTicks) {
+ if (answer == -1) return;
+ drawPressKey();
+ }
+
+ @Override
+ public void drawWorld(float partialTicks) {
+ super.drawWorld(partialTicks);
+
+ if (answer == -1) return;
+ for (int i = 0; i < 9; i++) {
+ BlockPos pos = grid[i];
+ int direction = answers[i];
+ String charac = arrows.get(direction);
+
+ RenderUtils.drawTextAtWorld(charac, pos.getX()+ 0.5f, pos.getY()+ 0.5f, pos.getZ()+ 0.5f, 0xFFFFFFFF, 0.05F, false, false, partialTicks);
+ }
+ }
+
+ @Override
+ public void onSendData() {
+ if (answer == -1) return;
+ NBTTagCompound nbt = new NBTTagCompound();
+ nbt.setByte("a", (byte) 3);
+ nbt.setInteger("b", answer);
+ getSolver().communicate(nbt);
+ }
+
+ @Override
+ public void onDataRecieve(NBTTagCompound compound) {
+ if (3 == compound.getByte("a")) {
+ answer = compound.getInteger("b");
+ for (int i = 8; i >= 0; i--) {
+ answers[i] = answer % 10;
+ answer = answer / 10;
+ }
+ answer = compound.getInteger("b");
+ }
+ }
+
+ private int match(EntityArmorStand armorStand) {
+ if (armorStand == null) return -1;
+ ItemStack item = armorStand.getInventory()[4];
+ NBTTagList list = item.getTagCompound().getCompoundTag("SkullOwner").getCompoundTag("Properties").getTagList("textures", 10);
+ String str = ((NBTTagCompound)list.get(0)).getString("Value");
+ return !integers.containsKey(str) ? -1 : integers.get(str);
+ }
+
+ private static final BiMap<String, Integer> integers = HashBiMap.create(8);
+ private static final Map<Integer, String> arrows = new HashMap<Integer, String>();
+ {
+ integers.put("eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNDczZTFmZTBmZmNkNTQ2YzIxYjYzZWFhOTEwYWI1YzkzMTMyYTY0ZTY0NDE3OWZjY2FhMjFkYzhiYzY2MCJ9fX0=", 1);
+ integers.put("eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNThmZTI1MWE0MGU0MTY3ZDM1ZDA4MWMyNzg2OWFjMTUxYWY5NmI2YmQxNmRkMjgzNGQ1ZGM3MjM1ZjQ3NzkxZCJ9fX0=", 2);
+ integers.put("eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNTc3ZWM0NGZiNzUwM2RlNmFmZTNiZGQ3ZTU4M2M3YjkzOTc5ZjU5ZjZkNjM0YjZiNmE1YWY3ZjNhMWM1ODUxNSJ9fX0=", 3);
+ integers.put("eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZjJmM2EyZGZjZTBjM2RhYjdlZTEwZGIzODVlNTIyOWYxYTM5NTM0YThiYTI2NDYxNzhlMzdjNGZhOTNiIn19fQ==", 4);
+ integers.put("eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOGUxY2U5YzBkMzMyMzZmOTkyMWQyMmM0ZWM0YmY1MDkyMzdhZWY2NzZiNWQxZDJiYWNjOTNmNWE4MTk0ODAifX19", 5);
+ integers.put("eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOWI3Y2U2ODNkMDg2OGFhNDM3OGFlYjYwY2FhNWVhODA1OTZiY2ZmZGFiNmI1YWYyZDEyNTk1ODM3YTg0ODUzIn19fQ==", 6);
+ integers.put("eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNTI2NTFlY2QzNzgwY2Y2ZTQ1MWVjYWNjZGVlNjk3MTVjMDhjYWU3Y2Q0NTA5MDg0NDYyY2RjZDk2M2E2YjMyMiJ9fX0=", 7);
+ integers.put("eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYmIwZjZlOGFmNDZhYzZmYWY4ODkxNDE5MWFiNjZmMjYxZDY3MjZhNzk5OWM2MzdjZjJlNDE1OWZlMWZjNDc3In19fQ==", 8);
+
+ arrows.put(0, "?");
+ arrows.put(1, "↖");
+ arrows.put(2, "↑");
+ arrows.put(3, "↗");
+ arrows.put(4, "→");
+ arrows.put(5, "↘");
+ arrows.put(6, "↓");
+ arrows.put(7, "↙");
+ arrows.put(8, "←");
+ }
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bombdefuse/chambers/arrow/ArrowProcessorMatcher.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bombdefuse/chambers/arrow/ArrowProcessorMatcher.java
new file mode 100644
index 00000000..82a972b2
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bombdefuse/chambers/arrow/ArrowProcessorMatcher.java
@@ -0,0 +1,52 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.bombdefuse.chambers.arrow;
+
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.bombdefuse.RoomProcessorBombDefuseSolver;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.bombdefuse.chambers.BDChamber;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.bombdefuse.chambers.BombDefuseChamberGenerator;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.bombdefuse.chambers.ChamberProcessor;
+import net.minecraft.init.Blocks;
+
+public class ArrowProcessorMatcher implements BombDefuseChamberGenerator {
+ @Override
+ public boolean match(BDChamber left, BDChamber right) {
+ return left.getBlock(8,1,1).getBlock() == Blocks.planks &&
+ left.getBlock(8,1,2).getBlock() == Blocks.planks &&
+ left.getBlock(8,1,3).getBlock() == Blocks.planks &&
+ right.getBlock(0,1,1).getBlock() == Blocks.planks &&
+ right.getBlock(0,1,2).getBlock() == Blocks.planks &&
+ right.getBlock(0,1,3).getBlock() == Blocks.planks;
+ }
+
+ @Override
+ public String getName() {
+ return "arrowMatch";
+ }
+
+ @Override
+ public ChamberProcessor createLeft(BDChamber left, RoomProcessorBombDefuseSolver solver) {
+ return new ArrowLeftProcessor(solver, left);
+ }
+
+ @Override
+ public ChamberProcessor createRight(BDChamber right, RoomProcessorBombDefuseSolver solver) {
+ return new ArrowRightProcessor(solver, right);
+ }
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bombdefuse/chambers/arrow/ArrowRightProcessor.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bombdefuse/chambers/arrow/ArrowRightProcessor.java
new file mode 100644
index 00000000..9c293bc7
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bombdefuse/chambers/arrow/ArrowRightProcessor.java
@@ -0,0 +1,126 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.bombdefuse.chambers.arrow;
+
+import com.google.common.collect.BiMap;
+import com.google.common.collect.HashBiMap;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.bombdefuse.RoomProcessorBombDefuseSolver;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.bombdefuse.chambers.BDChamber;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.bombdefuse.chambers.GeneralDefuseChamberProcessor;
+import kr.syeyoung.dungeonsguide.mod.utils.RenderUtils;
+import net.minecraft.entity.item.EntityArmorStand;
+import net.minecraft.item.ItemStack;
+import net.minecraft.nbt.NBTTagCompound;
+import net.minecraft.nbt.NBTTagList;
+import net.minecraft.util.BlockPos;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class ArrowRightProcessor extends GeneralDefuseChamberProcessor {
+ public ArrowRightProcessor(RoomProcessorBombDefuseSolver solver, BDChamber chamber) {
+ super(solver, chamber);
+
+ for (int i = 0; i < 9; i++) {
+ grid[i] = chamber.getBlockPos(1,1 + (i / 3),1 + (2 - (i % 3)));
+ }
+
+ center = chamber.getBlockPos(4,4,4);
+ }
+
+ @Override
+ public String getName() {
+ return "arrowRight";
+ }
+
+
+ private int answer = -1;
+ private final int[] correctAnswers = new int[9];
+ private final int[] currentAnswers = new int[9];
+ private final BlockPos[] grid = new BlockPos[9];
+ private final BlockPos center;
+ @Override
+ public void tick() {
+ super.tick();
+ for (int i = 0; i < 9; i++)
+ currentAnswers[i] = match(getChamber().getEntityAt(EntityArmorStand.class, grid[i].add(0, -1, 0)));
+ }
+
+ @Override
+ public void drawWorld(float partialTicks) {
+ super.drawWorld(partialTicks);
+
+ RenderUtils.drawTextAtWorld(answer == -1 ? "Answer not received yet. Visit left room to obtain solution" : "" , center.getX()+ 0.5f, center.getY(), center.getZ()+ 0.5f, 0xFFFFFFFF, 0.03F, false, false, partialTicks);
+
+ for (int i = 0; i < 9; i++) {
+ BlockPos pos = grid[i];
+ int direction = correctAnswers[i];
+ int direction2 = currentAnswers[i];
+ String charac = arrows.get(direction);
+ String car2 = arrows.get(direction2);
+
+ RenderUtils.drawTextAtWorld(car2, pos.getX()+ 0.5f, pos.getY()+ 0.6f, pos.getZ()+ 0.5f, direction == direction2 ? 0xFF00FF00 : 0xFFFF0000, 0.03F, false, false, partialTicks);
+ RenderUtils.drawTextAtWorld(charac, pos.getX()+ 0.5f, pos.getY()+ 0.2f, pos.getZ()+ 0.5f, 0xFFFFFF00, 0.03F, false, false, partialTicks);
+ }
+ }
+
+ @Override
+ public void onDataRecieve(NBTTagCompound compound) {
+ if (3 == compound.getByte("a")) {
+ answer = compound.getInteger("b");
+ for (int i = 8; i >= 0; i--) {
+ correctAnswers[i] = answer % 10;
+ answer = answer / 10;
+ }
+ answer = compound.getInteger("b");
+ }
+ }
+
+ private int match(EntityArmorStand armorStand) {
+ if (armorStand == null) return -1;
+ ItemStack item = armorStand.getInventory()[4];
+ NBTTagList list = item.getTagCompound().getCompoundTag("SkullOwner").getCompoundTag("Properties").getTagList("textures", 10);
+ String str = ((NBTTagCompound)list.get(0)).getString("Value");
+ return !integers.containsKey(str) ? -1 : integers.get(str);
+ }
+
+ private static final BiMap<String, Integer> integers = HashBiMap.create(8);
+ private static final Map<Integer, String> arrows = new HashMap<Integer, String>();
+ {
+ integers.put("eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvODY1NDI2YTMzZGY1OGI0NjVmMDYwMWRkOGI5YmVjMzY5MGIyMTkzZDFmOTUwM2MyY2FhYjc4ZjZjMjQzOCJ9fX0=", 1);
+ integers.put("eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMzA0MGZlODM2YTZjMmZiZDJjN2E5YzhlYzZiZTUxNzRmZGRmMWFjMjBmNTVlMzY2MTU2ZmE1ZjcxMmUxMCJ9fX0=", 2);
+ integers.put("eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOTBlMGE0ZDQ4Y2Q4MjlhNmQ1ODY4OTA5ZDY0M2ZhNGFmZmQzOWU4YWU2Y2FhZjZlYzc5NjA5Y2Y3NjQ5YjFjIn19fQ==", 3);
+ integers.put("eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMTliZjMyOTJlMTI2YTEwNWI1NGViYTcxM2FhMWIxNTJkNTQxYTFkODkzODgyOWM1NjM2NGQxNzhlZDIyYmYifX19", 4);
+ integers.put("eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMzVjYmRiMjg5OTFhMTZlYjJjNzkzNDc0ZWY3ZDBmNDU4YTVkMTNmZmZjMjgzYzRkNzRkOTI5OTQxYmIxOTg5In19fQ==", 5);
+ integers.put("eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNzQzNzM0NmQ4YmRhNzhkNTI1ZDE5ZjU0MGE5NWU0ZTc5ZGFlZGE3OTVjYmM1YTEzMjU2MjM2MzEyY2YifX19", 6);
+ integers.put("eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMzU0Y2U4MTU3ZTcxZGNkNWI2YjE2NzRhYzViZDU1NDkwNzAyMDI3YzY3NWU1Y2RjZWFjNTVkMmZiYmQ1YSJ9fX0=", 7);
+ integers.put("eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYmQ2OWUwNmU1ZGFkZmQ4NGU1ZjNkMWMyMTA2M2YyNTUzYjJmYTk0NWVlMWQ0ZDcxNTJmZGM1NDI1YmMxMmE5In19fQ==", 8);
+
+
+ arrows.put(0, "?");
+ arrows.put(1, "↖");
+ arrows.put(2, "↑");
+ arrows.put(3, "↗");
+ arrows.put(4, "→");
+ arrows.put(5, "↘");
+ arrows.put(6, "↓");
+ arrows.put(7, "↙");
+ arrows.put(8, "←");
+ }
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bombdefuse/chambers/bugged/ImpossibleMatcher.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bombdefuse/chambers/bugged/ImpossibleMatcher.java
new file mode 100644
index 00000000..42a00119
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bombdefuse/chambers/bugged/ImpossibleMatcher.java
@@ -0,0 +1,47 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.bombdefuse.chambers.bugged;
+
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.bombdefuse.RoomProcessorBombDefuseSolver;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.bombdefuse.chambers.BDChamber;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.bombdefuse.chambers.BombDefuseChamberGenerator;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.bombdefuse.chambers.ChamberProcessor;
+import net.minecraft.init.Blocks;
+
+public class ImpossibleMatcher implements BombDefuseChamberGenerator {
+ @Override
+ public boolean match(BDChamber left, BDChamber right) {
+ return left.getBlock(1,1,1).getBlock() == Blocks.barrier;
+ }
+
+ @Override
+ public String getName() {
+ return "buggedMazeMatcher";
+ }
+
+ @Override
+ public ChamberProcessor createLeft(BDChamber left, RoomProcessorBombDefuseSolver solver) {
+ return null;
+ }
+
+ @Override
+ public ChamberProcessor createRight(BDChamber right, RoomProcessorBombDefuseSolver solver) {
+ return null;
+ }
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bombdefuse/chambers/color/ColorLeftProcessor.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bombdefuse/chambers/color/ColorLeftProcessor.java
new file mode 100644
index 00000000..e0291d00
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bombdefuse/chambers/color/ColorLeftProcessor.java
@@ -0,0 +1,230 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.bombdefuse.chambers.color;
+
+import com.google.common.collect.BiMap;
+import com.google.common.collect.HashBiMap;
+import kr.syeyoung.dungeonsguide.mod.features.FeatureRegistry;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.bombdefuse.RoomProcessorBombDefuseSolver;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.bombdefuse.chambers.BDChamber;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.bombdefuse.chambers.GeneralDefuseChamberProcessor;
+import kr.syeyoung.dungeonsguide.mod.utils.RenderUtils;
+import net.minecraft.block.Block;
+import net.minecraft.entity.item.EntityArmorStand;
+import net.minecraft.item.ItemStack;
+import net.minecraft.nbt.NBTTagCompound;
+import net.minecraft.nbt.NBTTagList;
+import net.minecraft.util.BlockPos;
+import net.minecraft.world.World;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class ColorLeftProcessor extends GeneralDefuseChamberProcessor {
+ public ColorLeftProcessor(RoomProcessorBombDefuseSolver solver, BDChamber chamber) {
+ super(solver, chamber);
+ center = chamber.getBlockPos(4,6,4);
+ b1p = chamber.getBlockPos(1,1,4);
+ b2p = chamber.getBlockPos(4,1,4);
+ b3p = chamber.getBlockPos(7,1,4);
+ }
+
+ private final BlockPos center;
+
+ private Block w1, w2, w3, c1, c2, c3;
+ private final BlockPos b1p;
+ private final BlockPos b2p;
+ private final BlockPos b3p;
+ private int s1, s2, s3;
+ private int s1t, s2t, s3t;
+ private boolean solutionBuilt;
+
+ @Override
+ public String getName() {
+ return "colorRight";
+ }
+
+ @Override
+ public void tick() {
+ super.tick();
+ if (solutionBuilt) return;
+ World w = getChamber().getRoom().getContext().getWorld();
+ if ((c1 = w.getBlockState(b1p).getBlock()) == w1 && s1t < 7) {
+ int semi = match(getChamber().getEntityAt(EntityArmorStand.class,b1p.add(0, 1, 0)));
+ if (s1 == semi) {
+ s1t++;
+ } else {
+ s1 = semi;
+ s1t = 0;
+ }
+ }
+ if ((c2 = w.getBlockState(b2p).getBlock()) == w2 && s2t < 7) {
+ int semi = match(getChamber().getEntityAt(EntityArmorStand.class,b2p.add(0, 2, 0)));
+ if (s2 == semi) {
+ s2t++;
+ } else {
+ s2 = semi;
+ s2t = 0;
+ }
+ }
+ if ((c3 =w.getBlockState(b3p).getBlock()) == w3 && s3t < 7) {
+ int semi = match(getChamber().getEntityAt(EntityArmorStand.class,b3p.add(0, 1, 0)));
+ if (s3== semi) {
+ s3t++;
+ } else {
+ s3 = semi;
+ s3t = 0;
+ }
+ }
+
+ if (s1t > 5 && s2t > 5 && s3t > 5) {
+ solutionBuilt = true;
+ }
+ }
+
+ @Override
+ public void drawScreen(float partialTicks) {
+ super.drawScreen(partialTicks);
+ if (solutionBuilt)
+ drawPressKey();
+ }
+
+ @Override
+ public void drawWorld(float partialTicks) {
+ super.drawWorld(partialTicks);
+ RenderUtils.drawTextAtWorld(w1 == null ? "Request Not Received Yet" : "Building- "+w1.getLocalizedName() +" / "+w2.getLocalizedName() +" / "+w3.getLocalizedName() , center.getX()+ 0.5f, center.getY(), center.getZ()+ 0.5f, 0xFFFFFFFF, 0.03F, false, false, partialTicks);
+
+ RenderUtils.drawTextAtWorld(w1 == null ? "null" : w1.getLocalizedName(), b1p.getX()+ 0.5f, b1p.getY() + 0.2f, b1p.getZ()+ 0.5f, 0xFFFFFFFF, 0.03F, false, false, partialTicks);
+ RenderUtils.drawTextAtWorld(w2 == null ? "null" : w2.getLocalizedName(), b2p.getX()+ 0.5f, b2p.getY() + 0.2f, b2p.getZ()+ 0.5f, 0xFFFFFFFF, 0.03F, false, false, partialTicks);
+ RenderUtils.drawTextAtWorld(w3 == null ? "null" : w3.getLocalizedName(), b3p.getX()+ 0.5f, b3p.getY() + 0.2f, b3p.getZ()+ 0.5f, 0xFFFFFFFF, 0.03F, false, false, partialTicks);
+ RenderUtils.drawTextAtWorld(c1 == null ? "null" : c1.getLocalizedName(), b1p.getX()+ 0.5f, b1p.getY() + 0.6f, b1p.getZ()+ 0.5f, 0xFFFFFFFF, 0.03F, false, false, partialTicks);
+ RenderUtils.drawTextAtWorld(c2 == null ? "null" : c2.getLocalizedName(), b2p.getX()+ 0.5f, b2p.getY() + 0.6f, b2p.getZ()+ 0.5f, 0xFFFFFFFF, 0.03F, false, false, partialTicks);
+ RenderUtils.drawTextAtWorld(c3 == null ? "null" : c3.getLocalizedName(), b3p.getX()+ 0.5f, b3p.getY() + 0.6f, b3p.getZ()+ 0.5f, 0xFFFFFFFF, 0.03F, false, false, partialTicks);
+
+ if (FeatureRegistry.DEBUG.isEnabled()) {
+ RenderUtils.drawTextAtWorld(s1 + "", b1p.getX() + 0.5f, b1p.getY() + 2.6f, b1p.getZ() + 0.5f, 0xFFFFFFFF, 0.03F, false, false, partialTicks);
+ RenderUtils.drawTextAtWorld(s2 + "", b2p.getX() + 0.5f, b2p.getY() + 3.6f, b2p.getZ() + 0.5f, 0xFFFFFFFF, 0.03F, false, false, partialTicks);
+ RenderUtils.drawTextAtWorld(s3 + "", b3p.getX() + 0.5f, b3p.getY() + 2.6f, b3p.getZ() + 0.5f, 0xFFFFFFFF, 0.03F, false, false, partialTicks);
+ }
+
+ RenderUtils.drawTextAtWorld(colors.get(s1), b1p.getX()+ 0.5f, b1p.getY() + 2.2f, b1p.getZ()+ 0.5f, 0xFFFFFFFF, 0.03F, false, false, partialTicks);
+ RenderUtils.drawTextAtWorld(colors.get(s2), b2p.getX()+ 0.5f, b2p.getY() + 3.2f, b2p.getZ()+ 0.5f, 0xFFFFFFFF, 0.03F, false, false, partialTicks);
+ RenderUtils.drawTextAtWorld(colors.get(s3), b3p.getX()+ 0.5f, b3p.getY() + 2.2f, b3p.getZ()+ 0.5f, 0xFFFFFFFF, 0.03F, false, false, partialTicks);
+
+ if (FeatureRegistry.DEBUG.isEnabled()) {
+ RenderUtils.drawTextAtWorld(s1t + "", b1p.getX() + 0.5f, b1p.getY() + 1.5f, b1p.getZ() + 0.5f, 0xFFFFFFFF, 0.03F, false, false, partialTicks);
+ RenderUtils.drawTextAtWorld(s2t + "", b2p.getX() + 0.5f, b2p.getY() + 2f, b2p.getZ() + 0.5f, 0xFFFFFFFF, 0.03F, false, false, partialTicks);
+ RenderUtils.drawTextAtWorld(s3t + "", b3p.getX() + 0.5f, b3p.getY() + 1.5f, b3p.getZ() + 0.5f, 0xFFFFFFFF, 0.03F, false, false, partialTicks);
+ }
+ }
+
+ @Override
+ public void onSendData() {
+ super.onSendData();
+ if (!solutionBuilt) return;
+ NBTTagCompound nbt = new NBTTagCompound();
+ nbt.setByte("a", (byte) 7);
+ int answer = s1 * 10000 + s2 * 100 + s3;
+ nbt.setInteger("b", answer);
+ getSolver().communicate(nbt);
+ }
+
+ @Override
+ public void onDataRecieve(NBTTagCompound compound) {
+ if (6 == compound.getByte("a")) {
+ w1 = Block.getBlockById(compound.getByte("f"));
+ w2 = Block.getBlockById(compound.getByte("s"));
+ w3 = Block.getBlockById(compound.getByte("t"));
+ solutionBuilt = false;
+ s1 = s2 = s3 = s1t = s2t = s3t =0;
+ }
+ }
+
+ private byte match(EntityArmorStand armorStand) {
+ if (armorStand == null) {
+ return 0;
+ }
+ ItemStack item = armorStand.getInventory()[4];
+ NBTTagList list = item.getTagCompound().getCompoundTag("SkullOwner").getCompoundTag("Properties").getTagList("textures", 10);
+ String str = ((NBTTagCompound)list.get(0)).getString("Value");
+ return (byte) (!integers.containsKey(str) ? 0 : integers.get(str));
+ }
+
+ private static final Map<String, Integer> integers = new HashMap<String, Integer>();
+ private static final BiMap<Integer, String> colors = HashBiMap.create();
+ static {
+ colors.put(0, "?");
+ integers.put("eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvM2YzZTQwNjI5MTE3NGQyNGNkZjBmOTUzZjhhMTc0YTgyYmIzNDg5ZGNlOGY2NzlhNDQzZWYxYWFlMDE2OTA2MSJ9fX0=", 1);
+ integers.put("eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZWE4MWZjYjUxYmUyYTlmODliMWFkYzlkODcyMzliYTQyOWQ2MzVmYmUwMWIzN2VjMzI5MTY0ODg3YmY2NjViIn19fQ==", 1);
+ colors.put(1, "blue");
+ integers.put("eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvM2FiMDI2M2JkZDc2ZjNlNDE4ZGJhNWJmNDgxYjkyMWNlZDM5N2Q4YjhhMzRhNTU2MWZiN2JlYWE0NmVjZTEifX19", 2);
+ integers.put("eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvY2ZhNGRkYTZkMTlhMWZlMmQ5ODhkNjVkZWM1MzQyOTUwNTMwODE2NmM5MDY3YjY4YTQ3NzBjYTVjNDM2Y2Y5NCJ9fX0=", 2);
+ colors.put(2, "black");
+ integers.put("eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNDg0Njg0MzQ0YWUwOTg1MjlmYzk0MWFhODRlMTk1YmRjYTM3NDhkNjlhY2ZlZTJiYWMxMzMyMTM1ZWRkOThjIn19fQ==", 3);
+ integers.put("eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNTM1ODFjMmY5Y2YzNThkN2VkYzc4ZGQ2ZmQ0YjYyNTc1MDFiYzRlNjQ1NWUzM2ZhMGNhYWUyMDdjZjAzMjFhMiJ9fX0=", 3);
+ colors.put(3, "green");
+ integers.put("eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZTllNjkxN2YyZmI0ZWEwOGU3MTMyZGYzMDk2MWQyYjVjNTIzYWJiYTE5Y2U0M2Y4MzVmYzE0YzU2OGY0In19fQ==", 4);
+ integers.put("eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYWRmMjFmNTMyMTIyNTY2YWY4OTNkYTI3ODgwYTFiNjA5NWMzNTcxMmYyOWEzNzhjZmVjYzdmZTJiMTMyOGFiNCJ9fX0=", 4);
+ colors.put(4, "gray");
+ integers.put("eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvODhlZmFkNzRiMjU0ZTU3Yzc5OTc2M2RjZWVlNDUxMWZhMmY4NWFlOWZhNTU2ZWFhOTdkNDViZjY3ZTBiNmIzIn19fQ==", 5);
+ integers.put("eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMWZhZGY3NDFhYjc2Y2QzNjIwYWQxNjEzMDAyMDJkN2I1OWEzMzA1MWU1OTY3ZTRiNjE5NGJhYzQwYmIyODBmZiJ9fX0=", 5);
+ colors.put(5, "cyan");
+ integers.put("eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMzJlMzZmNmE2NTRkZTc0NTgzZDgwMzAxNzdhZDZlM2FjNjc1NWQ3NDM1ZDkxMjNlOGViZGZmNzRiMmQ5MGNiIn19fQ==", 6);
+ integers.put("eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMjJjYmQ5ZjQzNjE5YWI1Y2IxYjExZjkxY2IwM2U5NTVjNmZjNmM0NThhYmY4OWFiNjEwMzEzNDZhMDkwNjEyZSJ9fX0=", 6);
+ colors.put(6, "brown");
+ integers.put("eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZjFhZjQ2ZmViZDQ1YzBmNGQ4MWU4ZmExYjY2YjI3NWQ4OWUyNzJiMmFkNTVjOTc4NTUzYTk5YzczM2UxZmYifX19", 7);
+ integers.put("eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMTYzZTY2NDZmMWMwZDQxZmQzYmY1NTg0YTFjZTA0NGY1YzQ2ZDU5ODI1OGRiNDYyMTYxMTc4NTlmNTdhZjE5NyJ9fX0=", 7);
+ colors.put(7, "light-blue");
+ integers.put("eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZDY3NDcwYTBjMThmNjg1MWU5MTQzNTM3MTllNzk1ODc3ZDI5YjMyNTJmN2U2YmQ0YTFiODY1NzY1YmQ3NGZlYiJ9fX0=", 8);
+ integers.put("eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNzc0NzJkNjA4ODIxZjQ1YTg4MDUzNzZlYzBjNmZmY2I3ODExNzgyOWVhNWY5NjAwNDFjMmEwOWQxMGUwNGNiNCJ9fX0=", 8);
+ colors.put(8, "lime");
+ integers.put("eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYWJiNDM4NmJjZGE4NGUzNTNjMzFkNzc4ZDNiMTFiY2QyNmZlYTQ5NGRkNjM0OTZiOGE4MmM3Yzc4YTRhZCJ9fX0=", 9);
+ integers.put("eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZjk3MDEyZWQ2YTkyYjA1ZWEwZjE5NDk1MDc0ODU0NGUwNzViYWEyODc4MWNhMzczZDFiMjdlMjhjMjY5NTNjIn19fQ==", 9);
+ colors.put(9, "magenta");
+ integers.put("eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvY2JmNzc5N2EyNGE2YWY4NzVmNWM4MjcxYzViOGM0MjVlMTlmMzcyYTQxNWUwNTUyZmMyNDc3NjNmMjg1OWQxIn19fQ==", 10);
+ integers.put("eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYWRmMmViMjA1YTIzYzExOTZiM2VjZjIxZTY4YzA3NmI2OTZlNzYxNjNhYzhmYzRmYjlmNTMxOGMyYTVlNWIxYSJ9fX0=", 10);
+ colors.put(10, "orange");
+ integers.put("eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNmJlY2ZiMzg3OTkzNmI4OTllNDIwYmZjZDNhNzRmOGExYmY5ZGQ1NGM1OGVjN2ZiOWY4MWQ5YTVkOTg4ZSJ9fX0=", 11);
+ integers.put("eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZDA4ODM2NTBlYTkyOWRiMGVhYmRmNWJjNzU1OTlkOGVmMDBkNzAzNDBjZDFjZTVlMDRhZDk1ZWY4ZWQ4M2I3MyJ9fX0=", 11);
+ colors.put(11, "pink");
+ integers.put("eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYmE5NGNiMjVkZTYyOGNhMzU5YjJmNmVhNWE4ODY4Y2JlMjY1OTVlZWRiMmJmZmI3NTA5NjdhZDFlZTE4NTAifX19", 12);
+ integers.put("eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvODllYzVhMzAyMjJkMDY1OWIwZGJlZTg0NGI4ZjUzZWFlNjJmZTk1YjRhMzQ0OGE5ZWY3OTBhN2FlZGIyOTZkOSJ9fX0=", 12);
+ colors.put(12, "purple");
+ integers.put("eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvODZkMzVhOTYzZDU5ODc4OTRiNmJjMjE0ZTMyOGIzOWNkMjM4MjQyNmZmOWM4ZTA4MmIwYjZhNmUwNDRkM2EzIn19fQ==", 13);
+ integers.put("eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNjk1M2IxMmEwOTQ2YjYyOWI0YzA4ODlkNDFmZDI2ZWQyNmZiNzI5ZDRkNTE0YjU5NzI3MTI0YzM3YmI3MGQ4ZCJ9fX0=", 13);
+ colors.put(13, "red");
+ integers.put("eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOTk4YmEyYjM3NGNmYzg5NDU0YzFiOGMzMmRiNDU4YTI3MDY3NTQzOWE0OTU0OTZjOTY3NzFjOTg5MTE2MTYyIn19fQ==", 14);
+ integers.put("eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNTUyODhkZGM5MTFhNzVmNzdjM2E1ZDMzNjM2NWE4ZjhiMTM5ZmE1MzkzMGI0YjZlZTEzOTg3NWM4MGNlMzY2YyJ9fX0=", 14);
+ colors.put(14, "light-gray");
+ integers.put("eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvM2ZhZjRjMjlmMWU3NDA1ZjQ2ODBjNWMyYjAzZWY5Mzg0ZjFhZWNmZTI5ODZhZDUwMTM4YzYwNWZlZmZmMmYxNSJ9fX0=", 15);
+ integers.put("eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZDA4ZGY2MGM1MTA3NGVlZjI1NDRmZjM4Y2VhZDllMTY2NzVhZTQyNTE5MTYxMDUxODBlMWY4Y2UxOTdhYjNiYyJ9fX0=", 15);
+ integers.put("eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMTVhZDkzZDU2NTQ2ZjEyZDUzNTZlZmZjYmM2ZWM0Yzg3YmEyNDVkODFlMTY2MmM0YjgzMGY3ZDI5OGU5In19fQ==", 15);
+ colors.put(15, "white");
+ integers.put("eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNDRiMDM3OTRiOWIzZTNiNWQwN2UzYmU2OGI5NmFmODdkZjIxNWMzNzUyZTU0NzM2YzgwZjdkNTBiZDM0MzdhNCJ9fX0=", 16);
+ colors.put(16, "rainbow");
+ integers.put("eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZTkxMjdjYjdiZDNhOTg5ZDcyYzJlNWM0MjZlMWNjMTQ0NmI1ZTZkZTc0MTRkNDI3ODNmMmZlNmJhZGIxNzdkNCJ9fX0=", 17);
+ colors.put(17, "lilac");
+ integers.put("eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZTkxMjdjYjdiZDNhOTg5ZDcyYzJlNWM0MjZlMWNjMTQ0NmI1ZTZkZTc0MTRkNDI3ODNmMmZlNmJhZGIxNzdkNCJ9fX0=", 18);
+ colors.put(18, "dark-red");
+ integers.put("eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMzM4NmY5YjBiMWQ5ODc5YzNkYTMzYzdhOGNhMjQ0MGMxZTQxMWZlOTNjMjdjOWRiYmZmNTZiZDY5N2JiNzM3NSJ9fX0=", 19);
+ colors.put(19, "i-rainbow");
+ integers.put("eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMjdiYmQwYjI5MTFjOTZiNWQ4N2IyZGY3NjY5MWE1MWI4YjEyYzZmZWZkNTIzMTQ2ZDhhYzVlZjFiOGVlIn19fQ==", 20);
+ colors.put(20, "yellow");
+ }
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bombdefuse/chambers/color/ColorProcessorMatcher.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bombdefuse/chambers/color/ColorProcessorMatcher.java
new file mode 100644
index 00000000..5505fe9c
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bombdefuse/chambers/color/ColorProcessorMatcher.java
@@ -0,0 +1,49 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.bombdefuse.chambers.color;
+
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.bombdefuse.RoomProcessorBombDefuseSolver;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.bombdefuse.chambers.BDChamber;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.bombdefuse.chambers.BombDefuseChamberGenerator;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.bombdefuse.chambers.ChamberProcessor;
+import net.minecraft.init.Blocks;
+
+public class ColorProcessorMatcher implements BombDefuseChamberGenerator {
+ @Override
+ public boolean match(BDChamber left, BDChamber right) {
+ return
+ right.getBlock(0,1,1).getBlock() == Blocks.stonebrick &&
+ right.getBlock(0,1,2).getBlock() == Blocks.stonebrick &&
+ right.getBlock(0,1,3).getBlock() == Blocks.stonebrick;
+ }
+
+ @Override
+ public String getName() {
+ return "colorMatch";
+ }
+ @Override
+ public ChamberProcessor createLeft(BDChamber left, RoomProcessorBombDefuseSolver solver) {
+ return new ColorLeftProcessor(solver,left);
+ }
+
+ @Override
+ public ChamberProcessor createRight(BDChamber right, RoomProcessorBombDefuseSolver solver) {
+ return new ColorRightProcessor(solver,right);
+ }
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bombdefuse/chambers/color/ColorRightProcessor.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bombdefuse/chambers/color/ColorRightProcessor.java
new file mode 100644
index 00000000..5c77abe1
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bombdefuse/chambers/color/ColorRightProcessor.java
@@ -0,0 +1,175 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.bombdefuse.chambers.color;
+
+import com.google.common.collect.BiMap;
+import com.google.common.collect.HashBiMap;
+import kr.syeyoung.dungeonsguide.mod.features.FeatureRegistry;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.bombdefuse.RoomProcessorBombDefuseSolver;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.bombdefuse.chambers.BDChamber;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.bombdefuse.chambers.GeneralDefuseChamberProcessor;
+import kr.syeyoung.dungeonsguide.mod.utils.RenderUtils;
+import net.minecraft.block.Block;
+import net.minecraft.client.settings.GameSettings;
+import net.minecraft.entity.item.EntityArmorStand;
+import net.minecraft.item.ItemStack;
+import net.minecraft.nbt.NBTTagCompound;
+import net.minecraft.nbt.NBTTagList;
+import net.minecraft.util.BlockPos;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class ColorRightProcessor extends GeneralDefuseChamberProcessor {
+ public ColorRightProcessor(RoomProcessorBombDefuseSolver solver, BDChamber chamber) {
+ super(solver, chamber);
+ center = chamber.getBlockPos(4,4,4);
+ b1 = chamber.getBlockPos(1,3,3);
+ b2 = chamber.getBlockPos(1,3,2);
+ b3 = chamber.getBlockPos(1,3,1);
+ }
+
+ private final BlockPos center;
+
+ private final BlockPos b1;
+ private final BlockPos b2;
+ private final BlockPos b3;
+ private byte b1b = 0, b2b = 0, b3b = 0, c1b, c2b, c3b;
+ private int answer = -1;
+
+ @Override
+ public String getName() {
+ return "colorRight";
+ }
+
+ @Override
+ public void tick() {
+ super.tick();
+ c1b = match(getChamber().getEntityAt(EntityArmorStand.class,b1.add(0, -1, 0)));
+ c2b = match(getChamber().getEntityAt(EntityArmorStand.class,b2.add(0, -1, 0)));
+ c3b = match(getChamber().getEntityAt(EntityArmorStand.class,b3.add(0, -1, 0)));
+ }
+
+ @Override
+ public void drawWorld(float partialTicks) {
+ super.drawWorld(partialTicks);
+ RenderUtils.drawTextAtWorld(answer == -1 ? "Press "+ GameSettings.getKeyDisplayString(FeatureRegistry.SOLVER_BOMBDEFUSE.<Integer>getParameter("key").getValue()) +" to request solution" : "" , center.getX()+ 0.5f, center.getY(), center.getZ()+ 0.5f, 0xFFFFFFFF, 0.03F, false, false, partialTicks);
+ RenderUtils.drawTextAtWorld( colors.get((int) c1b), b1.getX()+ 0.5f, b1.getY()+0.6f, b1.getZ()+ 0.5f,c1b == b1b ? 0xFF00FF00 : 0xFFFF0000, 0.03F, false, false, partialTicks);
+ RenderUtils.drawTextAtWorld( colors.get((int) c2b), b2.getX()+ 0.5f, b2.getY()+0.6f, b2.getZ()+ 0.5f,c2b == b2b ? 0xFF00FF00 : 0xFFFF0000, 0.03F, false, false, partialTicks);
+ RenderUtils.drawTextAtWorld( colors.get((int) c3b), b3.getX()+ 0.5f, b3.getY()+0.6f, b3.getZ()+ 0.5f,c3b == b3b ? 0xFF00FF00 : 0xFFFF0000, 0.03F, false, false, partialTicks);
+
+ RenderUtils.drawTextAtWorld( colors.get((int) b1b), b1.getX()+ 0.5f, b1.getY()+0.2f, b1.getZ()+ 0.5f,0xFFFFFF00, 0.03F, false, false, partialTicks);
+ RenderUtils.drawTextAtWorld( colors.get((int) b2b), b2.getX()+ 0.5f, b2.getY()+0.2f, b2.getZ()+ 0.5f,0xFFFFFF00, 0.03F, false, false, partialTicks);
+ RenderUtils.drawTextAtWorld( colors.get((int) b3b), b3.getX()+ 0.5f, b3.getY()+0.2f, b3.getZ()+ 0.5f,0xFFFFFF00, 0.03F, false, false, partialTicks);
+ }
+
+ @Override
+ public void onSendData() {
+ super.onSendData();
+ NBTTagCompound nbt = new NBTTagCompound();
+ nbt.setByte("a", (byte) 6);
+ nbt.setByte("f", (byte) Block.getIdFromBlock(getChamber().getBlock(0,3,3).getBlock()));
+ nbt.setByte("s", (byte) Block.getIdFromBlock(getChamber().getBlock(0,3,2).getBlock()));
+ nbt.setByte("t", (byte) Block.getIdFromBlock(getChamber().getBlock(0,3,1).getBlock()));
+ getSolver().communicate(nbt);
+ }
+
+ @Override
+ public void onDataRecieve(NBTTagCompound compound) {
+ if (7 == compound.getByte("a")) {
+ answer = compound.getInteger("b");
+ b3b = (byte) (answer / 10000);
+ b2b = (byte) ((answer % 10000) / 100);
+ b1b = (byte) (answer % 100);
+
+ }
+ }
+
+ private byte match(EntityArmorStand armorStand) {
+ if (armorStand == null) {
+ return 0;
+ }
+ ItemStack item = armorStand.getInventory()[4];
+ NBTTagList list = item.getTagCompound().getCompoundTag("SkullOwner").getCompoundTag("Properties").getTagList("textures", 10);
+ String str = ((NBTTagCompound)list.get(0)).getString("Value");
+ return (byte) (!integers.containsKey(str) ? 0 : integers.get(str));
+ }
+
+ private static final Map<String, Integer> integers = new HashMap<String, Integer>();
+ private static final BiMap<Integer, String> colors = HashBiMap.create();
+ static {
+ colors.put(0, "?");
+ integers.put("eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvM2YzZTQwNjI5MTE3NGQyNGNkZjBmOTUzZjhhMTc0YTgyYmIzNDg5ZGNlOGY2NzlhNDQzZWYxYWFlMDE2OTA2MSJ9fX0=", 1);
+ integers.put("eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZWE4MWZjYjUxYmUyYTlmODliMWFkYzlkODcyMzliYTQyOWQ2MzVmYmUwMWIzN2VjMzI5MTY0ODg3YmY2NjViIn19fQ==", 1);
+ colors.put(1, "blue");
+ integers.put("eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvM2FiMDI2M2JkZDc2ZjNlNDE4ZGJhNWJmNDgxYjkyMWNlZDM5N2Q4YjhhMzRhNTU2MWZiN2JlYWE0NmVjZTEifX19", 2);
+ integers.put("eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvY2ZhNGRkYTZkMTlhMWZlMmQ5ODhkNjVkZWM1MzQyOTUwNTMwODE2NmM5MDY3YjY4YTQ3NzBjYTVjNDM2Y2Y5NCJ9fX0=", 2);
+ colors.put(2, "black");
+ integers.put("eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNDg0Njg0MzQ0YWUwOTg1MjlmYzk0MWFhODRlMTk1YmRjYTM3NDhkNjlhY2ZlZTJiYWMxMzMyMTM1ZWRkOThjIn19fQ==", 3);
+ integers.put("eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNTM1ODFjMmY5Y2YzNThkN2VkYzc4ZGQ2ZmQ0YjYyNTc1MDFiYzRlNjQ1NWUzM2ZhMGNhYWUyMDdjZjAzMjFhMiJ9fX0=", 3);
+ colors.put(3, "green");
+ integers.put("eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZTllNjkxN2YyZmI0ZWEwOGU3MTMyZGYzMDk2MWQyYjVjNTIzYWJiYTE5Y2U0M2Y4MzVmYzE0YzU2OGY0In19fQ==", 4);
+ integers.put("eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYWRmMjFmNTMyMTIyNTY2YWY4OTNkYTI3ODgwYTFiNjA5NWMzNTcxMmYyOWEzNzhjZmVjYzdmZTJiMTMyOGFiNCJ9fX0=", 4);
+ colors.put(4, "gray");
+ integers.put("eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvODhlZmFkNzRiMjU0ZTU3Yzc5OTc2M2RjZWVlNDUxMWZhMmY4NWFlOWZhNTU2ZWFhOTdkNDViZjY3ZTBiNmIzIn19fQ==", 5);
+ integers.put("eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMWZhZGY3NDFhYjc2Y2QzNjIwYWQxNjEzMDAyMDJkN2I1OWEzMzA1MWU1OTY3ZTRiNjE5NGJhYzQwYmIyODBmZiJ9fX0=", 5);
+ colors.put(5, "cyan");
+ integers.put("eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMzJlMzZmNmE2NTRkZTc0NTgzZDgwMzAxNzdhZDZlM2FjNjc1NWQ3NDM1ZDkxMjNlOGViZGZmNzRiMmQ5MGNiIn19fQ==", 6);
+ integers.put("eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMjJjYmQ5ZjQzNjE5YWI1Y2IxYjExZjkxY2IwM2U5NTVjNmZjNmM0NThhYmY4OWFiNjEwMzEzNDZhMDkwNjEyZSJ9fX0=", 6);
+ colors.put(6, "brown");
+ integers.put("eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZjFhZjQ2ZmViZDQ1YzBmNGQ4MWU4ZmExYjY2YjI3NWQ4OWUyNzJiMmFkNTVjOTc4NTUzYTk5YzczM2UxZmYifX19", 7);
+ integers.put("eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMTYzZTY2NDZmMWMwZDQxZmQzYmY1NTg0YTFjZTA0NGY1YzQ2ZDU5ODI1OGRiNDYyMTYxMTc4NTlmNTdhZjE5NyJ9fX0=", 7);
+ colors.put(7, "light-blue");
+ integers.put("eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZDY3NDcwYTBjMThmNjg1MWU5MTQzNTM3MTllNzk1ODc3ZDI5YjMyNTJmN2U2YmQ0YTFiODY1NzY1YmQ3NGZlYiJ9fX0=", 8);
+ integers.put("eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNzc0NzJkNjA4ODIxZjQ1YTg4MDUzNzZlYzBjNmZmY2I3ODExNzgyOWVhNWY5NjAwNDFjMmEwOWQxMGUwNGNiNCJ9fX0=", 8);
+ colors.put(8, "lime");
+ integers.put("eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYWJiNDM4NmJjZGE4NGUzNTNjMzFkNzc4ZDNiMTFiY2QyNmZlYTQ5NGRkNjM0OTZiOGE4MmM3Yzc4YTRhZCJ9fX0=", 9);
+ integers.put("eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZjk3MDEyZWQ2YTkyYjA1ZWEwZjE5NDk1MDc0ODU0NGUwNzViYWEyODc4MWNhMzczZDFiMjdlMjhjMjY5NTNjIn19fQ==", 9);
+ colors.put(9, "magenta");
+ integers.put("eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvY2JmNzc5N2EyNGE2YWY4NzVmNWM4MjcxYzViOGM0MjVlMTlmMzcyYTQxNWUwNTUyZmMyNDc3NjNmMjg1OWQxIn19fQ==", 10);
+ integers.put("eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYWRmMmViMjA1YTIzYzExOTZiM2VjZjIxZTY4YzA3NmI2OTZlNzYxNjNhYzhmYzRmYjlmNTMxOGMyYTVlNWIxYSJ9fX0=", 10);
+ colors.put(10, "orange");
+ integers.put("eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNmJlY2ZiMzg3OTkzNmI4OTllNDIwYmZjZDNhNzRmOGExYmY5ZGQ1NGM1OGVjN2ZiOWY4MWQ5YTVkOTg4ZSJ9fX0=", 11);
+ integers.put("eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZDA4ODM2NTBlYTkyOWRiMGVhYmRmNWJjNzU1OTlkOGVmMDBkNzAzNDBjZDFjZTVlMDRhZDk1ZWY4ZWQ4M2I3MyJ9fX0=", 11);
+ colors.put(11, "pink");
+ integers.put("eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYmE5NGNiMjVkZTYyOGNhMzU5YjJmNmVhNWE4ODY4Y2JlMjY1OTVlZWRiMmJmZmI3NTA5NjdhZDFlZTE4NTAifX19", 12);
+ integers.put("eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvODllYzVhMzAyMjJkMDY1OWIwZGJlZTg0NGI4ZjUzZWFlNjJmZTk1YjRhMzQ0OGE5ZWY3OTBhN2FlZGIyOTZkOSJ9fX0=", 12);
+ colors.put(12, "purple");
+ integers.put("eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvODZkMzVhOTYzZDU5ODc4OTRiNmJjMjE0ZTMyOGIzOWNkMjM4MjQyNmZmOWM4ZTA4MmIwYjZhNmUwNDRkM2EzIn19fQ==", 13);
+ integers.put("eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNjk1M2IxMmEwOTQ2YjYyOWI0YzA4ODlkNDFmZDI2ZWQyNmZiNzI5ZDRkNTE0YjU5NzI3MTI0YzM3YmI3MGQ4ZCJ9fX0=", 13);
+ colors.put(13, "red");
+ integers.put("eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOTk4YmEyYjM3NGNmYzg5NDU0YzFiOGMzMmRiNDU4YTI3MDY3NTQzOWE0OTU0OTZjOTY3NzFjOTg5MTE2MTYyIn19fQ==", 14);
+ integers.put("eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNTUyODhkZGM5MTFhNzVmNzdjM2E1ZDMzNjM2NWE4ZjhiMTM5ZmE1MzkzMGI0YjZlZTEzOTg3NWM4MGNlMzY2YyJ9fX0=", 14);
+ colors.put(14, "light-gray");
+ integers.put("eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvM2ZhZjRjMjlmMWU3NDA1ZjQ2ODBjNWMyYjAzZWY5Mzg0ZjFhZWNmZTI5ODZhZDUwMTM4YzYwNWZlZmZmMmYxNSJ9fX0=", 15);
+ integers.put("eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZDA4ZGY2MGM1MTA3NGVlZjI1NDRmZjM4Y2VhZDllMTY2NzVhZTQyNTE5MTYxMDUxODBlMWY4Y2UxOTdhYjNiYyJ9fX0=", 15);
+ integers.put("eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMTVhZDkzZDU2NTQ2ZjEyZDUzNTZlZmZjYmM2ZWM0Yzg3YmEyNDVkODFlMTY2MmM0YjgzMGY3ZDI5OGU5In19fQ==", 15);
+ colors.put(15, "white");
+ integers.put("eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNDRiMDM3OTRiOWIzZTNiNWQwN2UzYmU2OGI5NmFmODdkZjIxNWMzNzUyZTU0NzM2YzgwZjdkNTBiZDM0MzdhNCJ9fX0=", 16);
+ colors.put(16, "rainbow");
+ integers.put("eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZTkxMjdjYjdiZDNhOTg5ZDcyYzJlNWM0MjZlMWNjMTQ0NmI1ZTZkZTc0MTRkNDI3ODNmMmZlNmJhZGIxNzdkNCJ9fX0=", 17);
+ colors.put(17, "lilac");
+ integers.put("eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZTkxMjdjYjdiZDNhOTg5ZDcyYzJlNWM0MjZlMWNjMTQ0NmI1ZTZkZTc0MTRkNDI3ODNmMmZlNmJhZGIxNzdkNCJ9fX0=", 18);
+ colors.put(18, "dark-red");
+ integers.put("eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMzM4NmY5YjBiMWQ5ODc5YzNkYTMzYzdhOGNhMjQ0MGMxZTQxMWZlOTNjMjdjOWRiYmZmNTZiZDY5N2JiNzM3NSJ9fX0=", 19);
+ colors.put(19, "i-rainbow");
+ integers.put("eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMjdiYmQwYjI5MTFjOTZiNWQ4N2IyZGY3NjY5MWE1MWI4YjEyYzZmZWZkNTIzMTQ2ZDhhYzVlZjFiOGVlIn19fQ==", 20);
+ colors.put(20, "yellow");
+ }
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bombdefuse/chambers/creeper/CreeperLeftProcessor.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bombdefuse/chambers/creeper/CreeperLeftProcessor.java
new file mode 100644
index 00000000..f651a780
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bombdefuse/chambers/creeper/CreeperLeftProcessor.java
@@ -0,0 +1,95 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.bombdefuse.chambers.creeper;
+
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.bombdefuse.RoomProcessorBombDefuseSolver;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.bombdefuse.chambers.BDChamber;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.bombdefuse.chambers.GeneralDefuseChamberProcessor;
+import kr.syeyoung.dungeonsguide.mod.utils.RenderUtils;
+import net.minecraft.init.Blocks;
+import net.minecraft.nbt.NBTTagCompound;
+import net.minecraft.util.BlockPos;
+
+import java.awt.*;
+
+public class CreeperLeftProcessor extends GeneralDefuseChamberProcessor {
+ public CreeperLeftProcessor(RoomProcessorBombDefuseSolver solver, BDChamber chamber) {
+ super(solver, chamber);
+
+ poses = new BlockPos[9];
+ for (int i = 0; i < 9; i++) {
+ poses[i] = chamber.getBlockPos(3+(i%3), 1, 1+(i/3));
+ }
+ }
+
+ @Override
+ public String getName() {
+ return "creeperLeft";
+ }
+
+
+ private int answer = -1;
+ private final BlockPos[] poses;
+ @Override
+ public void tick() {
+ super.tick();
+ if (answer != -1) return;
+ answer = 0;
+ for (int i = 0; i < poses.length; i++) {
+ BlockPos pos = poses[i];
+ if (getChamber().getRoom().getContext().getWorld().getBlockState(pos).getBlock() == Blocks.air) {
+ answer |= (1 << i);
+ }
+ }
+ }
+
+ @Override
+ public void drawScreen(float partialTicks) {
+ if (answer == -1) return;
+ drawPressKey();
+ }
+
+ @Override
+ public void drawWorld(float partialTicks) {
+ super.drawWorld(partialTicks);
+ for (int i = 0; i < 9; i++) {
+ if (((answer >> i) & 0x01) != 0) {
+ RenderUtils.highlightBlock(poses[i], new Color(255,0,0,100), partialTicks, false);
+ } else {
+ RenderUtils.highlightBlock(poses[i], new Color(0,255,0,100), partialTicks, false);
+ }
+ }
+ }
+
+ @Override
+ public void onSendData() {
+ if (answer == -1) return;
+ NBTTagCompound nbt = new NBTTagCompound();
+ nbt.setByte("a", (byte) 2);
+ nbt.setInteger("b", answer);
+ getSolver().communicate(nbt);
+ }
+
+ @Override
+ public void onDataRecieve(NBTTagCompound compound) {
+ if (2 == compound.getByte("a")) {
+ answer = compound.getInteger("b");
+ }
+ }
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bombdefuse/chambers/creeper/CreeperProcessorMatcher.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bombdefuse/chambers/creeper/CreeperProcessorMatcher.java
new file mode 100644
index 00000000..f2ad23b6
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bombdefuse/chambers/creeper/CreeperProcessorMatcher.java
@@ -0,0 +1,52 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.bombdefuse.chambers.creeper;
+
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.bombdefuse.RoomProcessorBombDefuseSolver;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.bombdefuse.chambers.BDChamber;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.bombdefuse.chambers.BombDefuseChamberGenerator;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.bombdefuse.chambers.ChamberProcessor;
+import net.minecraft.init.Blocks;
+
+public class CreeperProcessorMatcher implements BombDefuseChamberGenerator {
+ @Override
+ public boolean match(BDChamber left, BDChamber right) {
+ int airs = 0;
+ for (int x = 0; x < 3; x ++) {
+ for (int y = 0; y < 3; y++) {
+ if (right.getBlock(3 + x, 1, y + 1).getBlock() != Blocks.stone) return false;
+ }
+ }
+ return true;
+ }
+
+ @Override
+ public String getName() {
+ return "creeperMatch";
+ }
+ @Override
+ public ChamberProcessor createLeft(BDChamber left, RoomProcessorBombDefuseSolver solver) {
+ return new CreeperLeftProcessor(solver, left);
+ }
+
+ @Override
+ public ChamberProcessor createRight(BDChamber right, RoomProcessorBombDefuseSolver solver) {
+ return new CreeperRightProcessor(solver, right);
+ }
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bombdefuse/chambers/creeper/CreeperRightProcessor.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bombdefuse/chambers/creeper/CreeperRightProcessor.java
new file mode 100644
index 00000000..258c0e8f
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bombdefuse/chambers/creeper/CreeperRightProcessor.java
@@ -0,0 +1,73 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.bombdefuse.chambers.creeper;
+
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.bombdefuse.RoomProcessorBombDefuseSolver;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.bombdefuse.chambers.BDChamber;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.bombdefuse.chambers.GeneralDefuseChamberProcessor;
+import kr.syeyoung.dungeonsguide.mod.utils.RenderUtils;
+import net.minecraft.nbt.NBTTagCompound;
+import net.minecraft.util.BlockPos;
+
+import java.awt.*;
+
+public class CreeperRightProcessor extends GeneralDefuseChamberProcessor {
+ public CreeperRightProcessor(RoomProcessorBombDefuseSolver solver, BDChamber chamber) {
+ super(solver, chamber);
+
+ poses = new BlockPos[9];
+ for (int i = 0; i < 9; i++) {
+ poses[i] = chamber.getBlockPos(3+(i%3), 1, 1+(i/3));
+ }
+ center = chamber.getBlockPos(4,4,4);
+ }
+
+ @Override
+ public String getName() {
+ return "creeperRight";
+ }
+
+
+ private int answer = -1;
+ private final BlockPos[] poses;
+ private final BlockPos center;
+ @Override
+ public void tick() {
+ super.tick();
+ }
+
+ @Override
+ public void drawWorld(float partialTicks) {
+ super.drawWorld(partialTicks);
+ RenderUtils.drawTextAtWorld(answer == -1 ? "Answer not received yet. Visit left room to obtain solution" : "" , center.getX()+ 0.5f, center.getY(), center.getZ()+ 0.5f, 0xFFFFFFFF, 0.03F, false, false, partialTicks);
+ if (answer != -1) {
+ for (int i = 0; i < 9; i++) {
+ if (((answer >> i) & 0x01) == 0) {
+ RenderUtils.highlightBlock(poses[i], new Color(0,255,0, 50), partialTicks, false);
+ }
+ }
+ }
+ }
+ @Override
+ public void onDataRecieve(NBTTagCompound compound) {
+ if (2 == compound.getByte("a")) {
+ answer = compound.getInteger("b");
+ }
+ }
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bombdefuse/chambers/goldenpath/GoldenPathLeftProcessor.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bombdefuse/chambers/goldenpath/GoldenPathLeftProcessor.java
new file mode 100644
index 00000000..6a531aed
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bombdefuse/chambers/goldenpath/GoldenPathLeftProcessor.java
@@ -0,0 +1,141 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.bombdefuse.chambers.goldenpath;
+
+import kr.syeyoung.dungeonsguide.mod.config.types.AColor;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.bombdefuse.RoomProcessorBombDefuseSolver;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.bombdefuse.chambers.BDChamber;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.bombdefuse.chambers.GeneralDefuseChamberProcessor;
+import kr.syeyoung.dungeonsguide.mod.utils.RenderUtils;
+import kr.syeyoung.dungeonsguide.mod.utils.TextUtils;
+import net.minecraft.client.Minecraft;
+import net.minecraft.init.Blocks;
+import net.minecraft.util.BlockPos;
+import net.minecraft.util.ChatComponentText;
+import net.minecraft.util.IChatComponent;
+
+import java.awt.*;
+import java.util.*;
+import java.util.List;
+
+public class GoldenPathLeftProcessor extends GeneralDefuseChamberProcessor {
+ public GoldenPathLeftProcessor(RoomProcessorBombDefuseSolver solver, BDChamber chamber) {
+ super(solver, chamber);
+
+ }
+
+ @Override
+ public String getName() {
+ return "goldenPathLeft";
+ }
+
+
+ // 1 up 2 right 3 down 4 left
+ private static final Point[] vectors = new Point[] {
+ new Point(0,1),
+ new Point(-1,0),
+ new Point(0, -1),
+ new Point(1, 0)
+ };
+
+ private final LinkedList<BlockPos> blocksolution = new LinkedList<BlockPos>();
+ private String goldenPathsolution;
+ @Override
+ public void tick() {
+ super.tick();
+ if (goldenPathsolution != null) return;
+
+ List<Integer> solution = new ArrayList<Integer>();
+ Set<BlockPos> visited = new HashSet<BlockPos>();
+ BlockPos lastLoc = new BlockPos(4,0,0);
+ visited.add(lastLoc);
+ blocksolution.add(getChamber().getBlockPos(4,1,0));
+ BlockPos target = new BlockPos(4,0,5);
+ while (!lastLoc.equals(target)) {
+ boolean solution2 = false;
+ for (int i =0; i<vectors.length; i++) {
+ BlockPos target2 = lastLoc.add(vectors[i].x, 0, vectors[i].y);
+ if (visited.contains(target2)) continue;
+ if (target2.getX() < 0 || target2.getZ() < 0 || target2.getX() > 8 || target2.getZ() > 5) continue;
+
+ visited.add(target2);
+ if (getChamber().getBlock(target2.getX(), 0, target2.getZ()).getBlock() == Blocks.hardened_clay
+ || getChamber().getBlock(target2.getX(), 0, target2.getZ()).getBlock() == Blocks.stained_hardened_clay) {
+ lastLoc = target2;
+
+ blocksolution.add(getChamber().getBlockPos(lastLoc.getX(), 1, lastLoc.getZ()));
+ solution.add(i);
+ solution2 = true;
+ break;
+ }
+ }
+ if (!solution2){
+ return;
+ }
+ }
+
+ goldenPathsolution = "";
+ for (Integer i:solution)
+ goldenPathsolution += i;
+ }
+
+ @Override
+ public void drawScreen(float partialTicks) {
+ if (goldenPathsolution == null) return;
+ drawPressKey();
+ }
+
+ @Override
+ public void drawWorld(float partialTicks) {
+ super.drawWorld(partialTicks);
+ RenderUtils.drawLines(blocksolution, new AColor(0,0,255,0), 1,partialTicks, false);
+ }
+
+ @Override
+ public void onSendData() {
+ if (goldenPathsolution == null) return;
+ Minecraft.getMinecraft().thePlayer.sendChatMessage("/pc $DG-BDGP "+goldenPathsolution);
+
+ ChatComponentText text = new ChatComponentText("$DG-BDGP "+goldenPathsolution);
+ for (RoomProcessorBombDefuseSolver.ChamberSet ch: getSolver().getChambers()) {
+ if (ch.getLeft() != null && ch.getLeft().getProcessor() != null)
+ ch.getLeft().getProcessor().chatReceived(text);
+ if (ch.getRight() != null && ch.getRight().getProcessor() != null)
+ ch.getRight().getProcessor().chatReceived(text);
+ }
+ }
+
+ @Override
+ public void chatReceived(IChatComponent chat) {
+ super.chatReceived(chat);
+ if (chat.getFormattedText().contains("$DG-BDGP ")) {
+ String data = chat.getFormattedText().substring(chat.getFormattedText().indexOf("$DG-BDGP "));
+ String actual = TextUtils.stripColor(data).trim().split(" ")[1].trim();
+
+ blocksolution.clear();
+ BlockPos lastLoc = new BlockPos(4,0,0);
+ blocksolution.addFirst(getChamber().getBlockPos(4,1,0));
+ for (Character c:actual.toCharArray()) {
+ int dir = Integer.parseInt(c+"") % 4;
+ lastLoc = lastLoc.add(vectors[dir].x, 0, vectors[dir].y);
+ blocksolution.add(getChamber().getBlockPos(lastLoc.getX(), 1, lastLoc.getZ()));
+ }
+ }
+ }
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bombdefuse/chambers/goldenpath/GoldenPathProcessorMatcher.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bombdefuse/chambers/goldenpath/GoldenPathProcessorMatcher.java
new file mode 100644
index 00000000..5f5ac89b
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bombdefuse/chambers/goldenpath/GoldenPathProcessorMatcher.java
@@ -0,0 +1,47 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.bombdefuse.chambers.goldenpath;
+
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.bombdefuse.RoomProcessorBombDefuseSolver;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.bombdefuse.chambers.BDChamber;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.bombdefuse.chambers.BombDefuseChamberGenerator;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.bombdefuse.chambers.ChamberProcessor;
+import net.minecraft.init.Blocks;
+
+public class GoldenPathProcessorMatcher implements BombDefuseChamberGenerator {
+ @Override
+ public boolean match(BDChamber left, BDChamber right) {
+ return left.getBlock(4,0,0).getBlock() == Blocks.hardened_clay
+ || left.getBlock(4,0,0).getBlock() == Blocks.stained_hardened_clay;
+ }
+
+ @Override
+ public String getName() {
+ return "goldPath";
+ }
+ @Override
+ public ChamberProcessor createLeft(BDChamber left, RoomProcessorBombDefuseSolver solver) {
+ return new GoldenPathLeftProcessor(solver, left);
+ }
+
+ @Override
+ public ChamberProcessor createRight(BDChamber right, RoomProcessorBombDefuseSolver solver) {
+ return new GoldenPathRightProcessor(solver, right);
+ }
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bombdefuse/chambers/goldenpath/GoldenPathRightProcessor.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bombdefuse/chambers/goldenpath/GoldenPathRightProcessor.java
new file mode 100644
index 00000000..d432da80
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bombdefuse/chambers/goldenpath/GoldenPathRightProcessor.java
@@ -0,0 +1,97 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.bombdefuse.chambers.goldenpath;
+
+import kr.syeyoung.dungeonsguide.mod.config.types.AColor;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.bombdefuse.RoomProcessorBombDefuseSolver;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.bombdefuse.chambers.BDChamber;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.bombdefuse.chambers.GeneralDefuseChamberProcessor;
+import kr.syeyoung.dungeonsguide.mod.utils.RenderUtils;
+import kr.syeyoung.dungeonsguide.mod.utils.TextUtils;
+import net.minecraft.init.Blocks;
+import net.minecraft.util.BlockPos;
+import net.minecraft.util.IChatComponent;
+import net.minecraft.world.World;
+
+import java.awt.*;
+import java.util.*;
+
+public class GoldenPathRightProcessor extends GeneralDefuseChamberProcessor {
+ public GoldenPathRightProcessor(RoomProcessorBombDefuseSolver solver, BDChamber chamber) {
+ super(solver, chamber);
+
+ center = chamber.getBlockPos(4,4,4);
+ }
+
+ @Override
+ public String getName() {
+ return "goldenPathRight";
+ }
+
+
+ private final BlockPos center;
+ // 1 up 2 right 3 down 4 left
+ private static final Point[] vectors = new Point[] {
+ new Point(0,1),
+ new Point(-1,0),
+ new Point(0, -1),
+ new Point(1, 0)
+ };
+
+ private final LinkedList<BlockPos> blocksolution = new LinkedList<BlockPos>();
+
+ @Override
+ public void drawWorld(float partialTicks) {
+ super.drawWorld(partialTicks);
+ RenderUtils.drawTextAtWorld(blocksolution.size() == 0 ? "Answer not received yet. Visit left room to obtain solution" : "" , center.getX()+ 0.5f, center.getY(), center.getZ()+ 0.5f, 0xFFFFFFFF, 0.03F, false, false, partialTicks);
+
+ RenderUtils.drawLines(blocksolution, new AColor(0,0,255,0),1, partialTicks, false);
+
+ }
+
+ @Override
+ public void chatReceived(IChatComponent chat) {
+ super.chatReceived(chat);
+ if (chat.getFormattedText().contains("$DG-BDGP ")) {
+ String data = chat.getFormattedText().substring(chat.getFormattedText().indexOf("$DG-BDGP"));
+ String actual = TextUtils.stripColor(data).trim().split(" ")[1].trim();
+
+ blocksolution.clear();
+ BlockPos lastLoc = new BlockPos(4,0,0);
+ blocksolution.addFirst(getChamber().getBlockPos(4,1,0));
+ for (Character c:actual.toCharArray()) {
+ int dir = Integer.parseInt(c+"") % 4;
+ lastLoc = lastLoc.add(vectors[dir].x, 0, vectors[dir].y);
+ blocksolution.add(getChamber().getBlockPos(lastLoc.getX(), 1, lastLoc.getZ()));
+ }
+
+ World w = getChamber().getRoom().getContext().getWorld();
+ for (int x = 0; x <9; x++) {
+ for (int z =0; z < 6; z++) {
+ BlockPos pos = getChamber().getBlockPos(x,1,z);
+ if (blocksolution.contains(pos)) {
+ w.setBlockState(pos, Blocks.light_weighted_pressure_plate.getDefaultState());
+ } else {
+ w.setBlockState(pos, Blocks.wooden_pressure_plate.getDefaultState());
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bombdefuse/chambers/maze/MazeLeftProcessor.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bombdefuse/chambers/maze/MazeLeftProcessor.java
new file mode 100644
index 00000000..d2b9927c
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bombdefuse/chambers/maze/MazeLeftProcessor.java
@@ -0,0 +1,80 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.bombdefuse.chambers.maze;
+
+import kr.syeyoung.dungeonsguide.mod.DungeonsGuide;
+import kr.syeyoung.dungeonsguide.mod.features.FeatureRegistry;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.bombdefuse.RoomProcessorBombDefuseSolver;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.bombdefuse.chambers.BDChamber;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.bombdefuse.chambers.GeneralDefuseChamberProcessor;
+import net.minecraft.block.Block;
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.gui.FontRenderer;
+import net.minecraft.client.gui.ScaledResolution;
+import net.minecraft.client.renderer.GlStateManager;
+import net.minecraft.client.settings.GameSettings;
+import net.minecraft.nbt.NBTTagCompound;
+import net.minecraft.util.BlockPos;
+import net.minecraft.util.MovingObjectPosition;
+import org.lwjgl.opengl.GL11;
+import org.lwjgl.opengl.GL14;
+
+public class MazeLeftProcessor extends GeneralDefuseChamberProcessor {
+ public MazeLeftProcessor(RoomProcessorBombDefuseSolver solver, BDChamber chamber) {
+ super(solver, chamber);
+ }
+
+ @Override
+ public String getName() {
+ return "mazeLeft";
+ }
+
+
+ @Override
+ public void drawScreen(float partialTicks) {
+ if (Minecraft.getMinecraft().objectMouseOver == null ) return;
+ MovingObjectPosition pos = Minecraft.getMinecraft().objectMouseOver;
+ if (pos.typeOfHit != MovingObjectPosition.MovingObjectType.BLOCK) return;
+
+ Block b = DungeonsGuide.getDungeonsGuide().getBlockCache().getBlockState(pos.getBlockPos()).getBlock();
+
+ FontRenderer fr = Minecraft.getMinecraft().fontRendererObj;
+ ScaledResolution sr = new ScaledResolution(Minecraft.getMinecraft());
+ String str = "Press "+ GameSettings.getKeyDisplayString(FeatureRegistry.SOLVER_BOMBDEFUSE.<Integer>getParameter("key").getValue()) + " to request open "+b.getLocalizedName();
+ GlStateManager.enableBlend();
+ GL14.glBlendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA);
+ GlStateManager.tryBlendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA);
+ fr.drawString(str, (sr.getScaledWidth() - fr.getStringWidth(str)) / 2, (sr.getScaledHeight() - fr.FONT_HEIGHT) / 2, 0xFFFFFFFF);
+ }
+
+ @Override
+ public void onSendData() {
+ if (Minecraft.getMinecraft().objectMouseOver == null ) return;
+ MovingObjectPosition pos = Minecraft.getMinecraft().objectMouseOver;
+ if (pos.typeOfHit != MovingObjectPosition.MovingObjectType.BLOCK) return;
+
+ BlockPos block = pos.getBlockPos();
+ Block b = getChamber().getRoom().getContext().getWorld().getBlockState(block).getBlock();
+
+ NBTTagCompound nbt = new NBTTagCompound();
+ nbt.setByte("a", (byte) 5);
+ nbt.setInteger("b", Block.getIdFromBlock(b));
+ getSolver().communicate(nbt);
+ }
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bombdefuse/chambers/maze/MazeProcessorMatcher.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bombdefuse/chambers/maze/MazeProcessorMatcher.java
new file mode 100644
index 00000000..1429d302
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bombdefuse/chambers/maze/MazeProcessorMatcher.java
@@ -0,0 +1,47 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.bombdefuse.chambers.maze;
+
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.bombdefuse.RoomProcessorBombDefuseSolver;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.bombdefuse.chambers.BDChamber;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.bombdefuse.chambers.BombDefuseChamberGenerator;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.bombdefuse.chambers.ChamberProcessor;
+import net.minecraft.init.Blocks;
+
+public class MazeProcessorMatcher implements BombDefuseChamberGenerator {
+ @Override
+ public boolean match(BDChamber left, BDChamber right) {
+ return right.getBlock(1,0,1).getBlock() != Blocks.double_stone_slab &&
+ left.getBlock(1,1,1).getBlock() != Blocks.barrier;
+ }
+
+ @Override
+ public String getName() {
+ return "mazeMatch";
+ }
+ @Override
+ public ChamberProcessor createLeft(BDChamber left, RoomProcessorBombDefuseSolver solver) {
+ return new MazeLeftProcessor(solver, left);
+ }
+
+ @Override
+ public ChamberProcessor createRight(BDChamber right, RoomProcessorBombDefuseSolver solver) {
+ return new MazeRightProcessor(solver, right);
+ }
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bombdefuse/chambers/maze/MazeRightProcessor.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bombdefuse/chambers/maze/MazeRightProcessor.java
new file mode 100644
index 00000000..df9f8f93
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bombdefuse/chambers/maze/MazeRightProcessor.java
@@ -0,0 +1,73 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.bombdefuse.chambers.maze;
+
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.bombdefuse.RoomProcessorBombDefuseSolver;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.bombdefuse.chambers.BDChamber;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.bombdefuse.chambers.GeneralDefuseChamberProcessor;
+import kr.syeyoung.dungeonsguide.mod.utils.RenderUtils;
+import net.minecraft.block.Block;
+import net.minecraft.nbt.NBTTagCompound;
+import net.minecraft.util.BlockPos;
+
+import java.awt.*;
+import java.util.HashMap;
+import java.util.Map;
+
+public class MazeRightProcessor extends GeneralDefuseChamberProcessor {
+ public MazeRightProcessor(RoomProcessorBombDefuseSolver solver, BDChamber chamber) {
+ super(solver, chamber);
+ center = chamber.getBlockPos(4,4,4);
+
+ for (int x = 0; x < 9; x++) {
+ for (int y =0; y< 6; y++) {
+ Block b = chamber.getBlock(x,0,y).getBlock();
+ BlockPos pos = chamber.getBlockPos(x,0,y);
+ blockToBlockPosMap.put(b, pos);
+ }
+ }
+ }
+
+ private final BlockPos center;
+ private final Map<Block, BlockPos> blockToBlockPosMap = new HashMap<Block, BlockPos>();
+ @Override
+ public String getName() {
+ return "mazeRight";
+ }
+
+
+ private Block latestRequest = null;
+
+ @Override
+ public void drawWorld(float partialTicks) {
+ super.drawWorld(partialTicks);
+ RenderUtils.drawTextAtWorld(latestRequest == null ? "Request not received yet" : "Requested received "+latestRequest.getLocalizedName() , center.getX()+ 0.5f, center.getY(), center.getZ()+ 0.5f, 0xFFFFFFFF, 0.03F, false, false, partialTicks);
+ BlockPos pos = blockToBlockPosMap.get(latestRequest);
+ if (pos == null) return;
+ RenderUtils.highlightBlock(pos, new Color(0,255,0,100), partialTicks, false);
+ }
+
+ @Override
+ public void onDataRecieve(NBTTagCompound compound) {
+ if (5 == compound.getByte("a")) {
+ int latestRequestid = compound.getInteger("b");
+ latestRequest = Block.getBlockById(latestRequestid);
+ }
+ }
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bombdefuse/chambers/number/NumberLeftProcessor.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bombdefuse/chambers/number/NumberLeftProcessor.java
new file mode 100644
index 00000000..11c7fefd
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bombdefuse/chambers/number/NumberLeftProcessor.java
@@ -0,0 +1,125 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.bombdefuse.chambers.number;
+
+import com.google.common.collect.BiMap;
+import com.google.common.collect.HashBiMap;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.bombdefuse.RoomProcessorBombDefuseSolver;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.bombdefuse.chambers.BDChamber;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.bombdefuse.chambers.GeneralDefuseChamberProcessor;
+import kr.syeyoung.dungeonsguide.mod.utils.RenderUtils;
+import net.minecraft.entity.item.EntityArmorStand;
+import net.minecraft.item.ItemStack;
+import net.minecraft.nbt.NBTTagCompound;
+import net.minecraft.nbt.NBTTagList;
+import net.minecraft.util.BlockPos;
+
+public class NumberLeftProcessor extends GeneralDefuseChamberProcessor {
+ public NumberLeftProcessor(RoomProcessorBombDefuseSolver solver, BDChamber chamber) {
+ super(solver, chamber);
+
+ d1p = chamber.getBlockPos(1,1,4);
+ d2p = chamber.getBlockPos(2,1,4);
+ d3p = chamber.getBlockPos(6,1,4);
+ d4p = chamber.getBlockPos(7,1,4);
+ }
+
+ @Override
+ public String getName() {
+ return "numberLeft";
+ }
+
+
+ private int answer = -1, d1, d2, d3 ,d4;
+ private final BlockPos d1p;
+ private final BlockPos d2p;
+ private final BlockPos d3p;
+ private final BlockPos d4p;
+ @Override
+ public void tick() {
+ super.tick();
+ if (answer != -1) return;
+ d1 = match(getChamber().getEntityAt(EntityArmorStand.class,d1p));
+ d2 = match(getChamber().getEntityAt(EntityArmorStand.class,d2p));
+ d3 = match(getChamber().getEntityAt(EntityArmorStand.class,d3p));
+ d4 = match(getChamber().getEntityAt(EntityArmorStand.class,d4p));
+ if (d1 == -1 || d2 == -1 || d3 == -1 || d4 == -1) return;
+
+ answer = d1 * 1000 + d2 * 100 + d3 * 10 + d4;
+ }
+
+ @Override
+ public void drawScreen(float partialTicks) {
+ if (answer == -1) return;
+ drawPressKey();
+ }
+
+ @Override
+ public void drawWorld(float partialTicks) {
+ super.drawWorld(partialTicks);
+ RenderUtils.drawTextAtWorld(d1+"", d1p.getX()+ 0.5f, d1p.getY()+ 0.5f, d1p.getZ()+ 0.5f, 0xFFFFFFFF, 0.03F, false, false, partialTicks);
+ RenderUtils.drawTextAtWorld(d2+"", d2p.getX()+ 0.5f, d2p.getY()+ 0.5f, d2p.getZ()+ 0.5f, 0xFFFFFFFF, 0.03F, false, false, partialTicks);
+ RenderUtils.drawTextAtWorld(d3+"", d3p.getX()+ 0.5f, d3p.getY()+ 0.5f, d3p.getZ()+ 0.5f, 0xFFFFFFFF, 0.03F, false, false, partialTicks);
+ RenderUtils.drawTextAtWorld(d4+"", d4p.getX()+ 0.5f, d4p.getY()+ 0.5f, d4p.getZ()+ 0.5f, 0xFFFFFFFF, 0.03F, false, false, partialTicks);
+
+ }
+
+ @Override
+ public void onSendData() {
+ if (answer == -1) return;
+ NBTTagCompound nbt = new NBTTagCompound();
+ nbt.setByte("a", (byte) 1);
+ nbt.setInteger("b", answer);
+ getSolver().communicate(nbt);
+ }
+
+ @Override
+ public void onDataRecieve(NBTTagCompound compound) {
+ if (1 == compound.getByte("a")) {
+ answer = compound.getInteger("b");
+ d1 = answer / 1000;
+ d2 = (answer % 1000) / 100;
+ d3 = (answer % 100) / 10;
+ d4 = (answer % 10);
+ answer = d1 * 1000 + d2 * 100 + d3 * 10 + d4;
+ }
+ }
+
+ private int match(EntityArmorStand armorStand) {
+ if (armorStand == null) return -1;
+ ItemStack item = armorStand.getInventory()[4];
+ NBTTagList list = item.getTagCompound().getCompoundTag("SkullOwner").getCompoundTag("Properties").getTagList("textures", 10);
+ String str = ((NBTTagCompound)list.get(0)).getString("Value");
+ return !integers.containsKey(str) ? -1 : integers.get(str);
+ }
+
+ private static final BiMap<String, Integer> integers = HashBiMap.create(10);
+ {
+ integers.put("eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMzFhOTQ2M2ZkM2M0MzNkNWUxZDlmZWM2ZDVkNGIwOWE4M2E5NzBiMGI3NGRkNTQ2Y2U2N2E3MzM0OGNhYWIifX19", 1);
+ integers.put("eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYWNiNDE5ZDk4NGQ4Nzk2MzczYzk2NDYyMzNjN2EwMjY2NGJkMmNlM2ExZDM0NzZkZDliMWM1NDYzYjE0ZWJlIn19fQ==", 2);
+ integers.put("eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZjhlYmFiNTdiNzYxNGJiMjJhMTE3YmU0M2U4NDhiY2QxNGRhZWNiNTBlOGY1ZDA5MjZlNDg2NGRmZjQ3MCJ9fX0=", 3);
+ integers.put("eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNjJiZmNmYjQ4OWRhODY3ZGNlOTZlM2MzYzE3YTNkYjdjNzljYWU4YWMxZjlhNWE4YzhhYzk1ZTRiYTMifX19", 4);
+ integers.put("eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZWY0ZWNmMTEwYjBhY2VlNGFmMWRhMzQzZmIxMzZmMWYyYzIxNjg1N2RmZGE2OTYxZGVmZGJlZTdiOTUyOCJ9fX0=", 5);
+ integers.put("eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZjMzMWE2YTZmY2Q2OTk1YjYyMDg4ZDM1M2JmYjY4ZDliODlhZTI1ODMyNWNhZjNmMjg4NjQ2NGY1NGE3MzI5In19fQ==", 6);
+ integers.put("eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZDRiYTZhYzA3ZDQyMjM3N2E4NTU3OTNmMzZkZWEyZWQyNDAyMjNmNTJmZDE2NDgxODE2MTJlY2QxYTBjZmQ1In19fQ==", 7);
+ integers.put("eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYzYxYThhNjQxNDM3YmU5YWVhMjA3MjUzZGQzZjI1NDQwZDk1NGVhMmI1ODY2YzU1MmYzODZiMjlhYzRkMDQ5In19fQ==", 8);
+ integers.put("eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYTE5MjhlMWJmZDg2YTliNzkzOTdjNGNiNGI2NWVmOTlhZjQ5YjdkNWY3OTU3YWQ2MmMwYzY5OWE2MjJjZmJlIn19fQ==", 9);
+ integers.put("eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNTVhMjI0ODA3NjkzOTc4ZWQ4MzQzNTVmOWU1MTQ1ZjljNTZlZjY4Y2Y2ZjJjOWUxNzM0YTQ2ZTI0NmFhZTEifX19", 0);
+ }
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bombdefuse/chambers/number/NumberProcessorMatcher.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bombdefuse/chambers/number/NumberProcessorMatcher.java
new file mode 100644
index 00000000..488583ff
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bombdefuse/chambers/number/NumberProcessorMatcher.java
@@ -0,0 +1,53 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.bombdefuse.chambers.number;
+
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.bombdefuse.RoomProcessorBombDefuseSolver;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.bombdefuse.chambers.BDChamber;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.bombdefuse.chambers.BombDefuseChamberGenerator;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.bombdefuse.chambers.ChamberProcessor;
+import net.minecraft.init.Blocks;
+
+public class NumberProcessorMatcher implements BombDefuseChamberGenerator {
+ @Override
+ public boolean match(BDChamber left, BDChamber right) {
+ return left.getBlock(1,1,4).getBlock() == Blocks.stone &&
+ left.getBlock(2,1,4).getBlock() == Blocks.stone &&
+ left.getBlock(6,1,4).getBlock() == Blocks.stone &&
+ left.getBlock(7,1,4).getBlock() == Blocks.stone &&
+ right.getBlock(1,1,4).getBlock() == Blocks.stone &&
+ right.getBlock(2,1,4).getBlock() == Blocks.stone &&
+ right.getBlock(6,1,4).getBlock() == Blocks.stone &&
+ right.getBlock(7,1,4).getBlock() == Blocks.stone;
+ }
+
+ @Override
+ public String getName() {
+ return "numberMatch";
+ }
+ @Override
+ public ChamberProcessor createLeft(BDChamber left, RoomProcessorBombDefuseSolver solver) {
+ return new NumberLeftProcessor(solver, left);
+ }
+
+ @Override
+ public ChamberProcessor createRight(BDChamber right, RoomProcessorBombDefuseSolver solver) {
+ return new NumberRightProcessor(solver, right);
+ }
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bombdefuse/chambers/number/NumberRightProcessor.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bombdefuse/chambers/number/NumberRightProcessor.java
new file mode 100644
index 00000000..66ba993a
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bombdefuse/chambers/number/NumberRightProcessor.java
@@ -0,0 +1,114 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.bombdefuse.chambers.number;
+
+import com.google.common.collect.BiMap;
+import com.google.common.collect.HashBiMap;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.bombdefuse.RoomProcessorBombDefuseSolver;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.bombdefuse.chambers.BDChamber;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.bombdefuse.chambers.GeneralDefuseChamberProcessor;
+import kr.syeyoung.dungeonsguide.mod.utils.RenderUtils;
+import net.minecraft.entity.item.EntityArmorStand;
+import net.minecraft.item.ItemStack;
+import net.minecraft.nbt.NBTTagCompound;
+import net.minecraft.nbt.NBTTagList;
+import net.minecraft.util.BlockPos;
+
+public class NumberRightProcessor extends GeneralDefuseChamberProcessor {
+ public NumberRightProcessor(RoomProcessorBombDefuseSolver solver, BDChamber chamber) {
+ super(solver, chamber);
+
+ d1p = chamber.getBlockPos(1,1,4);
+ d2p = chamber.getBlockPos(2,1,4);
+ d3p = chamber.getBlockPos(6,1,4);
+ d4p = chamber.getBlockPos(7,1,4);
+ center = chamber.getBlockPos(4,4,4);
+ }
+
+ @Override
+ public String getName() {
+ return "numberRight";
+ }
+
+
+ private int answer = -1, d1, d2, d3 ,d4, a1, a2, a3, a4;
+ private final BlockPos d1p;
+ private final BlockPos d2p;
+ private final BlockPos d3p;
+ private final BlockPos d4p;
+ private final BlockPos center;
+ @Override
+ public void tick() {
+ super.tick();
+ a1 = match(getChamber().getEntityAt(EntityArmorStand.class,d1p));
+ a2 = match(getChamber().getEntityAt(EntityArmorStand.class,d2p));
+ a3 = match(getChamber().getEntityAt(EntityArmorStand.class,d3p));
+ a4 = match(getChamber().getEntityAt(EntityArmorStand.class,d4p));
+ }
+
+ @Override
+ public void drawWorld(float partialTicks) {
+ super.drawWorld(partialTicks);
+ RenderUtils.drawTextAtWorld(a1+"", d1p.getX()+ 0.5f, d1p.getY()+ 0.6f, d1p.getZ()+ 0.5f, a1 == d1 ? 0xFF00FF00 : 0xFFFF0000, 0.03F, false, false, partialTicks);
+ RenderUtils.drawTextAtWorld(a2+"", d2p.getX()+ 0.5f, d2p.getY()+ 0.6f, d2p.getZ()+ 0.5f, a2 == d2 ? 0xFF00FF00 : 0xFFFF0000, 0.03F, false, false, partialTicks);
+ RenderUtils.drawTextAtWorld(a3+"", d3p.getX()+ 0.5f, d3p.getY()+ 0.6f, d3p.getZ()+ 0.5f, a3 == d3 ? 0xFF00FF00 : 0xFFFF0000, 0.03F, false, false, partialTicks);
+ RenderUtils.drawTextAtWorld(a4+"", d4p.getX()+ 0.5f, d4p.getY()+ 0.6f, d4p.getZ()+ 0.5f, a4 == d4 ? 0xFF00FF00 : 0xFFFF0000, 0.03F, false, false, partialTicks);
+ RenderUtils.drawTextAtWorld(answer == -1 ? "Answer not received yet. Visit left room to obtain solution" : ("Solution: "+answer) , center.getX()+ 0.5f, center.getY(), center.getZ()+ 0.5f, 0xFFFFFFFF, 0.03F, false, false, partialTicks);
+ RenderUtils.drawTextAtWorld(d1+"", d1p.getX()+ 0.5f, d1p.getY()+ 0.2f, d1p.getZ()+ 0.5f, 0xFFFFFF00, 0.03F, false, false, partialTicks);
+ RenderUtils.drawTextAtWorld(d2+"", d2p.getX()+ 0.5f, d2p.getY()+ 0.2f, d2p.getZ()+ 0.5f, 0xFFFFFF00, 0.03F, false, false, partialTicks);
+ RenderUtils.drawTextAtWorld(d3+"", d3p.getX()+ 0.5f, d3p.getY()+ 0.2f, d3p.getZ()+ 0.5f, 0xFFFFFF00, 0.03F, false, false, partialTicks);
+ RenderUtils.drawTextAtWorld(d4+"", d4p.getX()+ 0.5f, d4p.getY()+ 0.2f, d4p.getZ()+ 0.5f, 0xFFFFFF00, 0.03F, false, false, partialTicks);
+ }
+
+ @Override
+ public void onDataRecieve(NBTTagCompound compound) {
+ if (1 == compound.getByte("a")) {
+ answer = compound.getInteger("b");
+ d1 = answer / 1000;
+ d2 = (answer % 1000) / 100;
+ d3 = (answer % 100) / 10;
+ d4 = (answer % 10);
+ answer = d4 * 1000 + d3 * 100 + d2 * 10 + d1;
+ }
+ }
+
+ private int match(EntityArmorStand armorStand) {
+ if (armorStand == null) {
+ return -1;
+ }
+ ItemStack item = armorStand.getInventory()[4];
+ NBTTagList list = item.getTagCompound().getCompoundTag("SkullOwner").getCompoundTag("Properties").getTagList("textures", 10);
+ String str = ((NBTTagCompound)list.get(0)).getString("Value");
+ return !integers.containsKey(str) ? -1 : integers.get(str);
+ }
+
+ private static final BiMap<String, Integer> integers = HashBiMap.create(10);
+ {
+ integers.put("eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNzFiYzJiY2ZiMmJkMzc1OWU2YjFlODZmYzdhNzk1ODVlMTEyN2RkMzU3ZmMyMDI4OTNmOWRlMjQxYmM5ZTUzMCJ9fX0=", 1);
+ integers.put("eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNGNkOWVlZWU4ODM0Njg4ODFkODM4NDhhNDZiZjMwMTI0ODVjMjNmNzU3NTNiOGZiZTg0ODczNDE0MTk4NDcifX19", 2);
+ integers.put("eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMWQ0ZWFlMTM5MzM4NjBhNmRmNWU4ZTk1NTY5M2I5NWE4YzNiMTVjMzZiOGI1ODc1MzJhYzA5OTZiYzM3ZTUifX19", 3);
+ integers.put("eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZDJlNzhmYjIyNDI0MjMyZGMyN2I4MWZiY2I0N2ZkMjRjMWFjZjc2MDk4NzUzZjJkOWMyODU5ODI4N2RiNSJ9fX0=", 4);
+ integers.put("eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNmQ1N2UzYmM4OGE2NTczMGUzMWExNGUzZjQxZTAzOGE1ZWNmMDg5MWE2YzI0MzY0M2I4ZTU0NzZhZTIifX19", 5);
+ integers.put("eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMzM0YjM2ZGU3ZDY3OWI4YmJjNzI1NDk5YWRhZWYyNGRjNTE4ZjVhZTIzZTcxNjk4MWUxZGNjNmIyNzIwYWIifX19", 6);
+ integers.put("eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNmRiNmViMjVkMWZhYWJlMzBjZjQ0NGRjNjMzYjU4MzI0NzVlMzgwOTZiN2UyNDAyYTNlYzQ3NmRkN2I5In19fQ==", 7);
+ integers.put("eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNTkxOTQ5NzNhM2YxN2JkYTk5NzhlZDYyNzMzODM5OTcyMjI3NzRiNDU0Mzg2YzgzMTljMDRmMWY0Zjc0YzJiNSJ9fX0=", 8);
+ integers.put("eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZTY3Y2FmNzU5MWIzOGUxMjVhODAxN2Q1OGNmYzY0MzNiZmFmODRjZDQ5OWQ3OTRmNDFkMTBiZmYyZTViODQwIn19fQ==", 9);
+ integers.put("eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMGViZTdlNTIxNTE2OWE2OTlhY2M2Y2VmYTdiNzNmZGIxMDhkYjg3YmI2ZGFlMjg0OWZiZTI0NzE0YjI3In19fQ==", 0);
+ }
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bossfight/BossfightProcessor.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bossfight/BossfightProcessor.java
new file mode 100644
index 00000000..12ef6bdf
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bossfight/BossfightProcessor.java
@@ -0,0 +1,33 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.bossfight;
+
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.RoomProcessor;
+
+import java.util.List;
+
+public interface BossfightProcessor extends RoomProcessor {
+ List<String> getPhases();
+ String getCurrentPhase();
+ List<String> getNextPhases();
+
+ List<HealthData> getHealths();
+
+ String getBossName();
+} \ No newline at end of file
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bossfight/BossfightProcessorBonzo.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bossfight/BossfightProcessorBonzo.java
new file mode 100644
index 00000000..3380a447
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bossfight/BossfightProcessorBonzo.java
@@ -0,0 +1,85 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.bossfight;
+
+import kr.syeyoung.dungeonsguide.mod.utils.TextUtils;
+import net.minecraft.entity.item.EntityArmorStand;
+import net.minecraftforge.event.entity.living.LivingEvent;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class BossfightProcessorBonzo extends GeneralBossfightProcessor {
+ public BossfightProcessorBonzo() {
+ addPhase(GeneralBossfightProcessor.PhaseData.builder()
+ .phase("start")
+ .signatureMsg("§r§c[BOSS] Bonzo §r§f: Gratz for making it this far, but I’m basically unbeatable.§r")
+ .nextPhase("fight-1").build()
+ );
+
+ addPhase(GeneralBossfightProcessor.PhaseData.builder()
+ .phase("fight-1")
+ .signatureMsg("§r§c[BOSS] Bonzo §r§f: I can summon lots of undead! Check this out.§r")
+ .nextPhase("first-defeat").build()
+ );
+ addPhase(GeneralBossfightProcessor.PhaseData.builder()
+ .phase("first-defeat")
+ .signatureMsg("§r§c[BOSS] Bonzo §r§f: Oh I'm dead!§r").signatureMsg("§r§c[BOSS] Bonzo §r§f: Hoho, looks like you killed me!§r")
+ .nextPhase("fight-2").build()
+ );
+ addPhase(GeneralBossfightProcessor.PhaseData.builder()
+ .phase("fight-2")
+ .signatureMsg("§r§c[BOSS] Bonzo §r§f: Sike§r").signatureMsg("§r§c[BOSS] Bonzo §r§f: I can revive myself and become much stronger!§r")
+ .nextPhase("final-defeat").build()
+ );
+ addPhase(GeneralBossfightProcessor.PhaseData.builder()
+ .phase("final-defeat")
+ .signatureMsg("§r§c[BOSS] Bonzo §r§f: Alright, maybe I'm just weak after all..§r").build()
+ );
+ }
+
+
+ @Override
+ public List<HealthData> getHealths() {
+ List<HealthData> healths = new ArrayList<HealthData>();
+ long health = 0;
+ if (bonzoStand != null) {
+ String name = TextUtils.stripColor(bonzoStand.getName());
+ String healthPart = name.split(" ")[2];
+ health = TextUtils.reverseFormat(healthPart.substring(0, healthPart.length() - 1));
+ }
+ healths.add(new HealthData("Bonzo", (int) health,250000 , this.getCurrentPhase().startsWith("fight-")));
+ return healths;
+ }
+
+ @Override
+ public String getBossName() {
+ return "Bonzo";
+ }
+
+ private EntityArmorStand bonzoStand;
+ @Override
+ // §e﴾ §c§lBonzo§r §e71k§c❤ §e﴿
+ // §e﴾ §c§lBonzo§r §a250k§c❤ §e﴿
+ public void onEntityUpdate(LivingEvent.LivingUpdateEvent updateEvent) {
+ if (updateEvent.entityLiving.getName().startsWith("§e﴾ §c§lBonzo§r ") && updateEvent.entityLiving instanceof EntityArmorStand) {
+ bonzoStand = (EntityArmorStand) updateEvent.entityLiving;
+ }
+ }
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bossfight/BossfightProcessorLivid.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bossfight/BossfightProcessorLivid.java
new file mode 100644
index 00000000..f75226b6
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bossfight/BossfightProcessorLivid.java
@@ -0,0 +1,90 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.bossfight;
+
+import kr.syeyoung.dungeonsguide.mod.utils.TextUtils;
+import lombok.Getter;
+import net.minecraft.client.entity.EntityOtherPlayerMP;
+import net.minecraft.entity.item.EntityArmorStand;
+import net.minecraftforge.event.entity.living.LivingEvent;
+
+import java.util.*;
+
+@Getter
+public class BossfightProcessorLivid extends GeneralBossfightProcessor {
+ private String realLividName;
+ private String prefix;
+ private EntityOtherPlayerMP realLivid;
+
+ private final Set<String> knownLivids = new HashSet<String>();
+
+ private boolean isMasterMode;
+
+ public BossfightProcessorLivid(boolean isMasterMode) {
+ addPhase(PhaseData.builder().phase("start").build());
+ this.isMasterMode = isMasterMode;
+ }
+ private static final Map<String, String> lividColorPrefix = new HashMap<String, String>() {{
+ put("Vendetta", "§f");
+ put("Crossed", "§d");
+ put("Hockey", "§c");
+ put("Doctor", "§7");
+ put("Frog", "§2");
+ put("Smile", "§a");
+ put("Scream", "§1");
+ put("Purple", "§5");
+ put("Arcade", "§e");
+ }};
+ @Override
+ public void onEntityUpdate(LivingEvent.LivingUpdateEvent updateEvent) {
+ if (updateEvent.entityLiving.getName().endsWith("Livid") && updateEvent.entityLiving instanceof EntityOtherPlayerMP) {
+ if (!knownLivids.contains(updateEvent.entityLiving.getName())) {
+ knownLivids.add(updateEvent.entityLiving.getName());
+ realLividName = updateEvent.entityLiving.getName();
+ realLivid = (EntityOtherPlayerMP) updateEvent.entityLiving;
+ prefix = lividColorPrefix.get(realLividName.split(" ")[0]);
+ } else if (realLividName.equalsIgnoreCase(updateEvent.entityLiving.getName())) {
+ realLivid = (EntityOtherPlayerMP) updateEvent.entityLiving;
+ }
+ } else if (updateEvent.entityLiving.getName().startsWith(prefix+"﴾ ") && updateEvent.entityLiving instanceof EntityArmorStand) {
+ lividStand = (EntityArmorStand) updateEvent.entityLiving;
+ }
+ }
+ private EntityArmorStand lividStand;
+
+ @Override
+ public List<HealthData> getHealths() {
+ List<HealthData> healths = new ArrayList<HealthData>();
+ long health = 0;
+ if (lividStand != null) {
+ try {
+ String name = TextUtils.stripColor(lividStand.getName());
+ String healthPart = name.split(" ")[2];
+ health = TextUtils.reverseFormat(healthPart.substring(0, healthPart.length() - 1));
+ } catch (Exception e) {e.printStackTrace();}
+ }
+ healths.add(new HealthData(realLividName == null ? "unknown" : realLividName, (int) health,isMasterMode ? 600000000 : 7000000 , true));
+ return healths;
+ }
+
+ @Override
+ public String getBossName() {
+ return realLividName == null ? "Livid" : realLividName;
+ }
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bossfight/BossfightProcessorNecron.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bossfight/BossfightProcessorNecron.java
new file mode 100644
index 00000000..49b572fe
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bossfight/BossfightProcessorNecron.java
@@ -0,0 +1,77 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.bossfight;
+
+import net.minecraft.entity.boss.BossStatus;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class BossfightProcessorNecron extends GeneralBossfightProcessor {
+ // \A7 to §
+ public BossfightProcessorNecron() {
+ addPhase(PhaseData.builder()
+ .phase("crystals")
+ .signatureMsg("§r§4[BOSS] Necron§r§c: §r§cFinally, I heard so much about you. The Eye likes you very much.§r")
+ .nextPhase("laser-attack").nextPhase("lost").build()
+ );
+ addPhase(PhaseData.builder()
+ .phase("laser-attack")
+ .signatureMsg("§r§4[BOSS] Necron§r§c: §r§cYou tricked me!§r")
+ .nextPhase("fight-1").nextPhase("lost").build()
+ );
+ addPhase(PhaseData.builder()
+ .phase("fight-1")
+ .signatureMsg("§r§4[BOSS] Necron§r§c: §r§cFINE! LET'S MOVE TO SOMEWHERE ELSE!!§r")
+ .nextPhase("terminals").nextPhase("lost").build()
+ );
+ addPhase(PhaseData.builder()
+ .phase("terminals")
+ .signatureMsg("§r§4[BOSS] Necron§r§c: §r§cCRAP!! IT BROKE THE FLOOR!§r")
+ .nextPhase("fight-2").nextPhase("lost").build()
+ );
+ addPhase(PhaseData.builder()
+ .phase("fight-2")
+ .signatureMsg("§r§4[BOSS] Necron§r§c: §r§cTHAT'S IT YOU HAVE DONE IT!§r")
+ .nextPhase("won").nextPhase("lost").build()
+ );
+ addPhase(PhaseData.builder()
+ .phase("won")
+ .signatureMsg("§r§4[BOSS] Necron§r§c: §r§cAll this, for nothing...§r").build()
+ );
+ addPhase(PhaseData.builder()
+ .phase("lost")
+ .signatureMsg("§r§4[BOSS] Necron§r§c: §r§cFINALLY! This took way too long.§r").build()
+ );
+ }
+
+
+ @Override
+ public List<HealthData> getHealths() {
+ List<HealthData> healths = new ArrayList<HealthData>();
+ int maxHealth = 1_000_000_000;
+ healths.add(new HealthData("Necron", (int) (BossStatus.healthScale * maxHealth),maxHealth , this.getCurrentPhase().startsWith("fight-")));
+ return healths;
+ }
+
+ @Override
+ public String getBossName() {
+ return "Necron";
+ }
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bossfight/BossfightProcessorProf.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bossfight/BossfightProcessorProf.java
new file mode 100644
index 00000000..169b9773
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bossfight/BossfightProcessorProf.java
@@ -0,0 +1,144 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.bossfight;
+
+import kr.syeyoung.dungeonsguide.mod.utils.TextUtils;
+import net.minecraft.entity.item.EntityArmorStand;
+import net.minecraftforge.event.entity.living.LivingEvent;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class BossfightProcessorProf extends GeneralBossfightProcessor {
+ public BossfightProcessorProf() {
+ addPhase(GeneralBossfightProcessor.PhaseData.builder()
+ .phase("start")
+ .signatureMsg("§r§c[BOSS] The Professor§r§f: I was burdened with terrible news recently...§r")
+ .nextPhase("fight-1").build()
+ );
+ addPhase(GeneralBossfightProcessor.PhaseData.builder()
+ .phase("fight-1")
+ .signatureMsg("§r§c[BOSS] The Professor§r§f: I'll show you real power!§r")
+ .nextPhase("first-defeat").build()
+ );
+ addPhase(GeneralBossfightProcessor.PhaseData.builder()
+ .phase("first-defeat")
+ .signatureMsg("§r§c[BOSS] The Professor§r§f: Oh? You found my Guardians one weakness?§r")
+ .nextPhase("fight-2").build()
+ );
+ addPhase(GeneralBossfightProcessor.PhaseData.builder()
+ .phase("fight-2")
+ .signatureMsg("§r§c[BOSS] The Professor§r§f: This time I'll be your opponent!§r")
+ .nextPhase("second-defeat").build()
+ );
+ addPhase(GeneralBossfightProcessor.PhaseData.builder()
+ .phase("second-defeat")
+ .signatureMsg("§r§c[BOSS] The Professor§r§f: I see. You have forced me to use my ultimate technique.§r")
+ .nextPhase("fight-3").build()
+ );
+ addPhase(GeneralBossfightProcessor.PhaseData.builder()
+ .phase("fight-3")
+ .signatureMsg("§r§c[BOSS] The Professor§r§f: The process is irreversible, but I'll be stronger than a Wither now!§r")
+ .nextPhase("final-defeat").build()
+ );
+ addPhase(GeneralBossfightProcessor.PhaseData.builder()
+ .phase("final-defeat")
+ .signatureMsg("§r§c[BOSS] The Professor§r§f: What?! My Guardian power is unbeatable!§r").build()
+ );
+ }
+
+ @Override
+ public List<HealthData> getHealths() {
+ List<HealthData> healths = new ArrayList<HealthData>();
+ {
+ long health = 0;
+ if (profStand != null) {
+ String name = TextUtils.stripColor(profStand.getName());
+ String healthPart = name.split(" ")[3];
+ health = TextUtils.reverseFormat(healthPart.substring(0, healthPart.length() - 1));
+ }
+ healths.add(new HealthData("The Professor", (int) health, 3000000, this.getCurrentPhase().startsWith("fight-") && !this.getCurrentPhase().equals("fight-1")));
+ }
+ if (!getCurrentPhase().equals("second-defeat") && !getCurrentPhase().equals("fight-3") && !getCurrentPhase().equals("final-defeat")) {
+ {
+ long health = 0;
+ if (healthyGuard != null) {
+ String name = TextUtils.stripColor(healthyGuard.getName());
+ String healthPart = name.split(" ")[2];
+ health = TextUtils.reverseFormat(healthPart.substring(0, healthPart.length() - 1));
+ }
+ healths.add(new HealthData("Healthy Guardian", (int) health, 1000000, this.getCurrentPhase().equals("fight-1")));
+ }
+ {
+ long health = 0;
+ if (chaosGuard != null) {
+ String name = TextUtils.stripColor(chaosGuard.getName());
+ String healthPart = name.split(" ")[2];
+ health = TextUtils.reverseFormat(healthPart.substring(0, healthPart.length() - 1));
+ }
+ healths.add(new HealthData("Chaos Guardian", (int) health, 1000000, this.getCurrentPhase().equals("fight-1")));
+ }
+ {
+ long health = 0;
+ if (laserGuard != null) {
+ String name = TextUtils.stripColor(laserGuard.getName());
+ String healthPart = name.split(" ")[2];
+ health = TextUtils.reverseFormat(healthPart.substring(0, healthPart.length() - 1));
+ }
+ healths.add(new HealthData("Laser Guardian", (int) health, 1000000, this.getCurrentPhase().equals("fight-1")));
+ }
+ {
+ long health = 0;
+ if (reinforcedGuard != null) {
+ String name = TextUtils.stripColor(reinforcedGuard.getName());
+ String healthPart = name.split(" ")[2];
+ health = TextUtils.reverseFormat(healthPart.substring(0, healthPart.length() - 1));
+ }
+ healths.add(new HealthData("Reinforced Guardian", (int) health, 1000000, this.getCurrentPhase().equals("fight-1")));
+ }
+ }
+ return healths;
+ }
+
+ @Override
+ public String getBossName() {
+ return "The Professor";
+ }
+
+ private EntityArmorStand profStand;
+ private EntityArmorStand laserGuard;
+ private EntityArmorStand chaosGuard;
+ private EntityArmorStand reinforcedGuard;
+ private EntityArmorStand healthyGuard;
+ @Override
+ public void onEntityUpdate(LivingEvent.LivingUpdateEvent updateEvent) {
+ if (updateEvent.entityLiving instanceof EntityArmorStand) {
+ if (updateEvent.entityLiving.getName().startsWith("§e﴾ §c§lThe Professor§r "))
+ profStand = (EntityArmorStand) updateEvent.entityLiving;
+ else if (updateEvent.entityLiving.getName().startsWith("§cHealthy Guardian "))
+ healthyGuard = (EntityArmorStand) updateEvent.entityLiving;
+ else if (updateEvent.entityLiving.getName().startsWith("§cChaos Guardian "))
+ chaosGuard = (EntityArmorStand) updateEvent.entityLiving;
+ else if (updateEvent.entityLiving.getName().startsWith("§cLaser Guardian "))
+ laserGuard = (EntityArmorStand) updateEvent.entityLiving;
+ else if (updateEvent.entityLiving.getName().startsWith("§cReinforced Guardian "))
+ reinforcedGuard = (EntityArmorStand) updateEvent.entityLiving;
+ }
+ }
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bossfight/BossfightProcessorSadan.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bossfight/BossfightProcessorSadan.java
new file mode 100644
index 00000000..0de8aa56
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bossfight/BossfightProcessorSadan.java
@@ -0,0 +1,144 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.bossfight;
+
+import kr.syeyoung.dungeonsguide.mod.utils.TextUtils;
+import net.minecraft.entity.item.EntityArmorStand;
+import net.minecraftforge.event.entity.living.LivingEvent;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class BossfightProcessorSadan extends GeneralBossfightProcessor {
+ public BossfightProcessorSadan() {
+ addPhase(PhaseData.builder()
+ .phase("start")
+ .signatureMsg("So you made it all the way §r§fhere...and§r§f you wish to defy me? Sadan?!§r")
+ .nextPhase("fight-1").build()
+ );
+ addPhase(PhaseData.builder()
+ .phase("fight-1")
+ .signatureMsg("§r§c[BOSS] Sadan §r§f: I am the bridge between this realm and the world below! You shall not pass!§r")
+ .nextPhase("first-defeat").build()
+ );
+ addPhase(PhaseData.builder()
+ .phase("first-defeat")
+ .signatureMsg("§r§c[BOSS] Sadan §r§f: ENOUGH!§r")
+ .nextPhase("fight-2").build()
+ );
+ addPhase(PhaseData.builder()
+ .phase("fight-2")
+ .signatureMsg("§r§c[BOSS] Sadan §r§f: My giants! Unleashed!§r")
+ .nextPhase("second-defeat").build()
+ );
+ addPhase(PhaseData.builder()
+ .phase("second-defeat")
+ .signatureMsg("§r§c[BOSS] Sadan §r§f: You did it. I understand now, you have earned my respect.§r")
+ .nextPhase("fight-3").build()
+ );
+ addPhase(PhaseData.builder()
+ .phase("fight-3")
+ .signatureMsg("§r§c[BOSS] Sadan §r§f: I'm sorry but I need to concentrate. I wish it didn't have to come to this.§r")
+ .nextPhase("final-defeat").build()
+ );
+ addPhase(PhaseData.builder()
+ .phase("final-defeat")
+ .signatureMsg("§r§c[BOSS] Sadan §r§f: NOOOOOOOOO!!! THIS IS IMPOSSIBLE!!§r").build()
+ );
+ }
+
+ @Override
+ public List<HealthData> getHealths() {
+ List<HealthData> healths = new ArrayList<HealthData>();
+ {
+ long health = 0;
+ if (sadanStand != null) {
+ String name = TextUtils.stripColor(sadanStand.getName());
+ String healthPart = name.split(" ")[2];
+ health = TextUtils.reverseFormat(healthPart.substring(0, healthPart.length() - 1));
+ }
+ healths.add(new HealthData("Sadan", (int) health, 40000000, this.getCurrentPhase().equals("fight-3")));
+ }
+ if (getCurrentPhase().equals("fight-2")) {
+ {
+ long health = 0;
+ if (diamondGiant != null) {
+ String name = TextUtils.stripColor(diamondGiant.getName());
+ String healthPart = name.split(" ")[3];
+ health = TextUtils.reverseFormat(healthPart.substring(0, healthPart.length() - 1));
+ }
+ healths.add(new HealthData("The Diamond Giant", (int) health, 25000000, this.getCurrentPhase().startsWith("fight-")));
+ }
+ {
+ long health = 0;
+ if (bigfootGiant != null) {
+ String name = TextUtils.stripColor(bigfootGiant.getName());
+ String healthPart = name.split(" ")[1];
+ health = TextUtils.reverseFormat(healthPart.substring(0, healthPart.length() - 1));
+ }
+ healths.add(new HealthData("Bigfoot", (int) health, 25000000, this.getCurrentPhase().startsWith("fight-")));
+ }
+ {
+ long health = 0;
+ if (laserGiant != null) {
+ String name = TextUtils.stripColor(laserGiant.getName());
+ String healthPart = name.split(" ")[1];
+ health = TextUtils.reverseFormat(healthPart.substring(0, healthPart.length() - 1));
+ }
+ healths.add(new HealthData("L.A.S.R.", (int) health, 25000000, this.getCurrentPhase().startsWith("fight-")));
+ }
+ {
+ long health = 0;
+ if (boulderGiant != null) {
+ String name = TextUtils.stripColor(boulderGiant.getName());
+ String healthPart = name.split(" ")[3];
+ health = TextUtils.reverseFormat(healthPart.substring(0, healthPart.length() - 1));
+ }
+ healths.add(new HealthData("Jolly Pink Giant", (int) health, 25000000, this.getCurrentPhase().startsWith("fight-")));
+ }
+ }
+ return healths;
+ }
+
+ @Override
+ public String getBossName() {
+ return "Sadan";
+ }
+
+ private EntityArmorStand sadanStand;
+ private EntityArmorStand diamondGiant;
+ private EntityArmorStand laserGiant;
+ private EntityArmorStand bigfootGiant;
+ private EntityArmorStand boulderGiant;
+ @Override
+ public void onEntityUpdate(LivingEvent.LivingUpdateEvent updateEvent) {
+ if (updateEvent.entityLiving instanceof EntityArmorStand) {
+ if (updateEvent.entityLiving.getName().startsWith("§e﴾ §c§lSadan§r "))
+ sadanStand = (EntityArmorStand) updateEvent.entityLiving;
+ else if (updateEvent.entityLiving.getName().startsWith("§c§d§lJolly Pink Giant "))
+ boulderGiant = (EntityArmorStand) updateEvent.entityLiving;
+ else if (updateEvent.entityLiving.getName().startsWith("§c§4§lL.A.S.R. "))
+ laserGiant = (EntityArmorStand) updateEvent.entityLiving;
+ else if (updateEvent.entityLiving.getName().startsWith("§c§3§lThe Diamond Giant "))
+ diamondGiant = (EntityArmorStand) updateEvent.entityLiving;
+ else if (updateEvent.entityLiving.getName().startsWith("§c§c§lBigfoot "))
+ bigfootGiant = (EntityArmorStand) updateEvent.entityLiving;
+ }
+ }
+} \ No newline at end of file
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bossfight/BossfightProcessorScarf.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bossfight/BossfightProcessorScarf.java
new file mode 100644
index 00000000..44fdea1b
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bossfight/BossfightProcessorScarf.java
@@ -0,0 +1,134 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.bossfight;
+
+import kr.syeyoung.dungeonsguide.mod.utils.TextUtils;
+import net.minecraft.entity.item.EntityArmorStand;
+import net.minecraftforge.event.entity.living.LivingEvent;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class BossfightProcessorScarf extends GeneralBossfightProcessor {
+ public BossfightProcessorScarf() {
+ addPhase(GeneralBossfightProcessor.PhaseData.builder()
+ .phase("start")
+ .signatureMsg("§r§c[BOSS] Scarf §r§f: This is where the journey ends for you, Adventurers.§r")
+ .nextPhase("fight-1").build()
+ );
+ addPhase(GeneralBossfightProcessor.PhaseData.builder()
+ .phase("fight-1")
+ .signatureMsg("§r§c[BOSS] Scarf §r§f: ARISE, MY CREATIONS!§r")
+ .nextPhase("first-defeat").build()
+ );
+ addPhase(GeneralBossfightProcessor.PhaseData.builder()
+ .phase("first-defeat")
+ .signatureMsg("§r§c[BOSS] Scarf §r§f: Those toys are not strong enough I see.§r")
+ .nextPhase("fight-2").build()
+ );
+ addPhase(GeneralBossfightProcessor.PhaseData.builder()
+ .phase("fight-2")
+ .signatureMsg("§r§c[BOSS] Scarf §r§f: Did you forget? I was taught by the best! Let's dance.§r")
+ .nextPhase("final-defeat").build()
+ );
+ addPhase(GeneralBossfightProcessor.PhaseData.builder()
+ .phase("final-defeat")
+ .signatureMsg("§r§c[BOSS] Scarf §r§f: Whatever...§r").build()
+ );
+ }
+
+ @Override
+ public List<HealthData> getHealths() {
+ List<HealthData> healths = new ArrayList<HealthData>();
+ {
+ long health = 0;
+ if (scarfStand != null) {
+ String name = TextUtils.stripColor(scarfStand.getName());
+ String healthPart = name.split(" ")[2];
+ health = TextUtils.reverseFormat(healthPart.substring(0, healthPart.length() - 1));
+ }
+ healths.add(new HealthData("Scarf", (int) health, 1000000, this.getCurrentPhase().equals("fight-2")));
+ }
+ if (!getCurrentPhase().equals("start") && !getCurrentPhase().equals("final-defeat")) {
+ {
+ long health = 0;
+ if (priestStand != null) {
+ String name = TextUtils.stripColor(priestStand.getName());
+ String healthPart = name.split(" ")[2];
+ health = TextUtils.reverseFormat(healthPart.substring(0, healthPart.length() - 1));
+ }
+ healths.add(new HealthData("Undead Priest", (int) health, 600000, this.getCurrentPhase().startsWith("fight-")));
+ }
+ {
+ long health = 0;
+ if (berserkStand != null) {
+ String name = TextUtils.stripColor(berserkStand.getName());
+ String healthPart = name.split(" ")[2];
+ health = TextUtils.reverseFormat(healthPart.substring(0, healthPart.length() - 1));
+ }
+ healths.add(new HealthData("Undead Warrior", (int) health, 500000, this.getCurrentPhase().startsWith("fight-")));
+ }
+ {
+ long health = 0;
+ if (mageStand != null) {
+ String name = TextUtils.stripColor(mageStand.getName());
+ String healthPart = name.split(" ")[2];
+ health = TextUtils.reverseFormat(healthPart.substring(0, healthPart.length() - 1));
+ }
+ healths.add(new HealthData("Undead Mage", (int) health, 400000, this.getCurrentPhase().startsWith("fight-")));
+ }
+ {
+ long health = 0;
+ if (archerStand != null) {
+ String name = TextUtils.stripColor(archerStand.getName());
+ String healthPart = name.split(" ")[2];
+ health = TextUtils.reverseFormat(healthPart.substring(0, healthPart.length() - 1));
+ }
+ healths.add(new HealthData("Undead Archer", (int) health, 400000, this.getCurrentPhase().startsWith("fight-")));
+ }
+ }
+ return healths;
+ }
+
+ @Override
+ public String getBossName() {
+ return "Scarf";
+ }
+
+ private EntityArmorStand scarfStand;
+ private EntityArmorStand priestStand;
+ private EntityArmorStand mageStand;
+ private EntityArmorStand berserkStand;
+ private EntityArmorStand archerStand;
+ @Override
+ public void onEntityUpdate(LivingEvent.LivingUpdateEvent updateEvent) {
+ if (updateEvent.entityLiving instanceof EntityArmorStand) {
+ if (updateEvent.entityLiving.getName().startsWith("§e﴾ §c§lScarf§r "))
+ scarfStand = (EntityArmorStand) updateEvent.entityLiving;
+ else if (updateEvent.entityLiving.getName().startsWith("§6§4§lUndead Archer "))
+ archerStand = (EntityArmorStand) updateEvent.entityLiving;
+ else if (updateEvent.entityLiving.getName().startsWith("§6§4§lUndead Mage "))
+ mageStand = (EntityArmorStand) updateEvent.entityLiving;
+ else if (updateEvent.entityLiving.getName().startsWith("§6§4§lUndead Priest "))
+ priestStand = (EntityArmorStand) updateEvent.entityLiving;
+ else if (updateEvent.entityLiving.getName().startsWith("§6§4§lUndead Warrior "))
+ berserkStand = (EntityArmorStand) updateEvent.entityLiving;
+ }
+ }
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bossfight/BossfightProcessorThorn.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bossfight/BossfightProcessorThorn.java
new file mode 100644
index 00000000..eb5a71d6
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bossfight/BossfightProcessorThorn.java
@@ -0,0 +1,103 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.bossfight;
+
+import kr.syeyoung.dungeonsguide.mod.DungeonsGuide;
+import kr.syeyoung.dungeonsguide.mod.features.FeatureRegistry;
+import kr.syeyoung.dungeonsguide.mod.utils.RenderUtils;
+import net.minecraft.block.Block;
+import net.minecraft.entity.boss.BossStatus;
+import net.minecraft.init.Blocks;
+import net.minecraft.util.BlockPos;
+import net.minecraft.world.World;
+
+import java.awt.*;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+public class BossfightProcessorThorn extends GeneralBossfightProcessor {
+
+
+ public BossfightProcessorThorn() {
+ addPhase(GeneralBossfightProcessor.PhaseData.builder()
+ .phase("fight").build()
+ );
+ w= DungeonsGuide.getDungeonsGuide().getDungeonFacade().getContext().getWorld();
+ }
+ private final Set<BlockPos> progressBar = new HashSet<BlockPos>();
+ private final World w;
+
+ private int ticksPassed = 0;
+
+ @Override
+ public void tick() {
+ ticksPassed ++;
+ if (ticksPassed == 20) {
+ progressBar.clear();
+ for (int x = -30; x <= 30; x++) {
+ for (int y = -30; y <= 30; y++) {
+ BlockPos newPos = new BlockPos(5 + x, 77, 5 + y);
+ Block b = w.getBlockState(newPos).getBlock();
+ if ((b == Blocks.coal_block || b == Blocks.sea_lantern) && w.getBlockState(newPos.add(0, 1, 0)).getBlock() != Blocks.carpet)
+ progressBar.add(newPos);
+ }
+ }
+ }
+ }
+
+ @Override
+ public List<HealthData> getHealths() {
+ List<HealthData> healths = new ArrayList<HealthData>();
+ healths.add(new HealthData("Thorn", Math.round(BossStatus.healthScale * 4),4, true));
+ return healths;
+ }
+
+ @Override
+ public String getBossName() {
+ return "Thorn";
+ }
+
+ public double calculatePercentage() {
+ int total = progressBar.size(), lit = 0;
+ if (total == 0) return 0;
+ for (BlockPos pos : progressBar) {
+ if (w.getBlockState(pos).getBlock() == Blocks.sea_lantern ) lit++;
+ }
+
+ return lit / (double)total;
+ }
+
+ @Override
+ public void drawWorld(float partialTicks) {
+ super.drawWorld(partialTicks);
+ if (!FeatureRegistry.DEBUG.isEnabled()) return;
+ try {
+ BlockPos pos = new BlockPos(205,77, 205);
+ RenderUtils.highlightBlock(pos, new Color(0, 255, 255, 50), partialTicks, false);
+ for (BlockPos pos2 : progressBar) {
+ RenderUtils.highlightBlock(pos2, w.getBlockState(pos2).getBlock() == Blocks.sea_lantern ?
+ new Color(0, 255, 0, 50) : new Color(255,0,0, 50), partialTicks, false);
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bossfight/GeneralBossfightProcessor.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bossfight/GeneralBossfightProcessor.java
new file mode 100644
index 00000000..50fd9868
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bossfight/GeneralBossfightProcessor.java
@@ -0,0 +1,155 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.bossfight;
+
+import kr.syeyoung.dungeonsguide.mod.events.impl.BlockUpdateEvent;
+import kr.syeyoung.dungeonsguide.mod.events.impl.KeyBindPressedEvent;
+import kr.syeyoung.dungeonsguide.mod.events.impl.PlayerInteractEntityEvent;
+import lombok.*;
+import net.minecraft.util.IChatComponent;
+import net.minecraft.world.World;
+import net.minecraftforge.client.event.GuiScreenEvent;
+import net.minecraftforge.event.entity.living.LivingDeathEvent;
+import net.minecraftforge.event.entity.living.LivingEvent;
+import net.minecraftforge.event.entity.player.PlayerInteractEvent;
+
+import java.util.*;
+
+public abstract class GeneralBossfightProcessor implements BossfightProcessor {
+ private final Map<String, PhaseData> phases = new HashMap<String, PhaseData>();
+ private PhaseData currentPhase = null;
+
+ @Getter
+ @Setter
+ private String name;
+
+ private World world;
+
+ public void addPhase(PhaseData phaseData) {
+ if (phaseData == null) return;
+ if (currentPhase == null) currentPhase = phaseData;
+ phases.put(phaseData.getPhase(), phaseData);
+ }
+
+ @Override
+ public List<String> getPhases() {
+ List<String> phases = new ArrayList<String>();
+ for (PhaseData pd:this.phases.values())
+ phases.add(pd.getPhase());
+ return phases;
+ }
+
+ @Override
+ public List<String> getNextPhases() {
+ if (currentPhase == null) return Collections.emptyList();
+ List<String> phases = new ArrayList<String>(this.currentPhase.getNextPhases());
+ return phases;
+ }
+
+
+ @Override
+ public String getCurrentPhase() {
+ return currentPhase == null ? "unknown" : currentPhase.getPhase();
+ }
+
+ @Override
+ public void chatReceived(IChatComponent chat) {
+ if (currentPhase == null) return;
+
+ for (String nextPhase : currentPhase.getNextPhases()) {
+ PhaseData phaseData = phases.get(nextPhase);
+ if (phaseData == null) continue;
+ if (phaseData.signatureMsgs.contains(chat.getFormattedText().replace(" ", ""))) {
+ currentPhase = phaseData;
+ onPhaseChange();
+ return;
+ }
+ }
+ }
+
+ @Override
+ public void actionbarReceived(IChatComponent chat) {}
+
+ @Override
+ public void tick() {}
+
+ @Override
+ public void drawScreen(float partialTicks) {}
+
+ @Override
+ public void drawWorld(float partialTicks) {}
+
+ @Override
+ public boolean readGlobalChat() {return true;}
+
+ @Override
+ public void onPostGuiRender(GuiScreenEvent.DrawScreenEvent.Post event) {
+
+ }
+
+ @Override
+ public void onEntityUpdate(LivingEvent.LivingUpdateEvent updateEvent) {
+
+ }
+
+ @Override
+ public void onInteract(PlayerInteractEntityEvent event) {
+
+ }
+
+ @Override
+ public void onKeybindPress(KeyBindPressedEvent keyInputEvent) {
+
+ }
+
+ @Override
+ public void onInteractBlock(PlayerInteractEvent event) {
+
+ }
+ @Override
+ public void onEntityDeath(LivingDeathEvent deathEvent) {
+
+ }
+ @Override
+ public void onBlockUpdate(BlockUpdateEvent blockUpdateEvent) {
+
+ }
+
+ public void onPhaseChange() {}
+
+ @Data
+ @Builder
+ public static class PhaseData {
+ private PhaseData(String phase, Set<String> signatureMsgs, Set<String> nextPhase) {
+ this.phase = phase;
+ this.nextPhases = new HashSet<>(nextPhase);
+ this.signatureMsgs = new HashSet<>();
+ for (String signatureMsg : signatureMsgs) {
+ this.signatureMsgs.add(signatureMsg.replace(" ", ""));
+ }
+ }
+
+ private String phase;
+ @Singular
+ private Set<String> signatureMsgs;
+ @Singular
+ private Set<String> nextPhases;
+
+ }
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bossfight/HealthData.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bossfight/HealthData.java
new file mode 100644
index 00000000..ace9b39b
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/bossfight/HealthData.java
@@ -0,0 +1,33 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.bossfight;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class HealthData {
+ private String name;
+ private int health;
+ private int maxHealth;
+ private boolean attackable;
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/boxpuzzle/BoxPuzzleSolvingThread.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/boxpuzzle/BoxPuzzleSolvingThread.java
new file mode 100755
index 00000000..feeb7228
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/boxpuzzle/BoxPuzzleSolvingThread.java
@@ -0,0 +1,182 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.boxpuzzle;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.awt.*;
+import java.util.*;
+import java.util.List;
+
+@Getter
+@Setter
+public class BoxPuzzleSolvingThread extends Thread {
+ private byte[][] data;
+ private int playerX;
+ private int playerY;
+ private Runnable callback;
+
+
+ public BoxPuzzleSolvingThread(byte[][] data, int playerX, int playerY, Runnable onDone) {
+ this.data = data;
+ this.playerX = playerX;
+ this.playerY = playerY;
+ this.callback = onDone;
+ }
+
+ Route solution = null;
+
+ private boolean solved = false;
+
+ @Override
+ public void run() {
+ solved = false;
+ solution = solve(data,playerX,playerY, 20);
+ solved = true;
+ callback.run();
+ }
+
+
+ public static String stateString(byte[][] array) {
+ StringBuilder sb = new StringBuilder();
+ for (int y = 0; y < array.length; y++)
+ for(int x = 0; x < array[y].length; x++)
+ sb.append(array[y][x]);
+
+ return sb.toString();
+ }
+
+
+ private static final List<Point> directions = Arrays.asList(new Point(-1,0), new Point(1,0), new Point(0,1), new Point(0,-1));
+ private static Route solve(byte[][] boardStart, int playerX, int playerY, int maxRecursion) { // result:: playerY == 0
+ Queue<Route> routes = new LinkedList<Route>();
+ Set<String> globalStatesBeen = new HashSet<String>();
+
+ Route r = new Route();
+ r.currentState = boardStart;
+ routes.add(r);
+
+ while (!routes.isEmpty()) {
+ Route route = routes.poll();
+
+ if (routes.size() > 3000000) return null;
+
+ String stateId = stateString(route.currentState);
+ if (maxRecursion < route.boxMoves.size()) continue;
+ if (globalStatesBeen.contains(stateId)) continue;
+
+ Queue<Point> points = new LinkedList<Point>();
+ Set<Point> reached= new HashSet<Point>();
+ List<BoxMove> possibleBoxMoves = new ArrayList<BoxMove>();
+ points.add(new Point(playerX, playerY));
+
+ while (!points.isEmpty()) {
+ Point pt = points.poll();
+ if (pt.y == 0) {
+ return route;
+ }
+ if (reached.contains(pt)) continue;
+ reached.add(pt);
+ for (Point dir:directions) {
+ int resX= pt.x + dir.x;
+ int resY = pt.y + dir.y;
+ if (resX < 0 || resY < 0 || resX >= route.currentState[0].length || resY >= route.currentState.length) {
+ continue;
+ }
+ if (route.currentState[resY][resX] > 0) {
+ possibleBoxMoves.add(new BoxMove(resX, resY, dir.x, dir.y));
+ continue;
+ }
+ points.add(new Point(resX, resY));
+ }
+ }
+
+ globalStatesBeen.add(stateId);
+ for (BoxMove possibleBoxMove : possibleBoxMoves) {
+ byte[][] copied = new byte[route.currentState.length][];
+ for (int y = 0; y < copied.length; y++)
+ copied[y] = route.currentState[y].clone();
+
+ if (push(copied, possibleBoxMove.x, possibleBoxMove.y, possibleBoxMove.dx, possibleBoxMove.dy)){
+ String stateId2 = stateString(copied);
+ if (globalStatesBeen.contains(stateId2)) continue;
+
+ Route route2 = new Route();
+ route2.boxMoves = new ArrayList<BoxMove>(route.boxMoves);
+ route2.boxMoves.add(possibleBoxMove);
+ route2.currentState = copied;
+
+ routes.add(route2);
+ }
+ }
+ }
+
+
+ return null;
+ }
+
+
+ public static boolean push(byte[][] board, int x,int y,int dx,int dy) {
+ if (board[y][x] != 1) return false;
+ int resultingX= x + dx;
+ int resultingY = y +dy;
+ if (resultingX < 0 || resultingY < 0 || resultingX >= board[0].length || resultingY >= board.length) return false;
+ if (board[resultingY][resultingX] == 1 || resultingY == 6) return false;
+
+ board[resultingY][resultingX] = 1;
+ board[y][x] = 0;
+ return true;
+ }
+
+ public static class BoxMove {
+ int x;
+ int y;
+ int dx;
+ int dy;
+
+ public BoxMove(int x, int y, int dx, int dy) {
+ this.x = x;
+ this.y = y;
+ this.dx = dx;
+ this.dy = dy;
+ }
+
+ public int getX() {
+ return x;
+ }
+
+ public int getY() {
+ return y;
+ }
+
+ public int getDx() {
+ return dx;
+ }
+
+ public int getDy() {
+ return dy;
+ }
+ }
+
+ public static class Route {
+ List<BoxMove> boxMoves = new LinkedList<BoxMove>();
+ byte[][] currentState;
+ }
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/boxpuzzle/RoomProcessorBoxSolver.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/boxpuzzle/RoomProcessorBoxSolver.java
new file mode 100755
index 00000000..f4c80a57
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/boxpuzzle/RoomProcessorBoxSolver.java
@@ -0,0 +1,392 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.boxpuzzle;
+
+import kr.syeyoung.dungeonsguide.mod.chat.ChatTransmitter;
+import kr.syeyoung.dungeonsguide.mod.config.types.AColor;
+import kr.syeyoung.dungeonsguide.dungeon.data.OffsetPointSet;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomfinder.DungeonRoom;
+import kr.syeyoung.dungeonsguide.mod.features.FeatureRegistry;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.GeneralRoomProcessor;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.RoomProcessorGenerator;
+import kr.syeyoung.dungeonsguide.mod.utils.RenderUtils;
+import net.minecraft.block.Block;
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.gui.FontRenderer;
+import net.minecraft.client.renderer.GlStateManager;
+import net.minecraft.init.Blocks;
+import net.minecraft.util.*;
+import net.minecraft.world.World;
+import org.lwjgl.opengl.GL11;
+import org.lwjgl.opengl.GL14;
+
+import java.awt.*;
+import java.util.*;
+import java.util.List;
+
+public class RoomProcessorBoxSolver extends GeneralRoomProcessor {
+
+
+ private BlockPos[][] poses = new BlockPos[7][7];
+ private boolean bugged= true;
+
+ private BoxPuzzleSolvingThread puzzleSolvingThread;
+
+ public RoomProcessorBoxSolver(DungeonRoom dungeonRoom) {
+ super(dungeonRoom);
+
+ OffsetPointSet ops = (OffsetPointSet) dungeonRoom.getDungeonRoomInfo().getProperties().get("board");
+ try {
+ if (ops != null) {
+ for (int y = 0; y < 7; y++) {
+ for (int x = 0; x < 7; x++) {
+ poses[y][x] = ops.getOffsetPointList().get(y * 7 + x).getBlockPos(dungeonRoom);
+ }
+ }
+ bugged = false;
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ private byte[][] buildCurrentState() {
+ World w = getDungeonRoom().getContext().getWorld();
+ byte[][] board = new byte[poses.length][poses[0].length];
+ for (int y = 0; y < poses.length; y++) {
+ for (int x = 0; x < poses[0].length; x++) {
+ if (y == 6) {
+ board[y][x] = -1;
+ continue;
+ }
+ BlockPos pos = poses[y][x];
+ Block b = w.getChunkFromBlockCoords(pos).getBlock(pos);
+ if (b == Blocks.air)
+ board[y][x] = 0;
+ else
+ board[y][x] = 1;
+ }
+ }
+ return board;
+ }
+
+ private boolean calcReq = true;
+
+ private boolean calcDone= false;
+ private boolean calcDone2 = false;
+ private int step = 0;
+ private byte[][] lastState;
+
+ @Override
+ public void tick() {
+ super.tick();
+ if (!FeatureRegistry.SOLVER_BOX.isEnabled()) return;
+ if (bugged) return;
+ byte[][] currboard = buildCurrentState();
+ if (puzzleSolvingThread == null) {
+ calcDone = false;
+ puzzleSolvingThread = new BoxPuzzleSolvingThread(currboard, 0, 6, new Runnable() {
+ @Override
+ public void run() {
+ calcDone = true;
+ calcDone2 = true;
+ }
+ });
+ puzzleSolvingThread.start();
+ }
+ if (calcReq) {
+ OffsetPointSet ops = (OffsetPointSet) getDungeonRoom().getDungeonRoomInfo().getProperties().get("board");
+ if (ops != null) {
+ poses = new BlockPos[7][7];
+ for (int y = 0; y < 7; y++) {
+ for (int x = 0; x < 7; x++) {
+ poses[y][x] = ops.getOffsetPointList().get(y * 7 + x).getBlockPos(getDungeonRoom());
+ }
+ }
+ bugged = false;
+ }
+
+ calcDone = false;
+ if (puzzleSolvingThread != null)
+ puzzleSolvingThread.stop();
+ puzzleSolvingThread = new BoxPuzzleSolvingThread(currboard, 0, 6, new Runnable() {
+ @Override
+ public void run() {
+ calcDone = true;
+ calcDone2 = true;
+ }
+ });
+ puzzleSolvingThread.start();
+ calcReq = false;
+ }
+
+ boolean pathFindReq = false;
+ if (calcDone2) {
+ BoxPuzzleSolvingThread.Route semi_solution = puzzleSolvingThread.solution;
+ if (semi_solution == null) {
+ ChatTransmitter.addToQueue(new ChatComponentText("§eDungeons Guide §7:: §eBox Solver §7:: §cCouldn't find solution involving less than 20 box moves within 3m concurrent possibility"));
+ step = 0;
+ calcDone2 = false;
+ pathFindReq = true;
+ totalPath = new LinkedList<BlockPos>();
+ totalPushedBlocks = new LinkedList<BlockPos>();
+ solution = new LinkedList<BoxPuzzleSolvingThread.BoxMove>();
+ return;
+ } else{
+ solution = semi_solution.boxMoves;
+ ChatTransmitter.addToQueue(new ChatComponentText("§eDungeons Guide §7:: §eBox Solver §7:: Solution Found!"));
+ }
+ step = 0;
+ lastState = currboard;
+ calcDone2 = false;
+ pathFindReq = true;
+
+ calcTotalPath();
+ }
+
+ if (lastState == null) return;
+ boolean moved = false;
+ label:
+ for (int y = 0 ; y < currboard.length; y++) {
+ for (int x = 0; x < currboard[y].length; x++) {
+ if (lastState[y][x] != currboard[y][x]) {
+ moved = true;
+ lastState = currboard;
+ break label;
+ }
+ }
+ }
+
+ if (moved) {
+ step++;
+ }
+
+ Point player = getPlayerPos(currboard);
+ boolean currYState = Minecraft.getMinecraft().thePlayer.getPosition().getY() < 68;
+ if (((currYState && !player.equals(lastPlayer)) || (currYState != yState) || (moved) || pathFindReq) && solution != null) {
+ Point target = null;
+ if (step < solution.size()) {
+ BoxPuzzleSolvingThread.BoxMove boxMove = solution.get(step);
+ target = new Point(boxMove.x - boxMove.dx, boxMove.y - boxMove.dy);
+ }
+ List<Point> semi_pathFound = pathfind(currboard, player, target);
+ pathFound = new LinkedList<BlockPos>();
+ for (Point point : semi_pathFound) {
+ pathFound.add(poses[point.y][point.x].add(0,-1,0));
+ }
+
+ lastPlayer = player;
+ yState = currYState;
+ }
+
+ }
+
+ public void calcTotalPath() {
+ Point player = new Point(0,6);
+ totalPath = new LinkedList<BlockPos>();
+ totalPushedBlocks = new LinkedList<BlockPos>();
+ byte[][] currboard = buildCurrentState();
+ for (int i = 0; i <= solution.size(); i++) {
+ Point target = null;
+ BoxPuzzleSolvingThread.BoxMove boxMove = null;
+ if (i < solution.size()) {
+ boxMove = solution.get(i);
+ target = new Point(boxMove.x - boxMove.dx, boxMove.y - boxMove.dy);
+ }
+ List<Point> semi_pathFound = pathfind(currboard, player, target);
+ for (int i1 = semi_pathFound.size() - 1; i1 >= 0; i1--) {
+ Point point = semi_pathFound.get(i1);
+ totalPath.add(poses[point.y][point.x].add(0, -1, 0));
+ }
+
+ player = target;
+ if (boxMove != null) {
+ BoxPuzzleSolvingThread.push(currboard, boxMove.x, boxMove.y, boxMove.dx, boxMove.dy);
+ int fromX = boxMove.x - boxMove.dx;
+ int fromY = boxMove.y - boxMove.dy;
+
+ BlockPos pos = poses[fromY][fromX];
+ BlockPos pos2 = poses[boxMove.y][boxMove.x];
+ BlockPos dir = pos.subtract(pos2);
+ dir = new BlockPos(MathHelper.clamp_int(dir.getX(), -1,1), 0, MathHelper.clamp_double(dir.getZ(), -1, 1));
+
+ BlockPos highlight = pos2.add(dir);
+ totalPushedBlocks.add(highlight);
+ }
+ }
+ }
+
+ private boolean yState = true;
+ public Point getPlayerPos(byte[][] map) {
+ BlockPos playerPos = Minecraft.getMinecraft().thePlayer.getPosition();
+ int minDir = Integer.MAX_VALUE;
+ Point pt = null;
+ for (int y = 0; y < poses.length; y++) {
+ for (int x = 0; x < poses[0].length; x++) {
+ if (map[y][x] == 1) continue;
+ int dir = (int) poses[y][x].distanceSq(playerPos);
+ if (dir < minDir) {
+ minDir = dir;
+ pt = new Point(x,y);
+ }
+ }
+ }
+ return pt;
+ }
+
+ private List<BoxPuzzleSolvingThread.BoxMove> solution;
+ private List<BlockPos> pathFound;
+ private List<BlockPos> totalPath;
+ private List<BlockPos> totalPushedBlocks;
+ private Point lastPlayer;
+
+ private static final java.util.List<Point> directions = Arrays.asList(new Point(-1,0), new Point(1,0), new Point(0,1), new Point(0,-1));
+ public List<Point> pathfind(byte[][] map, Point start, Point target2) {
+ int[][] distances = new int[map.length][map[0].length];
+
+ Queue<Point> evalulate = new LinkedList<Point>();
+ evalulate.add(start);
+ Point target = null;
+ while (!evalulate.isEmpty()) {
+ Point p = evalulate.poll();
+ if (p.equals(target2) || (target2 == null &&p.y == 0)) {
+ target = p;
+ break;
+ }
+ int max = 0;
+ for (Point dir:directions) {
+ int resX= p.x + dir.x;
+ int resY = p.y + dir.y;
+ if (resX < 0 || resY < 0 || resX >= distances[0].length || resY >= distances.length) {
+ continue;
+ }
+
+ if (max < distances[resY][resX]) {
+ max = distances[resY][resX];
+ }
+ if (distances[resY][resX] == 0 && (map[resY][resX] == 0 ||map[resY][resX] == -1)) {
+ evalulate.add(new Point(resX, resY));
+ }
+ }
+ distances[p.y][p.x] = max + 1;
+ }
+ if (target == null) return Collections.emptyList();
+
+ List<Point> route = new LinkedList<Point>();
+ while(!target.equals(start)) {
+ route.add(target);
+ int min = Integer.MAX_VALUE;
+ Point minPoint = null;
+ for (Point dir:directions) {
+ int resX= target.x + dir.x;
+ int resY = target.y + dir.y;
+ if (resX < 0 || resY < 0 || resX >= distances[0].length || resY >= distances.length) {
+ continue;
+ }
+
+ if (min > distances[resY][resX] && distances[resY][resX] != 0) {
+ min = distances[resY][resX];
+ minPoint = new Point(resX, resY);
+ }
+ }
+ target = minPoint;
+ }
+ route.add(start);
+ return route;
+ }
+
+ @Override
+ public void chatReceived(IChatComponent chat) {
+ if (!FeatureRegistry.SOLVER_BOX.isEnabled()) return;
+ if (chat.getFormattedText().toLowerCase().contains("recalc")) {
+ if (calcDone) {
+ calcReq = true;
+ ChatTransmitter.addToQueue(new ChatComponentText("§eDungeons Guide :::: Recalculating Route..."));
+ } else {
+ calcReq = true;
+ ChatTransmitter.addToQueue(new ChatComponentText("§eDungeons Guide :::: Currently Calculating Route..."));
+ }
+ }
+ }
+
+ @Override
+ public void drawScreen(float partialTicks) {
+ super.drawScreen(partialTicks);
+ if (!FeatureRegistry.SOLVER_BOX.isEnabled()) return;
+ if (FeatureRegistry.SOLVER_BOX.disableText()) return;
+ FontRenderer fr = Minecraft.getMinecraft().fontRendererObj;
+ GlStateManager.enableBlend();
+ GL14.glBlendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA);
+ GlStateManager.tryBlendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA);
+ fr.drawString("Type \"recalc\" in chat to recalculate the solution", 0, 0, 0xFFFFFFFF);
+ }
+
+ @Override
+ public void drawWorld(float partialTicks) {
+ super.drawWorld(partialTicks);
+ if (!FeatureRegistry.SOLVER_BOX.isEnabled()) return;
+ if (bugged) return;
+ if (!calcDone) return;
+ if (solution == null) return;
+ if (Minecraft.getMinecraft().thePlayer.getPosition().getY() < 68) {
+ if (step < solution.size()) {
+ BoxPuzzleSolvingThread.BoxMove boxMove = solution.get(step);
+ int fromX = boxMove.x - boxMove.dx;
+ int fromY = boxMove.y - boxMove.dy;
+
+ BlockPos pos = poses[fromY][fromX];
+ BlockPos pos2 = poses[boxMove.y][boxMove.x];
+ BlockPos dir = pos.subtract(pos2);
+ dir = new BlockPos(MathHelper.clamp_int(dir.getX(), -1, 1), 0, MathHelper.clamp_double(dir.getZ(), -1, 1));
+
+ BlockPos highlight = pos2.add(dir);
+ AColor color = FeatureRegistry.SOLVER_BOX.getTargetColor().multiplyAlpha(MathHelper.clamp_double(Minecraft.getMinecraft().thePlayer.getPosition().distanceSq(highlight), 100, 255) / 255);
+ RenderUtils.highlightBoxAColor(AxisAlignedBB.fromBounds(highlight.getX(), highlight.getY(), highlight.getZ(), highlight.getX()+1, highlight.getY() + 1, highlight.getZ() + 1), color, partialTicks, false);
+ }
+
+ if (pathFound != null) {
+ RenderUtils.drawLines(pathFound, FeatureRegistry.SOLVER_BOX.getLineColor(),FeatureRegistry.SOLVER_BOX.getLineWidth(), partialTicks, true);
+ }
+ } else {
+ if (totalPath != null) {
+ RenderUtils.drawLines(totalPath, FeatureRegistry.SOLVER_BOX.getLineColor(),FeatureRegistry.SOLVER_BOX.getLineWidth(), partialTicks, false);
+ }
+ if (totalPushedBlocks != null) {
+ for (int i = 0; i < totalPushedBlocks.size(); i++) {
+ BlockPos pos = totalPushedBlocks.get(i);
+ RenderUtils.highlightBoxAColor(AxisAlignedBB.fromBounds(pos.getX(), pos.getY(), pos.getZ(), pos.getX()+1, pos.getY() + 1, pos.getZ() + 1), FeatureRegistry.SOLVER_BOX.getTargetColor(), partialTicks, false);
+ RenderUtils.drawTextAtWorld("#"+i, pos.getX()+0.5f, pos.getY() +0.5f, pos.getZ() + 0.5f, i != step ?
+ RenderUtils.getColorAt(pos.getX(), pos.getY(), pos.getZ(), FeatureRegistry.SOLVER_BOX.getTextColor2()) : RenderUtils.getColorAt(pos.getX(), pos.getY(), pos.getZ(), FeatureRegistry.SOLVER_BOX.getTextColor()), 0.1f, false, false, partialTicks);
+ }
+ }
+ }
+
+ }
+
+ public static class Generator implements RoomProcessorGenerator<RoomProcessorBoxSolver> {
+ @Override
+ public RoomProcessorBoxSolver createNew(DungeonRoom dungeonRoom) {
+ RoomProcessorBoxSolver defaultRoomProcessor = new RoomProcessorBoxSolver(dungeonRoom);
+ return defaultRoomProcessor;
+ }
+ }
+
+
+
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/icefill/RoomProcessorIcePath2.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/icefill/RoomProcessorIcePath2.java
new file mode 100755
index 00000000..94732dc9
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/icefill/RoomProcessorIcePath2.java
@@ -0,0 +1,151 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.icefill;
+
+import kr.syeyoung.dungeonsguide.mod.chat.ChatTransmitter;
+import kr.syeyoung.dungeonsguide.dungeon.data.OffsetPointSet;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomfinder.DungeonRoom;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.GeneralRoomProcessor;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.RoomProcessorGenerator;
+import kr.syeyoung.dungeonsguide.mod.features.FeatureRegistry;
+import kr.syeyoung.dungeonsguide.mod.utils.RenderUtils;
+import net.minecraft.init.Blocks;
+import net.minecraft.util.BlockPos;
+
+import java.awt.*;
+import java.util.Arrays;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+public class RoomProcessorIcePath2 extends GeneralRoomProcessor {
+ private final List<List<BlockPos>> solution = new CopyOnWriteArrayList<List<BlockPos>>();
+
+
+ public RoomProcessorIcePath2(DungeonRoom dungeonRoom) {
+
+ super(dungeonRoom);
+
+ String levels = (String) dungeonRoom.getDungeonRoomInfo().getProperties().get("levels");
+ if (levels == null) {
+ return;
+ }
+
+ for (final String s : levels.split(",")) {
+ try {
+ OffsetPointSet level = (OffsetPointSet) dungeonRoom.getDungeonRoomInfo().getProperties().get(s + "-board");
+ String data = (String) dungeonRoom.getDungeonRoomInfo().getProperties().get(s + "-level");
+ final int width = Integer.parseInt(data.split(":")[0]);
+ final int height = Integer.parseInt(data.split(":")[1]);
+ final int startX = Integer.parseInt(data.split(":")[2]);
+ final int startY = Integer.parseInt(data.split(":")[3]);
+ final int endX = Integer.parseInt(data.split(":")[4]);
+ final int endY = Integer.parseInt(data.split(":")[5]);
+
+ final int[][] map = new int[height][width];
+ final BlockPos[][] map2 = new BlockPos[height][width];
+ for (int y = 0; y < height; y++) {
+ for (int x = 0; x < width; x++) {
+ map2[y][x] = level.getOffsetPointList().get(y * width + x).getBlockPos(dungeonRoom);
+ map[y][x] = level.getOffsetPointList().get(y * width + x).getBlock(dungeonRoom) == Blocks.air ? 0 : 1;
+ }
+ }
+
+ new Thread() {
+ public void run() {
+ List<Point> hamiltonianPath = findFirstHamiltonianPath(map, startX, startY, endX, endY);
+ if (hamiltonianPath == null) {
+ ChatTransmitter.addToQueue("§eDungeons Guide §7:: §eIcePath §7:: §cCouldn't find solution for floor "+s);
+ return;
+ }
+ hamiltonianPath.add(0,new Point(startX, startY));
+ List<BlockPos> poses = new LinkedList<BlockPos>();
+ for (int i = 0; i < hamiltonianPath.size(); i++) {
+ Point p = hamiltonianPath.get(i);
+ poses.add(map2[p.y][p.x]);
+ }
+ solution.add(poses);
+ }
+ }.start();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ @Override
+ public void tick() {
+ super.tick();
+ if (!FeatureRegistry.SOLVER_ICEPATH.isEnabled()) return;
+ }
+
+ @Override
+ public void drawWorld(float partialTicks) {
+ if (!FeatureRegistry.SOLVER_ICEPATH.isEnabled()) return;
+ for (List<BlockPos> solution:this.solution)
+ RenderUtils.drawLines(solution, FeatureRegistry.SOLVER_ICEPATH.getLineColor(),FeatureRegistry.SOLVER_ICEPATH.getLineWidth(), partialTicks, true);
+ }
+
+ public static class Generator implements RoomProcessorGenerator<RoomProcessorIcePath2> {
+ @Override
+ public RoomProcessorIcePath2 createNew(DungeonRoom dungeonRoom) {
+ RoomProcessorIcePath2 defaultRoomProcessor = new RoomProcessorIcePath2(dungeonRoom);
+ return defaultRoomProcessor;
+ }
+ }
+
+ private static List<Point> findFirstHamiltonianPath(int[][] map, int startX, int startY, int endX, int endY) {
+ int emptySpace =0;
+ for (int y = 0; y < map.length; y++)
+ for (int x = 0; x < map[y].length; x++)
+ if (map[y][x] == 0) emptySpace++;
+
+ map[startY][startX] = 2;
+
+ return findHamiltonianPath(map, startX, startY, endX, endY, 0, emptySpace-1);
+ }
+
+
+ private static final List<Point> directions = Arrays.asList(new Point(0,-1), new Point(-1,0), new Point(1,0), new Point(0,1));
+ private static LinkedList<Point> findHamiltonianPath(int[][] map, int startX, int startY, int endX, int endY, int depth, int reqDepth) {
+ if (endX == startX && endY == startY) {
+ if (depth != reqDepth) return null;
+ LinkedList<Point> path = new LinkedList<Point>();
+ path.add(new Point(startX, startY));
+ return path;
+ }
+
+ for (Point p : directions) {
+ int y = p.y +startY,x=p.x + startX;
+ if (y <0 || y >= map.length || x <0 || x >= map[0].length || map[y][x] != 0) continue;
+
+ int[][] copiedMap = new int[map.length][map[0].length];
+ for (int y2 = 0; y2 < copiedMap.length; y2++)
+ copiedMap[y2] = map[y2].clone();
+ copiedMap[y][x] = 2;
+
+ LinkedList<Point> potentialRoute = findHamiltonianPath(copiedMap, x,y,endX,endY, depth +1, reqDepth);
+ if (potentialRoute != null) {
+ potentialRoute.addFirst(new Point(x,y));
+ return potentialRoute;
+ }
+ }
+ return null;
+ }
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/waterpuzzle/LeverState.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/waterpuzzle/LeverState.java
new file mode 100755
index 00000000..e86fdd5c
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/waterpuzzle/LeverState.java
@@ -0,0 +1,33 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.waterpuzzle;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+
+@Data
+@AllArgsConstructor
+public class LeverState {
+ private String blockId;
+ private boolean requiredState;
+
+ public LeverState invert() {
+ return new LeverState(blockId, !requiredState);
+ }
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/waterpuzzle/LeverStateContradict.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/waterpuzzle/LeverStateContradict.java
new file mode 100755
index 00000000..a574d6bf
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/waterpuzzle/LeverStateContradict.java
@@ -0,0 +1,25 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.waterpuzzle;
+
+public class LeverStateContradict extends LeverState {
+ public LeverStateContradict() {
+ super("contradict", true);
+ }
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/waterpuzzle/RoomProcessorWaterPuzzle.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/waterpuzzle/RoomProcessorWaterPuzzle.java
new file mode 100755
index 00000000..d4b05bc9
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/waterpuzzle/RoomProcessorWaterPuzzle.java
@@ -0,0 +1,124 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.waterpuzzle;
+
+import kr.syeyoung.dungeonsguide.dungeon.data.OffsetPoint;
+import kr.syeyoung.dungeonsguide.dungeon.data.OffsetPointSet;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomfinder.DungeonRoom;
+import kr.syeyoung.dungeonsguide.mod.features.FeatureRegistry;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.GeneralRoomProcessor;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.RoomProcessorGenerator;
+import kr.syeyoung.dungeonsguide.mod.utils.RenderUtils;
+import net.minecraft.util.BlockPos;
+
+import java.awt.*;
+import java.util.List;
+
+public class RoomProcessorWaterPuzzle extends GeneralRoomProcessor {
+
+ private boolean argumentsFulfilled = false;
+
+ private WaterBoard waterBoard;
+ private final OffsetPointSet doorsClosed;
+ private final OffsetPointSet levers;
+ private final OffsetPointSet frontBoard;
+ private final OffsetPointSet backBoard;
+ private final OffsetPoint water_lever;
+
+ public RoomProcessorWaterPuzzle(DungeonRoom dungeonRoom) {
+ super(dungeonRoom);
+ frontBoard = (OffsetPointSet) dungeonRoom.getDungeonRoomInfo().getProperties().get("front");
+ backBoard = (OffsetPointSet) dungeonRoom.getDungeonRoomInfo().getProperties().get("back");
+ levers = (OffsetPointSet) dungeonRoom.getDungeonRoomInfo().getProperties().get("levers");
+ doorsClosed = (OffsetPointSet) dungeonRoom.getDungeonRoomInfo().getProperties().get("doors");
+ water_lever = (OffsetPoint) dungeonRoom.getDungeonRoomInfo().getProperties().get("water-lever");
+
+ if (frontBoard == null || backBoard == null || levers == null || doorsClosed == null ||water_lever == null) {
+ argumentsFulfilled = false;
+ } else {
+ argumentsFulfilled = true;
+
+ try {
+ waterBoard = new WaterBoard(this, frontBoard, backBoard, levers, doorsClosed, water_lever);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ @Override
+ public void tick() {
+ super.tick();
+ if (!FeatureRegistry.SOLVER_WATERPUZZLE.isEnabled()) return;
+ if (!argumentsFulfilled) return;
+ try {
+ waterBoard.tick();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ @Override
+ public void drawScreen(float partialTicks) {
+ super.drawScreen(partialTicks);
+ }
+
+ @Override
+ public void drawWorld(float partialTicks) {
+ super.drawWorld(partialTicks);
+ if (!FeatureRegistry.SOLVER_WATERPUZZLE.isEnabled()) return;
+ if (!argumentsFulfilled) return;
+ if (waterBoard == null) return;
+
+ Route route = waterBoard.getCurrentRoute();
+ if (route != null) {
+ int j = 1;
+ for (int i = 0; i < route.getConditionList().size(); i++) {
+ LeverState condition = route.getConditionList().get(i);
+ if (condition == null) continue;
+ SwitchData switchData = waterBoard.getValidSwitches().get(condition.getBlockId());
+ if (switchData.getCurrentState(getDungeonRoom().getContext().getWorld()) != condition.isRequiredState()) {
+
+ RenderUtils.highlightBlock(switchData.getSwitchLoc(), new Color(0,255,0,50), partialTicks, true);
+ RenderUtils.drawTextAtWorld("#"+j,switchData.getSwitchLoc().getX(), switchData.getSwitchLoc().getY()+1, switchData.getSwitchLoc().getZ(), 0xFF000000,0.1f, false, false, partialTicks);
+ RenderUtils.drawTextAtWorld(condition.isRequiredState() ? "on":"off",switchData.getSwitchLoc().getX(), switchData.getSwitchLoc().getY(), switchData.getSwitchLoc().getZ(), 0xFF000000,0.1f, false, false, partialTicks);
+ j++;
+ }
+ }
+ for (WaterNode node : route.getNodes()) {
+ RenderUtils.highlightBlock(node.getBlockPos(), new Color(0,255,255,50), partialTicks, true);
+ }
+ }
+ List<BlockPos> targets = waterBoard.getTarget();
+ if (targets != null) {
+ for (BlockPos target : targets) {
+ RenderUtils.highlightBlock(target, new Color(0,255,255,100), partialTicks, true);
+ }
+ RenderUtils.highlightBlock(waterBoard.getToggleableMap().get("mainStream").getBlockPos(), new Color(0,255,0,255), partialTicks, true);
+ }
+ }
+
+ public static class Generator implements RoomProcessorGenerator<RoomProcessorWaterPuzzle> {
+ @Override
+ public RoomProcessorWaterPuzzle createNew(DungeonRoom dungeonRoom) {
+ RoomProcessorWaterPuzzle defaultRoomProcessor = new RoomProcessorWaterPuzzle(dungeonRoom);
+ return defaultRoomProcessor;
+ }
+ }
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/waterpuzzle/Route.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/waterpuzzle/Route.java
new file mode 100755
index 00000000..a122d83f
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/waterpuzzle/Route.java
@@ -0,0 +1,60 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.waterpuzzle;
+
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.waterpuzzle.nodes.WaterNodeEnd;
+import lombok.Data;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.*;
+
+@Data
+public class Route implements Cloneable, Comparable {
+ private Set<WaterNode> nodes = new LinkedHashSet<WaterNode>();
+ private List<LeverState> conditionList = new ArrayList<LeverState>();
+ private Set<WaterNodeEnd> endingNodes = new HashSet<WaterNodeEnd>();
+
+
+ private int matches = 0;
+ private int stateFlops = 0;
+ private int notMatches = 0;
+
+ public double calculateCost() {
+ return (1.0/matches) * 50 + stateFlops * 20 + notMatches * 10000;
+ }
+
+ @Override
+ protected Route clone() {
+ Route r = new Route();
+ r.getNodes().addAll(nodes);
+ r.getConditionList().addAll(conditionList);
+ r.getEndingNodes().addAll(endingNodes);
+ return r;
+ }
+
+ @Override
+ public int compareTo(@NotNull Object o) {
+ if (o instanceof Route) {
+ double var0 = calculateCost();
+ double var1 = ((Route)o).calculateCost();
+ return Double.compare(var0, var1);
+ }
+ return 0;
+ }
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/waterpuzzle/SwitchData.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/waterpuzzle/SwitchData.java
new file mode 100755
index 00000000..1b43448f
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/waterpuzzle/SwitchData.java
@@ -0,0 +1,46 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.waterpuzzle;
+
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.waterpuzzle.nodes.WaterNodeStart;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.waterpuzzle.nodes.WaterNodeToggleable;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import net.minecraft.util.BlockPos;
+import net.minecraft.world.World;
+
+@Data
+@AllArgsConstructor
+public class SwitchData {
+ private WaterBoard waterBoard;
+
+ private BlockPos switchLoc;
+ private BlockPos blockLoc;
+
+ private String blockId;
+
+ public boolean getCurrentState(World w) {
+ WaterNode waterNode = waterBoard.getToggleableMap().get(blockId);
+ if (waterNode instanceof WaterNodeStart)
+ return ((WaterNodeStart) waterNode).isTriggered(w);
+ else if (waterNode instanceof WaterNodeToggleable)
+ return ((WaterNodeToggleable) waterNode).isTriggered(w);
+ return false;
+ }
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/waterpuzzle/WaterBoard.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/waterpuzzle/WaterBoard.java
new file mode 100755
index 00000000..56b372e4
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/waterpuzzle/WaterBoard.java
@@ -0,0 +1,424 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.waterpuzzle;
+
+import kr.syeyoung.dungeonsguide.mod.DungeonsGuide;
+import kr.syeyoung.dungeonsguide.dungeon.data.OffsetPoint;
+import kr.syeyoung.dungeonsguide.dungeon.data.OffsetPointSet;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.waterpuzzle.nodes.*;
+import lombok.Getter;
+import net.minecraft.block.Block;
+import net.minecraft.block.BlockLever;
+import net.minecraft.init.Blocks;
+import net.minecraft.util.BlockPos;
+import net.minecraft.util.EnumFacing;
+import net.minecraft.util.Tuple;
+import net.minecraft.world.World;
+
+import java.util.*;
+import java.util.List;
+
+public class WaterBoard {
+ @Getter
+ WaterNode[][] board;
+ RoomProcessorWaterPuzzle waterPuzzle;
+
+ private final OffsetPointSet frontPlate;
+ private final OffsetPointSet backPlate;
+ private final OffsetPointSet levers;
+ private final OffsetPointSet doors;
+ private final OffsetPoint lever;
+
+ @Getter
+ private final List<SwitchData> switchData = new ArrayList<SwitchData>();
+ @Getter
+ private final Map<String, SwitchData> validSwitches = new HashMap<String, SwitchData>();
+
+ private WaterNodeStart waterNodeStart;
+ private final Map<String, WaterNodeEnd> waterNodeEndMap = new HashMap<String, WaterNodeEnd>();
+
+ @Getter
+ private final Map<String, WaterNode> toggleableMap = new HashMap<String, WaterNode>();
+
+ @Getter
+ private Set<String> reqOpen = new HashSet<String>();
+ @Getter
+ private Route currentRoute;
+ @Getter
+ private List<BlockPos> target;
+ @Getter
+ private List<String> target2;
+
+ public WaterBoard(RoomProcessorWaterPuzzle roomProcessorWaterPuzzle, OffsetPointSet frontPlate, OffsetPointSet backPlate, OffsetPointSet levers, OffsetPointSet doors, OffsetPoint leverMain) {
+ this.waterPuzzle = roomProcessorWaterPuzzle;
+ this.frontPlate = frontPlate;
+ this.backPlate = backPlate;
+ this.levers = levers;
+ this.doors = doors;
+ this.lever = leverMain;
+
+ buildLeverStates();
+ buildNodes();
+ }
+
+ private void buildLeverStates(){
+ for (OffsetPoint offsetPoint : levers.getOffsetPointList()) {
+ if (offsetPoint.getBlock(waterPuzzle.getDungeonRoom()) == Blocks.lever){
+ BlockPos pos = offsetPoint.getBlockPos(waterPuzzle.getDungeonRoom());
+ World w= waterPuzzle.getDungeonRoom().getContext().getWorld();
+ BlockLever.EnumOrientation enumOrientation = w.getBlockState(pos).getValue(BlockLever.FACING);
+ EnumFacing enumFacing = enumOrientation.getFacing();
+ BlockPos newPos = pos.add(-enumFacing.getDirectionVec().getX(),0,-enumFacing.getDirectionVec().getZ());
+
+ int id = Block.getIdFromBlock(w.getChunkFromBlockCoords(newPos).getBlock(newPos));
+ int data = w.getChunkFromBlockCoords(newPos).getBlockMetadata(newPos);
+
+ SwitchData sw;
+ switchData.add(sw = new SwitchData(this, pos,newPos,id+":"+data));
+ validSwitches.put(id+":"+data, sw);
+ }
+ }
+ SwitchData sw;
+ switchData.add(sw = new SwitchData(this, lever.getBlockPos(waterPuzzle.getDungeonRoom()),lever.getBlockPos(waterPuzzle.getDungeonRoom()).add(0,-1,0),"mainStream"));
+ validSwitches.put("mainStream", sw);
+ }
+
+ public void tick() {
+ Set<String> doorsToOpen = new HashSet<String>();
+ for (OffsetPoint offsetPoint : doors.getOffsetPointList()) {
+ Block b =offsetPoint.getBlock(waterPuzzle.getDungeonRoom());
+ if (b != Blocks.air) {
+ doorsToOpen.add(Block.getIdFromBlock(b)+":"+offsetPoint.getData(waterPuzzle.getDungeonRoom()));
+ }
+ }
+// if (!(reqOpen.containsAll(doorsToOpen) && doorsToOpen.containsAll(reqOpen))) {
+ reqOpen = doorsToOpen;
+ if (doorsToOpen.size() != 0) {
+ Set<WaterNodeEnd> ends = new HashSet<WaterNodeEnd>();
+ for (String s : doorsToOpen) {
+ ends.add(waterNodeEndMap.get(s));
+ }
+ currentRoute = getBestRoute(ends);
+// {
+//
+// Set<LeverState> currentState = new HashSet<LeverState>();
+// World w = waterPuzzle.getDungeonRoom().getContext().getWorld();
+// for (SwitchData switchDatum : this.switchData) {
+// currentState.add(new LeverState(switchDatum.getBlockId(), switchDatum.getCurrentState(w)));
+// }
+// currentRoute = simulate(currentState);
+// }
+
+ target = new ArrayList<BlockPos>();
+ target2 = new ArrayList<String>();
+ if (currentRoute != null) {
+ for (WaterNodeEnd endingNode : currentRoute.getEndingNodes()) {
+ target.add(endingNode.getBlockPos());
+ target2.add(endingNode.getResultId());
+ }
+ }
+ }
+// }
+ }
+
+ public Route getBestRoute(Set<WaterNodeEnd> potentialEnds) {
+ int totalStates = (int) Math.pow(2, validSwitches.size() - 1);
+ List<SwitchData> switchData = new ArrayList<SwitchData>();
+ Set<LeverState> currentState = new HashSet<LeverState>();
+ World w = waterPuzzle.getDungeonRoom().getContext().getWorld();
+ for (SwitchData switchDatum : this.switchData) {
+ if (!switchDatum.getBlockId().equals("mainStream")) {
+ switchData.add(switchDatum);
+ }
+ currentState.add(new LeverState(switchDatum.getBlockId(), switchDatum.getCurrentState(w)));
+ }
+ PriorityQueue<Route> routes = new PriorityQueue<Route>();
+
+ for (int i = 0; i < totalStates; i++) {
+ Set<LeverState> states = new HashSet<LeverState>();
+ for (int i1 = 0; i1 < switchData.size(); i1++) {
+ states.add(new LeverState(switchData.get(i1).getBlockId(), ((i >> i1) & 0x1) > 0));
+ }
+ states.add(new LeverState("mainStream", true));
+
+ Route r = simulate(states);
+
+ for (LeverState leverState : currentState) {
+ if (!states.contains(leverState))
+ r.setStateFlops(r.getStateFlops() + 1);
+ }
+ for (WaterNodeEnd potentialEnd : r.getEndingNodes()) {
+ if (potentialEnds.contains(potentialEnd)) {
+ r.setMatches(r.getMatches() + 1);
+ } else {
+ r.setNotMatches(r.getNotMatches() + 1);
+ }
+ }
+ if (r.getMatches() > 0)
+ routes.add(r);
+ }
+
+
+ return routes.peek();
+ }
+
+ public Route simulate(Set<LeverState> leverStates) {
+ leverStates.add(null);
+ Route r = new Route();
+ final Queue<WaterNode> toGoDownTo = new LinkedList<WaterNode>();
+ Set<WaterNode> searched = new HashSet<WaterNode>();
+ Set<LeverState> waterBlockingStates = new HashSet<LeverState>();
+ World w = waterPuzzle.getDungeonRoom().getContext().getWorld();
+// toGoDownTo.add(getNodeAt(waterNodeStart.getX(), waterNodeStart.getY() + 1));
+ {
+ Queue<Tuple<WaterNode, Boolean>> toGo = new LinkedList<>();
+ toGo.add(new Tuple<>(waterNodeStart, true));
+ toGoDownTo.add(getNodeAt(waterNodeStart.getX(), waterNodeStart.getY() + 1));
+ Set<WaterNode> visited = new HashSet<>();
+ while (!toGo.isEmpty()) {
+ Tuple<WaterNode, Boolean> waterNode = toGo.poll();
+ if (waterNode.getFirst() == null) continue;
+ if (visited.contains(waterNode.getFirst())) continue;
+ if (!waterNode.getFirst().canWaterGoThrough()) continue;
+ if (waterNode.getFirst() instanceof WaterNodeEnd) continue;
+ visited.add(waterNode.getFirst());
+
+ boolean water = waterNode.getFirst().isWaterFilled(w);
+ if (water && !waterNode.getSecond()) {
+ toGoDownTo.add(getNodeAt(waterNode.getFirst().getX(), waterNode.getFirst().getY()));
+ }
+
+ int x = waterNode.getFirst().getX(), y = waterNode.getFirst().getY();
+ toGo.add(new Tuple<>(getNodeAt(x+1, y), water));
+ toGo.add(new Tuple<>(getNodeAt(x-1, y), water));
+ toGo.add(new Tuple<>(getNodeAt(x, y+1), water));
+ }
+ }
+ while (!toGoDownTo.isEmpty()) {
+ WaterNode asd = toGoDownTo.poll();
+ if (asd == null) continue;
+ if (searched.contains(asd)) continue;
+ searched.add(asd);
+
+ if (asd instanceof WaterNodeEnd) {
+ if (!asd.isWaterFilled(w))
+ r.getEndingNodes().add((WaterNodeEnd) asd);
+ continue;
+ }
+
+ r.getNodes().add(asd);
+
+ if (asd.isWaterFilled(w) && (
+ (getNodeAt(asd.getX() + 1, asd.getY()) != null && getNodeAt(asd.getX() + 1, asd.getY()).isWaterFilled(w))
+ || (getNodeAt(asd.getX() - 1, asd.getY()) != null && getNodeAt(asd.getX() - 1, asd.getY()).isWaterFilled(w)))) {
+ boolean followWater = getNodeAt(asd.getX() - 1, asd.getY()) != null && leverStates.contains(getNodeAt(asd.getX() - 1, asd.getY()).getCondition())
+ && getNodeAt(asd.getX() - 2, asd.getY()) != null && leverStates.contains(getNodeAt(asd.getX() - 2, asd.getY()).getCondition());
+ for (int i = asd.getX(); i < asd.getX() + 8; i++) {
+ WaterNode nodehere = getNodeAt(i, asd.getY());
+ if (nodehere == null) break;
+ if (followWater && !nodehere.isWaterFilled(w)) break;
+ if (!nodehere.canWaterGoThrough()) break;
+ if (!leverStates.contains(nodehere.getCondition()) && !nodehere.isWaterFilled(w)) break;
+ if (nodehere.getCondition() != null && leverStates.contains(nodehere.getCondition().invert()) && nodehere.isWaterFilled(w)) waterBlockingStates.add(nodehere.getCondition().invert());
+ WaterNode down = getNodeAt(i, asd.getY() + 1);
+ if (i != asd.getX())
+ followWater = nodehere.isWaterFilled(w) && (down == null || (down.canWaterGoThrough() && leverStates.contains(down.getCondition())));
+ r.getNodes().add(nodehere);
+ if (down != null && down.canWaterGoThrough() && down.getCondition() != null && leverStates.contains(down.getCondition().invert())) {
+ waterBlockingStates.add(down.getCondition().invert());
+ }
+ if (down != null && ((down.canWaterGoThrough() && leverStates.contains(down.getCondition())) || down.isWaterFilled(w))) {
+ toGoDownTo.add(down);
+ if (!followWater) break;
+ }
+ }
+ followWater = getNodeAt(asd.getX() +1, asd.getY()) != null && leverStates.contains(getNodeAt(asd.getX() + 1, asd.getY()).getCondition())
+ && getNodeAt(asd.getX() +2, asd.getY()) != null && leverStates.contains(getNodeAt(asd.getX() + 2, asd.getY()).getCondition());
+ for (int i = asd.getX(); i > asd.getX() - 8; i--) {
+ WaterNode nodehere = getNodeAt(i, asd.getY());
+ if (nodehere == null) break;
+ if (followWater && !nodehere.isWaterFilled(w)) break;
+ if (!nodehere.canWaterGoThrough()) break;
+ if (!leverStates.contains(nodehere.getCondition()) && !nodehere.isWaterFilled(w)) break;
+ if (nodehere.getCondition() != null && leverStates.contains(nodehere.getCondition().invert()) && nodehere.isWaterFilled(w)) waterBlockingStates.add(nodehere.getCondition().invert());
+ WaterNode down = getNodeAt(i, asd.getY() + 1);
+ if (i != asd.getX())
+ followWater = nodehere.isWaterFilled(w) && (down == null || (down.canWaterGoThrough() && leverStates.contains(down.getCondition())));
+ r.getNodes().add(nodehere);
+ if (down != null && down.canWaterGoThrough() && down.getCondition() != null && leverStates.contains(down.getCondition().invert())) {
+ waterBlockingStates.add(down.getCondition().invert());
+ }
+ if (down != null && ((down.canWaterGoThrough() && leverStates.contains(down.getCondition())) || down.isWaterFilled(w))) {
+ toGoDownTo.add(down);
+ if (!followWater) break;
+ }
+ }
+ } else {
+ int minDistToDropRight = 9999;
+ for (int i = asd.getX(); i < asd.getX() + 8; i++) {
+ WaterNode nodehere = getNodeAt(i, asd.getY());
+ if (nodehere == null) break;
+ if (!nodehere.canWaterGoThrough()) break;
+ if (!leverStates.contains(nodehere.getCondition()) && !nodehere.isWaterFilled(w)) break;
+ WaterNode down = getNodeAt(i, asd.getY() + 1);
+ if (down != null && ((down.canWaterGoThrough() && leverStates.contains(down.getCondition())))) {
+ int dist = i - asd.getX();
+ if (dist < minDistToDropRight)
+ minDistToDropRight = dist;
+ break;
+ }
+ }
+ int minDistToDropLeft = 9999;
+ for (int i = asd.getX(); i > asd.getX() - 8; i--) {
+ WaterNode nodehere = getNodeAt(i, asd.getY());
+ if (nodehere == null) break;
+ if (!nodehere.canWaterGoThrough()) break;
+ if (!leverStates.contains(nodehere.getCondition()) && !nodehere.isWaterFilled(w)) break;
+ WaterNode down = getNodeAt(i, asd.getY() + 1);
+ if (down != null && ((down.canWaterGoThrough() && leverStates.contains(down.getCondition())))) {
+ int dist = asd.getX() - i;
+ if (dist < minDistToDropLeft)
+ minDistToDropLeft = dist;
+ break;
+ }
+ }
+
+ int min = Math.min(minDistToDropRight, minDistToDropLeft);
+ if (min == 9999) continue;
+ if (minDistToDropRight == min) {
+ for (int i = asd.getX(); i <= asd.getX() + minDistToDropRight; i++) {
+ WaterNode nodehere = getNodeAt(i, asd.getY());
+ if (nodehere.getCondition() != null && leverStates.contains(nodehere.getCondition().invert()) && nodehere.isWaterFilled(w)) waterBlockingStates.add(nodehere.getCondition().invert());
+ r.getNodes().add(nodehere);
+ WaterNode down = getNodeAt(i, asd.getY() + 1);
+ if (down != null && ((down.canWaterGoThrough() && leverStates.contains(down.getCondition())) || down.isWaterFilled(w))) {
+ toGoDownTo.add(down);
+ }
+ if (down != null && down.canWaterGoThrough() && down.getCondition() != null && leverStates.contains(down.getCondition().invert())) {
+ waterBlockingStates.add(down.getCondition().invert());
+ }
+ }
+ }
+ if (minDistToDropLeft == min) {
+ for (int i = asd.getX(); i >= asd.getX() - minDistToDropLeft; i--) {
+ WaterNode nodehere = getNodeAt(i, asd.getY());
+ if (nodehere.getCondition() != null && leverStates.contains(nodehere.getCondition().invert()) && nodehere.isWaterFilled(w)) waterBlockingStates.add(nodehere.getCondition().invert());
+ r.getNodes().add(nodehere);
+ WaterNode down = getNodeAt(i, asd.getY() + 1);
+ if (down != null && ((down.canWaterGoThrough() && leverStates.contains(down.getCondition())) || down.isWaterFilled(w))) {
+ toGoDownTo.add(down);
+ }
+ if (down != null && down.canWaterGoThrough() && down.getCondition() != null && leverStates.contains(down.getCondition().invert())) {
+ waterBlockingStates.add(down.getCondition().invert());
+ }
+ }
+ }
+ }
+ }
+ ArrayList<LeverState> state = new ArrayList<LeverState>(waterBlockingStates);
+ state.remove(null);
+ Collections.sort(state, new Comparator<LeverState>() {
+ @Override
+ public int compare(LeverState leverState, LeverState t1) {
+ int var0 = toggleableMap.get(leverState.getBlockId()).getY();
+ int var1 = toggleableMap.get(t1.getBlockId()).getY();
+ return var0 < var1 ? -1 : (var0 == var1 ? 0 : 1);
+ }
+ });
+ LinkedList<LeverState> states = new LinkedList<LeverState>(state);
+ for (LeverState ls : leverStates) {
+ if (!states.contains(ls)) {
+ states.add(ls);
+ }
+ }
+ states.remove(null);
+
+
+ r.setConditionList(states);
+ return r;
+ }
+
+
+ public WaterNode getNodeAt(int x, int y) {
+ if (x < 0 || y < 0) return null;
+ if (x >= board[0].length || y >= board.length) return null;
+ return board[y][x];
+ }
+
+ private void buildNodes() {
+ List<OffsetPoint> frontPoints = frontPlate.getOffsetPointList();
+ List<OffsetPoint> backPoints = backPlate.getOffsetPointList();
+
+ board = new WaterNode[25][19];
+ for (int x = 0; x < 19; x++) {
+ for (int y = 0; y < 25; y++) {
+ OffsetPoint front = frontPoints.get(x *25 +y);
+ OffsetPoint back = backPoints.get(x * 25 +y);
+ int frontId = Block.getIdFromBlock(front.getBlock(waterPuzzle.getDungeonRoom()));
+ int backId = Block.getIdFromBlock(back.getBlock(waterPuzzle.getDungeonRoom()));
+ int frontData = front.getData(waterPuzzle.getDungeonRoom());
+ int backData = back.getData(waterPuzzle.getDungeonRoom());
+ WaterNode node;
+ if (validSwitches.containsKey(backId +":"+backData)) {
+ String resId = backId + ":"+backData;
+ node = new WaterNodeToggleable(resId, isSwitchActive(validSwitches.get(resId)), front.getBlockPos(waterPuzzle.getDungeonRoom()),x,y);
+
+ toggleableMap.put(resId, node);
+ } else if (validSwitches.containsKey(frontId +":"+frontData)) {
+ String resId = frontId +":"+frontData;
+ node = new WaterNodeToggleable(resId, !isSwitchActive(validSwitches.get(resId)), front.getBlockPos(waterPuzzle.getDungeonRoom()),x,y);
+
+ toggleableMap.put(resId, node);
+ } else if (frontId == 0 || frontId == 8 || frontId == 9) {
+ if (y == 24) {
+ OffsetPoint pos;
+ if (x != 0) {
+ pos = frontPoints.get((x-1)*25+y);
+ } else {
+ pos = frontPoints.get((x+1) * 25 +y);
+ }
+
+ int id = Block.getIdFromBlock(pos.getBlock(waterPuzzle.getDungeonRoom()));
+ int data= pos.getData(waterPuzzle.getDungeonRoom());
+ node = new WaterNodeEnd(id+":"+data, front.getBlockPos(waterPuzzle.getDungeonRoom()),x,y);
+ waterNodeEndMap.put(id+":"+data, (WaterNodeEnd) node);
+ } else if (y == 2 && x == 9) {
+ waterNodeStart = (WaterNodeStart) (node = new WaterNodeStart(front.getBlockPos(waterPuzzle.getDungeonRoom()),
+ frontId != 0 ^ isSwitchActive(validSwitches.get("mainStream")),x,y));
+ } else {
+ node = new WaterNodeAir(front.getBlockPos(waterPuzzle.getDungeonRoom()),x,y);
+ }
+ } else {
+ node = new WaterNodeWall(front.getBlockPos(waterPuzzle.getDungeonRoom()),x,y);
+ }
+ board[y][x] =node;
+ }
+ }
+ toggleableMap.put("mainStream", waterNodeStart);
+ }
+
+ private boolean isSwitchActive(SwitchData switchData) {
+ BlockPos switch2 = switchData.getSwitchLoc();
+ World w= waterPuzzle.getDungeonRoom().getContext().getWorld();
+ boolean bool = DungeonsGuide.getDungeonsGuide().getBlockCache().getBlockState(switch2).getValue(BlockLever.POWERED);
+ return bool;
+ }
+
+
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/waterpuzzle/WaterNode.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/waterpuzzle/WaterNode.java
new file mode 100755
index 00000000..cbcb1cb0
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/waterpuzzle/WaterNode.java
@@ -0,0 +1,36 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.waterpuzzle;
+
+import net.minecraft.util.BlockPos;
+import net.minecraft.world.World;
+
+public interface WaterNode {
+ boolean canWaterGoThrough();
+
+ // condition for water go
+ LeverState getCondition();
+
+ boolean isWaterFilled(World w);
+
+ BlockPos getBlockPos();
+
+ int getX();
+ int getY();
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/waterpuzzle/nodes/WaterNodeAir.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/waterpuzzle/nodes/WaterNodeAir.java
new file mode 100755
index 00000000..274a232b
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/waterpuzzle/nodes/WaterNodeAir.java
@@ -0,0 +1,59 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.waterpuzzle.nodes;
+
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.waterpuzzle.LeverState;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.waterpuzzle.WaterNode;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import net.minecraft.block.Block;
+import net.minecraft.init.Blocks;
+import net.minecraft.util.BlockPos;
+import net.minecraft.world.World;
+
+@Data
+@AllArgsConstructor
+public class WaterNodeAir implements WaterNode {
+ BlockPos blockPos;
+ @Override
+ public boolean canWaterGoThrough() {
+ return true;
+ }
+
+ @Override
+ public LeverState getCondition() {
+ return null;
+ }
+
+ @Override
+ public boolean isWaterFilled(World w) {
+ Block b = w.getChunkFromBlockCoords(blockPos).getBlock(blockPos);
+ return b == Blocks.water || b == Blocks.flowing_water;
+ }
+
+ public BlockPos getBlockPos() {
+ return blockPos;
+ }
+
+ private int x,y;
+
+ public String toString() {
+ return "A";
+ }
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/waterpuzzle/nodes/WaterNodeEnd.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/waterpuzzle/nodes/WaterNodeEnd.java
new file mode 100755
index 00000000..3ca59934
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/waterpuzzle/nodes/WaterNodeEnd.java
@@ -0,0 +1,60 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.waterpuzzle.nodes;
+
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.waterpuzzle.LeverState;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.waterpuzzle.WaterNode;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import net.minecraft.block.Block;
+import net.minecraft.init.Blocks;
+import net.minecraft.util.BlockPos;
+import net.minecraft.world.World;
+
+@Data
+@AllArgsConstructor
+public class WaterNodeEnd implements WaterNode {
+ private String resultId;
+ BlockPos blockPos;
+
+ @Override
+ public boolean canWaterGoThrough() {
+ return true;
+ }
+
+ @Override
+ public LeverState getCondition() {
+ return null;
+ }
+
+ @Override
+ public boolean isWaterFilled(World w) {
+ Block b = w.getChunkFromBlockCoords(blockPos).getBlock(blockPos);
+ return b == Blocks.water || b == Blocks.flowing_water;
+ }
+
+ public BlockPos getBlockPos() {
+ return blockPos;
+ }
+ private int x,y;
+
+ public String toString() {
+ return "E";
+ }
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/waterpuzzle/nodes/WaterNodeStart.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/waterpuzzle/nodes/WaterNodeStart.java
new file mode 100755
index 00000000..09ec7070
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/waterpuzzle/nodes/WaterNodeStart.java
@@ -0,0 +1,66 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.waterpuzzle.nodes;
+
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.waterpuzzle.LeverState;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.waterpuzzle.WaterNode;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import net.minecraft.block.Block;
+import net.minecraft.init.Blocks;
+import net.minecraft.util.BlockPos;
+import net.minecraft.world.World;
+
+@Data
+@AllArgsConstructor
+public class WaterNodeStart implements WaterNode {
+
+ private BlockPos blockPos;
+ private boolean isReversed;
+
+ @Override
+ public boolean canWaterGoThrough() {
+ return true;
+ }
+
+ @Override
+ public LeverState getCondition() {
+ return new LeverState("mainStream", !isReversed);
+ }
+
+ @Override
+ public boolean isWaterFilled(World w) {
+ Block b = w.getChunkFromBlockCoords(blockPos).getBlock(blockPos);
+ return b == Blocks.water || b == Blocks.flowing_water;
+ }
+
+ public boolean isTriggered(World w) {
+ return isWaterFilled(w);
+ }
+
+
+ public BlockPos getBlockPos() {
+ return blockPos;
+ }
+ private int x,y;
+
+ public String toString() {
+ return "S";
+ }
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/waterpuzzle/nodes/WaterNodeToggleable.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/waterpuzzle/nodes/WaterNodeToggleable.java
new file mode 100755
index 00000000..039c1cf9
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/waterpuzzle/nodes/WaterNodeToggleable.java
@@ -0,0 +1,71 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.waterpuzzle.nodes;
+
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.waterpuzzle.LeverState;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.waterpuzzle.WaterNode;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import net.minecraft.block.Block;
+import net.minecraft.init.Blocks;
+import net.minecraft.util.BlockPos;
+import net.minecraft.world.World;
+
+@Data
+@AllArgsConstructor
+public class WaterNodeToggleable implements WaterNode {
+ private String blockId;
+ private boolean invert;
+
+ BlockPos blockPos;
+
+ @Override
+ public boolean canWaterGoThrough() {
+ return true;
+ }
+
+ @Override
+ public LeverState getCondition() {
+ return new LeverState(blockId, invert);
+ }
+
+
+ @Override
+ public boolean isWaterFilled(World w) {
+ Block b = w.getChunkFromBlockCoords(blockPos).getBlock(blockPos);
+ return b == Blocks.water || b == Blocks.flowing_water;
+ }
+ private int x,y;
+
+ public boolean isTriggered(World w) {
+ Block b= w.getChunkFromBlockCoords(blockPos).getBlock(blockPos);
+
+ return !(b == Blocks.air || b == Blocks.water || b == Blocks.flowing_water) ^ invert;
+ }
+
+
+ public BlockPos getBlockPos() {
+ return blockPos;
+ }
+
+
+ public String toString() {
+ return "T:"+blockId+(invert ? ":Y":":N");
+ }
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/waterpuzzle/nodes/WaterNodeWall.java b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/waterpuzzle/nodes/WaterNodeWall.java
new file mode 100755
index 00000000..b09750f2
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/roomprocessor/waterpuzzle/nodes/WaterNodeWall.java
@@ -0,0 +1,62 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.waterpuzzle.nodes;
+
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.waterpuzzle.LeverState;
+import kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.waterpuzzle.WaterNode;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import net.minecraft.block.Block;
+import net.minecraft.init.Blocks;
+import net.minecraft.util.BlockPos;
+import net.minecraft.world.World;
+
+@Data
+@AllArgsConstructor
+public class WaterNodeWall implements WaterNode {
+
+ BlockPos blockPos;
+ @Override
+ public boolean canWaterGoThrough() {
+ return false;
+ }
+
+ @Override
+ public LeverState getCondition() {
+ return null;
+ }
+
+
+ @Override
+ public boolean isWaterFilled(World w) {
+ Block b = w.getChunkFromBlockCoords(blockPos).getBlock(blockPos);
+ return b == Blocks.water || b == Blocks.flowing_water;
+ }
+
+ private int x,y;
+
+ public BlockPos getBlockPos() {
+ return blockPos;
+ }
+
+
+ public String toString() {
+ return "W";
+ }
+}