11package ru.octol1ttle.flightassistant.impl.computer.safety
22
3+ import kotlin.math.abs
34import kotlin.math.max
45import net.minecraft.network.chat.Component
56import net.minecraft.resources.ResourceLocation
@@ -22,7 +23,6 @@ import ru.octol1ttle.flightassistant.api.util.inverseMin
2223import ru.octol1ttle.flightassistant.api.util.throwIfNotInRange
2324import ru.octol1ttle.flightassistant.config.FAConfig
2425import ru.octol1ttle.flightassistant.impl.computer.autoflight.base.PitchComputer
25- import ru.octol1ttle.flightassistant.impl.computer.data.AirDataComputer
2626
2727class GroundProximityComputer (computers : ComputerBus ) : Computer(computers), FlightController {
2828 private var groundImpactTime: Double = Double .MAX_VALUE
@@ -34,13 +34,13 @@ class GroundProximityComputer(computers: ComputerBus) : Computer(computers), Fli
3434
3535 private var anyBlocksAbove = false
3636 val safeThreshold: Double
37- get() = if (anyBlocksAbove) 7.5 else 10.0
37+ get() = if (anyBlocksAbove) 5.0 else 10.0
3838 val cautionThreshold: Double
39- get() = if (anyBlocksAbove) 7.5 else 10.0
39+ get() = if (anyBlocksAbove) 3.0 else 7.5
4040 val warningThreshold: Double
41- get() = if (anyBlocksAbove) 7 .5 else 10 .0
41+ get() = if (anyBlocksAbove) 1 .5 else 3 .0
4242 val recoverThreshold: Double
43- get() = if (anyBlocksAbove) 7.5 else 10.0
43+ get() = 0.75
4444
4545 var groundY: Double? = null
4646 val groundOrVoidY: Double
@@ -57,48 +57,32 @@ class GroundProximityComputer(computers: ComputerBus) : Computer(computers), Fli
5757 groundY = computeGroundY()?.throwIfNotInRange(computers.data.level.bottomY.toDouble().. Double .MAX_VALUE )
5858 }
5959
60- val data: AirDataComputer = computers.data
61- if (! data.flying || data.player.isInWater) {
60+ if (! computers.data.flying || computers.data.player.isInWater) {
6261 groundImpactStatus = Status .SAFE
6362 obstacleImpactStatus = Status .SAFE
6463 return
6564 }
6665
67- anyBlocksAbove = data.level.getHeight(Heightmap .Types .MOTION_BLOCKING , data.player.blockX, data.player.blockZ) > data.player.y
68-
69- groundImpactTime = computeGroundImpactTime(data).throwIfNotInRange(0.0 .. Double .MAX_VALUE )
70- groundImpactStatus =
71- if (data.fallDistanceSafe) {
72- Status .SAFE
73- } else if (groundImpactStatus == Status .SAFE && (data.velocityPerSecond.y > - 10 || groundImpactTime > cautionThreshold)) {
74- Status .SAFE
75- } else if (data.velocityPerSecond.y > - 8.5 || groundImpactTime > safeThreshold) {
76- Status .SAFE
77- } else if (groundImpactStatus >= Status .CAUTION && groundImpactTime > warningThreshold) {
78- Status .CAUTION
79- } else if (groundImpactStatus >= Status .WARNING && groundImpactTime > recoverThreshold) {
80- Status .WARNING
81- } else {
82- Status .RECOVER
83- }
66+ anyBlocksAbove = computers.data.level.getHeight(Heightmap .Types .MOTION_BLOCKING , computers.data.player.blockX, computers.data.player.blockZ) > computers.data.player.y
8467
85- obstacleImpactTime = computeObstacleImpactTime(data, safeThreshold).throwIfNotInRange(0.0 .. Double .MAX_VALUE )
86-
87- val damageOnCollision: Double = data.velocity.horizontalDistance() * 10 - 3
88- obstacleImpactStatus =
89- if (data.isInvulnerableTo(data.player.damageSources().flyIntoWall())) {
90- Status .SAFE
91- } else if (obstacleImpactStatus == Status .SAFE && (damageOnCollision < data.player.health * 0.5f || obstacleImpactTime > groundImpactTime * 1.1f || obstacleImpactTime > cautionThreshold)) {
92- Status .SAFE
93- } else if (damageOnCollision < data.player.health * 0.25f || obstacleImpactTime > groundImpactTime * 1.2f || obstacleImpactTime > safeThreshold) {
94- Status .SAFE
95- } else if (obstacleImpactStatus >= Status .CAUTION && obstacleImpactTime > warningThreshold) {
96- Status .CAUTION
97- } else if (obstacleImpactStatus >= Status .WARNING && obstacleImpactTime > recoverThreshold) {
98- Status .WARNING
99- } else {
100- Status .RECOVER
101- }
68+ groundImpactTime = computeGroundImpactTime().throwIfNotInRange(0.0 .. Double .MAX_VALUE )
69+ groundImpactStatus = computeStatus(groundImpactStatus,
70+ { computers.data.fallDistanceSafe || computers.data.velocityPerSecond.y > - 8.5 || groundImpactTime >= safeThreshold },
71+ { computers.data.velocityPerSecond.y <= - 10 && groundImpactTime <= cautionThreshold },
72+ { groundImpactTime <= warningThreshold },
73+ { groundImpactTime <= recoverThreshold }
74+ )
75+
76+ obstacleImpactTime = computeObstacleImpactTime(computers.data.velocityPerSecond, safeThreshold).throwIfNotInRange(0.0 .. Double .MAX_VALUE )
77+ val thresholdMultiplier = computeThresholdMultiplier()
78+ val damageOnCollision: Double = computers.data.velocity.horizontalDistance() * 10 - 3
79+ val invulnerable = computers.data.isInvulnerableTo(computers.data.player.damageSources().flyIntoWall())
80+ obstacleImpactStatus = computeStatus(obstacleImpactStatus,
81+ { invulnerable || damageOnCollision < computers.data.player.health * 0.25f || obstacleImpactTime > groundImpactTime * 1.2f || obstacleImpactTime >= safeThreshold * thresholdMultiplier },
82+ { abs(computers.data.yaw - computers.data.flightYaw) < 10.0f && damageOnCollision >= computers.data.player.health * 0.5f && obstacleImpactTime < groundImpactTime * 1.1f && obstacleImpactTime <= cautionThreshold * thresholdMultiplier },
83+ { obstacleImpactTime <= warningThreshold * thresholdMultiplier },
84+ { obstacleImpactTime <= recoverThreshold },
85+ )
10286 }
10387
10488 private fun computeGroundY (): Double? {
@@ -117,23 +101,69 @@ class GroundProximityComputer(computers: ComputerBus) : Computer(computers), Fli
117101 return groundY
118102 }
119103
120- private fun computeGroundImpactTime (data : AirDataComputer ): Double {
121- if (data.velocity.y >= 0.0 ) {
122- return Double .MAX_VALUE
104+ private fun computeThresholdMultiplier (): Double {
105+ val maxRaycastDistance = computers.data.forwardVelocityPerSecond.length() * safeThreshold
106+
107+ val xzOffsets = listOf (- 1.0 , 0.0 , 1.0 )
108+ val yOffsets = listOf (- 1.0 , 0.0 , 1.0 )
109+
110+ val distances = ArrayList <Double >()
111+ for (x in xzOffsets) { for (y in yOffsets) { for (z in xzOffsets) {
112+ val offset = Vec3 (x, y, z).normalize().scale(maxRaycastDistance)
113+ if (offset.lengthSqr() == 0.0 ) {
114+ continue
115+ }
116+ val raycast: BlockHitResult = computers.data.level.clip(
117+ ClipContext (
118+ computers.data.position,
119+ computers.data.position.add(offset),
120+ ClipContext .Block .COLLIDER ,
121+ ClipContext .Fluid .ANY ,
122+ computers.data.player
123+ )
124+ )
125+ if (raycast.type == HitResult .Type .BLOCK ) {
126+ distances.add(computers.data.position.distanceTo(raycast.location))
127+ }
128+ }}}
129+
130+ return distances.average() / maxRaycastDistance
131+ }
132+
133+ private fun computeStatus (current : Status , safe : () -> Boolean , caution : () -> Boolean , warning : () -> Boolean , recover : () -> Boolean ): Status {
134+ if (safe()) {
135+ return Status .SAFE
136+ }
137+
138+ var status: Status = current
139+ while (true ) {
140+ val next = when (status) {
141+ Status .SAFE -> if (caution()) Status .CAUTION else null
142+ Status .CAUTION -> if (caution() && warning()) Status .WARNING else null
143+ Status .WARNING -> if (caution() && warning() && recover()) Status .RECOVER else null
144+ Status .RECOVER -> null
145+ }
146+ if (next == null ) {
147+ break
148+ }
149+ status = next
123150 }
124- return max(0.0 , data.altitude - groundOrVoidY) / - data.velocityPerSecond.y
151+
152+ return status
125153 }
126154
127- private fun computeObstacleImpactTime (data : AirDataComputer , lookAheadTime : Double ): Double {
128- val end: Vec3 = data.position.add(data.forwardVelocityPerSecond.multiply(lookAheadTime, 0.0 , lookAheadTime))
129- return computeObstacleImpactTime(end, computers.data.forwardVelocityPerSecond)
155+ private fun computeGroundImpactTime (): Double {
156+ if (computers.data.velocity.y >= 0.0 ) {
157+ return Double .MAX_VALUE
158+ }
159+ return max(0.0 , computers.data.altitude - groundOrVoidY) / - computers.data.velocityPerSecond.y
130160 }
131161
132- fun computeObstacleImpactTime (raycastEnd : Vec3 , velocity : Vec3 ): Double {
162+ fun computeObstacleImpactTime (velocity : Vec3 , lookAheadTime : Double ): Double {
133163 val result: BlockHitResult = computers.data.level.clip(
134164 ClipContext (
135165 computers.data.position,
136- raycastEnd ,
166+ computers.data.position.add(velocity.scale(lookAheadTime)) ,
137167 ClipContext .Block .COLLIDER ,
138168 ClipContext .Fluid .ANY ,
139169 computers.data.player
@@ -205,7 +235,6 @@ class GroundProximityComputer(computers: ComputerBus) : Computer(computers), Fli
205235 groundImpactStatus = Status .SAFE
206236 obstacleImpactTime = Double .MAX_VALUE
207237 obstacleImpactStatus = Status .SAFE
208- anyBlocksAbove = false
209238 groundY = null
210239 }
211240
0 commit comments