/* * 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 . */ package kr.syeyoung.dungeonsguide.roomprocessor; import kr.syeyoung.dungeonsguide.DungeonsGuide; import kr.syeyoung.dungeonsguide.Keybinds; import kr.syeyoung.dungeonsguide.dungeon.DungeonContext; import kr.syeyoung.dungeonsguide.dungeon.DungeonActionManager; import kr.syeyoung.dungeonsguide.dungeon.actions.ActionComplete; import kr.syeyoung.dungeonsguide.dungeon.actions.ActionMove; import kr.syeyoung.dungeonsguide.dungeon.actions.ActionMoveNearestAir; import kr.syeyoung.dungeonsguide.dungeon.actions.tree.ActionRoute; import kr.syeyoung.dungeonsguide.dungeon.data.OffsetPoint; import kr.syeyoung.dungeonsguide.dungeon.doorfinder.DungeonDoor; import kr.syeyoung.dungeonsguide.dungeon.mechanics.DungeonMechanic; import kr.syeyoung.dungeonsguide.dungeon.mechanics.DungeonRoomDoor; import kr.syeyoung.dungeonsguide.dungeon.mechanics.DungeonSecret; import kr.syeyoung.dungeonsguide.dungeon.roomfinder.DungeonRoom; import kr.syeyoung.dungeonsguide.events.BlockUpdateEvent; import kr.syeyoung.dungeonsguide.events.KeyBindPressedEvent; import kr.syeyoung.dungeonsguide.events.PlayerInteractEntityEvent; import kr.syeyoung.dungeonsguide.features.FeatureRegistry; import kr.syeyoung.dungeonsguide.pathfinding.NodeProcessorDungeonRoom; import kr.syeyoung.dungeonsguide.roomedit.EditingContext; import kr.syeyoung.dungeonsguide.roomedit.gui.GuiDungeonAddSet; import kr.syeyoung.dungeonsguide.roomedit.gui.GuiDungeonRoomEdit; import kr.syeyoung.dungeonsguide.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(); if (!ticked && FeatureRegistry.SECRET_PATHFIND_ALL.isEnabled()) { for (Map.Entry 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()); } } } if (!ticked && FeatureRegistry.SECRET_BLOOD_RUSH.isEnabled()) { for (Map.Entry 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 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 visited = new HashSet(); public void searchForNextTarget() { if (getDungeonRoom().getCurrentState() == DungeonRoom.RoomState.FINISHED) { cancelAll(); return; } BlockPos pos = Minecraft.getMinecraft().thePlayer.getPosition(); double lowestCost = 99999999999999.0; Map.Entry lowestWeightMechanic = null; for (Map.Entry 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 (DungeonActionManager.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 " + DungeonActionManager.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 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) { DungeonsGuide.sendDebugChat(new ChatComponentText(chat.getFormattedText().replace('§', '&') + " - received")); } if (!chat.getFormattedText().contains("/")) return; BlockPos pos = Minecraft.getMinecraft().thePlayer.getPosition(); DungeonContext context = DungeonsGuide.getDungeonsGuide().getSkyblockStatus().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 path = new HashMap<>(); public ActionRoute getPath(String id){ return path.get(id); } public String pathfind(String mechanic, String state, ActionRoute.ActionRouteProperties actionRouteProperties) { String str; pathfind(str = UUID.randomUUID().toString(), mechanic, state, actionRouteProperties); return str; } public void pathfind(String id, String mechanic, String state, ActionRoute.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.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, DungeonActionManager.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, DungeonActionManager.getSpawnLocation().get(deathEvent.entity.getEntityId()) )); ((GuiDungeonRoomEdit) EditingContext.getEditingContext().getCurrent()).getSep().createNewMechanic("BAT-"+ UUID.randomUUID(), secret); } } } } @Override public void onBlockUpdate(BlockUpdateEvent blockUpdateEvent) { for (Tuple updatedBlock : blockUpdateEvent.getUpdatedBlocks()) { if (updatedBlock.getSecond().equals(NodeProcessorDungeonRoom.preBuilt)) continue; dungeonRoom.resetBlock(updatedBlock.getFirst()); } } public static class Generator implements RoomProcessorGenerator { @Override public GeneralRoomProcessor createNew(DungeonRoom dungeonRoom) { GeneralRoomProcessor defaultRoomProcessor = new GeneralRoomProcessor(dungeonRoom); return defaultRoomProcessor; } } }