From cd8ac5e57458fa2331c2c5ae196841e186655908 Mon Sep 17 00:00:00 2001 From: Gabber235 Date: Fri, 6 Sep 2024 09:18:25 +0200 Subject: [PATCH 1/2] Make sure an npc doesn't go through negative nodes --- .../engine/paper/entry/roadnetwork/gps/GPS.kt | 38 +++++++++++++------ .../activity/NavigationActivityTask.kt | 38 ++++++++++++++++--- 2 files changed, 60 insertions(+), 16 deletions(-) diff --git a/engine/engine-paper/src/main/kotlin/com/typewritermc/engine/paper/entry/roadnetwork/gps/GPS.kt b/engine/engine-paper/src/main/kotlin/com/typewritermc/engine/paper/entry/roadnetwork/gps/GPS.kt index 1c5c6eecb9..45f1f864a7 100644 --- a/engine/engine-paper/src/main/kotlin/com/typewritermc/engine/paper/entry/roadnetwork/gps/GPS.kt +++ b/engine/engine-paper/src/main/kotlin/com/typewritermc/engine/paper/entry/roadnetwork/gps/GPS.kt @@ -2,16 +2,19 @@ package com.typewritermc.engine.paper.entry.roadnetwork.gps import com.extollit.gaming.ai.path.HydrazinePathFinder import com.extollit.gaming.ai.path.model.* +import com.typewritermc.core.entries.Ref +import com.typewritermc.core.utils.point.Vector import com.typewritermc.engine.paper.entry.entity.toProperty +import com.typewritermc.engine.paper.entry.entries.RoadNetworkEntry import com.typewritermc.engine.paper.entry.entries.RoadNode import com.typewritermc.engine.paper.entry.entries.roadNetworkMaxDistance import com.typewritermc.engine.paper.entry.roadnetwork.pathfinding.PFEmptyEntity import com.typewritermc.engine.paper.entry.roadnetwork.pathfinding.PFInstanceSpace -import com.typewritermc.core.utils.point.Vector import com.typewritermc.engine.paper.utils.distanceSqrt import org.bukkit.Location interface GPS { + val roadNetwork: Ref suspend fun findPath(): Result> } @@ -23,7 +26,6 @@ data class GPSEdge( val isFastTravel: Boolean get() = weight == 0.0 } - fun roadNetworkFindPath( start: RoadNode, end: RoadNode, @@ -31,6 +33,16 @@ fun roadNetworkFindPath( instance: PFInstanceSpace = PFInstanceSpace(start.location.world), nodes: List = emptyList(), negativeNodes: List = emptyList(), +): IPath? { + return roadNetworkFindPath(start, end, HydrazinePathFinder(entity, instance), nodes, negativeNodes) +} + +fun roadNetworkFindPath( + start: RoadNode, + end: RoadNode, + pathfinder: HydrazinePathFinder, + nodes: List = emptyList(), + negativeNodes: List = emptyList(), ): IPath? { val interestingNodes = nodes.filter { if (it.id == start.id) return@filter false @@ -42,25 +54,29 @@ fun roadNetworkFindPath( distance > it.radius * it.radius && distance < roadNetworkMaxDistance * roadNetworkMaxDistance } - val pathfinder = HydrazinePathFinder(entity, instance) - val additionalRadius = entity.width().toDouble() + val additionalRadius = pathfinder.subject().width().toDouble() - // When the pathfinder wants to go through another intermediary node, we know that we probably want to use that. - // So we don't want this edge to be used. - pathfinder.withGraphNodeFilter { node -> - if (node.isInRangeOf(interestingNegativeNodes, additionalRadius)) return@withGraphNodeFilter Passibility.dangerous - node.passibility() + // We want to avoid going through negative nodes + if (interestingNegativeNodes.isNotEmpty()) { + pathfinder.withGraphNodeFilter { node -> + if (node.isInRangeOf(interestingNegativeNodes, additionalRadius)) { + return@withGraphNodeFilter Passibility.dangerous + } + node.passibility() + } } + // When the pathfinder wants to go through another intermediary node, we know that we probably want to use that. + // So we don't want this edge to be used. val path = pathfinder.computePathTo(end.location.x, end.location.y, end.location.z) ?: return null - if (path.any { it.isInRangeOf(interestingNodes, additionalRadius) }) { + if (interestingNodes.isNotEmpty() && path.any { it.isInRangeOf(interestingNodes, additionalRadius) }) { return null } return path } -private fun INode.isInRangeOf(roadNodes: List, additionalRadius: Double = 0.0): Boolean { +fun INode.isInRangeOf(roadNodes: List, additionalRadius: Double = 0.0): Boolean { return roadNodes.any { roadNode -> val point = this.coordinates().toVector().mid() val radius = roadNode.radius + additionalRadius diff --git a/extensions/EntityExtension/src/main/kotlin/com/typewritermc/entity/entries/activity/NavigationActivityTask.kt b/extensions/EntityExtension/src/main/kotlin/com/typewritermc/entity/entries/activity/NavigationActivityTask.kt index 9236d53a18..1b84d77f04 100644 --- a/extensions/EntityExtension/src/main/kotlin/com/typewritermc/entity/entries/activity/NavigationActivityTask.kt +++ b/extensions/EntityExtension/src/main/kotlin/com/typewritermc/entity/entries/activity/NavigationActivityTask.kt @@ -6,10 +6,15 @@ import com.extollit.gaming.ai.path.model.IPath import com.extollit.gaming.ai.path.model.IPathingEntity import com.extollit.gaming.ai.path.model.Passibility import com.extollit.linalg.immutable.Vec3d +import com.typewritermc.core.entries.Ref import com.typewritermc.core.utils.point.Vector import com.typewritermc.engine.paper.entry.entity.* +import com.typewritermc.engine.paper.entry.entries.RoadNetworkEntry +import com.typewritermc.engine.paper.entry.entries.roadNetworkMaxDistance +import com.typewritermc.engine.paper.entry.roadnetwork.RoadNetworkManager import com.typewritermc.engine.paper.entry.roadnetwork.gps.GPS import com.typewritermc.engine.paper.entry.roadnetwork.gps.GPSEdge +import com.typewritermc.engine.paper.entry.roadnetwork.gps.isInRangeOf import com.typewritermc.engine.paper.entry.roadnetwork.gps.toVector import com.typewritermc.engine.paper.entry.roadnetwork.pathfinding.PFCapabilities import com.typewritermc.engine.paper.entry.roadnetwork.pathfinding.PFInstanceSpace @@ -17,6 +22,7 @@ import com.typewritermc.engine.paper.logger import com.typewritermc.engine.paper.utils.* import kotlinx.coroutines.Job import org.bukkit.util.BoundingBox +import org.koin.java.KoinJavaComponent.get import kotlin.math.atan2 import kotlin.math.cos import kotlin.math.min @@ -24,7 +30,7 @@ import kotlin.math.sin class NavigationActivity( - gps: GPS, + private val gps: GPS, startLocation: PositionProperty, ) : GenericEntityActivity { private var path: List? = null @@ -49,7 +55,7 @@ class NavigationActivity( state = when { currentEdge.isFastTravel -> NavigationActivityTaskState.FastTravel(currentEdge) - context.isViewed -> NavigationActivityTaskState.Walking(currentEdge, currentPosition) + context.isViewed -> NavigationActivityTaskState.Walking(gps.roadNetwork, currentEdge, currentPosition) else -> NavigationActivityTaskState.FakeNavigation(currentEdge) } @@ -59,7 +65,7 @@ class NavigationActivity( // The fake navigation is used to improve the performance, it however, goes through buildings // So, we switch to walking when the entity is viewed if (state is NavigationActivityTaskState.FakeNavigation && context.isViewed) { - this.state = NavigationActivityTaskState.Walking(state.edge, currentPosition) + this.state = NavigationActivityTaskState.Walking(gps.roadNetwork, state.edge, currentPosition) } // And we switch back to fake navigation when the entity is not viewed @@ -133,7 +139,11 @@ private sealed interface NavigationActivityTaskState { override fun isComplete(): Boolean = true } - class Walking(val edge: GPSEdge, startLocation: PositionProperty) : NavigationActivityTaskState, IPathingEntity { + class Walking( + roadNetwork: Ref, + val edge: GPSEdge, + startLocation: PositionProperty + ) : NavigationActivityTaskState, IPathingEntity { private var location: PositionProperty = startLocation private var path: IPath? @@ -148,7 +158,25 @@ private sealed interface NavigationActivityTaskState { val instance = PFInstanceSpace(startLocation.toBukkitLocation().world) navigator = HydrazinePathFinder(this, instance) - path = navigator.initiatePathTo(edge.end.x, edge.end.y, edge.end.z) + // We want to avoid going through negative nodes + // Since we just queried the network, it is likely that the network is already loaded. + get(RoadNetworkManager::class.java).getNetworkOrNull(roadNetwork)?.let { network -> + val interestingNegativeNodes = network.negativeNodes.filter { + val distance = edge.start.distanceSqrt(it.location) ?: 0.0 + distance > it.radius * it.radius && distance < roadNetworkMaxDistance * roadNetworkMaxDistance + } + val additionalRadius = navigator.subject().width().toDouble() + + navigator.withGraphNodeFilter { node -> + if (node.isInRangeOf(interestingNegativeNodes, additionalRadius)) { + return@withGraphNodeFilter Passibility.dangerous + } + node.passibility() + } + } + + + path = navigator.computePathTo(edge.end.x, edge.end.y, edge.end.z) } override fun location(): PositionProperty = location From a80c494c07e3720f2522d0a20d74ed28558b26c9 Mon Sep 17 00:00:00 2001 From: Gabber235 Date: Fri, 6 Sep 2024 09:44:13 +0200 Subject: [PATCH 2/2] Rename thread when tied to task --- discord_bot/src/discord/create_task.rs | 6 +++++- discord_bot/src/webhooks/tasks.rs | 1 + 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/discord_bot/src/discord/create_task.rs b/discord_bot/src/discord/create_task.rs index 2111bb9147..302dc1a904 100644 --- a/discord_bot/src/discord/create_task.rs +++ b/discord_bot/src/discord/create_task.rs @@ -4,7 +4,7 @@ use crate::{ Context, WinstonError, }; use poise::{ - serenity_prelude::{CreateEmbed, CreateMessage}, + serenity_prelude::{CreateEmbed, CreateMessage, EditThread}, CreateReply, }; @@ -79,6 +79,10 @@ pub async fn create_task( ) .await?; + channel + .edit_thread(ctx, EditThread::default().name(title)) + .await?; + Ok(()) } diff --git a/discord_bot/src/webhooks/tasks.rs b/discord_bot/src/webhooks/tasks.rs index 330f8ad8e8..02929d9dc2 100644 --- a/discord_bot/src/webhooks/tasks.rs +++ b/discord_bot/src/webhooks/tasks.rs @@ -91,6 +91,7 @@ async fn update_discord_channel(task_id: &str, moved: bool) -> Result<(), Winsto .edit_thread( &discord, EditThread::default() + .name(task.name) .applied_tags(new_tags) .locked(lock) .archived(lock),