diff --git a/src/main/kotlin/gg/skytils/skytilsmod/Skytils.kt b/src/main/kotlin/gg/skytils/skytilsmod/Skytils.kt index 3c01a4d13..4e04f98c2 100644 --- a/src/main/kotlin/gg/skytils/skytilsmod/Skytils.kt +++ b/src/main/kotlin/gg/skytils/skytilsmod/Skytils.kt @@ -368,6 +368,7 @@ class Skytils { cch.registerCommand(FragBotCommand) cch.registerCommand(HollowWaypointCommand) cch.registerCommand(LimboCommand) + cch.registerCommand(OrderedWaypointCommand) cch.registerCommand(ScamCheckCommand) cch.registerCommand(SlayerCommand) diff --git a/src/main/kotlin/gg/skytils/skytilsmod/commands/impl/OrderedWaypointCommand.kt b/src/main/kotlin/gg/skytils/skytilsmod/commands/impl/OrderedWaypointCommand.kt new file mode 100644 index 000000000..3cb2e3e95 --- /dev/null +++ b/src/main/kotlin/gg/skytils/skytilsmod/commands/impl/OrderedWaypointCommand.kt @@ -0,0 +1,103 @@ +/* + * Skytils - Hypixel Skyblock Quality of Life Mod + * Copyright (C) 2020-2023 Skytils + * + * 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 gg.skytils.skytilsmod.commands.impl + +import gg.essential.universal.UChat +import gg.essential.universal.utils.MCClickEventAction +import gg.essential.universal.wrappers.message.UMessage +import gg.essential.universal.wrappers.message.UTextComponent +import gg.skytils.skytilsmod.Skytils +import gg.skytils.skytilsmod.commands.BaseCommand +import gg.skytils.skytilsmod.features.impl.handlers.Waypoint +import gg.skytils.skytilsmod.features.impl.handlers.WaypointCategory +import gg.skytils.skytilsmod.features.impl.handlers.Waypoints +import gg.skytils.skytilsmod.utils.SBInfo +import gg.skytils.skytilsmod.utils.SkyblockIsland +import gg.skytils.skytilsmod.utils.Utils +import net.minecraft.client.entity.EntityPlayerSP +import net.minecraft.command.WrongUsageException +import kotlin.random.Random + +object OrderedWaypointCommand : BaseCommand("skytilsorderedwaypoint") { + private val lineId = Random.nextInt() + private var categoryCache = emptyList() + var trackedIsland: SkyblockIsland? = null + var trackedSet: MutableList? = null + + private val categoryComparator: Comparator = Comparator.comparing { + it.name ?: "" + }.thenBy { + it.isExpanded + }.thenBy { + it.waypoints.size + } + + override fun getCommandUsage(player: EntityPlayerSP): String = + "/${commandName}" + + override fun processCommand(player: EntityPlayerSP, args: Array) { + if (!Utils.inSkyblock) throw WrongUsageException("You must be in Skyblock to use this command!") + if (args.isEmpty()) { + val isUnknownIsland = SkyblockIsland.entries.none { it.mode == SBInfo.mode } + categoryCache = Waypoints.categories.filter { + it.island.mode == SBInfo.mode || (isUnknownIsland && it.island == SkyblockIsland.Unknown) + }.sortedWith(categoryComparator) + } + val subcommand = args.getOrNull(0) + if (subcommand == null || subcommand == "selectmenu") { + val startIndex = args.getOrNull(1)?.toIntOrNull() ?: 0 + val toIndex = startIndex + 10.coerceAtMost(categoryCache.size) + val list = categoryCache.subList(startIndex, toIndex) + UMessage("${Skytils.prefix} §bSelect a Waypoint Category!").apply { + chatLineId = lineId + list.withIndex().forEach { (i, c) -> + addTextComponent(UTextComponent("\n§a${c.name}§7 (${c.waypoints.size})").setClick(MCClickEventAction.RUN_COMMAND, "/${commandName} select ${i + startIndex}")) + } + if (startIndex >= 10) { + addTextComponent(UTextComponent("\n§7[§aPrevious§7]").setClick(MCClickEventAction.RUN_COMMAND, "/${commandName} selectmenu ${startIndex - 10}")) + } + if (toIndex < categoryCache.size) { + addTextComponent(UTextComponent("\n§7[§aNext§7]").setClick(MCClickEventAction.RUN_COMMAND, "/${commandName} selectmenu $toIndex")) + } + }.chat() + } else if (subcommand == "select") { + val category = categoryCache.getOrNull(args.getOrNull(1)?.toIntOrNull() ?: 0) + ?: throw WrongUsageException("Invalid category!") + UMessage("${Skytils.successPrefix} §aSelected category §b${category.name}§a!\n" + + "§b§lNote: this is a BETA feature!\n" + + "§bReport bugs on Discord!\n" + + "§bUpdates to waypoints will not be reflected." + ).apply { + chatLineId = lineId + }.chat() + trackedSet = category.waypoints.sortedBy { it.name }.toMutableList() + trackedIsland = category.island + } else if (subcommand == "stop") { + trackedSet = null + trackedIsland = null + UChat.chat("${Skytils.successPrefix} §aStopped tracking waypoints!") + } + } + + fun doneTracking() { + trackedSet = null + trackedIsland = null + UChat.chat("${Skytils.successPrefix} §aDone tracking waypoints!") + } +} \ No newline at end of file diff --git a/src/main/kotlin/gg/skytils/skytilsmod/features/impl/handlers/Waypoints.kt b/src/main/kotlin/gg/skytils/skytilsmod/features/impl/handlers/Waypoints.kt index 30d6d9261..3776ad5db 100644 --- a/src/main/kotlin/gg/skytils/skytilsmod/features/impl/handlers/Waypoints.kt +++ b/src/main/kotlin/gg/skytils/skytilsmod/features/impl/handlers/Waypoints.kt @@ -21,6 +21,7 @@ import gg.essential.elementa.utils.withAlpha import gg.essential.universal.UGraphics import gg.essential.universal.UMatrixStack import gg.skytils.skytilsmod.Skytils +import gg.skytils.skytilsmod.commands.impl.OrderedWaypointCommand import gg.skytils.skytilsmod.core.PersistentSave import gg.skytils.skytilsmod.core.tickTimer import gg.skytils.skytilsmod.events.impl.skyblock.LocrawReceivedEvent @@ -31,6 +32,8 @@ import net.minecraft.util.BlockPos import net.minecraftforge.client.event.RenderWorldLastEvent import net.minecraftforge.event.world.WorldEvent import net.minecraftforge.fml.common.eventhandler.SubscribeEvent +import net.minecraftforge.fml.common.gameevent.TickEvent +import net.minecraftforge.fml.common.gameevent.TickEvent.ClientTickEvent import org.apache.commons.codec.binary.Base64 import org.apache.commons.codec.binary.Base64InputStream import org.apache.commons.compress.compressors.gzip.GzipCompressorInputStream @@ -38,6 +41,7 @@ import java.awt.Color import java.io.File import java.io.Reader import java.io.Writer +import java.util.TreeSet object Waypoints : PersistentSave(File(Skytils.modDir, "waypoints.json")) { val categories = HashSet() @@ -142,9 +146,25 @@ object Waypoints : PersistentSave(File(Skytils.modDir, "waypoints.json")) { tickTimer(20, task = ::computeVisibleWaypoints) } + @SubscribeEvent + fun onPlayerMove(event: ClientTickEvent) { + if (event.phase == TickEvent.Phase.END || mc.thePlayer?.hasMoved != true) return + if (SBInfo.mode != null && OrderedWaypointCommand.trackedIsland?.mode == SBInfo.mode) { + val tracked = OrderedWaypointCommand.trackedSet?.firstOrNull() + if (tracked == null) { + OrderedWaypointCommand.doneTracking() + } else if (tracked.pos.distanceSq(mc.thePlayer.position) < 2 * 2) { + OrderedWaypointCommand.trackedSet?.removeFirstOrNull() + } + } + } + @SubscribeEvent fun onWorldRender(event: RenderWorldLastEvent) { val matrixStack = UMatrixStack() + if (OrderedWaypointCommand.trackedIsland?.mode == SBInfo.mode) { + OrderedWaypointCommand.trackedSet?.firstOrNull()?.draw(event.partialTicks, matrixStack) + } visibleWaypoints.forEach { it.draw(event.partialTicks, matrixStack) } @@ -205,7 +225,6 @@ data class WaypointCategory( @Serializable(with = SkyblockIsland.ModeSerializer::class) var island: SkyblockIsland ) - @Serializable data class Waypoint @OptIn(ExperimentalSerializationApi::class) constructor( var name: String,