diff options
author | syeyoung <cyoung06@naver.com> | 2021-09-18 12:29:50 +0900 |
---|---|---|
committer | syeyoung <cyoung06@naver.com> | 2021-09-18 12:29:50 +0900 |
commit | 3d42886e90d2d41603d5741a3d5d07907f7758fe (patch) | |
tree | 725c2c886d42fd9cb858a49bb9be326dbc6030d7 /src/main/java/kr | |
parent | b5f5a1a613ab534e247c8eb04110344e2161d8d3 (diff) | |
download | Skyblock-Dungeons-Guide-3d42886e90d2d41603d5741a3d5d07907f7758fe.tar.gz Skyblock-Dungeons-Guide-3d42886e90d2d41603d5741a3d5d07907f7758fe.tar.bz2 Skyblock-Dungeons-Guide-3d42886e90d2d41603d5741a3d5d07907f7758fe.zip |
- Waypoints? and new JPS Pathfinding Algorithm
Diffstat (limited to 'src/main/java/kr')
14 files changed, 873 insertions, 68 deletions
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/DungeonsGuide.java b/src/main/java/kr/syeyoung/dungeonsguide/DungeonsGuide.java index 4875029d..7554c6b5 100755 --- a/src/main/java/kr/syeyoung/dungeonsguide/DungeonsGuide.java +++ b/src/main/java/kr/syeyoung/dungeonsguide/DungeonsGuide.java @@ -26,6 +26,7 @@ import kr.syeyoung.dungeonsguide.dungeon.roomfinder.DungeonRoomInfoRegistry; import kr.syeyoung.dungeonsguide.eventlistener.DungeonListener; import kr.syeyoung.dungeonsguide.eventlistener.FeatureListener; import kr.syeyoung.dungeonsguide.eventlistener.PacketListener; +import kr.syeyoung.dungeonsguide.eventlistener.PathfindListener; import kr.syeyoung.dungeonsguide.events.StompConnectedEvent; import kr.syeyoung.dungeonsguide.features.FeatureRegistry; import kr.syeyoung.dungeonsguide.features.impl.discord.inviteViewer.PartyInviteViewer; @@ -120,6 +121,8 @@ public class DungeonsGuide implements DGInterface, CloseListener { MinecraftForge.EVENT_BUS.register(new PacketListener()); MinecraftForge.EVENT_BUS.register(new Keybinds()); + MinecraftForge.EVENT_BUS.register(PathfindListener.INSTANCE); + MinecraftForge.EVENT_BUS.register(PartyManager.INSTANCE); MinecraftForge.EVENT_BUS.register(StaticResourceCache.INSTANCE); diff --git a/src/main/java/kr/syeyoung/dungeonsguide/commands/CommandDungeonsGuide.java b/src/main/java/kr/syeyoung/dungeonsguide/commands/CommandDungeonsGuide.java index 08f01248..82f5af4f 100644 --- a/src/main/java/kr/syeyoung/dungeonsguide/commands/CommandDungeonsGuide.java +++ b/src/main/java/kr/syeyoung/dungeonsguide/commands/CommandDungeonsGuide.java @@ -21,8 +21,10 @@ package kr.syeyoung.dungeonsguide.commands; import com.google.gson.JsonObject; import com.sun.jna.Pointer; import kr.syeyoung.dungeonsguide.DungeonsGuide; +import kr.syeyoung.dungeonsguide.eventlistener.PathfindListener; import kr.syeyoung.dungeonsguide.gamesdk.jna.enumuration.EDiscordActivityActionType; import kr.syeyoung.dungeonsguide.gamesdk.jna.interfacestruct.IDiscordOverlayManager; +import kr.syeyoung.dungeonsguide.pathfinding.JPSPathfinder; import kr.syeyoung.dungeonsguide.rpc.JDiscordRelation; import kr.syeyoung.dungeonsguide.rpc.RichPresenceManager; import kr.syeyoung.dungeonsguide.SkyblockStatus; @@ -63,10 +65,7 @@ import net.minecraft.command.ICommandSender; import net.minecraft.nbt.CompressedStreamTools; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.server.MinecraftServer; -import net.minecraft.util.BlockPos; -import net.minecraft.util.ChatComponentText; -import net.minecraft.util.ChatStyle; -import net.minecraft.util.Tuple; +import net.minecraft.util.*; import net.minecraft.world.World; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; @@ -173,7 +172,7 @@ public class CommandDungeonsGuide extends CommandBase { DungeonRoom dungeonRoom = context.getRoomMapper().get(roomPt); GeneralRoomProcessor grp = (GeneralRoomProcessor) dungeonRoom.getRoomProcessor(); - grp.pathfind(args[1], args[2]); + grp.pathfind("COMMAND", args[1], args[2]); } catch (Throwable t) { t.printStackTrace(); } @@ -216,7 +215,7 @@ public class CommandDungeonsGuide extends CommandBase { if (value instanceof DungeonSecret && (((DungeonSecret) value).getSecretType() == DungeonSecret.SecretType.BAT || ((DungeonSecret) value).getSecretType() == DungeonSecret.SecretType.CHEST) - && ((DungeonSecret) value).getSecretPoint().getY() == 0 ) { + && ((DungeonSecret) value).getSecretPoint().getY() == 0) { OffsetPoint offsetPoint = ((DungeonSecret) value).getSecretPoint(); if (dri.getBlocks()[offsetPoint.getZ()][offsetPoint.getX()] != -1) { dri.getBlocks()[offsetPoint.getZ()][offsetPoint.getX()] = -1; @@ -224,21 +223,21 @@ public class CommandDungeonsGuide extends CommandBase { } } else if (value instanceof DungeonOnewayDoor) { for (OffsetPoint offsetPoint : ((DungeonOnewayDoor) value).getSecretPoint().getOffsetPointList()) { - if (offsetPoint.getY() == 0&& dri.getBlocks()[offsetPoint.getZ()][offsetPoint.getX()] != -1) { + if (offsetPoint.getY() == 0 && dri.getBlocks()[offsetPoint.getZ()][offsetPoint.getX()] != -1) { dri.getBlocks()[offsetPoint.getZ()][offsetPoint.getX()] = -1; System.out.println("Fixing " + value2.getKey() + " - o-door - at " + offsetPoint); } } } else if (value instanceof DungeonDoor) { for (OffsetPoint offsetPoint : ((DungeonDoor) value).getSecretPoint().getOffsetPointList()) { - if (offsetPoint.getY() == 0&& dri.getBlocks()[offsetPoint.getZ()][offsetPoint.getX()] != -1) { + if (offsetPoint.getY() == 0 && dri.getBlocks()[offsetPoint.getZ()][offsetPoint.getX()] != -1) { dri.getBlocks()[offsetPoint.getZ()][offsetPoint.getX()] = -1; System.out.println("Fixing " + value2.getKey() + " - door - at " + offsetPoint); } } } else if (value instanceof DungeonBreakableWall) { for (OffsetPoint offsetPoint : ((DungeonBreakableWall) value).getSecretPoint().getOffsetPointList()) { - if (offsetPoint.getY() == 0&& dri.getBlocks()[offsetPoint.getZ()][offsetPoint.getX()] != -1) { + if (offsetPoint.getY() == 0 && dri.getBlocks()[offsetPoint.getZ()][offsetPoint.getX()] != -1) { dri.getBlocks()[offsetPoint.getZ()][offsetPoint.getX()] = -1; System.out.println("Fixing " + value2.getKey() + " - wall - at " + offsetPoint); } @@ -276,7 +275,7 @@ public class CommandDungeonsGuide extends CommandBase { .thenAccept(a -> { if (a == null) return; ApiFetchur.fetchMostRecentProfileAsync(a.get(), FeatureRegistry.PARTYKICKER_APIKEY.getAPIKey()); - Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText("§eDungeons Guide §7:: §e"+s+"§f's Profile ").appendSibling(new ChatComponentText("§7view").setChatStyle(new ChatStyle().setChatHoverEvent(new FeatureViewPlayerOnJoin.HoverEventRenderPlayer(a.orElse(null)))))); + Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText("§eDungeons Guide §7:: §e" + s + "§f's Profile ").appendSibling(new ChatComponentText("§7view").setChatStyle(new ChatStyle().setChatHoverEvent(new FeatureViewPlayerOnJoin.HoverEventRenderPlayer(a.orElse(null)))))); }); } }); @@ -420,12 +419,12 @@ public class CommandDungeonsGuide extends CommandBase { } else if (args[0].equals("requeststaticresource")) { UUID uid = UUID.fromString(args[1]); StaticResourceCache.INSTANCE.getResource(uid).thenAccept(a -> { - sender.addChatMessage(new ChatComponentText(a.getResourceID()+": "+a.getValue()+": "+a.isExists())); + sender.addChatMessage(new ChatComponentText(a.getResourceID() + ": " + a.getValue() + ": " + a.isExists())); }); - } else if (args[0].equals("createFakeRoom")&& Minecraft.getMinecraft().getSession().getPlayerID().replace("-", "").equals("e686fe0aab804a71ac7011dc8c2b534c")) { + } else if (args[0].equals("createFakeRoom") && Minecraft.getMinecraft().getSession().getPlayerID().replace("-", "").equals("e686fe0aab804a71ac7011dc8c2b534c")) { // load schematic - File f=new File(DungeonsGuide.getDungeonsGuide().getConfigDir(), "schematics/new roonm-b2df250c-4af2-4201-963c-0ee1cb6bd3de-5efb1f0c-c05f-4064-bde7-cad0874fdf39.schematic"); + File f = new File(DungeonsGuide.getDungeonsGuide().getConfigDir(), "schematics/new roonm-b2df250c-4af2-4201-963c-0ee1cb6bd3de-5efb1f0c-c05f-4064-bde7-cad0874fdf39.schematic"); NBTTagCompound compound; try { compound = CompressedStreamTools.readCompressed(new FileInputStream(f)); @@ -437,10 +436,10 @@ public class CommandDungeonsGuide extends CommandBase { byte[] blocks = compound.getByteArray("Blocks"); byte[] meta = compound.getByteArray("Data"); for (int x = 0; x < compound.getShort("Width"); x++) { - for (int y = 0; y < compound.getShort("Height"); y++) { + 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 = new BlockPos(x,y,z); + BlockPos pos = new BlockPos(x, y, z); World w = MinecraftServer.getServer().getEntityWorld(); w.setBlockState(pos, Block.getBlockById(blocks[index] & 0xFF).getStateFromMeta(meta[index] & 0xFF), 2); } @@ -451,7 +450,7 @@ public class CommandDungeonsGuide extends CommandBase { DungeonSpecificDataProviderRegistry.doorFinders.put(Pattern.compile("TEST DG"), new DungeonSpecificDataProvider() { @Override public BlockPos findDoor(World w, String dungeonName) { - return new BlockPos(0,0,0); + return new BlockPos(0, 0, 0); } @Override @@ -475,16 +474,16 @@ public class CommandDungeonsGuide extends CommandBase { skyblockStatus.setContext(fakeContext); skyblockStatus.setForceIsOnDungeon(true); MapProcessor mapProcessor = fakeContext.getMapProcessor(); - mapProcessor.setUnitRoomDimension(new Dimension(16,16)); + mapProcessor.setUnitRoomDimension(new Dimension(16, 16)); mapProcessor.setBugged(false); - mapProcessor.setDoorDimension(new Dimension(4,4)); - mapProcessor.setTopLeftMapPoint(new Point(0,0)); - fakeContext.setDungeonMin(new BlockPos(0,70,0)); + mapProcessor.setDoorDimension(new Dimension(4, 4)); + mapProcessor.setTopLeftMapPoint(new Point(0, 0)); + fakeContext.setDungeonMin(new BlockPos(0, 70, 0)); - DungeonRoom dungeonRoom = new DungeonRoom(Arrays.asList(new Point(0,0)), ShortUtils.topLeftifyInt((short) 1), (byte) 63, new BlockPos(0,70,0), new BlockPos(31,70,31), fakeContext); + DungeonRoom dungeonRoom = new DungeonRoom(Arrays.asList(new Point(0, 0)), ShortUtils.topLeftifyInt((short) 1), (byte) 63, new BlockPos(0, 70, 0), new BlockPos(31, 70, 31), fakeContext); fakeContext.getDungeonRoomList().add(dungeonRoom); - for (Point p:Arrays.asList(new Point(0,0))) { + for (Point p : Arrays.asList(new Point(0, 0))) { fakeContext.getRoomMapper().put(p, dungeonRoom); } @@ -503,7 +502,7 @@ public class CommandDungeonsGuide extends CommandBase { if (currentRoot.children().containsKey(s)) currentRoot = currentRoot.children().get(s); else { - currentRoot.child(currentRoot = new NestedCategory(finalCurrentRoot.categoryFull()+"."+s)); + currentRoot.child(currentRoot = new NestedCategory(finalCurrentRoot.categoryFull() + "." + s)); } } } @@ -525,7 +524,7 @@ public class CommandDungeonsGuide extends CommandBase { if (n.getFirst().categoryFull().equals("ROOT")) continue; String prefix = ""; - for (int i = 0; i < n.getSecond()-1; i++) { + for (int i = 0; i < n.getSecond() - 1; i++) { prefix += " "; } @@ -538,6 +537,24 @@ public class CommandDungeonsGuide extends CommandBase { } System.out.println(stringBuilder.toString()); System.out.println(stringBuilder2.toString()); + } else if (args[0].equalsIgnoreCase("pathfindtest")) { + if (args[1].equalsIgnoreCase("setbounds")) { + PathfindListener.INSTANCE.jpsPathfinder = new JPSPathfinder(Minecraft.getMinecraft().theWorld, new BlockPos(Integer.parseInt(args[2]), Integer.parseInt(args[3]), Integer.parseInt(args[4])), + new BlockPos(Integer.parseInt(args[5]), Integer.parseInt(args[6]),Integer.parseInt(args[7]))); + } else { + new Thread(){ + @Override + public void run() { + try { + boolean res = PathfindListener.INSTANCE.jpsPathfinder.pathfind(new Vec3(Float.parseFloat(args[2]), Float.parseFloat(args[3]), Float.parseFloat(args[4])), + new Vec3(Float.parseFloat(args[5]), Float.parseFloat(args[6]), Float.parseFloat(args[7]))); + System.out.println("done-"+res); + } catch (Exception e) { + e.printStackTrace(); + } + } + }.start(); + } } else{ sender.addChatMessage(new ChatComponentText("§eDungeons Guide §7:: §e/dg §7-§fOpens configuration gui")); sender.addChatMessage(new ChatComponentText("§eDungeons Guide §7:: §e/dg gui §7-§fOpens configuration gui")); diff --git a/src/main/java/kr/syeyoung/dungeonsguide/dungeon/actions/ActionMove.java b/src/main/java/kr/syeyoung/dungeonsguide/dungeon/actions/ActionMove.java index 3f03cb86..26ab9176 100755 --- a/src/main/java/kr/syeyoung/dungeonsguide/dungeon/actions/ActionMove.java +++ b/src/main/java/kr/syeyoung/dungeonsguide/dungeon/actions/ActionMove.java @@ -26,6 +26,7 @@ import kr.syeyoung.dungeonsguide.utils.RenderUtils; import lombok.Data; import net.minecraft.client.Minecraft; import net.minecraft.pathfinding.PathEntity; +import net.minecraft.pathfinding.PathFinder; import net.minecraft.pathfinding.PathPoint; import net.minecraft.util.BlockPos; import net.minecraft.util.MathHelper; @@ -68,16 +69,20 @@ public class ActionMove extends AbstractAction { RenderUtils.drawTextAtWorld("Destination", pos.getX() + 0.5f, pos.getY() + 0.5f + scale, pos.getZ() + 0.5f, 0xFF00FF00, 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, 1f, true, false, partialTicks); - if (FeatureRegistry.SECRET_TOGGLE_KEY.isEnabled() && Keybinds.togglePathfindStatus) return; - - if (poses != null){ - RenderUtils.drawLines(poses, FeatureRegistry.SECRET_BROWSE.getColor(), FeatureRegistry.SECRET_BROWSE.getThickness(), partialTicks, true); + if (!FeatureRegistry.SECRET_TOGGLE_KEY.isEnabled() || !Keybinds.togglePathfindStatus) { + if (poses != null){ + RenderUtils.drawLines(poses, FeatureRegistry.SECRET_BROWSE.getColor(), FeatureRegistry.SECRET_BROWSE.getThickness(), partialTicks, true); + } + } + if (FeatureRegistry.SECRET_BEACONS.isEnabled()) { + RenderUtils.renderBeaconBeam(pos.getX(), pos.getY(), pos.getZ(), FeatureRegistry.SECRET_BROWSE.getColor(), partialTicks); } } private int tick = -1; private List<BlockPos> poses; private Future<List<BlockPos>> latestFuture; + @Override public void onTick(DungeonRoom dungeonRoom) { tick = (tick+1) % Math.max(1, FeatureRegistry.SECRET_BROWSE.getRefreshRate()); diff --git a/src/main/java/kr/syeyoung/dungeonsguide/dungeon/actions/ActionMoveNearestAir.java b/src/main/java/kr/syeyoung/dungeonsguide/dungeon/actions/ActionMoveNearestAir.java index a657bbe3..beaa4076 100755 --- a/src/main/java/kr/syeyoung/dungeonsguide/dungeon/actions/ActionMoveNearestAir.java +++ b/src/main/java/kr/syeyoung/dungeonsguide/dungeon/actions/ActionMoveNearestAir.java @@ -67,9 +67,13 @@ public class ActionMoveNearestAir extends AbstractAction { RenderUtils.drawTextAtWorld("Destination", pos.getX() + 0.5f, pos.getY() + 0.5f + scale, pos.getZ() + 0.5f, 0xFF00FF00, 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, 1f, true, false, partialTicks); - if (FeatureRegistry.SECRET_TOGGLE_KEY.isEnabled() && Keybinds.togglePathfindStatus) return; - if (poses != null){ - RenderUtils.drawLines(poses, FeatureRegistry.SECRET_BROWSE.getColor(), FeatureRegistry.SECRET_BROWSE.getThickness(), partialTicks, true); + if (!FeatureRegistry.SECRET_TOGGLE_KEY.isEnabled() || !Keybinds.togglePathfindStatus) { + if (poses != null){ + RenderUtils.drawLines(poses, FeatureRegistry.SECRET_BROWSE.getColor(), FeatureRegistry.SECRET_BROWSE.getThickness(), partialTicks, true); + } + } + if (FeatureRegistry.SECRET_BEACONS.isEnabled()) { + RenderUtils.renderBeaconBeam(pos.getX(), pos.getY(), pos.getZ(), FeatureRegistry.SECRET_BROWSE.getColor(), partialTicks); } } diff --git a/src/main/java/kr/syeyoung/dungeonsguide/dungeon/actions/tree/ActionRoute.java b/src/main/java/kr/syeyoung/dungeonsguide/dungeon/actions/tree/ActionRoute.java index c38990a0..cdfc5040 100644 --- a/src/main/java/kr/syeyoung/dungeonsguide/dungeon/actions/tree/ActionRoute.java +++ b/src/main/java/kr/syeyoung/dungeonsguide/dungeon/actions/tree/ActionRoute.java @@ -21,6 +21,7 @@ package kr.syeyoung.dungeonsguide.dungeon.actions.tree; import kr.syeyoung.dungeonsguide.dungeon.actions.Action; import kr.syeyoung.dungeonsguide.dungeon.actions.ActionChangeState; import kr.syeyoung.dungeonsguide.dungeon.actions.ActionComplete; +import kr.syeyoung.dungeonsguide.dungeon.actions.ActionMove; import kr.syeyoung.dungeonsguide.dungeon.roomfinder.DungeonRoom; import kr.syeyoung.dungeonsguide.events.PlayerInteractEntityEvent; import lombok.Getter; @@ -79,6 +80,7 @@ public class ActionRoute { getCurrentAction().onLivingDeath(dungeonRoom, event); } public void onRenderWorld(float partialTicks) { + if (current -1 >= 0 && actions.get(current-1) instanceof ActionMove) actions.get(current-1).onRenderScreen(dungeonRoom, partialTicks); getCurrentAction().onRenderWorld(dungeonRoom, partialTicks); } diff --git a/src/main/java/kr/syeyoung/dungeonsguide/dungeon/roomfinder/DungeonRoom.java b/src/main/java/kr/syeyoung/dungeonsguide/dungeon/roomfinder/DungeonRoom.java index 5c6a7023..85970fa3 100755 --- a/src/main/java/kr/syeyoung/dungeonsguide/dungeon/roomfinder/DungeonRoom.java +++ b/src/main/java/kr/syeyoung/dungeonsguide/dungeon/roomfinder/DungeonRoom.java @@ -91,11 +91,9 @@ public class DungeonRoom { this.currentState = currentState; } - @Getter - private final PathFinder pathFinder; - public ScheduledFuture<List<BlockPos>> createEntityPathTo(IBlockAccess blockaccess, Entity entityIn, BlockPos targetPos, float dist) { - return asyncPathFinder.schedule(() -> { + ScheduledFuture<List<BlockPos>> sf = asyncPathFinder.schedule(() -> { + PathFinder pathFinder = new PathFinder(nodeProcessorDungeonRoom); PathEntity latest = pathFinder.createEntityPathTo(blockaccess, entityIn, targetPos, dist); if (latest != null) { List<BlockPos> poses = new ArrayList<>(); @@ -107,9 +105,11 @@ public class DungeonRoom { } return new ArrayList<>(); }, 0, TimeUnit.MILLISECONDS); + asyncPathFinder.schedule(() -> sf.cancel(true), 10, TimeUnit.SECONDS); + return sf; } - private static final ScheduledExecutorService asyncPathFinder = Executors.newScheduledThreadPool(2); + private static final ScheduledExecutorService asyncPathFinder = Executors.newScheduledThreadPool(4); @Getter private final NodeProcessorDungeonRoom nodeProcessorDungeonRoom; @@ -144,7 +144,6 @@ public class DungeonRoom { buildDoors(); buildRoom(); nodeProcessorDungeonRoom = new NodeProcessorDungeonRoom(this); - pathFinder = new PathFinder(nodeProcessorDungeonRoom); updateRoomProcessor(); } diff --git a/src/main/java/kr/syeyoung/dungeonsguide/eventlistener/PathfindListener.java b/src/main/java/kr/syeyoung/dungeonsguide/eventlistener/PathfindListener.java new file mode 100644 index 00000000..fb19063d --- /dev/null +++ b/src/main/java/kr/syeyoung/dungeonsguide/eventlistener/PathfindListener.java @@ -0,0 +1,67 @@ +/* + * 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.eventlistener; + +import kr.syeyoung.dungeonsguide.DungeonsGuide; +import kr.syeyoung.dungeonsguide.SkyblockStatus; +import kr.syeyoung.dungeonsguide.config.types.AColor; +import kr.syeyoung.dungeonsguide.features.AbstractFeature; +import kr.syeyoung.dungeonsguide.features.FeatureRegistry; +import kr.syeyoung.dungeonsguide.features.listener.WorldRenderListener; +import kr.syeyoung.dungeonsguide.pathfinding.JPSPathfinder; +import kr.syeyoung.dungeonsguide.utils.RenderUtils; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.util.AxisAlignedBB; +import net.minecraft.util.BlockPos; +import net.minecraft.util.Tuple; +import net.minecraft.util.Vec3; +import net.minecraftforge.client.event.RenderWorldLastEvent; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; + +import java.awt.*; + +public class PathfindListener { + public JPSPathfinder jpsPathfinder; + + public static final PathfindListener INSTANCE = new PathfindListener(); + + private void renderBox(Vec3 node, Color c, float partialTicks) { + if (node == null) return; + RenderUtils.highlightBox(AxisAlignedBB.fromBounds(node.xCoord - 0.25f, node.yCoord, node.zCoord - 0.25f, node.xCoord + 0.25f, node.yCoord + 0.5f, node.zCoord + 0.25f),c, partialTicks, false); + + } + + @SubscribeEvent + public void onRenderWorld(RenderWorldLastEvent postRender) { + try { + if (jpsPathfinder == null) return; + GlStateManager.pushMatrix(); + for (JPSPathfinder.Node node : jpsPathfinder.getOpen()) { + renderBox(new Vec3(node.getX() / 2.0, node.getY() / 2.0, node.getZ() / 2.0), new Color(255,0,0,50), postRender.partialTicks); + } + + RenderUtils.drawLinesVec3(jpsPathfinder.getRoute(), new AColor(0, 255, 0, 255), 1, postRender.partialTicks, false); + for (Vec3 vec3 : jpsPathfinder.getRoute()) { + renderBox(vec3, new Color(0, 255,0, 50), postRender.partialTicks); + } + GlStateManager.popMatrix(); + } catch (Throwable t) { + } + } +} diff --git a/src/main/java/kr/syeyoung/dungeonsguide/features/FeatureRegistry.java b/src/main/java/kr/syeyoung/dungeonsguide/features/FeatureRegistry.java index 0fac0dba..72eb809b 100644 --- a/src/main/java/kr/syeyoung/dungeonsguide/features/FeatureRegistry.java +++ b/src/main/java/kr/syeyoung/dungeonsguide/features/FeatureRegistry.java @@ -161,10 +161,12 @@ public class FeatureRegistry { public static final FeatureMechanicBrowse SECRET_BROWSE = register(new FeatureMechanicBrowse()); public static final FeatureActions SECRET_ACTIONS = register(new FeatureActions()); public static final FeatureSoulRoomWarning SECRET_FAIRYSOUL = register(new FeatureSoulRoomWarning()); - public static final SimpleFeature SECRET_AUTO_BROWSE_NEXT = register(new SimpleFeature("Dungeon Secret.Secret Pathfind", "Auto Pathfind to next secret", "Auto browse best next secret after current one completes.\nthe first pathfinding of first secret needs to be triggered first in order for this option to work", "secret.autobrowse", false)); - public static final SimpleFeature SECRET_AUTO_START = register(new SimpleFeature("Dungeon Secret.Secret Pathfind", "Auto pathfind to new secret", "Auto browse best secret upon entering the room.", "secret.autouponenter", false)); - public static final SimpleFeature SECRET_NEXT_KEY = register(new SimpleFeature("Dungeon Secret.Secret Pathfind", "Auto Pathfind to new secret upon pressing a key", "Auto browse the best next secret when you press key.\nChange key at your key settings (Settings -> Controls)", "secret.keyfornext", false)); + public static final SimpleFeature SECRET_AUTO_BROWSE_NEXT = register(new SimpleFeature("Dungeon Secret.Secret Pathfind.Legacy AutoPathfind", "Auto Pathfind to next secret", "Auto browse best next secret after current one completes.\nthe first pathfinding of first secret needs to be triggered first in order for this option to work", "secret.autobrowse", false)); + public static final SimpleFeature SECRET_AUTO_START = register(new SimpleFeature("Dungeon Secret.Secret Pathfind.Legacy AutoPathfind", "Auto pathfind to new secret", "Auto browse best secret upon entering the room.", "secret.autouponenter", false)); + public static final SimpleFeature SECRET_NEXT_KEY = register(new SimpleFeature("Dungeon Secret.Secret Pathfind.Legacy AutoPathfind", "Auto Pathfind to new secret upon pressing a key", "Auto browse the best next secret when you press key.\nChange key at your key settings (Settings -> Controls)", "secret.keyfornext", false)); + public static final SimpleFeature SECRET_PATHFIND_ALL = register(new SimpleFeature("Dungeon Secret.Secret Pathfind", "Start pathfind to all secrets upon entering a room", "Auto browse to all secrets in the room", "secret.secretpathfind.allbrowse", false)); public static final SimpleFeature SECRET_TOGGLE_KEY = register(new SimpleFeature("Dungeon Secret.Pathfind Display", "Toggle Pathfind Lines", "A key for toggling pathfound line visibility.\nChange key at your key settings (Settings -> Controls)", "secret.togglePathfind")); + public static final SimpleFeature SECRET_BEACONS = register(new SimpleFeature("Dungeon Secret.Pathfind Display", "Beacons on pathfind", "When pathfinding, display beacons as well as lines", "secret.beacons")); public static final SimpleFeature SECRET_FREEZE_LINES = register(new FeatureFreezePathfind()); public static final FeatureNicknamePrefix COSMETIC_PREFIX = register(new FeatureNicknamePrefix()); diff --git a/src/main/java/kr/syeyoung/dungeonsguide/features/impl/secret/FeatureActions.java b/src/main/java/kr/syeyoung/dungeonsguide/features/impl/secret/FeatureActions.java index b62a168f..0ae1e668 100644 --- a/src/main/java/kr/syeyoung/dungeonsguide/features/impl/secret/FeatureActions.java +++ b/src/main/java/kr/syeyoung/dungeonsguide/features/impl/secret/FeatureActions.java @@ -115,9 +115,7 @@ public class FeatureActions extends TextHUDFeature { Point roomPt = context.getMapProcessor().worldPointToRoomPoint(thePlayer.getPosition()); DungeonRoom dungeonRoom = context.getRoomMapper().get(roomPt); - ActionRoute path = ((GeneralRoomProcessor)dungeonRoom.getRoomProcessor()).getPath(); - - if (path != null) { + for (ActionRoute path : ((GeneralRoomProcessor) dungeonRoom.getRoomProcessor()).getPath().values()) { actualBit.add(new StyledText("Pathfinding ","pathfinding")); actualBit.add(new StyledText(path.getMechanic()+" ","mechanic")); actualBit.add(new StyledText("-> ","separator")); diff --git a/src/main/java/kr/syeyoung/dungeonsguide/features/impl/secret/mechanicbrowser/PanelMechanicBrowser.java b/src/main/java/kr/syeyoung/dungeonsguide/features/impl/secret/mechanicbrowser/PanelMechanicBrowser.java index 72ce5e01..5a558a1e 100644 --- a/src/main/java/kr/syeyoung/dungeonsguide/features/impl/secret/mechanicbrowser/PanelMechanicBrowser.java +++ b/src/main/java/kr/syeyoung/dungeonsguide/features/impl/secret/mechanicbrowser/PanelMechanicBrowser.java @@ -93,10 +93,10 @@ public class PanelMechanicBrowser extends MPanelScaledGUI { 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("Selected: ", 2,2, 0xFFAAAAAA); - if (grp.getPath() == null) + if (grp.getPath("MECH-BROWSER") == null) fr.drawString("Nothing", fr.getStringWidth("Selected: ") + 2,2, 0xFFAA0000); else { - ActionRoute route = grp.getPath(); + ActionRoute route = grp.getPath("MECH-BROWSER"); fr.drawString(route.getMechanic()+" -> "+route.getState(), fr.getStringWidth("Selected: ") + 2,2, 0xFFFFFF00); } fr.drawString("Open Chat to Select Secrets", 2, fr.FONT_HEIGHT + 5, 0xFFAAAAAA); @@ -256,7 +256,7 @@ public class PanelMechanicBrowser extends MPanelScaledGUI { for (String state : states) { mechanicBrowserTooltip.getMList().add(new MechanicBrowserElement(() -> state, false, (m2, pt2) -> { if (dungeonRoom.getRoomProcessor() instanceof GeneralRoomProcessor) - ((GeneralRoomProcessor)dungeonRoom.getRoomProcessor()).pathfind(id, state); + ((GeneralRoomProcessor)dungeonRoom.getRoomProcessor()).pathfind("MECH-BROWSER", id, state); mechanicBrowserTooltip.close(); mechanicBrowserTooltip = null; })); @@ -276,7 +276,7 @@ public class PanelMechanicBrowser extends MPanelScaledGUI { if (!dungeonRoomOpt.isPresent()) return; DungeonRoom dungeonRoom = dungeonRoomOpt.get(); if (!(dungeonRoom.getRoomProcessor() instanceof GeneralRoomProcessor)) return; - ((GeneralRoomProcessor) dungeonRoom.getRoomProcessor()).cancel(); + ((GeneralRoomProcessor) dungeonRoom.getRoomProcessor()).cancel("MECH-BROWSER"); } public void toggleTooltip(boolean open) { diff --git a/src/main/java/kr/syeyoung/dungeonsguide/pathfinding/CachedWorld.java b/src/main/java/kr/syeyoung/dungeonsguide/pathfinding/CachedWorld.java new file mode 100644 index 00000000..ac9234c6 --- /dev/null +++ b/src/main/java/kr/syeyoung/dungeonsguide/pathfinding/CachedWorld.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.pathfinding; + +import lombok.AllArgsConstructor; +import net.minecraft.block.state.IBlockState; +import net.minecraft.entity.EnumCreatureType; +import net.minecraft.profiler.Profiler; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.BlockPos; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.IProgressUpdate; +import net.minecraft.world.*; +import net.minecraft.world.biome.BiomeGenBase; +import net.minecraft.world.chunk.Chunk; +import net.minecraft.world.chunk.IChunkProvider; +import net.minecraft.world.storage.ISaveHandler; +import net.minecraft.world.storage.WorldInfo; + +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import java.util.List; + +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/pathfinding/JPSPathfinder.java b/src/main/java/kr/syeyoung/dungeonsguide/pathfinding/JPSPathfinder.java new file mode 100644 index 00000000..8ee1251f --- /dev/null +++ b/src/main/java/kr/syeyoung/dungeonsguide/pathfinding/JPSPathfinder.java @@ -0,0 +1,368 @@ +/* + * 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.pathfinding; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import net.minecraft.block.Block; +import net.minecraft.block.state.IBlockState; +import net.minecraft.util.*; +import net.minecraft.world.ChunkCache; +import net.minecraft.world.World; + +import java.lang.reflect.Proxy; +import java.util.*; + +public class JPSPathfinder { + private final BlockPos min, max; + private final World world; + + private Vec3 start; + private Vec3 destination; + + @Getter + private AxisAlignedBB destinationBB; + + public JPSPathfinder(World world, BlockPos min, BlockPos max ){ + this.min = min; + this.max = max; + + ChunkCache chunkCache = new ChunkCache(world, min, max, 0); + this.world = new CachedWorld(chunkCache); + + minx = min.getX() * 2; miny = min.getY() * 2; minz = min.getZ() * 2; + maxx = max.getX() * 2 + 2; maxy = max.getY() * 2 + 2; maxz = max.getZ() * 2 + 2; + + lenx = maxx - minx; + leny = maxy - miny; + lenz = maxz - minz; + + } + + private IntHashMap<Node> nodeMap = new IntHashMap(); + + private Node openNode(int x, int y, int z) + { + int i = Node.makeHash(x, y, z); + Node 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.f).thenComparing(a -> a.x).thenComparing(a -> a.y).thenComparing(a -> a.z)); + + private int tx, ty, tz; + + private final int minx, miny, minz, maxx, maxy, maxz; + private final int lenx, leny, lenz; + + 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) { + route.clear(); nodeMap.clearMap(); + + this.start = from; this.destination = to; + tx = (int)(to.xCoord * 2); + ty = (int)(to.yCoord * 2); + tz = (int)(to.zCoord * 2); + + arr = new long[lenx *leny * lenz * 2 / 8]; + + destinationBB = AxisAlignedBB.fromBounds((to.xCoord - 0.6)* 2, (to.yCoord - 0.6) * 2, (to.zCoord - 0.6) * 2, (to.xCoord + 0.6) * 2, (to.yCoord + 0.6)* 2, (to.zCoord + 0.6) *2); + open.clear(); + Node start; + open.add(start = openNode((int)from.xCoord* 2 + 1, (int)from.yCoord* 2 + 1, (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() + 3000; + while(!open.isEmpty()) { +// if (forceEnd < System.currentTimeMillis()) 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)) { + expand(n.x, n.y, n.z, neighbor.x - n.x, neighbor.y - n.y, neighbor.z - n.z, n); + } + } + + if (end == null) return false; + Node p = end; + while (p != null) { + route.addLast(new Vec3(p.x / 2.0f, p.y / 2.0f, 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 && isBlocked(x, y + i, z + j)) nexts.add(openNode(nx,y+i,z+j)); + if (dy != 0 && isBlocked(x + i, y, z + j)) nexts.add(openNode(x+i,ny,z+j)); + if (dz != 0 && 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 (isBlocked(x, y, z-dz)) { + nexts.add(openNode(x, ny, z-dz)); + if (isBlocked(x+1, y, z-dz)) nexts.add(openNode(x+1, ny, z-dz)); + if (isBlocked(x-1, y, z-dz)) nexts.add(openNode(x-1, ny, z-dz)); + } + if (isBlocked(x, y-dy, z)) { + nexts.add(openNode(x, y-dy, nz)); + if (isBlocked(x+1, y-dy, z))nexts.add(openNode(x+1, y-dy, nz)); + if (isBlocked(x-1, y-dy, z))nexts.add(openNode(x+1, y-dy, nz)); + } + } else if (dy == 0) { + if (isBlocked(x, y, z-dz)) { + nexts.add(openNode(x, ny, z-dz)); + if (isBlocked(x, y+1, z-dz)) nexts.add(openNode(nx, y+1, z-dz)); + if (isBlocked(x, y-1, z-dz)) nexts.add(openNode(nx, y-1, z-dz)); + } + if (isBlocked(x-dx, y, z)) { + nexts.add(openNode(x-dx, y, nz)); + if (isBlocked(x-dx, y+1, z))nexts.add(openNode(x-dx, y+1, nz)); + if (isBlocked(x-dx, y-1, z))nexts.add(openNode(x-dx, y-1, nz)); + } + } else if (dz == 0) { + if (isBlocked(x, y-dy, z)) { + nexts.add(openNode(nx, y-dy, z)); + if (isBlocked(x, y-dy, z+1))nexts.add(openNode(nx, y-dy, z+1)); + if (isBlocked(x, y-dy, z-1))nexts.add(openNode(nx, y-dy, z-1)); + } + if (isBlocked(x-dx, y, z)) { + nexts.add(openNode(x-dx, ny, z)); + if (isBlocked(x-dx, y, z+1))nexts.add(openNode(x-dx, ny, z+1)); + if (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 (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 (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 (isBlocked(x,y-dy,z)) { + nexts.add(openNode(x,y-dy,nz)); + nexts.add(openNode(nx,y-dy,x)); + nexts.add(openNode(nx,y-dy,nz)); + } + } + return nexts; + } + + public Node expand(int x, int y, int z, int dx, int dy, int dz, Node parent) { + while(true) { + int nx = x + dx, ny = y + dy, nz = z + dz; + if (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 addNode(parent, openNode(nx,ny,nz), true); + + 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 && isBlocked(nx, ny + i, nz + j) && !isBlocked(nx+dx, ny + i, nz + j)) return addNode(parent, openNode(nx,ny,nz), true); + if (dy != 0 && isBlocked(nx + i, ny, nz + j) && !isBlocked(nx + i, ny+dy, nz + j)) return addNode(parent, openNode(nx,ny,nz), true); + if (dz != 0 && isBlocked(nx + i, ny + j , nz) && !isBlocked(nx + i, ny + j , nz+dz)) return addNode(parent, openNode(nx,ny,nz), true); + } + } + } else if (determinant == 2) { + if ((dx != 0 && isBlocked(nx , y , z ) && !isBlocked(nx + dx, y , z)) + || (dy != 0 && isBlocked(x , ny , z) && !isBlocked(x , ny+dy , z)) + || (dz != 0 && isBlocked(x , y , nz ) && !isBlocked(x , y , nz+dz))) return addNode(parent, openNode(nx,ny,nz), true); + Node co_parent = openNode(nx,ny,nz); + addNode(parent, co_parent,false); + if (dx != 0) expand(nx, ny, nz, dx, 0,0, co_parent); + if (dy != 0) expand(nx, ny, nz, 0, dy,0, co_parent); + if (dz != 0) expand(nx, ny, nz, 0, 0,dz, co_parent); + } else if (determinant == 3) { + if (isBlocked(x, ny, nz ) || isBlocked(nx, y , nz) || isBlocked(nx, ny, z)) return addNode(parent, openNode(nx,ny,nz), true); + Node co_parent = openNode(nx,ny,nz); + addNode(parent, co_parent,false); + expand(nx, ny, nz, dx, 0, 0, co_parent); + expand(nx, ny, nz, dx, dy, 0, co_parent); + expand(nx, ny, nz, dx, 0, dz, co_parent); + expand(nx, ny, nz, 0, dy, 0, co_parent); + expand(nx, ny, nz, 0, dy, dz, co_parent); + expand(nx, ny, nz, 0, 0, dz, co_parent); + } + x = nx; y = ny; z = nz; + } + } + + 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 = world.getBlockState(blockPos); + Block b = iblockstate1.getBlock(); + if (!b.getMaterial().blocksMovement())continue; + if (b.isFullCube() && i2 == k-1) continue; + if (b.isFullCube()) { + theBit |= (3L << bitStart); + arr[location] = theBit; + return true; + } + try { + b.addCollisionBoxesToList(world, 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; + } + + + @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/roomprocessor/GeneralRoomProcessor.java b/src/main/java/kr/syeyoung/dungeonsguide/roomprocessor/GeneralRoomProcessor.java index 20de9e9d..68b460cb 100755 --- a/src/main/java/kr/syeyoung/dungeonsguide/roomprocessor/GeneralRoomProcessor.java +++ b/src/main/java/kr/syeyoung/dungeonsguide/roomprocessor/GeneralRoomProcessor.java @@ -70,26 +70,37 @@ public class GeneralRoomProcessor implements RoomProcessor { public void tick() { if (!ticked && FeatureRegistry.SECRET_AUTO_START.isEnabled()) searchForNextTarget(); - - ticked = true; - if (path != null) { - path.onTick(); - if (FeatureRegistry.SECRET_AUTO_BROWSE_NEXT.isEnabled() && path.getCurrentAction() instanceof ActionComplete) { - if (!path.getState().equals("found")) return; - if (!(dungeonRoom.getMechanics().get(path.getMechanic()) instanceof DungeonSecret)) return; - searchForNextTarget(); + 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) { + pathfind(value.getKey(), "found"); + } } } + 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) { - cancel(); + cancelAll(); return; } @@ -120,7 +131,7 @@ public class GeneralRoomProcessor implements RoomProcessor { } if (lowestWeightMechanic != null) { visited.add(lowestWeightMechanic.getKey()); - pathfind(lowestWeightMechanic.getKey(), "found"); + pathfind("AUTO-BROWSE", lowestWeightMechanic.getKey(), "found"); } else { visited.clear(); } @@ -128,7 +139,9 @@ public class GeneralRoomProcessor implements RoomProcessor { @Override public void drawScreen(float partialTicks) { - if (path != null) path.onRenderScreen(partialTicks); + path.values().forEach(a -> { + a.onRenderScreen(partialTicks); + }); if (FeatureRegistry.ADVANCED_ROOMEDIT.isEnabled() && FeatureRegistry.DEBUG.isEnabled()) { FontRenderer fr = Minecraft.getMinecraft().fontRendererObj; @@ -154,8 +167,9 @@ public class GeneralRoomProcessor implements RoomProcessor { value.getValue().highlight(new Color(0,255,255,50), value.getKey(), dungeonRoom, partialTicks); } } - if (path != null) path.onRenderWorld(partialTicks); - + path.values().forEach(a -> { + a.onRenderWorld(partialTicks); + }); } @Override @@ -217,13 +231,25 @@ public class GeneralRoomProcessor implements RoomProcessor { } @Getter - private ActionRoute path; + private Map<String, ActionRoute> path = new HashMap<>(); - public void pathfind(String mechanic, String state) { - path = new ActionRoute(getDungeonRoom(), mechanic, state); + public ActionRoute getPath(String id){ + return path.get(id); + } + + public String pathfind(String mechanic, String state) { + String str; + pathfind(str = UUID.randomUUID().toString(), mechanic, state); + return str; + } + public void pathfind(String id, String mechanic, String state) { + path.put(id, new ActionRoute(getDungeonRoom(), mechanic, state)); + } + public void cancelAll() { + path.clear(); } - public void cancel() { - path = null; + public void cancel(String id) { + path.remove(id); } @Override @@ -251,13 +277,17 @@ public class GeneralRoomProcessor implements RoomProcessor { @Override public void onInteract(PlayerInteractEntityEvent event) { - if (path != null) path.onLivingInteract(event); + path.values().forEach(a -> { + a.onLivingInteract(event); + }); } private boolean last = false; @Override public void onInteractBlock(PlayerInteractEvent event) { - if (path != null) path.onPlayerInteract(event); + path.values().forEach(a -> { + a.onPlayerInteract(event); + }); if (event.entityPlayer.getHeldItem() != null && event.entityPlayer.getHeldItem().getItem() == Items.stick && @@ -280,7 +310,9 @@ public class GeneralRoomProcessor implements RoomProcessor { @Override public void onEntityDeath(LivingDeathEvent deathEvent) { - if (path != null) path.onLivingDeath(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()) { diff --git a/src/main/java/kr/syeyoung/dungeonsguide/utils/RenderUtils.java b/src/main/java/kr/syeyoung/dungeonsguide/utils/RenderUtils.java index 9632d9d7..b0c54e17 100755 --- a/src/main/java/kr/syeyoung/dungeonsguide/utils/RenderUtils.java +++ b/src/main/java/kr/syeyoung/dungeonsguide/utils/RenderUtils.java @@ -46,6 +46,95 @@ import java.util.List; public class RenderUtils { public static final ResourceLocation icons = new ResourceLocation("textures/gui/icons.png"); + private static final ResourceLocation beaconBeam = new ResourceLocation("textures/entity/beacon_beam.png"); + + /** + * Taken from NotEnoughUpdates under Creative Commons Attribution-NonCommercial 3.0 + * And modified to fit out need. + * https://github.com/Moulberry/NotEnoughUpdates/blob/master/LICENSE + * @author Moulberry + */ + public static void renderBeaconBeam(double x, double y, double z, AColor aColor, float partialTicks) { + int height = 300; + int bottomOffset = 0; + int topOffset = bottomOffset + height; + + Tessellator tessellator = Tessellator.getInstance(); + WorldRenderer worldrenderer = tessellator.getWorldRenderer(); + + Minecraft.getMinecraft().getTextureManager().bindTexture(beaconBeam); + GL11.glTexParameterf(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, 10497.0F); + GL11.glTexParameterf(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, 10497.0F); + GlStateManager.disableLighting(); + GlStateManager.enableCull(); + GlStateManager.enableTexture2D(); + GlStateManager.tryBlendFuncSeparate(770, 1, 1, 0); + GlStateManager.enableBlend(); + GlStateManager.tryBlendFuncSeparate(770, 771, 1, 0); + + double time = Minecraft.getMinecraft().theWorld.getTotalWorldTime() + (double)partialTicks; + double d1 = MathHelper.func_181162_h(-time * 0.2D - (double)MathHelper.floor_double(-time * 0.1D)); + + int c = getColorAt(x,y,z, aColor); + float alpha = ((c >> 24) & 0xFF) / 255.0f; + + float r = ((c >> 16) & 0xFF) / 255f; + float g = ((c >> 8) & 0xFF) / 255f; + float b = (c & 0xFF) / 255f; + double d2 = time * 0.025D * -1.5D; + double d4 = 0.5D + Math.cos(d2 + 2.356194490192345D) * 0.2D; + double d5 = 0.5D + Math.sin(d2 + 2.356194490192345D) * 0.2D; + double d6 = 0.5D + Math.cos(d2 + (Math.PI / 4D)) * 0.2D; + double d7 = 0.5D + Math.sin(d2 + (Math.PI / 4D)) * 0.2D; + double d8 = 0.5D + Math.cos(d2 + 3.9269908169872414D) * 0.2D; + double d9 = 0.5D + Math.sin(d2 + 3.9269908169872414D) * 0.2D; + double d10 = 0.5D + Math.cos(d2 + 5.497787143782138D) * 0.2D; + double d11 = 0.5D + Math.sin(d2 + 5.497787143782138D) * 0.2D; + double d14 = -1.0D + d1; + double d15 = (double)(height) * 2.5D + d14; + worldrenderer.begin(7, DefaultVertexFormats.POSITION_TEX_COLOR); + worldrenderer.pos(x + d4, y + topOffset, z + d5).tex(1.0D, d15).color(r, g, b, alpha).endVertex(); + worldrenderer.pos(x + d4, y + bottomOffset, z + d5).tex(1.0D, d14).color(r, g, b, 1.0F).endVertex(); + worldrenderer.pos(x + d6, y + bottomOffset, z + d7).tex(0.0D, d14).color(r, g, b, 1.0F).endVertex(); + worldrenderer.pos(x + d6, y + topOffset, z + d7).tex(0.0D, d15).color(r, g, b, alpha).endVertex(); + worldrenderer.pos(x + d10, y + topOffset, z + d11).tex(1.0D, d15).color(r, g, b, alpha).endVertex(); + worldrenderer.pos(x + d10, y + bottomOffset, z + d11).tex(1.0D, d14).color(r, g, b, 1.0F).endVertex(); + worldrenderer.pos(x + d8, y + bottomOffset, z + d9).tex(0.0D, d14).color(r, g, b, 1.0F).endVertex(); + worldrenderer.pos(x + d8, y + topOffset, z + d9).tex(0.0D, d15).color(r, g, b, alpha).endVertex(); + worldrenderer.pos(x + d6, y + topOffset, z + d7).tex(1.0D, d15).color(r, g, b, alpha).endVertex(); + worldrenderer.pos(x + d6, y + bottomOffset, z + d7).tex(1.0D, d14).color(r, g, b, 1.0F).endVertex(); + worldrenderer.pos(x + d10, y + bottomOffset, z + d11).tex(0.0D, d14).color(r, g, b, 1.0F).endVertex(); + worldrenderer.pos(x + d10, y + topOffset, z + d11).tex(0.0D, d15).color(r, g, b, alpha).endVertex(); + worldrenderer.pos(x + d8, y + topOffset, z + d9).tex(1.0D, d15).color(r, g, b, alpha).endVertex(); + worldrenderer.pos(x + d8, y + bottomOffset, z + d9).tex(1.0D, d14).color(r, g, b, 1.0F).endVertex(); + worldrenderer.pos(x + d4, y + bottomOffset, z + d5).tex(0.0D, d14).color(r, g, b, 1.0F).endVertex(); + worldrenderer.pos(x + d4, y + topOffset, z + d5).tex(0.0D, d15).color(r, g, b, alpha).endVertex(); + tessellator.draw(); + + GlStateManager.disableCull(); + double d12 = -1.0D + d1; + double d13 = height + d12; + + worldrenderer.begin(7, DefaultVertexFormats.POSITION_TEX_COLOR); + worldrenderer.pos(x + 0.2D, y + topOffset, z + 0.2D).tex(1.0D, d13).color(r, g, b, 0.25F*alpha).endVertex(); + worldrenderer.pos(x + 0.2D, y + bottomOffset, z + 0.2D).tex(1.0D, d12).color(r, g, b, 0.25F).endVertex(); + worldrenderer.pos(x + 0.8D, y + bottomOffset, z + 0.2D).tex(0.0D, d12).color(r, g, b, 0.25F).endVertex(); + worldrenderer.pos(x + 0.8D, y + topOffset, z + 0.2D).tex(0.0D, d13).color(r, g, b, 0.25F*alpha).endVertex(); + worldrenderer.pos(x + 0.8D, y + topOffset, z + 0.8D).tex(1.0D, d13).color(r, g, b, 0.25F*alpha).endVertex(); + worldrenderer.pos(x + 0.8D, y + bottomOffset, z + 0.8D).tex(1.0D, d12).color(r, g, b, 0.25F).endVertex(); + worldrenderer.pos(x + 0.2D, y + bottomOffset, z + 0.8D).tex(0.0D, d12).color(r, g, b, 0.25F).endVertex(); + worldrenderer.pos(x + 0.2D, y + topOffset, z + 0.8D).tex(0.0D, d13).color(r, g, b, 0.25F*alpha).endVertex(); + worldrenderer.pos(x + 0.8D, y + topOffset, z + 0.2D).tex(1.0D, d13).color(r, g, b, 0.25F*alpha).endVertex(); + worldrenderer.pos(x + 0.8D, y + bottomOffset, z + 0.2D).tex(1.0D, d12).color(r, g, b, 0.25F).endVertex(); + worldrenderer.pos(x + 0.8D, y + bottomOffset, z + 0.8D).tex(0.0D, d12).color(r, g, b, 0.25F).endVertex(); + worldrenderer.pos(x + 0.8D, y + topOffset, z + 0.8D).tex(0.0D, d13).color(r, g, b, 0.25F*alpha).endVertex(); + worldrenderer.pos(x + 0.2D, y + topOffset, z + 0.8D).tex(1.0D, d13).color(r, g, b, 0.25F*alpha).endVertex(); + worldrenderer.pos(x + 0.2D, y + bottomOffset, z + 0.8D).tex(1.0D, d12).color(r, g, b, 0.25F).endVertex(); + worldrenderer.pos(x + 0.2D, y + bottomOffset, z + 0.2D).tex(0.0D, d12).color(r, g, b, 0.25F).endVertex(); + worldrenderer.pos(x + 0.2D, y + topOffset, z + 0.2D).tex(0.0D, d13).color(r, g, b, 0.25F*alpha).endVertex(); + tessellator.draw(); + } + public static void drawTexturedRect(float x, float y, float width, float height, int filter) { drawTexturedRect(x, y, width, height, 0.0F, 1.0F, 0.0F, 1.0F, filter); @@ -478,6 +567,54 @@ public class RenderUtils { GlStateManager.popMatrix(); } + public static void drawLinesVec3(List<Vec3> poses, AColor colour, float thickness, float partialTicks, boolean depth) { + Entity render = Minecraft.getMinecraft().getRenderViewEntity(); + WorldRenderer worldRenderer = Tessellator.getInstance().getWorldRenderer(); + + double realX = render.lastTickPosX + (render.posX - render.lastTickPosX) * partialTicks; + double realY = render.lastTickPosY + (render.posY - render.lastTickPosY) * partialTicks; + double realZ = render.lastTickPosZ + (render.posZ - render.lastTickPosZ) * partialTicks; + + GlStateManager.pushMatrix(); + GlStateManager.translate(-realX, -realY, -realZ); + GlStateManager.disableTexture2D(); + GL11.glDisable(GL11.GL_TEXTURE_2D); + GlStateManager.enableBlend(); + GlStateManager.disableAlpha(); + GL11.glLineWidth(thickness); + if (!depth) { + GlStateManager.disableDepth(); + GlStateManager.depthMask(false); + } + GlStateManager.tryBlendFuncSeparate(770, 771, 1, 0); + +// GlStateManager.color(colour.getRed() / 255f, colour.getGreen() / 255f, colour.getBlue()/ 255f, colour.getAlpha() / 255f); + GlStateManager.color(1,1,1,1); + worldRenderer.begin(GL11.GL_LINE_STRIP, DefaultVertexFormats.POSITION_COLOR); + int num = 0; + for (Vec3 pos:poses) { + int i = getColorAt(num++ * 10,0, colour); + worldRenderer.pos(pos.xCoord, pos.yCoord, pos.zCoord).color( + ((i >> 16) &0xFF)/255.0f, + ((i >> 8) &0xFF)/255.0f, + (i &0xFF)/255.0f, + ((i >> 24) &0xFF)/255.0f + ).endVertex(); + } + Tessellator.getInstance().draw(); + + GlStateManager.translate(realX, realY, realZ); + GlStateManager.disableBlend(); + GlStateManager.enableAlpha(); + GlStateManager.enableTexture2D(); + if (!depth) { + GlStateManager.enableDepth(); + GlStateManager.depthMask(true); + } + GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F); + GlStateManager.popMatrix(); + GL11.glLineWidth(1); + } public static void drawLines(List<BlockPos> poses, AColor colour, float thickness, float partialTicks, boolean depth) { Entity render = Minecraft.getMinecraft().getRenderViewEntity(); WorldRenderer worldRenderer = Tessellator.getInstance().getWorldRenderer(); @@ -643,6 +780,80 @@ public class RenderUtils { } + public static void highlightBox(AxisAlignedBB axisAlignedBB, Color c, float partialTicks, boolean depth) { + 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.enableBlend(); + GlStateManager.disableCull(); + GlStateManager.tryBlendFuncSeparate(770, 771, 1, 0); + GlStateManager.disableTexture2D(); + + if (!depth) { + GlStateManager.disableDepth(); + GlStateManager.depthMask(false); + } + int rgb = c.getRGB(); + GlStateManager.color(((rgb >> 16) &0XFF)/ 255.0f, ((rgb>>8) &0XFF)/ 255.0f, (rgb & 0xff)/ 255.0f, ((rgb >> 24) & 0xFF) / 255.0f); + + GlStateManager.translate(axisAlignedBB.minX, axisAlignedBB.minY, axisAlignedBB.minZ); + + double x = axisAlignedBB.maxX - axisAlignedBB.minX; + double y = axisAlignedBB.maxY - axisAlignedBB.minY; + double z = axisAlignedBB.maxZ - axisAlignedBB.minZ; + GL11.glBegin(GL11.GL_QUADS); + GL11.glVertex3d(0, 0, 0); + GL11.glVertex3d(0, 0, z); + GL11.glVertex3d(0, y, z); + GL11.glVertex3d(0, y, 0); // TOP LEFT / BOTTOM LEFT / TOP RIGHT/ BOTTOM RIGHT + + GL11.glVertex3d(x, 0, z); + GL11.glVertex3d(x, 0, 0); + GL11.glVertex3d(x, y, 0); + GL11.glVertex3d(x, y, z); + + GL11.glVertex3d(0, y, z); + GL11.glVertex3d(0, 0, z); + GL11.glVertex3d(x, 0, z); + GL11.glVertex3d(x, y, z); // TOP LEFT / BOTTOM LEFT / TOP RIGHT/ BOTTOM RIGHT + + GL11.glVertex3d(0, 0, 0); + GL11.glVertex3d(0, y, 0); + GL11.glVertex3d(x, y, 0); + GL11.glVertex3d(x, 0, 0); + + GL11.glVertex3d(0,y,0); + GL11.glVertex3d(0,y,z); + GL11.glVertex3d(x,y,z); + GL11.glVertex3d(x,y,0); + + GL11.glVertex3d(0,0,z); + GL11.glVertex3d(0,0,0); + GL11.glVertex3d(x,0,0); + GL11.glVertex3d(x,0,z); + + + + GL11.glEnd(); + + + if (!depth) { + GlStateManager.disableDepth(); + GlStateManager.depthMask(true); + } + GlStateManager.enableTexture2D(); + GlStateManager.enableLighting(); + GlStateManager.popMatrix(); + + } public static void highlightBox(Entity entity, AxisAlignedBB axisAlignedBB, AColor c, float partialTicks, boolean depth) { Entity viewing_from = Minecraft.getMinecraft().getRenderViewEntity(); |