From 2698f4f8d7615f3d8354bd019ac99f8f50f5db17 Mon Sep 17 00:00:00 2001 From: "nightowl.dev" Date: Sat, 7 Feb 2026 12:04:15 +0100 Subject: [PATCH 1/3] minor changes --- .../cobalt/api/rotation/RotationExecutor.kt | 26 ++++++++++++++++--- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/src/main/kotlin/org/cobalt/api/rotation/RotationExecutor.kt b/src/main/kotlin/org/cobalt/api/rotation/RotationExecutor.kt index 57bda1b..c9ae4d2 100644 --- a/src/main/kotlin/org/cobalt/api/rotation/RotationExecutor.kt +++ b/src/main/kotlin/org/cobalt/api/rotation/RotationExecutor.kt @@ -18,11 +18,27 @@ object RotationExecutor { private var currStrat: IRotationStrategy? = null private var isRotating: Boolean = false - fun rotateTo( - endRot: Rotation, - strategy: IRotationStrategy, - ) { + private var onFinish: (() -> Unit)? = null + +fun rotateTo( + endRot: Rotation, + strategy: IRotationStrategy, + onFinish: () -> Unit = {}, +) { stopRotating() + //if yaw same and pitch same dont rotate :v: + if (AngleUtils.getRotationDelta( + mc.player!!.yRot, + endRot.yaw + ) == 0f && AngleUtils.getRotationDelta( + mc.player!!.xRot, + endRot.pitch + ) == 0f + ) { + onFinish?.invoke() + return + } + this.onFinish = onFinish targetYaw = endRot.yaw targetPitch = endRot.pitch @@ -36,6 +52,8 @@ object RotationExecutor { currStrat?.onStop() currStrat = null isRotating = false + onFinish?.invoke() + onFinish = null } fun isRotating(): Boolean { From 95d820c3f9e4fd25d8cd3deacfecb02bd157bec5 Mon Sep 17 00:00:00 2001 From: "nightowl.dev" Date: Wed, 4 Mar 2026 19:41:12 +0100 Subject: [PATCH 2/3] feat: progress bar system --- src/main/kotlin/org/cobalt/Cobalt.kt | 3 +- .../api/module/setting/impl/InfoSetting.kt | 2 +- .../org/cobalt/api/progress/ProgressAPI.kt | 16 ++ .../org/cobalt/api/progress/ProgressHandle.kt | 28 ++++ .../org/cobalt/api/util/ui/NVGRenderer.kt | 18 ++ .../cobalt/internal/command/MainCommand.kt | 71 ++++++++ .../internal/ui/progress/ProgressManager.kt | 112 +++++++++++++ .../internal/ui/progress/ProgressPosition.kt | 7 + .../cobalt/internal/ui/progress/UIProgress.kt | 154 ++++++++++++++++++ 9 files changed, 409 insertions(+), 2 deletions(-) create mode 100644 src/main/kotlin/org/cobalt/api/progress/ProgressAPI.kt create mode 100644 src/main/kotlin/org/cobalt/api/progress/ProgressHandle.kt create mode 100644 src/main/kotlin/org/cobalt/internal/ui/progress/ProgressManager.kt create mode 100644 src/main/kotlin/org/cobalt/internal/ui/progress/ProgressPosition.kt create mode 100644 src/main/kotlin/org/cobalt/internal/ui/progress/UIProgress.kt diff --git a/src/main/kotlin/org/cobalt/Cobalt.kt b/src/main/kotlin/org/cobalt/Cobalt.kt index fde274b..2181aaf 100644 --- a/src/main/kotlin/org/cobalt/Cobalt.kt +++ b/src/main/kotlin/org/cobalt/Cobalt.kt @@ -10,6 +10,7 @@ import org.cobalt.api.util.TickScheduler import org.cobalt.internal.command.MainCommand import org.cobalt.internal.helper.Config import org.cobalt.internal.loader.AddonLoader +import org.cobalt.internal.ui.progress.ProgressManager @Suppress("UNUSED") object Cobalt : ClientModInitializer { @@ -24,7 +25,7 @@ object Cobalt : ClientModInitializer { CommandManager.dispatchAll() listOf( - TickScheduler, MainCommand, NotificationManager, + TickScheduler, MainCommand, NotificationManager, ProgressManager, RotationExecutor, ).forEach { EventBus.register(it) } diff --git a/src/main/kotlin/org/cobalt/api/module/setting/impl/InfoSetting.kt b/src/main/kotlin/org/cobalt/api/module/setting/impl/InfoSetting.kt index 55fa9c7..f1948df 100644 --- a/src/main/kotlin/org/cobalt/api/module/setting/impl/InfoSetting.kt +++ b/src/main/kotlin/org/cobalt/api/module/setting/impl/InfoSetting.kt @@ -8,7 +8,7 @@ enum class InfoType { INFO, WARNING, SUCCESS, ERROR } -internal class InfoSetting( +class InfoSetting( name: String?, val text: String, val type: InfoType = InfoType.INFO, diff --git a/src/main/kotlin/org/cobalt/api/progress/ProgressAPI.kt b/src/main/kotlin/org/cobalt/api/progress/ProgressAPI.kt new file mode 100644 index 0000000..2f432b9 --- /dev/null +++ b/src/main/kotlin/org/cobalt/api/progress/ProgressAPI.kt @@ -0,0 +1,16 @@ +package org.cobalt.api.progress + +import org.cobalt.api.util.ui.helper.Image +import org.cobalt.internal.ui.progress.ProgressPosition + +interface ProgressAPI { + + fun showProgress(progress: Int, color: Int, icon: Image? = null, position: ProgressPosition = ProgressPosition.TOP_CENTER): ProgressHandle + fun updateProgress(handle: String, progress: Int) + fun incrementProgress(handle: String, amount: Int) + fun decrementProgress(handle: String, amount: Int) + fun updateColor(handle: String, color: Int) + fun removeProgress(handle: String) + fun clear() + +} diff --git a/src/main/kotlin/org/cobalt/api/progress/ProgressHandle.kt b/src/main/kotlin/org/cobalt/api/progress/ProgressHandle.kt new file mode 100644 index 0000000..0e66c2a --- /dev/null +++ b/src/main/kotlin/org/cobalt/api/progress/ProgressHandle.kt @@ -0,0 +1,28 @@ +package org.cobalt.api.progress + +import org.cobalt.api.util.ui.helper.Image +import org.cobalt.internal.ui.progress.ProgressManager + +class ProgressHandle(private val manager: ProgressManager, private val internalHandle: String) { + + fun setProgress(progress: Int) { + manager.updateProgress(internalHandle, progress) + } + + fun increment(amount: Int = 1) { + manager.incrementProgress(internalHandle, amount) + } + + fun decrement(amount: Int = 1) { + manager.decrementProgress(internalHandle, amount) + } + + fun updateColor(newColor: Int) { + manager.updateColor(internalHandle, newColor) + } + + fun hide() { + manager.removeProgress(internalHandle) + } + +} diff --git a/src/main/kotlin/org/cobalt/api/util/ui/NVGRenderer.kt b/src/main/kotlin/org/cobalt/api/util/ui/NVGRenderer.kt index 10c5b7c..d3e7812 100644 --- a/src/main/kotlin/org/cobalt/api/util/ui/NVGRenderer.kt +++ b/src/main/kotlin/org/cobalt/api/util/ui/NVGRenderer.kt @@ -442,6 +442,24 @@ object NVGRenderer { }.id } + private var blurStrength: Float = 0f + + @JvmStatic + fun gaussianBlur(strength: Float) { + + blurStrength = strength.coerceIn(0f, 1f) + } + + fun enableBlur(f: Float) { + gaussianBlur(f) + } + + fun disableBlur() { + gaussianBlur(0f) + } + + internal fun getBlurStrength(): Float = blurStrength + private class Scissor(val previous: Scissor?, val x: Float, val y: Float, val maxX: Float, val maxY: Float) { fun applyScissor() { if (previous == null) nvgScissor(vg, x, y, maxX - x, maxY - y) diff --git a/src/main/kotlin/org/cobalt/internal/command/MainCommand.kt b/src/main/kotlin/org/cobalt/internal/command/MainCommand.kt index fe40a3c..d53f745 100644 --- a/src/main/kotlin/org/cobalt/internal/command/MainCommand.kt +++ b/src/main/kotlin/org/cobalt/internal/command/MainCommand.kt @@ -1,19 +1,27 @@ package org.cobalt.internal.command +import java.awt.Color import kotlin.random.Random import org.cobalt.api.command.Command import org.cobalt.api.command.annotation.DefaultHandler import org.cobalt.api.command.annotation.SubCommand import org.cobalt.api.notification.NotificationManager import org.cobalt.api.pathfinder.PathExecutor +import org.cobalt.api.progress.ProgressHandle import org.cobalt.api.rotation.EasingType import org.cobalt.api.rotation.RotationExecutor import org.cobalt.api.rotation.strategy.TimedEaseStrategy import org.cobalt.api.util.helper.Rotation +import org.cobalt.api.util.ui.NVGRenderer +import org.cobalt.api.util.ui.helper.Image +import org.cobalt.internal.ui.progress.ProgressManager +import org.cobalt.internal.ui.progress.ProgressPosition import org.cobalt.internal.ui.screen.UIConfig internal object MainCommand : Command(name = "cobalt", aliases = arrayOf("cb")) { + private var autoProgressHandles = mutableListOf() + @DefaultHandler fun main() { UIConfig.openUI() @@ -60,4 +68,67 @@ internal object MainCommand : Command(name = "cobalt", aliases = arrayOf("cb")) fun notification(title: String, description: String) { NotificationManager.sendNotification(title, description) } + + @SubCommand + fun progress(progress: Int) { + val image = NVGRenderer.createImage("/assets/cobalt/steve.png") + ProgressManager.showProgress(progress, Color(33, 150, 243).rgb, icon = image, position = ProgressPosition.CENTER) + } + + @SubCommand + fun increment(amount: Int = 1) { + if (autoProgressHandles.isEmpty()) { + NotificationManager.sendNotification("Progress", "No auto progress bars") + return + } + autoProgressHandles.forEach { it.increment(amount) } + } + + @SubCommand + fun decrement(amount: Int = 1) { + if (autoProgressHandles.isEmpty()) { + NotificationManager.sendNotification("Progress", "No auto progress bars") + return + } + autoProgressHandles.forEach { it.decrement(amount) } + } + + @SubCommand + fun progressauto(count: Int = 3) { + ProgressManager.clear() + autoProgressHandles.clear() + + val colors = listOf( + Color(244, 67, 54).rgb, + Color(33, 150, 243).rgb, + Color(76, 175, 80).rgb, + Color(255, 193, 7).rgb, + Color(156, 39, 176).rgb, + ) + + val positions = listOf( + ProgressPosition.TOP_LEFT, ProgressPosition.TOP_CENTER, ProgressPosition.TOP_RIGHT, + ProgressPosition.CENTER_LEFT, ProgressPosition.CENTER, ProgressPosition.CENTER_RIGHT, + ProgressPosition.BOTTOM_LEFT, ProgressPosition.BOTTOM_CENTER, ProgressPosition.BOTTOM_RIGHT, + ) + + repeat(count) { index -> + val image = NVGRenderer.createImage("/assets/cobalt/steve.png") + val handle = ProgressManager.showProgress( + progress = 0, + color = colors[index % colors.size], + icon = image, + position = positions[index % positions.size] + ) + autoProgressHandles.add(handle) + } + } + + @SubCommand + fun progresshide() { + ProgressManager.clear() + autoProgressHandles.clear() + NotificationManager.sendNotification("Progress", "All hidden") + } + } diff --git a/src/main/kotlin/org/cobalt/internal/ui/progress/ProgressManager.kt b/src/main/kotlin/org/cobalt/internal/ui/progress/ProgressManager.kt new file mode 100644 index 0000000..9c2af8a --- /dev/null +++ b/src/main/kotlin/org/cobalt/internal/ui/progress/ProgressManager.kt @@ -0,0 +1,112 @@ +package org.cobalt.internal.ui.progress + +import java.util.UUID +import net.minecraft.client.Minecraft +import net.minecraft.client.gui.screens.ChatScreen +import org.cobalt.api.event.annotation.SubscribeEvent +import org.cobalt.api.event.impl.render.NvgEvent +import org.cobalt.api.progress.ProgressAPI +import org.cobalt.api.progress.ProgressHandle +import org.cobalt.api.util.ui.NVGRenderer +import org.cobalt.api.util.ui.helper.Image + +object ProgressManager : ProgressAPI { + + private val mc: Minecraft = Minecraft.getInstance() + private val progressBars = mutableMapOf() + private const val GAP = 5F + private const val MARGIN = 15F + + override fun showProgress(progress: Int, color: Int, icon: Image?, position: ProgressPosition): ProgressHandle { + val handle = UUID.randomUUID().toString() + progressBars[handle] = UIProgress(handle, progress.coerceIn(0, 100), color, icon, position) + return ProgressHandle(this, handle) + } + + override fun updateProgress(handle: String, progress: Int) { + progressBars[handle]?.updateProgress(progress) + } + + override fun incrementProgress(handle: String, amount: Int) { + progressBars[handle]?.incrementProgress(amount) + } + + override fun decrementProgress(handle: String, amount: Int) { + progressBars[handle]?.decrementProgress(amount) + } + + override fun updateColor(handle: String, color: Int) { + progressBars[handle]?.updateColor(color) + } + + override fun removeProgress(handle: String) { + progressBars[handle]?.startClosing() + } + + override fun clear() { + progressBars.values.forEach { it.startClosing() } + } + + @Suppress("unused") + @SubscribeEvent + fun onRender(event: NvgEvent) { + val window = mc.window + val screenWidth = window.screenWidth.toFloat() + val screenHeight = window.screenHeight.toFloat() + + NVGRenderer.beginFrame(screenWidth, screenHeight) + + val toRemove = mutableListOf() + val shouldRender = if (mc.screen != null) { + mc.screen is ChatScreen + } else { + true + } + if (shouldRender) { + val grouped = progressBars.entries + .filter { !it.value.shouldRemove() } + .groupBy { it.value.position } + + grouped.forEach { (position, barEntries) -> + renderPositionBars(position, barEntries.map { it.value }, screenWidth, screenHeight) + } + } + + progressBars.forEach { (handle, progress) -> + if (progress.shouldRemove()) { + toRemove.add(handle) + } + } + + progressBars.keys.removeAll(toRemove) + NVGRenderer.endFrame() + } + + private fun renderPositionBars(position: ProgressPosition, bars: List, screenWidth: Float, screenHeight: Float) { + var yOffset = 0F + + bars.forEach { bar -> + val (x, y) = calculatePosition(position, bar, screenWidth, screenHeight, yOffset) + bar.updateBounds(x, y) + bar.render() + yOffset += bar.height + GAP + } + } + + private fun calculatePosition(position: ProgressPosition, bar: UIProgress, screenWidth: Float, screenHeight: Float, offset: Float): Pair { + return when (position) { + ProgressPosition.TOP_LEFT -> Pair(MARGIN, MARGIN + offset) + ProgressPosition.TOP_CENTER -> Pair((screenWidth - bar.width) / 2, MARGIN + offset) + ProgressPosition.TOP_RIGHT -> Pair(screenWidth - bar.width - MARGIN, MARGIN + offset) + + ProgressPosition.CENTER_LEFT -> Pair(MARGIN, (screenHeight - bar.height) / 2 + offset) + ProgressPosition.CENTER -> Pair((screenWidth - bar.width) / 2, (screenHeight - bar.height) / 2 + offset) + ProgressPosition.CENTER_RIGHT -> Pair(screenWidth - bar.width - MARGIN, (screenHeight - bar.height) / 2 + offset) + + ProgressPosition.BOTTOM_LEFT -> Pair(MARGIN, screenHeight - bar.height - MARGIN - offset) + ProgressPosition.BOTTOM_CENTER -> Pair((screenWidth - bar.width) / 2, screenHeight - bar.height - MARGIN - offset) + ProgressPosition.BOTTOM_RIGHT -> Pair(screenWidth - bar.width - MARGIN, screenHeight - bar.height - MARGIN - offset) + } + } + +} diff --git a/src/main/kotlin/org/cobalt/internal/ui/progress/ProgressPosition.kt b/src/main/kotlin/org/cobalt/internal/ui/progress/ProgressPosition.kt new file mode 100644 index 0000000..ffe1316 --- /dev/null +++ b/src/main/kotlin/org/cobalt/internal/ui/progress/ProgressPosition.kt @@ -0,0 +1,7 @@ +package org.cobalt.internal.ui.progress + +enum class ProgressPosition { + TOP_LEFT, TOP_CENTER, TOP_RIGHT, + CENTER_LEFT, CENTER, CENTER_RIGHT, + BOTTOM_LEFT, BOTTOM_CENTER, BOTTOM_RIGHT +} diff --git a/src/main/kotlin/org/cobalt/internal/ui/progress/UIProgress.kt b/src/main/kotlin/org/cobalt/internal/ui/progress/UIProgress.kt new file mode 100644 index 0000000..0e22516 --- /dev/null +++ b/src/main/kotlin/org/cobalt/internal/ui/progress/UIProgress.kt @@ -0,0 +1,154 @@ +package org.cobalt.internal.ui.progress + +import java.awt.Color +import org.cobalt.api.util.ui.NVGRenderer +import org.cobalt.api.util.ui.helper.Image +import org.cobalt.internal.ui.UIComponent +import org.cobalt.internal.ui.animation.EaseOutAnimation + +internal class UIProgress( + private val handle: String, + private var progress: Int, + private var color: Int, + private val icon: Image? = null, + val position: ProgressPosition = ProgressPosition.TOP_CENTER, +) : UIComponent( + x = 0F, + y = 0F, + width = 340F, + height = 35F +) { + + private var createdAt = System.currentTimeMillis() + private var completedAt: Long? = null + private val slideAnim = EaseOutAnimation(150L) + private val progressAnim = EaseOutAnimation(300L) + private var isClosing = false + private val barWidth = 250F + private val barHeight = 8F + private val containerPadding = 12F + private val iconSize = 24F + private val iconMargin = 10F + private var displayProgress = 0 + private var animationProgress = 0F + + init { + slideAnim.start() + } + + fun updateProgress(newProgress: Int) { + val capped = newProgress.coerceIn(0, 100) + displayProgress = progress + this.progress = capped + progressAnim.start() + if (capped >= 100) { + completedAt = System.currentTimeMillis() + } + } + + fun incrementProgress(amount: Int) { + val newVal = (progress + amount).coerceIn(0, 100) + displayProgress = progress + this.progress = newVal + progressAnim.start() + if (newVal >= 100) { + completedAt = System.currentTimeMillis() + } + } + + fun decrementProgress(amount: Int) { + this.progress = (progress - amount).coerceIn(0, 100) + } + + fun updateColor(newColor: Int) { + this.color = newColor + } + + fun startClosing() { + if (!isClosing) { + isClosing = true + slideAnim.start() + } + } + + fun shouldRemove(): Boolean { + if (completedAt != null) { + val elapsed = System.currentTimeMillis() - completedAt!! + if (elapsed > 1500L) { + if (!isClosing) { + isClosing = true + slideAnim.start() + } + } + } + + val elapsed = System.currentTimeMillis() - createdAt + return elapsed > 150L && isClosing && !slideAnim.isAnimating() + } + + private fun getOffsetX(): Float { + return if (isClosing) { + slideAnim.get(0F, width) + } else { + width - slideAnim.get(0F, width) + } + } + + fun getHandle(): String = handle + + override fun render() { + val offsetX = getOffsetX() + val finalX = x + offsetX + + val containerX = finalX + containerPadding + val containerY = y + (height - barHeight) / 2 + val containerWidth = iconSize + iconMargin + barWidth + containerPadding * 2 + val containerHeight = barHeight + containerPadding * 2 + + NVGRenderer.enableBlur(5F) + NVGRenderer.rect( + containerX - containerPadding, + containerY - containerPadding, + containerWidth, + containerHeight, + Color(40, 40, 40, 140).rgb, + 12F + ) + + NVGRenderer.disableBlur() + + if (icon != null) { + NVGRenderer.image( + icon, + containerX + iconMargin / 2 - 4F, + containerY + (containerHeight - iconSize) / 2 - 12F, + iconSize, + iconSize + ) + } + + val barX = containerX + iconSize + iconMargin + NVGRenderer.rect( + barX, + containerY, + barWidth, + barHeight, + Color(30, 30, 30, 120).rgb, + 4F + ) + + val animatedProgress = progressAnim.get(displayProgress.toFloat(), progress.toFloat(), false).toInt() + val filledWidth = (barWidth * animatedProgress.coerceAtMost(100)) / 100F + if (filledWidth > 0F) { + NVGRenderer.rect( + barX, + containerY, + filledWidth, + barHeight, + color, + 4F + ) + } + } + +} From 6bb50e6c4b5b240f83413e363c1d896176f01876 Mon Sep 17 00:00:00 2001 From: "nightowl.dev" Date: Wed, 4 Mar 2026 19:47:45 +0100 Subject: [PATCH 3/3] chore: cleanup code --- .../kotlin/org/cobalt/api/pathfinder/Node.kt | 50 --- .../org/cobalt/api/pathfinder/PathExecutor.kt | 178 ----------- .../pathfinder/pathfinder/AStarPathfinder.kt | 178 ----------- .../pathfinder/AbstractPathfinder.kt | 293 ------------------ .../pathfinder/heap/PrimitiveMinHeap.kt | 141 --------- .../processing/EvaluationContextImpl.kt | 52 ---- .../processing/SearchContextImpl.kt | 19 -- .../pathfinder/pathing/INeighborStrategy.kt | 13 - .../pathfinder/pathing/NeighborStrategies.kt | 49 --- .../api/pathfinder/pathing/Pathfinder.kt | 22 -- .../pathfinder/pathing/PathfindingProgress.kt | 9 - .../configuration/PathfinderConfiguration.kt | 51 --- .../pathing/context/EnvironmentContext.kt | 3 - .../pathing/heuristic/HeuristicContext.kt | 27 -- .../pathing/heuristic/HeuristicWeights.kt | 14 - .../pathing/heuristic/IHeuristicStrategy.kt | 10 - .../heuristic/InternalHeuristicUtils.kt | 51 --- .../heuristic/LinearHeuristicStrategy.kt | 54 ---- .../heuristic/SquaredHeuristicStrategy.kt | 55 ---- .../api/pathfinder/pathing/processing/Cost.kt | 15 - .../pathing/processing/NodeProcessor.kt | 10 - .../pathing/processing/Processor.kt | 12 - .../processing/context/EvaluationContext.kt | 37 --- .../processing/context/SearchContext.kt | 17 - .../processing/impl/MinecraftPathProcessor.kt | 122 -------- .../api/pathfinder/pathing/result/Path.kt | 12 - .../pathfinder/pathing/result/PathState.kt | 10 - .../pathing/result/PathfinderResult.kt | 11 - .../pathfinder/provider/NavigationPoint.kt | 9 - .../provider/NavigationPointProvider.kt | 14 - .../impl/MinecraftNavigationProvider.kt | 142 --------- .../cobalt/api/pathfinder/result/PathImpl.kt | 18 -- .../pathfinder/result/PathfinderResultImpl.kt | 28 -- .../cobalt/api/pathfinder/util/RegionKey.kt | 20 -- .../api/pathfinder/wrapper/PathPosition.kt | 70 ----- .../api/pathfinder/wrapper/PathVector.kt | 29 -- .../cobalt/internal/command/MainCommand.kt | 9 - 37 files changed, 1854 deletions(-) delete mode 100644 src/main/kotlin/org/cobalt/api/pathfinder/Node.kt delete mode 100644 src/main/kotlin/org/cobalt/api/pathfinder/PathExecutor.kt delete mode 100644 src/main/kotlin/org/cobalt/api/pathfinder/pathfinder/AStarPathfinder.kt delete mode 100644 src/main/kotlin/org/cobalt/api/pathfinder/pathfinder/AbstractPathfinder.kt delete mode 100644 src/main/kotlin/org/cobalt/api/pathfinder/pathfinder/heap/PrimitiveMinHeap.kt delete mode 100644 src/main/kotlin/org/cobalt/api/pathfinder/pathfinder/processing/EvaluationContextImpl.kt delete mode 100644 src/main/kotlin/org/cobalt/api/pathfinder/pathfinder/processing/SearchContextImpl.kt delete mode 100644 src/main/kotlin/org/cobalt/api/pathfinder/pathing/INeighborStrategy.kt delete mode 100644 src/main/kotlin/org/cobalt/api/pathfinder/pathing/NeighborStrategies.kt delete mode 100644 src/main/kotlin/org/cobalt/api/pathfinder/pathing/Pathfinder.kt delete mode 100644 src/main/kotlin/org/cobalt/api/pathfinder/pathing/PathfindingProgress.kt delete mode 100644 src/main/kotlin/org/cobalt/api/pathfinder/pathing/configuration/PathfinderConfiguration.kt delete mode 100644 src/main/kotlin/org/cobalt/api/pathfinder/pathing/context/EnvironmentContext.kt delete mode 100644 src/main/kotlin/org/cobalt/api/pathfinder/pathing/heuristic/HeuristicContext.kt delete mode 100644 src/main/kotlin/org/cobalt/api/pathfinder/pathing/heuristic/HeuristicWeights.kt delete mode 100644 src/main/kotlin/org/cobalt/api/pathfinder/pathing/heuristic/IHeuristicStrategy.kt delete mode 100644 src/main/kotlin/org/cobalt/api/pathfinder/pathing/heuristic/InternalHeuristicUtils.kt delete mode 100644 src/main/kotlin/org/cobalt/api/pathfinder/pathing/heuristic/LinearHeuristicStrategy.kt delete mode 100644 src/main/kotlin/org/cobalt/api/pathfinder/pathing/heuristic/SquaredHeuristicStrategy.kt delete mode 100644 src/main/kotlin/org/cobalt/api/pathfinder/pathing/processing/Cost.kt delete mode 100644 src/main/kotlin/org/cobalt/api/pathfinder/pathing/processing/NodeProcessor.kt delete mode 100644 src/main/kotlin/org/cobalt/api/pathfinder/pathing/processing/Processor.kt delete mode 100644 src/main/kotlin/org/cobalt/api/pathfinder/pathing/processing/context/EvaluationContext.kt delete mode 100644 src/main/kotlin/org/cobalt/api/pathfinder/pathing/processing/context/SearchContext.kt delete mode 100644 src/main/kotlin/org/cobalt/api/pathfinder/pathing/processing/impl/MinecraftPathProcessor.kt delete mode 100644 src/main/kotlin/org/cobalt/api/pathfinder/pathing/result/Path.kt delete mode 100644 src/main/kotlin/org/cobalt/api/pathfinder/pathing/result/PathState.kt delete mode 100644 src/main/kotlin/org/cobalt/api/pathfinder/pathing/result/PathfinderResult.kt delete mode 100644 src/main/kotlin/org/cobalt/api/pathfinder/provider/NavigationPoint.kt delete mode 100644 src/main/kotlin/org/cobalt/api/pathfinder/provider/NavigationPointProvider.kt delete mode 100644 src/main/kotlin/org/cobalt/api/pathfinder/provider/impl/MinecraftNavigationProvider.kt delete mode 100644 src/main/kotlin/org/cobalt/api/pathfinder/result/PathImpl.kt delete mode 100644 src/main/kotlin/org/cobalt/api/pathfinder/result/PathfinderResultImpl.kt delete mode 100644 src/main/kotlin/org/cobalt/api/pathfinder/util/RegionKey.kt delete mode 100644 src/main/kotlin/org/cobalt/api/pathfinder/wrapper/PathPosition.kt delete mode 100644 src/main/kotlin/org/cobalt/api/pathfinder/wrapper/PathVector.kt diff --git a/src/main/kotlin/org/cobalt/api/pathfinder/Node.kt b/src/main/kotlin/org/cobalt/api/pathfinder/Node.kt deleted file mode 100644 index cdc3b9f..0000000 --- a/src/main/kotlin/org/cobalt/api/pathfinder/Node.kt +++ /dev/null @@ -1,50 +0,0 @@ -package org.cobalt.api.pathfinder - -import org.cobalt.api.pathfinder.pathing.heuristic.HeuristicContext -import org.cobalt.api.pathfinder.pathing.heuristic.HeuristicWeights -import org.cobalt.api.pathfinder.pathing.heuristic.IHeuristicStrategy -import org.cobalt.api.pathfinder.wrapper.PathPosition - -class Node( - val position: PathPosition, - start: PathPosition, - target: PathPosition, - heuristicWeights: HeuristicWeights, - heuristicStrategy: IHeuristicStrategy, - val depth: Int, -) : Comparable { - - val heuristic: Double = - heuristicStrategy.calculate(HeuristicContext(position, start, target, heuristicWeights)) - - var gCost: Double = 0.0 - var parent: Node? = null - - val fCost: Double - get() = gCost + heuristic - - fun isTarget(target: PathPosition): Boolean = position == target - - override fun equals(other: Any?): Boolean { - if (other == null || this::class != other::class) return false - other as Node - return position == other.position - } - - override fun hashCode(): Int = position.hashCode() - - override fun compareTo(other: Node): Int { - val fCostComparison = fCost.compareTo(other.fCost) - if (fCostComparison != 0) { - return fCostComparison - } - - val heuristicComparison = heuristic.compareTo(other.heuristic) - if (heuristicComparison != 0) { - return heuristicComparison - } - - return this.depth.compareTo(other.depth) - } - -} diff --git a/src/main/kotlin/org/cobalt/api/pathfinder/PathExecutor.kt b/src/main/kotlin/org/cobalt/api/pathfinder/PathExecutor.kt deleted file mode 100644 index f8a4f5b..0000000 --- a/src/main/kotlin/org/cobalt/api/pathfinder/PathExecutor.kt +++ /dev/null @@ -1,178 +0,0 @@ -package org.cobalt.api.pathfinder - -import java.awt.Color -import net.minecraft.client.Minecraft -import net.minecraft.world.phys.AABB -import net.minecraft.world.phys.Vec3 -import org.cobalt.api.event.EventBus -import org.cobalt.api.event.annotation.SubscribeEvent -import org.cobalt.api.event.impl.client.TickEvent -import org.cobalt.api.event.impl.render.WorldRenderEvent -import org.cobalt.api.pathfinder.pathfinder.AStarPathfinder -import org.cobalt.api.pathfinder.pathing.NeighborStrategies -import org.cobalt.api.pathfinder.pathing.configuration.PathfinderConfiguration -import org.cobalt.api.pathfinder.pathing.processing.impl.MinecraftPathProcessor -import org.cobalt.api.pathfinder.pathing.result.Path -import org.cobalt.api.pathfinder.pathing.result.PathState -import org.cobalt.api.pathfinder.provider.impl.MinecraftNavigationProvider -import org.cobalt.api.pathfinder.result.PathImpl -import org.cobalt.api.pathfinder.wrapper.PathPosition -import org.cobalt.api.util.ChatUtils -import org.cobalt.api.util.render.Render3D - -/* - * TODO: im lazy right now, but chunk and world caching would be alot better, - * if someone could help me do this it would be a great help :)) - */ -object PathExecutor { - - private val mc: Minecraft = Minecraft.getInstance() - private var currentPath: Path? = null - private var currentWaypointIndex: Int = 0 - - init { - EventBus.register(this) - } - - fun start(x: Double, y: Double, z: Double) { - val player = mc.player ?: return - val start = PathPosition(player.x, player.y, player.z) - val target = PathPosition(x, y, z) - - val processor = MinecraftPathProcessor() - val config = - PathfinderConfiguration( - provider = MinecraftNavigationProvider(), - // as of now max iterations is 20,000 but maybe wanna higher - maxIterations = 20000, - async = true, - neighborStrategy = NeighborStrategies.HORIZONTAL_DIAGONAL_AND_VERTICAL, - processors = listOf(processor) - ) - - val pathfinder = AStarPathfinder(config) - - ChatUtils.sendDebug("Calculating path to $x, $y, $z...") - val startTime = System.currentTimeMillis() - pathfinder.findPath(start, target).thenAccept { result -> - mc.execute { - val duration = System.currentTimeMillis() - startTime - val state = result.getPathState() - if (state != PathState.FOUND) { - ChatUtils.sendMessage("§cFailed to find path: $state") - return@execute - } - - val rawPath = result.getPath() - val positions = rawPath.collect().toList() - val path = - if (positions.size <= 2) { - rawPath - } else { - val simplified = ArrayList(positions.size) - simplified.add(positions.first()) - - for (i in 1 until positions.size - 1) { - val prev = simplified.last() - val curr = positions[i] - val next = positions[i + 1] - - val prevDx = (curr.flooredX - prev.flooredX).coerceIn(-1, 1) - val prevDy = (curr.flooredY - prev.flooredY).coerceIn(-1, 1) - val prevDz = (curr.flooredZ - prev.flooredZ).coerceIn(-1, 1) - val nextDx = (next.flooredX - curr.flooredX).coerceIn(-1, 1) - val nextDy = (next.flooredY - curr.flooredY).coerceIn(-1, 1) - val nextDz = (next.flooredZ - curr.flooredZ).coerceIn(-1, 1) - - if (prevDx == nextDx && prevDy == nextDy && prevDz == nextDz) { - continue - } - simplified.add(curr) - } - - simplified.add(positions.last()) - PathImpl(rawPath.getStart(), rawPath.getEnd(), simplified) - } - currentPath = path - currentWaypointIndex = 0 - - ChatUtils.sendMessage( - "§aPath found! §7Calculated in §f${duration}ms §8(${path.length()} nodes)" - ) - } - } - } - - fun stop() { - currentPath = null - currentWaypointIndex = 0 - } - - /* - * as of writing this, there is intentionally no moving, rotations, - * or jumping yet. i ask that you make sure that the algo works good - * before implementing them, aswell as rots - */ - @SubscribeEvent - fun onTick(@Suppress("UNUSED_PARAMETER") event: TickEvent.Start) { - val path = currentPath ?: return - val player = mc.player ?: return - - val waypoints = path.collect().toList() - if (currentWaypointIndex >= waypoints.size) { - ChatUtils.sendMessage("Reached the end!") // this is kinda icky, someone change this lol - stop() - return - } - - val targetPos = waypoints[currentWaypointIndex].mid() - val targetVec = Vec3(targetPos.x, targetPos.y, targetPos.z) - - val horizontalDistSq = - (player.x - targetVec.x) * (player.x - targetVec.x) + - (player.z - targetVec.z) * (player.z - targetVec.z) - if (horizontalDistSq < 0.25) { - currentWaypointIndex++ - } - } - - @SubscribeEvent - fun onRender(event: WorldRenderEvent.Last) { - val path = currentPath ?: return - val waypoints = path.collect().toList() - - if (waypoints.size < 2) return - - for (i in 0 until waypoints.size - 1) { - val start = waypoints[i].mid() - val end = waypoints[i + 1].mid() - - Render3D.drawLine( - event.context, - Vec3(start.x, start.y, start.z), - Vec3(end.x, end.y, end.z), - Color.CYAN, - true, - 2.0f - ) - } - - if (currentWaypointIndex < waypoints.size) { - val currentPos = waypoints[currentWaypointIndex].mid() - Render3D.drawBox( - event.context, - AABB( - currentPos.x - 0.25, - currentPos.y - 0.25, - currentPos.z - 0.25, - currentPos.x + 0.25, - currentPos.y + 0.25, - currentPos.z + 0.25 - ), - Color.GREEN, - true - ) - } - } - -} diff --git a/src/main/kotlin/org/cobalt/api/pathfinder/pathfinder/AStarPathfinder.kt b/src/main/kotlin/org/cobalt/api/pathfinder/pathfinder/AStarPathfinder.kt deleted file mode 100644 index cf8b035..0000000 --- a/src/main/kotlin/org/cobalt/api/pathfinder/pathfinder/AStarPathfinder.kt +++ /dev/null @@ -1,178 +0,0 @@ -package org.cobalt.api.pathfinder.pathfinder - -import it.unimi.dsi.fastutil.longs.Long2ObjectMap -import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap -import it.unimi.dsi.fastutil.longs.LongOpenHashSet -import it.unimi.dsi.fastutil.longs.LongSet -import kotlin.math.abs -import kotlin.math.max -import org.cobalt.api.pathfinder.Node -import org.cobalt.api.pathfinder.pathfinder.heap.PrimitiveMinHeap -import org.cobalt.api.pathfinder.pathfinder.processing.EvaluationContextImpl -import org.cobalt.api.pathfinder.pathing.configuration.PathfinderConfiguration -import org.cobalt.api.pathfinder.pathing.processing.context.EvaluationContext -import org.cobalt.api.pathfinder.pathing.processing.context.SearchContext -import org.cobalt.api.pathfinder.util.RegionKey -import org.cobalt.api.pathfinder.wrapper.PathPosition - -class AStarPathfinder(configuration: PathfinderConfiguration) : AbstractPathfinder(configuration) { - - private val currentSession = ThreadLocal() - - override fun insertStartNode(node: Node, fCost: Double, openSet: PrimitiveMinHeap) { - val session = getSessionOrThrow() - val packedPos = RegionKey.pack(node.position) - openSet.insertOrUpdate(packedPos, fCost) - session.openSetNodes[packedPos] = node - } - - override fun extractBestNode(openSet: PrimitiveMinHeap): Node { - val session = getSessionOrThrow() - val packedPos = openSet.extractMin() - val node = session.openSetNodes[packedPos]!! - session.openSetNodes.remove(packedPos) - return node - } - - override fun initializeSearch() { - currentSession.set(PathfindingSession()) - } - - override fun processSuccessors( - requestStart: PathPosition, - requestTarget: PathPosition, - currentNode: Node, - openSet: PrimitiveMinHeap, - searchContext: SearchContext, - ) { - val session = getSessionOrThrow() - val offsets = neighborStrategy.getOffsets(currentNode.position) - - for (offset in offsets) { - val neighborPos = currentNode.position.add(offset) - val packedPos = RegionKey.pack(neighborPos) - - if (openSet.contains(packedPos)) { - val existing = session.openSetNodes[packedPos]!! - updateExistingNode(existing, packedPos, currentNode, searchContext, openSet) - continue - } - - if (session.closedSet.contains(packedPos)) { - continue - } - - val neighbor = createNeighborNode(neighborPos, requestStart, requestTarget, currentNode) - neighbor.parent = currentNode - - val context = - EvaluationContextImpl( - searchContext, - neighbor, - currentNode, - pathfinderConfiguration.heuristicStrategy - ) - - if (!isValidByCustomProcessors(context)) { - continue - } - - val gCost = calculateGCost(context) - neighbor.gCost = gCost - val fCost = neighbor.fCost - val heapKey = calculateHeapKey(neighbor, fCost) - - openSet.insertOrUpdate(packedPos, heapKey) - session.openSetNodes[packedPos] = neighbor - } - } - - private fun updateExistingNode( - existing: Node, - packedPos: Long, - currentNode: Node, - searchContext: SearchContext, - openSet: PrimitiveMinHeap, - ) { - val context = - EvaluationContextImpl( - searchContext, - existing, - currentNode, - pathfinderConfiguration.heuristicStrategy - ) - - val newG = calculateGCost(context) - val tol = Math.ulp(max(abs(newG), abs(existing.gCost))) - - if (newG + tol >= existing.gCost) return - - if (!isValidByCustomProcessors(context)) { - return - } - - existing.parent = currentNode - existing.gCost = newG - val newF = existing.fCost - val newKey = calculateHeapKey(existing, newF) - val oldKey = openSet.getCost(packedPos) - - if (newKey + Math.ulp(newKey) < oldKey) { - openSet.insertOrUpdate(packedPos, newKey) - } else if (abs(newKey - oldKey) <= Math.ulp(newKey)) { - openSet.insertOrUpdate(packedPos, oldKey - Math.ulp(oldKey)) - } - } - - private fun createNeighborNode( - position: PathPosition, - start: PathPosition, - target: PathPosition, - parent: Node, - ): Node { - return Node( - position, - start, - target, - pathfinderConfiguration.heuristicWeights, - pathfinderConfiguration.heuristicStrategy, - parent.depth + 1 - ) - } - - private fun isValidByCustomProcessors(context: EvaluationContext): Boolean { - return processors.all { it.isValid(context) } - } - - private fun calculateGCost(context: EvaluationContext): Double { - val baseCost = context.baseTransitionCost - val additionalCost = processors.sumOf { it.calculateCostContribution(context).value } - - val transitionCost = max(0.0, baseCost + additionalCost) - return context.pathCostToPreviousPosition + transitionCost - } - - override fun markNodeAsExpanded(node: Node) { - val session = getSessionOrThrow() - val packedPos = RegionKey.pack(node.position) - - session.closedSet.add(packedPos) - } - - override fun performAlgorithmCleanup() { - currentSession.remove() - } - - private fun getSessionOrThrow(): PathfindingSession { - return currentSession.get() - ?: throw IllegalStateException( - "Pathfinding session not initialized. Call initializeSearch() first." - ) - } - - private class PathfindingSession { - val openSetNodes: Long2ObjectMap = Long2ObjectOpenHashMap() - val closedSet: LongSet = LongOpenHashSet() - } - -} diff --git a/src/main/kotlin/org/cobalt/api/pathfinder/pathfinder/AbstractPathfinder.kt b/src/main/kotlin/org/cobalt/api/pathfinder/pathfinder/AbstractPathfinder.kt deleted file mode 100644 index e0f9b2f..0000000 --- a/src/main/kotlin/org/cobalt/api/pathfinder/pathfinder/AbstractPathfinder.kt +++ /dev/null @@ -1,293 +0,0 @@ -package org.cobalt.api.pathfinder.pathfinder - -import java.util.concurrent.* -import java.util.concurrent.atomic.AtomicBoolean -import kotlin.math.abs -import kotlin.math.max -import org.cobalt.api.pathfinder.Node -import org.cobalt.api.pathfinder.pathfinder.heap.PrimitiveMinHeap -import org.cobalt.api.pathfinder.pathfinder.processing.EvaluationContextImpl -import org.cobalt.api.pathfinder.pathfinder.processing.SearchContextImpl -import org.cobalt.api.pathfinder.pathing.INeighborStrategy -import org.cobalt.api.pathfinder.pathing.Pathfinder -import org.cobalt.api.pathfinder.pathing.configuration.PathfinderConfiguration -import org.cobalt.api.pathfinder.pathing.context.EnvironmentContext -import org.cobalt.api.pathfinder.pathing.processing.NodeProcessor -import org.cobalt.api.pathfinder.pathing.processing.context.SearchContext -import org.cobalt.api.pathfinder.pathing.result.Path -import org.cobalt.api.pathfinder.pathing.result.PathState -import org.cobalt.api.pathfinder.pathing.result.PathfinderResult -import org.cobalt.api.pathfinder.provider.NavigationPointProvider -import org.cobalt.api.pathfinder.result.PathImpl -import org.cobalt.api.pathfinder.result.PathfinderResultImpl -import org.cobalt.api.pathfinder.wrapper.PathPosition - -abstract class AbstractPathfinder( - protected val pathfinderConfiguration: PathfinderConfiguration, -) : Pathfinder { - - companion object { - private val EMPTY_PATH_POSITIONS: Set = LinkedHashSet(0) - private const val TIE_BREAKER_WEIGHT = 1e-6 - - private val PATHING_EXECUTOR_SERVICE: ExecutorService = - Executors.newWorkStealingPool(max(1, Runtime.getRuntime().availableProcessors() / 2)) - - init { - Runtime.getRuntime().addShutdownHook(Thread { shutdownExecutor() }) - } - - private fun shutdownExecutor() { - PATHING_EXECUTOR_SERVICE.shutdown() - try { - if (!PATHING_EXECUTOR_SERVICE.awaitTermination(5, TimeUnit.SECONDS)) { - PATHING_EXECUTOR_SERVICE.shutdownNow() - } - } catch (e: InterruptedException) { - PATHING_EXECUTOR_SERVICE.shutdownNow() - Thread.currentThread().interrupt() - } - } - } - - protected val navigationPointProvider: NavigationPointProvider = pathfinderConfiguration.provider - protected val processors: List = pathfinderConfiguration.processors - protected val neighborStrategy: INeighborStrategy = pathfinderConfiguration.neighborStrategy - - private val abortRequested = AtomicBoolean(false) - - override fun findPath( - start: PathPosition, - target: PathPosition, - context: EnvironmentContext?, - ): CompletionStage { - this.abortRequested.set(false) - return initiatePathing(start, target, context) - } - - override fun abort() { - this.abortRequested.set(true) - } - - private fun initiatePathing( - start: PathPosition, - target: PathPosition, - environmentContext: EnvironmentContext?, - ): CompletionStage { - val effectiveStart = start.floor() - val effectiveTarget = target.floor() - - return if (pathfinderConfiguration.async) { - CompletableFuture.supplyAsync( - { - executePathingAlgorithm(effectiveStart, effectiveTarget, environmentContext) - }, - PATHING_EXECUTOR_SERVICE - ) - .exceptionally { throwable -> handlePathingException(start, target, throwable) } - } else { - try { - CompletableFuture.completedFuture( - executePathingAlgorithm(effectiveStart, effectiveTarget, environmentContext) - ) - } catch (e: Exception) { - CompletableFuture.completedFuture(handlePathingException(start, target, e)) - } - } - } - - private fun executePathingAlgorithm( - start: PathPosition, - target: PathPosition, - environmentContext: EnvironmentContext?, - ): PathfinderResult { - initializeSearch() - - val searchContext = - SearchContextImpl( - start, - target, - this.pathfinderConfiguration, - this.navigationPointProvider, - environmentContext - ) - - try { - processors.forEach { it.initializeSearch(searchContext) } - - val startNode = createStartNode(start, target) - val startNodeContext = - EvaluationContextImpl( - searchContext, - startNode, - null, - pathfinderConfiguration.heuristicStrategy - ) - - val isStartNodeInvalid = processors.any { !it.isValid(startNodeContext) } - if (isStartNodeInvalid) { - return PathfinderResultImpl( - PathState.FAILED, - PathImpl(start, target, EMPTY_PATH_POSITIONS) - ) - } - - val openSet = PrimitiveMinHeap(1024) - val startKey = - try { - calculateHeapKey(startNode, startNode.fCost) - } catch (t: Throwable) { - startNode.fCost - } - - insertStartNode(startNode, startKey, openSet) - - var currentDepth = 0 - var bestFallbackNode = startNode - - while (!openSet.isEmpty() && currentDepth < pathfinderConfiguration.maxIterations) { - currentDepth++ - - if (this.abortRequested.get()) { - return createAbortedResult(start, target, bestFallbackNode) - } - - val currentNode = extractBestNode(openSet) - markNodeAsExpanded(currentNode) - - if (currentNode.heuristic < bestFallbackNode.heuristic) { - bestFallbackNode = currentNode - } - - if (hasReachedPathLengthLimit(currentNode)) { - return PathfinderResultImpl( - PathState.LENGTH_LIMITED, - reconstructPath(start, target, currentNode) - ) - } - - if (currentNode.isTarget(target)) { - return PathfinderResultImpl(PathState.FOUND, reconstructPath(start, target, currentNode)) - } - - processSuccessors(start, target, currentNode, openSet, searchContext) - } - - return determinePostLoopResult(currentDepth, start, target, bestFallbackNode) - } catch (e: Exception) { - return PathfinderResultImpl(PathState.FAILED, PathImpl(start, target, EMPTY_PATH_POSITIONS)) - } finally { - val finalizeErrors = mutableListOf() - processors.forEach { processor -> - try { - processor.finalizeSearch(searchContext) - } catch (e: Exception) { - finalizeErrors.add(e) - } - } - performAlgorithmCleanup() - } - } - - fun calculateHeapKey(neighbor: Node, fCost: Double): Double { - val heuristic = neighbor.heuristic - val tieBreaker = TIE_BREAKER_WEIGHT * (heuristic / (abs(fCost) + 1)) - var heapKey = fCost - tieBreaker - - if (heapKey.isNaN() || heapKey.isInfinite()) { - heapKey = fCost - } - - return heapKey - } - - private fun createAbortedResult( - start: PathPosition, - target: PathPosition, - fallbackNode: Node, - ): PathfinderResult { - this.abortRequested.set(false) - return PathfinderResultImpl(PathState.ABORTED, reconstructPath(start, target, fallbackNode)) - } - - private fun handlePathingException( - originalStart: PathPosition, - originalTarget: PathPosition, - @Suppress("UNUSED_PARAMETER") throwable: Throwable, - ): PathfinderResult { - return PathfinderResultImpl( - PathState.FAILED, - PathImpl(originalStart, originalTarget, EMPTY_PATH_POSITIONS) - ) - } - - protected fun createStartNode(startPos: PathPosition, targetPos: PathPosition): Node { - return Node( - startPos, - startPos, - targetPos, - pathfinderConfiguration.heuristicWeights, - pathfinderConfiguration.heuristicStrategy, - 0 - ) - } - - private fun hasReachedPathLengthLimit(currentNode: Node): Boolean { - val maxLength = pathfinderConfiguration.maxLength - return maxLength > 0 && currentNode.depth >= maxLength - } - - private fun determinePostLoopResult( - depthReached: Int, - start: PathPosition, - target: PathPosition, - fallbackNode: Node, - ): PathfinderResult { - return when { - depthReached >= pathfinderConfiguration.maxIterations -> { - PathfinderResultImpl( - PathState.MAX_ITERATIONS_REACHED, - reconstructPath(start, target, fallbackNode) - ) - } - - pathfinderConfiguration.fallback -> { - PathfinderResultImpl(PathState.FALLBACK, reconstructPath(start, target, fallbackNode)) - } - - else -> { - PathfinderResultImpl(PathState.FAILED, PathImpl(start, target, EMPTY_PATH_POSITIONS)) - } - } - } - - protected fun reconstructPath(start: PathPosition, target: PathPosition, endNode: Node): Path { - if (endNode.parent == null && endNode.depth == 0) { - return PathImpl(start, target, listOf(endNode.position)) - } - - val pathPositions = tracePathPositionsFromNode(endNode) - return PathImpl(start, target, pathPositions) - } - - private fun tracePathPositionsFromNode(leafNode: Node): List { - return generateSequence(leafNode) { it.parent } - .map { it.position } - .toList() - .reversed() - } - - protected abstract fun insertStartNode(node: Node, fCost: Double, openSet: PrimitiveMinHeap) - protected abstract fun extractBestNode(openSet: PrimitiveMinHeap): Node - protected abstract fun initializeSearch() - protected abstract fun markNodeAsExpanded(node: Node) - protected abstract fun performAlgorithmCleanup() - protected abstract fun processSuccessors( - requestStart: PathPosition, - requestTarget: PathPosition, - currentNode: Node, - openSet: PrimitiveMinHeap, - searchContext: SearchContext, - ) - -} diff --git a/src/main/kotlin/org/cobalt/api/pathfinder/pathfinder/heap/PrimitiveMinHeap.kt b/src/main/kotlin/org/cobalt/api/pathfinder/pathfinder/heap/PrimitiveMinHeap.kt deleted file mode 100644 index 713e3a2..0000000 --- a/src/main/kotlin/org/cobalt/api/pathfinder/pathfinder/heap/PrimitiveMinHeap.kt +++ /dev/null @@ -1,141 +0,0 @@ -package org.cobalt.api.pathfinder.pathfinder.heap - -import it.unimi.dsi.fastutil.longs.Long2IntOpenHashMap - -class PrimitiveMinHeap(initialCapacity: Int) { - - private val nodeToIndexMap: Long2IntOpenHashMap = - Long2IntOpenHashMap(initialCapacity).apply { defaultReturnValue(-1) } - - private var nodes: LongArray = LongArray(initialCapacity + 1) - private var costs: DoubleArray = DoubleArray(initialCapacity + 1) - private var size = 0 - - fun isEmpty(): Boolean = size == 0 - - fun size(): Int = size - - fun clear() { - size = 0 - nodeToIndexMap.clear() - } - - fun peekMin(): Long { - if (size == 0) throw NoSuchElementException() - return nodes[1] - } - - fun peekMinCost(): Double { - if (size == 0) throw NoSuchElementException() - return costs[1] - } - - fun contains(packedNode: Long): Boolean = nodeToIndexMap.containsKey(packedNode) - - fun getCost(packedNode: Long): Double { - val index = nodeToIndexMap.get(packedNode) - return if (index == -1) Double.MAX_VALUE else costs[index] - } - - fun insertOrUpdate(packedNode: Long, cost: Double) { - val existingIndex = nodeToIndexMap.get(packedNode) - - if (existingIndex != -1) { - if (cost < costs[existingIndex]) { - costs[existingIndex] = cost - siftUp(existingIndex) - } - } else { - ensureCapacity() - size++ - nodes[size] = packedNode - costs[size] = cost - nodeToIndexMap.put(packedNode, size) - siftUp(size) - } - } - - fun extractMin(): Long { - if (size == 0) throw NoSuchElementException() - - val minNode = nodes[1] - nodeToIndexMap.remove(minNode) - - val lastNode = nodes[size] - val lastCost = costs[size] - nodes[1] = lastNode - costs[1] = lastCost - size-- - - if (size > 0) { - nodeToIndexMap.put(lastNode, 1) - siftDown(1) - } - - return minNode - } - - private fun ensureCapacity() { - if (size >= nodes.size - 1) { - val newCap = nodes.size * 2 - nodes = nodes.copyOf(newCap) - costs = costs.copyOf(newCap) - } - } - - private fun siftUp(index: Int) { - var current = index - val nodeToMove = nodes[current] - val costToMove = costs[current] - - while (current > 1) { - val parentIndex = current shr 1 - val parentCost = costs[parentIndex] - - if (costToMove < parentCost) { - nodes[current] = nodes[parentIndex] - costs[current] = parentCost - nodeToIndexMap.put(nodes[current], current) - current = parentIndex - } else { - break - } - } - - nodes[current] = nodeToMove - costs[current] = costToMove - nodeToIndexMap.put(nodeToMove, current) - } - - private fun siftDown(index: Int) { - var current = index - val nodeToMove = nodes[current] - val costToMove = costs[current] - val half = size shr 1 - - while (current <= half) { - var childIndex = current shl 1 - var childCost = costs[childIndex] - val rightIndex = childIndex + 1 - - if (rightIndex <= size && costs[rightIndex] < childCost) { - childIndex = rightIndex - childCost = costs[rightIndex] - } - - if (costToMove > childCost) { - nodes[current] = nodes[childIndex] - costs[current] = childCost - nodeToIndexMap.put(nodes[current], current) - current = childIndex - } else { - break - } - } - - nodes[current] = nodeToMove - costs[current] = costToMove - nodeToIndexMap.put(nodeToMove, current) - } - -} diff --git a/src/main/kotlin/org/cobalt/api/pathfinder/pathfinder/processing/EvaluationContextImpl.kt b/src/main/kotlin/org/cobalt/api/pathfinder/pathfinder/processing/EvaluationContextImpl.kt deleted file mode 100644 index 8bb4b19..0000000 --- a/src/main/kotlin/org/cobalt/api/pathfinder/pathfinder/processing/EvaluationContextImpl.kt +++ /dev/null @@ -1,52 +0,0 @@ -package org.cobalt.api.pathfinder.pathfinder.processing - -import kotlin.math.max -import org.cobalt.api.pathfinder.Node -import org.cobalt.api.pathfinder.pathing.heuristic.IHeuristicStrategy -import org.cobalt.api.pathfinder.pathing.processing.context.EvaluationContext -import org.cobalt.api.pathfinder.pathing.processing.context.SearchContext -import org.cobalt.api.pathfinder.wrapper.PathPosition - -class EvaluationContextImpl( - override val searchContext: SearchContext, - private val engineNode: Node, - private val parentEngineNode: Node?, - private val heuristicStrategy: IHeuristicStrategy, -) : EvaluationContext { - - override val currentPathPosition: PathPosition - get() = engineNode.position - - override val previousPathPosition: PathPosition? - get() = parentEngineNode?.position - - override val currentNodeDepth: Int - get() = engineNode.depth - - override val currentNodeHeuristicValue: Double - get() = engineNode.heuristic - - override val pathCostToPreviousPosition: Double - get() = parentEngineNode?.gCost ?: 0.0 - - override val baseTransitionCost: Double - get() { - if (parentEngineNode == null) return 0.0 - - val from = parentEngineNode.position - val to = engineNode.position - val baseCost = heuristicStrategy.calculateTransitionCost(from, to) - - if (baseCost.isNaN() || baseCost.isInfinite()) { - throw IllegalStateException( - "Heuristic transition cost produced an invalid numeric value: $baseCost" - ) - } - - return max(baseCost, 0.0) - } - - override val grandparentPathPosition: PathPosition? - get() = parentEngineNode?.parent?.position - -} diff --git a/src/main/kotlin/org/cobalt/api/pathfinder/pathfinder/processing/SearchContextImpl.kt b/src/main/kotlin/org/cobalt/api/pathfinder/pathfinder/processing/SearchContextImpl.kt deleted file mode 100644 index 4f507d7..0000000 --- a/src/main/kotlin/org/cobalt/api/pathfinder/pathfinder/processing/SearchContextImpl.kt +++ /dev/null @@ -1,19 +0,0 @@ -package org.cobalt.api.pathfinder.pathfinder.processing - -import org.cobalt.api.pathfinder.pathing.configuration.PathfinderConfiguration -import org.cobalt.api.pathfinder.pathing.context.EnvironmentContext -import org.cobalt.api.pathfinder.pathing.processing.context.SearchContext -import org.cobalt.api.pathfinder.provider.NavigationPointProvider -import org.cobalt.api.pathfinder.wrapper.PathPosition - -class SearchContextImpl( - override val startPathPosition: PathPosition, - override val targetPathPosition: PathPosition, - override val pathfinderConfiguration: PathfinderConfiguration, - override val navigationPointProvider: NavigationPointProvider, - override val environmentContext: EnvironmentContext?, -) : SearchContext { - - override val sharedData: MutableMap = HashMap() - -} diff --git a/src/main/kotlin/org/cobalt/api/pathfinder/pathing/INeighborStrategy.kt b/src/main/kotlin/org/cobalt/api/pathfinder/pathing/INeighborStrategy.kt deleted file mode 100644 index 527cbcb..0000000 --- a/src/main/kotlin/org/cobalt/api/pathfinder/pathing/INeighborStrategy.kt +++ /dev/null @@ -1,13 +0,0 @@ -package org.cobalt.api.pathfinder.pathing - -import org.cobalt.api.pathfinder.wrapper.PathPosition -import org.cobalt.api.pathfinder.wrapper.PathVector - -fun interface INeighborStrategy { - - fun getOffsets(): Iterable - fun getOffsets(currentPosition: PathPosition): Iterable { - return getOffsets() - } - -} diff --git a/src/main/kotlin/org/cobalt/api/pathfinder/pathing/NeighborStrategies.kt b/src/main/kotlin/org/cobalt/api/pathfinder/pathing/NeighborStrategies.kt deleted file mode 100644 index f0220b3..0000000 --- a/src/main/kotlin/org/cobalt/api/pathfinder/pathing/NeighborStrategies.kt +++ /dev/null @@ -1,49 +0,0 @@ -package org.cobalt.api.pathfinder.pathing - -import org.cobalt.api.pathfinder.wrapper.PathVector - -object NeighborStrategies { - - private val VERTICAL_AND_HORIZONTAL_OFFSETS = - listOf( - PathVector(1.0, 0.0, 0.0), - PathVector(-1.0, 0.0, 0.0), - PathVector(0.0, 0.0, 1.0), - PathVector(0.0, 0.0, -1.0), - PathVector(0.0, 1.0, 0.0), - PathVector(0.0, -1.0, 0.0) - ) - - private val DIAGONAL_3D_OFFSETS = buildList { - for (x in -1..1) { - for (y in -1..1) { - for (z in -1..1) { - if (x == 0 && y == 0 && z == 0) continue - add(PathVector(x.toDouble(), y.toDouble(), z.toDouble())) - } - } - } - } - - private val HORIZONTAL_DIAGONAL_AND_VERTICAL_OFFSETS = - listOf( - PathVector(1.0, 0.0, 0.0), - PathVector(-1.0, 0.0, 0.0), - PathVector(0.0, 0.0, 1.0), - PathVector(0.0, 0.0, -1.0), - PathVector(0.0, 1.0, 0.0), - PathVector(0.0, -1.0, 0.0), - PathVector(1.0, 0.0, 1.0), - PathVector(1.0, 0.0, -1.0), - PathVector(-1.0, 0.0, 1.0), - PathVector(-1.0, 0.0, -1.0) - ) - - val VERTICAL_AND_HORIZONTAL = INeighborStrategy { VERTICAL_AND_HORIZONTAL_OFFSETS } - val DIAGONAL_3D = INeighborStrategy { DIAGONAL_3D_OFFSETS } - - val HORIZONTAL_DIAGONAL_AND_VERTICAL = INeighborStrategy { - HORIZONTAL_DIAGONAL_AND_VERTICAL_OFFSETS - } - -} diff --git a/src/main/kotlin/org/cobalt/api/pathfinder/pathing/Pathfinder.kt b/src/main/kotlin/org/cobalt/api/pathfinder/pathing/Pathfinder.kt deleted file mode 100644 index 45a07c6..0000000 --- a/src/main/kotlin/org/cobalt/api/pathfinder/pathing/Pathfinder.kt +++ /dev/null @@ -1,22 +0,0 @@ -package org.cobalt.api.pathfinder.pathing - -import java.util.concurrent.CompletionStage -import org.cobalt.api.pathfinder.pathing.context.EnvironmentContext -import org.cobalt.api.pathfinder.pathing.result.PathfinderResult -import org.cobalt.api.pathfinder.wrapper.PathPosition - -interface Pathfinder { - - fun findPath(start: PathPosition, target: PathPosition): CompletionStage { - return findPath(start, target, null) - } - - fun findPath( - start: PathPosition, - target: PathPosition, - context: EnvironmentContext?, - ): CompletionStage - - fun abort() - -} diff --git a/src/main/kotlin/org/cobalt/api/pathfinder/pathing/PathfindingProgress.kt b/src/main/kotlin/org/cobalt/api/pathfinder/pathing/PathfindingProgress.kt deleted file mode 100644 index 358a047..0000000 --- a/src/main/kotlin/org/cobalt/api/pathfinder/pathing/PathfindingProgress.kt +++ /dev/null @@ -1,9 +0,0 @@ -package org.cobalt.api.pathfinder.pathing - -import org.cobalt.api.pathfinder.wrapper.PathPosition - -data class PathfindingProgress( - val start: PathPosition, - val current: PathPosition, - val target: PathPosition, -) diff --git a/src/main/kotlin/org/cobalt/api/pathfinder/pathing/configuration/PathfinderConfiguration.kt b/src/main/kotlin/org/cobalt/api/pathfinder/pathing/configuration/PathfinderConfiguration.kt deleted file mode 100644 index 6c43fb3..0000000 --- a/src/main/kotlin/org/cobalt/api/pathfinder/pathing/configuration/PathfinderConfiguration.kt +++ /dev/null @@ -1,51 +0,0 @@ -package org.cobalt.api.pathfinder.pathing.configuration - -import org.cobalt.api.pathfinder.pathing.INeighborStrategy -import org.cobalt.api.pathfinder.pathing.NeighborStrategies -import org.cobalt.api.pathfinder.pathing.context.EnvironmentContext -import org.cobalt.api.pathfinder.pathing.heuristic.HeuristicWeights -import org.cobalt.api.pathfinder.pathing.heuristic.IHeuristicStrategy -import org.cobalt.api.pathfinder.pathing.heuristic.LinearHeuristicStrategy -import org.cobalt.api.pathfinder.pathing.processing.NodeProcessor -import org.cobalt.api.pathfinder.provider.NavigationPoint -import org.cobalt.api.pathfinder.provider.NavigationPointProvider -import org.cobalt.api.pathfinder.wrapper.PathPosition - -data class PathfinderConfiguration( - val maxIterations: Int = 5000, - val maxLength: Int = 0, - val async: Boolean = false, - val fallback: Boolean = true, - val provider: NavigationPointProvider = DefaultNavigationPointProvider, - val heuristicWeights: HeuristicWeights = HeuristicWeights.DEFAULT_WEIGHTS, - val processors: List = emptyList(), - val neighborStrategy: INeighborStrategy = NeighborStrategies.VERTICAL_AND_HORIZONTAL, - val heuristicStrategy: IHeuristicStrategy = LinearHeuristicStrategy(), -) { - - companion object { - val DEFAULT: PathfinderConfiguration = PathfinderConfiguration() - - fun deepCopy(pathfinderConfiguration: PathfinderConfiguration): PathfinderConfiguration { - return pathfinderConfiguration.copy(processors = pathfinderConfiguration.processors.toList()) - } - } - -} - -private object DefaultNavigationPointProvider : NavigationPointProvider { - - override fun getNavigationPoint( - position: PathPosition, - environmentContext: EnvironmentContext?, - ): NavigationPoint { - return object : NavigationPoint { - override fun isTraversable(): Boolean = true - override fun hasFloor(): Boolean = true - override fun getFloorLevel(): Double = 0.0 - override fun isClimbable(): Boolean = false - override fun isLiquid(): Boolean = false - } - } - -} diff --git a/src/main/kotlin/org/cobalt/api/pathfinder/pathing/context/EnvironmentContext.kt b/src/main/kotlin/org/cobalt/api/pathfinder/pathing/context/EnvironmentContext.kt deleted file mode 100644 index 84012c6..0000000 --- a/src/main/kotlin/org/cobalt/api/pathfinder/pathing/context/EnvironmentContext.kt +++ /dev/null @@ -1,3 +0,0 @@ -package org.cobalt.api.pathfinder.pathing.context - -interface EnvironmentContext diff --git a/src/main/kotlin/org/cobalt/api/pathfinder/pathing/heuristic/HeuristicContext.kt b/src/main/kotlin/org/cobalt/api/pathfinder/pathing/heuristic/HeuristicContext.kt deleted file mode 100644 index cf0561d..0000000 --- a/src/main/kotlin/org/cobalt/api/pathfinder/pathing/heuristic/HeuristicContext.kt +++ /dev/null @@ -1,27 +0,0 @@ -package org.cobalt.api.pathfinder.pathing.heuristic - -import org.cobalt.api.pathfinder.pathing.PathfindingProgress -import org.cobalt.api.pathfinder.wrapper.PathPosition - -class HeuristicContext( - val pathfindingProgress: PathfindingProgress, - val heuristicWeights: HeuristicWeights, -) { - - constructor( - position: PathPosition, - startPosition: PathPosition, - targetPosition: PathPosition, - heuristicWeights: HeuristicWeights, - ) : this(PathfindingProgress(startPosition, position, targetPosition), heuristicWeights) - - val position: PathPosition - get() = pathfindingProgress.current - - val startPosition: PathPosition - get() = pathfindingProgress.start - - val targetPosition: PathPosition - get() = pathfindingProgress.target - -} diff --git a/src/main/kotlin/org/cobalt/api/pathfinder/pathing/heuristic/HeuristicWeights.kt b/src/main/kotlin/org/cobalt/api/pathfinder/pathing/heuristic/HeuristicWeights.kt deleted file mode 100644 index f0a085e..0000000 --- a/src/main/kotlin/org/cobalt/api/pathfinder/pathing/heuristic/HeuristicWeights.kt +++ /dev/null @@ -1,14 +0,0 @@ -package org.cobalt.api.pathfinder.pathing.heuristic - -data class HeuristicWeights( - val manhattanWeight: Double, - val octileWeight: Double, - val perpendicularWeight: Double, - val heightWeight: Double, -) { - - companion object { - val DEFAULT_WEIGHTS = HeuristicWeights(0.0, 1.0, 0.0, 0.0) - } - -} diff --git a/src/main/kotlin/org/cobalt/api/pathfinder/pathing/heuristic/IHeuristicStrategy.kt b/src/main/kotlin/org/cobalt/api/pathfinder/pathing/heuristic/IHeuristicStrategy.kt deleted file mode 100644 index eef32d0..0000000 --- a/src/main/kotlin/org/cobalt/api/pathfinder/pathing/heuristic/IHeuristicStrategy.kt +++ /dev/null @@ -1,10 +0,0 @@ -package org.cobalt.api.pathfinder.pathing.heuristic - -import org.cobalt.api.pathfinder.wrapper.PathPosition - -interface IHeuristicStrategy { - - fun calculate(context: HeuristicContext): Double - fun calculateTransitionCost(from: PathPosition, to: PathPosition): Double - -} diff --git a/src/main/kotlin/org/cobalt/api/pathfinder/pathing/heuristic/InternalHeuristicUtils.kt b/src/main/kotlin/org/cobalt/api/pathfinder/pathing/heuristic/InternalHeuristicUtils.kt deleted file mode 100644 index 7111f34..0000000 --- a/src/main/kotlin/org/cobalt/api/pathfinder/pathing/heuristic/InternalHeuristicUtils.kt +++ /dev/null @@ -1,51 +0,0 @@ -package org.cobalt.api.pathfinder.pathing.heuristic - -import kotlin.math.sqrt -import org.cobalt.api.pathfinder.pathing.PathfindingProgress - -internal object InternalHeuristicUtils { - - private const val EPSILON = 1e-9 - - fun calculatePerpendicularDistanceSq(progress: PathfindingProgress): Double { - val s = progress.start - val c = progress.current - val t = progress.target - - val sx = s.centeredX - val sy = s.centeredY - val sz = s.centeredZ - val cx = c.centeredX - val cy = c.centeredY - val cz = c.centeredZ - val tx = t.centeredX - val ty = t.centeredY - val tz = t.centeredZ - - val lineX = tx - sx - val lineY = ty - sy - val lineZ = tz - sz - val lineSq = lineX * lineX + lineY * lineY + lineZ * lineZ - - if (lineSq < EPSILON) { - val dx = cx - sx - val dy = cy - sy - val dz = cz - sz - return dx * dx + dy * dy + dz * dz - } - - val toX = cx - sx - val toY = cy - sy - val toZ = cz - sz - val crossX = toY * lineZ - toZ * lineY - val crossY = toZ * lineX - toX * lineZ - val crossZ = toX * lineY - toY * lineX - val crossSq = crossX * crossX + crossY * crossY + crossZ * crossZ - - return crossSq / lineSq - } - - fun calculatePerpendicularDistance(progress: PathfindingProgress): Double = - sqrt(calculatePerpendicularDistanceSq(progress)) - -} diff --git a/src/main/kotlin/org/cobalt/api/pathfinder/pathing/heuristic/LinearHeuristicStrategy.kt b/src/main/kotlin/org/cobalt/api/pathfinder/pathing/heuristic/LinearHeuristicStrategy.kt deleted file mode 100644 index a596d69..0000000 --- a/src/main/kotlin/org/cobalt/api/pathfinder/pathing/heuristic/LinearHeuristicStrategy.kt +++ /dev/null @@ -1,54 +0,0 @@ -package org.cobalt.api.pathfinder.pathing.heuristic - -import kotlin.math.abs -import kotlin.math.sqrt -import org.cobalt.api.pathfinder.wrapper.PathPosition - -class LinearHeuristicStrategy : IHeuristicStrategy { - - companion object { - private const val D1 = 1.0 - private val D2 = sqrt(2.0) - private val D3 = sqrt(3.0) - } - - override fun calculate(context: HeuristicContext): Double { - val progress = context.pathfindingProgress - val weights = context.heuristicWeights - - val position = progress.current - val target = progress.target - - val manhattan = - (abs(position.flooredX - target.flooredX) + - abs(position.flooredY - target.flooredY) + - abs(position.flooredZ - target.flooredZ)) - .toDouble() - - val dx = abs(position.flooredX - target.flooredX) - val dy = abs(position.flooredY - target.flooredY) - val dz = abs(position.flooredZ - target.flooredZ) - - val min = minOf(dx, dy, dz) - val max = maxOf(dx, dy, dz) - val mid = dx + dy + dz - min - max - - val octile = (D3 - D2) * min + (D2 - D1) * mid + D1 * max - val perpendicular = InternalHeuristicUtils.calculatePerpendicularDistance(progress) - val height = abs(position.flooredY - target.flooredY).toDouble() - - return manhattan * weights.manhattanWeight + - octile * weights.octileWeight + - perpendicular * weights.perpendicularWeight + - height * weights.heightWeight - } - - override fun calculateTransitionCost(from: PathPosition, to: PathPosition): Double { - val dx = to.centeredX - from.centeredX - val dy = to.centeredY - from.centeredY - val dz = to.centeredZ - from.centeredZ - - return sqrt(dx * dx + dy * dy + dz * dz) - } - -} diff --git a/src/main/kotlin/org/cobalt/api/pathfinder/pathing/heuristic/SquaredHeuristicStrategy.kt b/src/main/kotlin/org/cobalt/api/pathfinder/pathing/heuristic/SquaredHeuristicStrategy.kt deleted file mode 100644 index 8c633ea..0000000 --- a/src/main/kotlin/org/cobalt/api/pathfinder/pathing/heuristic/SquaredHeuristicStrategy.kt +++ /dev/null @@ -1,55 +0,0 @@ -package org.cobalt.api.pathfinder.pathing.heuristic - -import kotlin.math.abs -import kotlin.math.sqrt -import org.cobalt.api.pathfinder.wrapper.PathPosition - -class SquaredHeuristicStrategy : IHeuristicStrategy { - - companion object { - private const val D1 = 1.0 - private val D2 = sqrt(2.0) - private val D3 = sqrt(3.0) - } - - override fun calculate(context: HeuristicContext): Double { - val p = context.pathfindingProgress - val w = context.heuristicWeights - - val current = p.current - val target = p.target - - val manhattan = - abs(current.flooredX - target.flooredX) + - abs(current.flooredY - target.flooredY) + - abs(current.flooredZ - target.flooredZ) - val manhattanSq = (manhattan * manhattan).toDouble() - - val dx = abs(current.flooredX - target.flooredX) - val dy = abs(current.flooredY - target.flooredY) - val dz = abs(current.flooredZ - target.flooredZ) - - val min = minOf(dx, dy, dz) - val max = maxOf(dx, dy, dz) - val mid = dx + dy + dz - min - max - - val octile = (D3 - D2) * min + (D2 - D1) * mid + D1 * max - val octileSq = octile * octile - val perpendicularSq = InternalHeuristicUtils.calculatePerpendicularDistanceSq(p) - val heightSq = (current.flooredY - target.flooredY).let { (it * it).toDouble() } - - return manhattanSq * w.manhattanWeight + - octileSq * w.octileWeight + - perpendicularSq * w.perpendicularWeight + - heightSq * w.heightWeight - } - - override fun calculateTransitionCost(from: PathPosition, to: PathPosition): Double { - val dx = to.centeredX - from.centeredX - val dy = to.centeredY - from.centeredY - val dz = to.centeredZ - from.centeredZ - - return dx * dx + dy * dy + dz * dz - } - -} diff --git a/src/main/kotlin/org/cobalt/api/pathfinder/pathing/processing/Cost.kt b/src/main/kotlin/org/cobalt/api/pathfinder/pathing/processing/Cost.kt deleted file mode 100644 index dbda4f3..0000000 --- a/src/main/kotlin/org/cobalt/api/pathfinder/pathing/processing/Cost.kt +++ /dev/null @@ -1,15 +0,0 @@ -package org.cobalt.api.pathfinder.pathing.processing - -@ConsistentCopyVisibility -data class Cost private constructor(val value: Double) { - - companion object { - val ZERO = Cost(0.0) - - fun of(value: Double): Cost { - require(!value.isNaN() && value >= 0) { "Cost must be a positive number or 0" } - return Cost(value) - } - } - -} diff --git a/src/main/kotlin/org/cobalt/api/pathfinder/pathing/processing/NodeProcessor.kt b/src/main/kotlin/org/cobalt/api/pathfinder/pathing/processing/NodeProcessor.kt deleted file mode 100644 index be52765..0000000 --- a/src/main/kotlin/org/cobalt/api/pathfinder/pathing/processing/NodeProcessor.kt +++ /dev/null @@ -1,10 +0,0 @@ -package org.cobalt.api.pathfinder.pathing.processing - -import org.cobalt.api.pathfinder.pathing.processing.context.EvaluationContext - -interface NodeProcessor : Processor { - - fun isValid(context: EvaluationContext): Boolean = true - fun calculateCostContribution(context: EvaluationContext): Cost = Cost.ZERO - -} diff --git a/src/main/kotlin/org/cobalt/api/pathfinder/pathing/processing/Processor.kt b/src/main/kotlin/org/cobalt/api/pathfinder/pathing/processing/Processor.kt deleted file mode 100644 index 70a36f1..0000000 --- a/src/main/kotlin/org/cobalt/api/pathfinder/pathing/processing/Processor.kt +++ /dev/null @@ -1,12 +0,0 @@ -package org.cobalt.api.pathfinder.pathing.processing - -import org.cobalt.api.pathfinder.pathing.processing.context.SearchContext - -interface Processor { - fun initializeSearch(context: SearchContext) { - } - - fun finalizeSearch(context: SearchContext) { - } - -} diff --git a/src/main/kotlin/org/cobalt/api/pathfinder/pathing/processing/context/EvaluationContext.kt b/src/main/kotlin/org/cobalt/api/pathfinder/pathing/processing/context/EvaluationContext.kt deleted file mode 100644 index db265b9..0000000 --- a/src/main/kotlin/org/cobalt/api/pathfinder/pathing/processing/context/EvaluationContext.kt +++ /dev/null @@ -1,37 +0,0 @@ -package org.cobalt.api.pathfinder.pathing.processing.context - -import org.cobalt.api.pathfinder.pathing.configuration.PathfinderConfiguration -import org.cobalt.api.pathfinder.pathing.context.EnvironmentContext -import org.cobalt.api.pathfinder.provider.NavigationPointProvider -import org.cobalt.api.pathfinder.wrapper.PathPosition - -interface EvaluationContext { - - val currentPathPosition: PathPosition - val previousPathPosition: PathPosition? - val currentNodeDepth: Int - val currentNodeHeuristicValue: Double - val pathCostToPreviousPosition: Double - val baseTransitionCost: Double - val searchContext: SearchContext - val grandparentPathPosition: PathPosition? - - val pathfinderConfiguration: PathfinderConfiguration - get() = searchContext.pathfinderConfiguration - - val navigationPointProvider: NavigationPointProvider - get() = searchContext.navigationPointProvider - - val sharedData: MutableMap - get() = searchContext.sharedData - - val startPathPosition: PathPosition - get() = searchContext.startPathPosition - - val targetPathPosition: PathPosition - get() = searchContext.targetPathPosition - - val environmentContext: EnvironmentContext? - get() = searchContext.environmentContext - -} diff --git a/src/main/kotlin/org/cobalt/api/pathfinder/pathing/processing/context/SearchContext.kt b/src/main/kotlin/org/cobalt/api/pathfinder/pathing/processing/context/SearchContext.kt deleted file mode 100644 index 89ede34..0000000 --- a/src/main/kotlin/org/cobalt/api/pathfinder/pathing/processing/context/SearchContext.kt +++ /dev/null @@ -1,17 +0,0 @@ -package org.cobalt.api.pathfinder.pathing.processing.context - -import org.cobalt.api.pathfinder.pathing.configuration.PathfinderConfiguration -import org.cobalt.api.pathfinder.pathing.context.EnvironmentContext -import org.cobalt.api.pathfinder.provider.NavigationPointProvider -import org.cobalt.api.pathfinder.wrapper.PathPosition - -interface SearchContext { - - val startPathPosition: PathPosition - val targetPathPosition: PathPosition - val pathfinderConfiguration: PathfinderConfiguration - val navigationPointProvider: NavigationPointProvider - val sharedData: MutableMap - val environmentContext: EnvironmentContext? - -} diff --git a/src/main/kotlin/org/cobalt/api/pathfinder/pathing/processing/impl/MinecraftPathProcessor.kt b/src/main/kotlin/org/cobalt/api/pathfinder/pathing/processing/impl/MinecraftPathProcessor.kt deleted file mode 100644 index 60befbe..0000000 --- a/src/main/kotlin/org/cobalt/api/pathfinder/pathing/processing/impl/MinecraftPathProcessor.kt +++ /dev/null @@ -1,122 +0,0 @@ -package org.cobalt.api.pathfinder.pathing.processing.impl - -import kotlin.math.sqrt -import net.minecraft.client.Minecraft -import net.minecraft.core.BlockPos -import org.cobalt.api.pathfinder.pathing.processing.Cost -import org.cobalt.api.pathfinder.pathing.processing.NodeProcessor -import org.cobalt.api.pathfinder.pathing.processing.context.EvaluationContext - -/* - * most logic in this file is derived from minecraft code - * or writeups on pathfinding algorithms, if you want to help contribute - * id prefer for you to keep it the same idea or whatever, but if not - * please write a comment explaining WHY you did it that way. i dont like - * magic numbers that i cant understand. - */ -class MinecraftPathProcessor : NodeProcessor { - - private val mc: Minecraft = Minecraft.getInstance() - - companion object { - private const val DEFAULT_MOB_JUMP_HEIGHT = 1.125 // WalkNodeEvaluator - } - - override fun isValid(context: EvaluationContext): Boolean { - val provider = context.navigationPointProvider - val pos = context.currentPathPosition - val prev = context.previousPathPosition - val env = context.environmentContext - - val currentPoint = provider.getNavigationPoint(pos, env) - - if (!currentPoint.isTraversable()) return false - if (prev == null) return true - - val prevPoint = provider.getNavigationPoint(prev, env) - val dy = pos.y - prev.y - val dx = pos.flooredX - prev.flooredX - val dz = pos.flooredZ - prev.flooredZ - - if (dy > DEFAULT_MOB_JUMP_HEIGHT) return false - - if (Math.abs(dx) == 1 && Math.abs(dz) == 1) { - val corner1Pos = prev.add(dx.toDouble(), 0.0, 0.0) - val corner2Pos = prev.add(0.0, 0.0, dz.toDouble()) - val c1Point = provider.getNavigationPoint(corner1Pos, env) - val c2Point = provider.getNavigationPoint(corner2Pos, env) - - // node3.y <= node.y && node2.y <= node.y - if (!c1Point.isTraversable() || !c2Point.isTraversable()) return false - } - - return when { - dy < -0.5 -> true // falling - dy > 0.5 -> - prevPoint.hasFloor() || - currentPoint.isClimbable() // jumping/climbing - else -> - currentPoint.hasFloor() || - prevPoint.hasFloor() || - currentPoint.isClimbable() || - prevPoint.isClimbable() - } - } - - override fun calculateCostContribution(context: EvaluationContext): Cost { - val level = mc.level ?: return Cost.ZERO - val currentPos = context.currentPathPosition - val prevPos = context.previousPathPosition ?: return Cost.ZERO - val provider = context.navigationPointProvider - val env = context.environmentContext - - val currentPoint = provider.getNavigationPoint(currentPos, env) - val prevPoint = provider.getNavigationPoint(prevPos, env) - - val dy = currentPoint.getFloorLevel() - prevPoint.getFloorLevel() - var additionalCost = 0.0 - - if (dy > 0.1) { - additionalCost += 0.5 * dy - } else if (dy < -0.1) { - additionalCost += 0.1 * Math.abs(dy) - } - - val blockPos = BlockPos(currentPos.flooredX, currentPos.flooredY, currentPos.flooredZ) - - // i dont want it to like tight corners so more cost - var crampedPenalty = 0.0 - for (i in 2..3) { - if (level.getBlockState(blockPos.above(i)).canOcclude()) { - crampedPenalty += 0.1 / i.toDouble() - } - } - if (level.getBlockState(blockPos.west()).canOcclude() || - level.getBlockState(blockPos.east()).canOcclude() || - level.getBlockState(blockPos.north()).canOcclude() || - level.getBlockState(blockPos.south()).canOcclude() - ) { - crampedPenalty += 0.05 - } - additionalCost += crampedPenalty - - // just make stuff smoother no more zigzags - val gpPos = context.grandparentPathPosition - if (gpPos != null) { - val v1x = prevPos.x - gpPos.x - val v1z = prevPos.z - gpPos.z - val v2x = currentPos.x - prevPos.x - val v2z = currentPos.z - prevPos.z - val dot = v1x * v2x + v1z * v2z - val mag1 = sqrt(v1x * v1x + v1z * v1z) - val mag2 = sqrt(v2x * v2x + v2z * v2z) - if (mag1 > 0.1 && mag2 > 0.1) { - val normalizedDot = dot / (mag1 * mag2) - if (normalizedDot < 0.99) additionalCost += 0.05 - } - } - - return Cost.of(additionalCost) - } - -} diff --git a/src/main/kotlin/org/cobalt/api/pathfinder/pathing/result/Path.kt b/src/main/kotlin/org/cobalt/api/pathfinder/pathing/result/Path.kt deleted file mode 100644 index 741e1f2..0000000 --- a/src/main/kotlin/org/cobalt/api/pathfinder/pathing/result/Path.kt +++ /dev/null @@ -1,12 +0,0 @@ -package org.cobalt.api.pathfinder.pathing.result - -import org.cobalt.api.pathfinder.wrapper.PathPosition - -interface Path : Iterable { - - fun length(): Int - fun getStart(): PathPosition - fun getEnd(): PathPosition - fun collect(): Collection - -} diff --git a/src/main/kotlin/org/cobalt/api/pathfinder/pathing/result/PathState.kt b/src/main/kotlin/org/cobalt/api/pathfinder/pathing/result/PathState.kt deleted file mode 100644 index b8a4c18..0000000 --- a/src/main/kotlin/org/cobalt/api/pathfinder/pathing/result/PathState.kt +++ /dev/null @@ -1,10 +0,0 @@ -package org.cobalt.api.pathfinder.pathing.result - -enum class PathState { - ABORTED, - FOUND, - FAILED, - FALLBACK, - LENGTH_LIMITED, - MAX_ITERATIONS_REACHED -} diff --git a/src/main/kotlin/org/cobalt/api/pathfinder/pathing/result/PathfinderResult.kt b/src/main/kotlin/org/cobalt/api/pathfinder/pathing/result/PathfinderResult.kt deleted file mode 100644 index bee1eb0..0000000 --- a/src/main/kotlin/org/cobalt/api/pathfinder/pathing/result/PathfinderResult.kt +++ /dev/null @@ -1,11 +0,0 @@ -package org.cobalt.api.pathfinder.pathing.result - -interface PathfinderResult { - - fun successful(): Boolean - fun hasFailed(): Boolean - fun hasFallenBack(): Boolean - fun getPathState(): PathState - fun getPath(): Path - -} diff --git a/src/main/kotlin/org/cobalt/api/pathfinder/provider/NavigationPoint.kt b/src/main/kotlin/org/cobalt/api/pathfinder/provider/NavigationPoint.kt deleted file mode 100644 index 1720983..0000000 --- a/src/main/kotlin/org/cobalt/api/pathfinder/provider/NavigationPoint.kt +++ /dev/null @@ -1,9 +0,0 @@ -package org.cobalt.api.pathfinder.provider - -interface NavigationPoint { - fun isTraversable(): Boolean - fun hasFloor(): Boolean - fun getFloorLevel(): Double - fun isClimbable(): Boolean - fun isLiquid(): Boolean -} diff --git a/src/main/kotlin/org/cobalt/api/pathfinder/provider/NavigationPointProvider.kt b/src/main/kotlin/org/cobalt/api/pathfinder/provider/NavigationPointProvider.kt deleted file mode 100644 index 465ac0c..0000000 --- a/src/main/kotlin/org/cobalt/api/pathfinder/provider/NavigationPointProvider.kt +++ /dev/null @@ -1,14 +0,0 @@ -package org.cobalt.api.pathfinder.provider - -import org.cobalt.api.pathfinder.pathing.context.EnvironmentContext -import org.cobalt.api.pathfinder.wrapper.PathPosition - -interface NavigationPointProvider { - - fun getNavigationPoint(position: PathPosition): NavigationPoint { - return getNavigationPoint(position, null) - } - - fun getNavigationPoint(position: PathPosition, environmentContext: EnvironmentContext?): NavigationPoint - -} diff --git a/src/main/kotlin/org/cobalt/api/pathfinder/provider/impl/MinecraftNavigationProvider.kt b/src/main/kotlin/org/cobalt/api/pathfinder/provider/impl/MinecraftNavigationProvider.kt deleted file mode 100644 index 189b0d5..0000000 --- a/src/main/kotlin/org/cobalt/api/pathfinder/provider/impl/MinecraftNavigationProvider.kt +++ /dev/null @@ -1,142 +0,0 @@ -package org.cobalt.api.pathfinder.provider.impl - -import net.minecraft.client.Minecraft -import net.minecraft.core.BlockPos -import net.minecraft.core.Direction.Axis -import net.minecraft.tags.BlockTags -import net.minecraft.tags.FluidTags -import net.minecraft.world.level.Level -import net.minecraft.world.level.block.* -import net.minecraft.world.level.block.state.BlockState -import net.minecraft.world.level.pathfinder.PathComputationType -import net.minecraft.world.phys.shapes.CollisionContext -import org.cobalt.api.pathfinder.pathing.context.EnvironmentContext -import org.cobalt.api.pathfinder.provider.NavigationPoint -import org.cobalt.api.pathfinder.provider.NavigationPointProvider -import org.cobalt.api.pathfinder.wrapper.PathPosition - -class MinecraftNavigationProvider : NavigationPointProvider { - - private val mc: Minecraft = Minecraft.getInstance() - - override fun getNavigationPoint( - position: PathPosition, - environmentContext: EnvironmentContext?, - ): NavigationPoint { - val level = - mc.level - ?: return object : NavigationPoint { - override fun isTraversable() = false - override fun hasFloor() = false - override fun getFloorLevel() = 0.0 - override fun isClimbable() = false - override fun isLiquid() = false - } - - val x = position.flooredX - val y = position.flooredY - val z = position.flooredZ - val blockPos = BlockPos(x, y, z) - - val feetState = level.getBlockState(blockPos) - val headState = level.getBlockState(blockPos.above()) - val belowState = level.getBlockState(blockPos.below()) - - val canPassFeetVal = canWalkThrough(level, feetState, blockPos) - val canPassHeadVal = canWalkThrough(level, headState, blockPos.above()) - val hasStableFloorVal = canWalkOn(level, belowState, blockPos.below()) - val floorLevelVal = calculateFloorLevel(level, blockPos) - val isClimbingVal = feetState.block is LadderBlock || feetState.block is VineBlock - val isLiquidVal = !feetState.fluidState.isEmpty - - return object : NavigationPoint { - override fun isTraversable(): Boolean = canPassFeetVal && canPassHeadVal - override fun hasFloor(): Boolean = hasStableFloorVal - override fun getFloorLevel(): Double = floorLevelVal - override fun isClimbable(): Boolean = isClimbingVal - override fun isLiquid(): Boolean = isLiquidVal - } - } - - private fun canWalkThrough(level: Level, state: BlockState, pos: BlockPos): Boolean { - if (state.isAir) return true - - if (state.`is`(BlockTags.TRAPDOORS) || - state.`is`(Blocks.LILY_PAD) || - state.`is`(Blocks.BIG_DRIPLEAF) - ) { - return true - } - - if (state.`is`(Blocks.POWDER_SNOW) || - state.`is`(Blocks.CACTUS) || - state.`is`(Blocks.SWEET_BERRY_BUSH) || - state.`is`(Blocks.HONEY_BLOCK) || - state.`is`(Blocks.COCOA) || - state.`is`(Blocks.WITHER_ROSE) || - state.`is`(Blocks.POINTED_DRIPSTONE) - ) { - return true - } - - val block = state.block - if (block is DoorBlock) { - return if (state.getValue(DoorBlock.OPEN)) true else block.type().canOpenByHand() - } - - if (block is FenceGateBlock) { - return state.getValue(FenceGateBlock.OPEN) - } - - if (block is BaseRailBlock) { - return true - } - - if (state.`is`(BlockTags.FENCES) || state.`is`(BlockTags.WALLS)) { - return false - } - - return state.isPathfindable(PathComputationType.LAND) || state.fluidState.`is`(FluidTags.WATER) - } - - private fun canWalkOn(level: Level, state: BlockState, pos: BlockPos): Boolean { - val block = state.block - if (state.isCollisionShapeFullBlock(level, pos) && - block != Blocks.MAGMA_BLOCK && - block != Blocks.BUBBLE_COLUMN && - block != Blocks.HONEY_BLOCK - ) { - return true - } - - return block is AzaleaBlock || - block is LadderBlock || - block is VineBlock || - block == Blocks.FARMLAND || - block == Blocks.DIRT_PATH || - block == Blocks.SOUL_SAND || - block == Blocks.CHEST || - block == Blocks.ENDER_CHEST || - block == Blocks.GLASS || - block is StairBlock || - block is SlabBlock || - block is BaseRailBlock - } - - private fun calculateFloorLevel(level: Level, pos: BlockPos): Double { - val state = level.getFluidState(pos) - if (state.`is`(FluidTags.WATER)) { - return pos.y.toDouble() + 0.5 - } - - val belowPos = pos.below() - val belowState = level.getBlockState(belowPos) - val shape = belowState.getCollisionShape(level, belowPos, CollisionContext.empty()) - return if (shape.isEmpty) { - belowPos.y.toDouble() - } else { - belowPos.y.toDouble() + shape.max(Axis.Y) - } - } - -} diff --git a/src/main/kotlin/org/cobalt/api/pathfinder/result/PathImpl.kt b/src/main/kotlin/org/cobalt/api/pathfinder/result/PathImpl.kt deleted file mode 100644 index de489ca..0000000 --- a/src/main/kotlin/org/cobalt/api/pathfinder/result/PathImpl.kt +++ /dev/null @@ -1,18 +0,0 @@ -package org.cobalt.api.pathfinder.result - -import org.cobalt.api.pathfinder.pathing.result.Path -import org.cobalt.api.pathfinder.wrapper.PathPosition - -class PathImpl( - private val start: PathPosition, - private val end: PathPosition, - private val positions: Collection, -) : Path { - - override fun getStart(): PathPosition = start - override fun getEnd(): PathPosition = end - override fun iterator(): Iterator = positions.iterator() - override fun length(): Int = positions.size - override fun collect(): Collection = positions.toList() - -} diff --git a/src/main/kotlin/org/cobalt/api/pathfinder/result/PathfinderResultImpl.kt b/src/main/kotlin/org/cobalt/api/pathfinder/result/PathfinderResultImpl.kt deleted file mode 100644 index 1b2027c..0000000 --- a/src/main/kotlin/org/cobalt/api/pathfinder/result/PathfinderResultImpl.kt +++ /dev/null @@ -1,28 +0,0 @@ -package org.cobalt.api.pathfinder.result - -import org.cobalt.api.pathfinder.pathing.result.Path -import org.cobalt.api.pathfinder.pathing.result.PathState -import org.cobalt.api.pathfinder.pathing.result.PathfinderResult - -class PathfinderResultImpl( - private val pathState: PathState, - private val path: Path, -) : PathfinderResult { - - override fun successful(): Boolean { - return pathState == PathState.FOUND || - pathState == PathState.FALLBACK || - pathState == PathState.MAX_ITERATIONS_REACHED - } - - override fun hasFailed(): Boolean { - return pathState == PathState.FAILED || - pathState == PathState.ABORTED || - pathState == PathState.LENGTH_LIMITED - } - - override fun hasFallenBack(): Boolean = pathState == PathState.FALLBACK - override fun getPathState(): PathState = pathState - override fun getPath(): Path = path - -} diff --git a/src/main/kotlin/org/cobalt/api/pathfinder/util/RegionKey.kt b/src/main/kotlin/org/cobalt/api/pathfinder/util/RegionKey.kt deleted file mode 100644 index cc26800..0000000 --- a/src/main/kotlin/org/cobalt/api/pathfinder/util/RegionKey.kt +++ /dev/null @@ -1,20 +0,0 @@ -package org.cobalt.api.pathfinder.util - -import org.cobalt.api.pathfinder.wrapper.PathPosition - -object RegionKey { - private const val MASK_Y = 0xFFFL // 12 Bit - private const val MASK_XZ = 0x3FFFFFFL // 26 Bit - private const val SHIFT_Z = 12 - private const val SHIFT_X = 38 // 12 + 26 - - fun pack(pos: PathPosition): Long = - pack(pos.flooredX, pos.flooredY, pos.flooredZ) - - fun pack(x: Int, y: Int, z: Int): Long { - return ((x.toLong() and MASK_XZ) shl SHIFT_X) or - ((z.toLong() and MASK_XZ) shl SHIFT_Z) or - (y.toLong() and MASK_Y) - } - -} diff --git a/src/main/kotlin/org/cobalt/api/pathfinder/wrapper/PathPosition.kt b/src/main/kotlin/org/cobalt/api/pathfinder/wrapper/PathPosition.kt deleted file mode 100644 index 80c1486..0000000 --- a/src/main/kotlin/org/cobalt/api/pathfinder/wrapper/PathPosition.kt +++ /dev/null @@ -1,70 +0,0 @@ -package org.cobalt.api.pathfinder.wrapper - -import kotlin.math.sqrt -import net.minecraft.util.Mth - -data class PathPosition(val x: Double, val y: Double, val z: Double) { - - val flooredX: Int - get() = Mth.floor(x) - val flooredY: Int - get() = Mth.floor(y) - val flooredZ: Int - get() = Mth.floor(z) - - val centeredX: Double - get() = flooredX + 0.5 - val centeredY: Double - get() = flooredY + 0.5 - val centeredZ: Double - get() = flooredZ + 0.5 - - fun distanceSquared(other: PathPosition): Double { - return Mth.square(x - other.x) + Mth.square(y - other.y) + Mth.square(z - other.z) - } - - fun distance(other: PathPosition): Double = sqrt(distanceSquared(other)) - fun setX(x: Double): PathPosition = copy(x = x) - fun setY(y: Double): PathPosition = copy(y = y) - fun setZ(z: Double): PathPosition = copy(z = z) - - fun add(x: Double, y: Double, z: Double): PathPosition = - PathPosition(this.x + x, this.y + y, this.z + z) - - fun add(vector: PathVector): PathPosition = - add(vector.x, vector.y, vector.z) - - fun subtract(x: Double, y: Double, z: Double): PathPosition = - PathPosition(this.x - x, this.y - y, this.z - z) - - fun subtract(vector: PathVector): PathPosition = - subtract(vector.x, vector.y, vector.z) - - fun toVector(): PathVector = - PathVector(x, y, z) - - fun floor(): PathPosition = - PathPosition(flooredX.toDouble(), flooredY.toDouble(), flooredZ.toDouble()) - - fun mid(): PathPosition = - PathPosition(flooredX + 0.5, flooredY + 0.5, flooredZ + 0.5) - - fun midPoint(end: PathPosition): PathPosition = - PathPosition((x + end.x) / 2, (y + end.y) / 2, (z + end.z) / 2) - - override fun equals(other: Any?): Boolean { - if (this === other) return true - return other is PathPosition && - flooredX == other.flooredX && - flooredY == other.flooredY && - flooredZ == other.flooredZ - } - - override fun hashCode(): Int { - var result = flooredX - result = 31 * result + flooredY - result = 31 * result + flooredZ - return result - } - -} diff --git a/src/main/kotlin/org/cobalt/api/pathfinder/wrapper/PathVector.kt b/src/main/kotlin/org/cobalt/api/pathfinder/wrapper/PathVector.kt deleted file mode 100644 index 99e14a0..0000000 --- a/src/main/kotlin/org/cobalt/api/pathfinder/wrapper/PathVector.kt +++ /dev/null @@ -1,29 +0,0 @@ -package org.cobalt.api.pathfinder.wrapper - -import kotlin.math.sqrt -import net.minecraft.util.Mth - -data class PathVector(val x: Double, val y: Double, val z: Double) { - - fun dot(other: PathVector): Double = x * other.x + y * other.y + z * other.z - fun length(): Double = sqrt(Mth.square(x) + Mth.square(y) + Mth.square(z)) - - fun distance(other: PathVector): Double = - sqrt(Mth.square(x - other.x) + Mth.square(y - other.y) + Mth.square(z - other.z)) - - fun setX(x: Double): PathVector = copy(x = x) - fun setY(y: Double): PathVector = copy(y = y) - fun setZ(z: Double): PathVector = copy(z = z) - - fun subtract(other: PathVector): PathVector = PathVector(x - other.x, y - other.y, z - other.z) - fun multiply(value: Double): PathVector = PathVector(x * value, y * value, z * value) - - fun normalize(): PathVector { - val magnitude = length() - return PathVector(x / magnitude, y / magnitude, z / magnitude) - } - - fun divide(value: Double): PathVector = PathVector(x / value, y / value, z / value) - fun add(other: PathVector): PathVector = PathVector(x + other.x, y + other.y, z + other.z) - -} diff --git a/src/main/kotlin/org/cobalt/internal/command/MainCommand.kt b/src/main/kotlin/org/cobalt/internal/command/MainCommand.kt index c4f4ce7..3a05916 100644 --- a/src/main/kotlin/org/cobalt/internal/command/MainCommand.kt +++ b/src/main/kotlin/org/cobalt/internal/command/MainCommand.kt @@ -6,7 +6,6 @@ import org.cobalt.api.command.Command import org.cobalt.api.command.annotation.DefaultHandler import org.cobalt.api.command.annotation.SubCommand import org.cobalt.api.notification.NotificationManager -import org.cobalt.api.pathfinder.PathExecutor import org.cobalt.api.rotation.EasingType import org.cobalt.api.rotation.RotationExecutor import org.cobalt.api.rotation.strategy.TimedEaseStrategy @@ -49,15 +48,7 @@ internal object MainCommand : Command(name = "cobalt", aliases = arrayOf("cb")) ) } - @SubCommand - fun start(x: Double, y: Double, z: Double) { - PathExecutor.start(x, y, z) - } - @SubCommand - fun stop() { - PathExecutor.stop() - } @SubCommand fun notification(title: String, description: String) {