Seriously. Weekend.
This commit is contained in:
parent
d0dcdffb9c
commit
c36583631c
@ -1,6 +1,7 @@
|
||||
package controllers
|
||||
|
||||
import java.awt.Point
|
||||
import kotlin.random.Random
|
||||
|
||||
|
||||
/**
|
||||
@ -55,4 +56,71 @@ interface InputController {
|
||||
* Same as [scrollIn] but moves the scroll wheel backward.
|
||||
*/
|
||||
fun scrollOut(sleepDurationMillis: Long, sleepDurationVarianceMillis: Long)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Generates a random point near the given [point] within specified bounds.
|
||||
*
|
||||
* The returned point will have a random offset from [point] in both x and y directions. The maximum offset in each
|
||||
* direction is controlled by [params].
|
||||
*
|
||||
* @param point The reference point to offset from
|
||||
* @param params The max x and y variance
|
||||
* @return A new random [Point] near [point]
|
||||
*/
|
||||
fun getNearbyPoint(point: Point, params: PointerVarianceBounds = PointerVarianceBounds()): Point {
|
||||
// Generate random x and y offsets within the given variance bounds
|
||||
val xDelta = Random.nextInt(0, params.xVariance)
|
||||
val yDelta = Random.nextInt(0, params.yVariance)
|
||||
|
||||
// Determine x and y direction (-1 or 1) by a random Boolean
|
||||
val xDirection = if (Random.nextBoolean()) 1 else -1
|
||||
val yDirection = if (Random.nextBoolean()) 1 else -1
|
||||
|
||||
// Apply the offsets in their random directions to the x and y values of the reference point
|
||||
return Point(
|
||||
point.x + (xDelta * xDirection),
|
||||
point.y + (yDelta * yDirection)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Animates mouse movement from a start point to an end point over a duration.
|
||||
*
|
||||
* The movement will follow an approximation of a sigmoid velocity curve, accelerating
|
||||
* at the start and decelerating at the end.
|
||||
*
|
||||
* The path between start and end points will be varied randomly within the given
|
||||
* variance bounds each tick to simulate human imperfection.
|
||||
*
|
||||
* @param startPoint The starting mouse location
|
||||
* @param endPoint The ending mouse location
|
||||
* @param travelDurationMillis Total time in milliseconds for the movement
|
||||
* @param varianceBounds The max x and y variance each tick
|
||||
*/
|
||||
@Deprecated("Not finished. This will panic. You were warned.",
|
||||
ReplaceWith("TODO(\"Implement this once we figure out how to approximate sigmoid movement and timing\")")
|
||||
)
|
||||
fun animateMoveMouse(
|
||||
startPoint: Point,
|
||||
endPoint: Point,
|
||||
travelDurationMillis: Long,
|
||||
varianceBounds: PointerVarianceBounds = PointerVarianceBounds()
|
||||
) {
|
||||
//we're going to leave this as something to do, but this will remove the need to implement it everywhere
|
||||
TODO("Implement this once we figure out how to approximate sigmoid movement and timing")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Holds x and y variance bounds for random point generation.
|
||||
*
|
||||
* Used as parameter in [MousePointerObserver.getNearbyPoint] to control the allowed offset range.
|
||||
*
|
||||
* @see MousePointerObserver.getNearbyPoint()
|
||||
*/
|
||||
data class PointerVarianceBounds(
|
||||
val xVariance: Int = 25,
|
||||
val yVariance: Int = 25
|
||||
)
|
||||
|
||||
@ -18,97 +18,13 @@ interface MousePointerObserver {
|
||||
/**
|
||||
* Gets the current pointer/mouse location on the desktop.
|
||||
*
|
||||
* This returns a [Point] representing the x, y coordinates of the mouse pointer on the screen.
|
||||
*
|
||||
* For example:
|
||||
*
|
||||
* ```
|
||||
* val mouseLocation = getPointerLocation()
|
||||
*
|
||||
* println(mouseLocation) // Might print "Point[x=1920,y=1080]"
|
||||
* ```
|
||||
*
|
||||
* @return The current [Point] location of the mouse pointer on the screen.
|
||||
* @return The current [Point] representing the x, y coordinates of the mouse pointer on the screen.
|
||||
*/
|
||||
fun getPointerLocation(): Point {
|
||||
return MouseInfo.getPointerInfo().location
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets a point near the given [point], with some random wiggle.
|
||||
*
|
||||
* This generates a new point that is randomly offset from the given [point]
|
||||
* by an amount controlled by the given [MouseWiggleParams].
|
||||
*
|
||||
* Usage example:
|
||||
*
|
||||
* ```
|
||||
* val base = Point(10, 20)
|
||||
* val params = WiggleParams(xWiggle = 5, yWiggle = 5)
|
||||
* val randomPoint = getAlmostPoint(base, params)
|
||||
*
|
||||
* // randomPoint might be (8, 22)
|
||||
* ```
|
||||
*
|
||||
* Alternatively, params may be omitted to use the default WiggleParams values
|
||||
* ```
|
||||
* val base = Point(10, 20)
|
||||
* val randomPoint = getAlmostPoint(base)
|
||||
*
|
||||
* // randomPoint might be (8, 22)
|
||||
* ```
|
||||
*
|
||||
* @param point The base point to start from
|
||||
* @param params The wiggle parameters that control the random offset amount
|
||||
* @return A new [Point] near the given point with some random wiggle applied
|
||||
*/
|
||||
fun getAlmostPoint(point: Point, params: MouseWiggleParams = MouseWiggleParams()): Point {
|
||||
val xDel = Random.nextInt(0, params.xWiggle)
|
||||
val yDel = Random.nextInt(0, params.yWiggle)
|
||||
|
||||
//flip two coins, determine direction based on the parity of the results
|
||||
val xDir = if (Random.nextDouble() > 0.5) {
|
||||
1
|
||||
} else {
|
||||
-1
|
||||
}
|
||||
val yDir = if (Random.nextDouble() > 0.5) {
|
||||
1
|
||||
} else {
|
||||
-1
|
||||
}
|
||||
|
||||
return Point(point.x + (xDel * xDir), point.y + (yDel * yDir))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Data class to hold wiggle parameters for mouse movement.
|
||||
*
|
||||
* This simple data class holds two integer properties for x and y wiggle amounts.
|
||||
* These are used when generating simulated mouse movements to add some variance
|
||||
* and randomness to the coordinates.
|
||||
*
|
||||
* For example, if a target destination point is (100, 200), the wiggle params
|
||||
* might generate an actual movement point like (102, 198) to add some randomness.
|
||||
*
|
||||
* Usage:
|
||||
*
|
||||
* ```
|
||||
* val controller = DesktopController()
|
||||
* val wiggle = WiggleParams(xWiggle = 10, yWiggle = 15)
|
||||
*
|
||||
* val target = Point(100, 200)
|
||||
* val actual = controller.getAlmostPoint(target, wiggle) // (104, 197)
|
||||
* ```
|
||||
*
|
||||
* @param xWiggle The max amount of variance in x direction. Default 25.
|
||||
* @param yWiggle The max amount of variance in y direction. Default 25.
|
||||
*/
|
||||
data class MouseWiggleParams(
|
||||
val xWiggle: Int = 25,
|
||||
val yWiggle: Int = 25
|
||||
)
|
||||
|
||||
|
||||
@ -105,7 +105,7 @@ open class RobotAutomaton(internal val robot: Robot = Robot()) : Automaton {
|
||||
}
|
||||
|
||||
/**
|
||||
* Scrolls the mouse wheel down by one unit.
|
||||
* Scrolls the mouse wheel up by one unit.
|
||||
*
|
||||
* Uses the [Robot.mouseWheel] method to scroll down and then sleeps for a random duration between the given
|
||||
* sleepDurationMillis + rand(0, sleepDurationVarianceMillis) ms. This adds variance in scrolling speed.
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
package game_logic.runescape
|
||||
|
||||
import controllers.Automaton
|
||||
import controllers.MouseWiggleParams
|
||||
import controllers.PointerVarianceBounds
|
||||
import controllers.RobotAutomaton
|
||||
import params.StandingTaskParams
|
||||
import params.TravelTaskParams
|
||||
@ -86,7 +86,7 @@ class RSAgent(override val automaton: Automaton = RobotAutomaton()) : RSOrchestr
|
||||
taskParams: StandingTaskParams
|
||||
) {
|
||||
//open the bank located by the chest parameter
|
||||
moveMouseLeftClickAndSleep(automaton.getAlmostPoint(taskParams.bankPoint, MouseWiggleParams(10, 10)), 900, 400)
|
||||
moveMouseLeftClickAndSleep(automaton.getNearbyPoint(taskParams.bankPoint, PointerVarianceBounds(10, 10)), 900, 400)
|
||||
//withdraw the desired inventory preset
|
||||
automaton.keyPress(taskParams.bankPresetHotkey)
|
||||
//sleep for a server tick
|
||||
@ -131,7 +131,7 @@ class RSAgent(override val automaton: Automaton = RobotAutomaton()) : RSOrchestr
|
||||
) {
|
||||
//move to the bank and open the interface
|
||||
moveMouseLeftClickAndSleep(
|
||||
automaton.getAlmostPoint(taskParams.bankPoint, MouseWiggleParams(10, 10)),
|
||||
automaton.getNearbyPoint(taskParams.bankPoint, PointerVarianceBounds(10, 10)),
|
||||
taskParams.travelDurationMillis,
|
||||
taskParams.travelDurationVarianceMillis
|
||||
)
|
||||
|
||||
@ -5,7 +5,7 @@ import org.mockito.Mockito.`when`
|
||||
import java.awt.Point
|
||||
import java.awt.event.InputEvent
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertTrue
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
|
||||
class AutomatonTest {
|
||||
@ -20,26 +20,21 @@ class AutomatonTest {
|
||||
*/
|
||||
@Test
|
||||
fun `Automaton extends DesktopController`() {
|
||||
|
||||
val automaton = mock(Automaton::class.java)
|
||||
val automaton = mock(MousePointerObserver::class.java)
|
||||
|
||||
|
||||
// Given
|
||||
val basePoint = Point(10, 10)
|
||||
val wiggleParams = MouseWiggleParams(xWiggle = 5, yWiggle = 5)
|
||||
|
||||
|
||||
// When
|
||||
`when`(automaton.getAlmostPoint(basePoint, wiggleParams)).thenReturn(Point(12, 8))
|
||||
`when`(automaton.getPointerLocation()).thenReturn(Point(10, 10))
|
||||
|
||||
val result = automaton.getAlmostPoint(basePoint, wiggleParams)
|
||||
val result = automaton.getPointerLocation()
|
||||
|
||||
// Then
|
||||
assertTrue(result.x >= basePoint.x - wiggleParams.xWiggle)
|
||||
assertTrue(result.x <= basePoint.x + wiggleParams.xWiggle)
|
||||
|
||||
assertTrue(result.y >= basePoint.y - wiggleParams.yWiggle)
|
||||
assertTrue(result.y <= basePoint.y + wiggleParams.yWiggle)
|
||||
assertEquals(basePoint.x, result.x)
|
||||
assertEquals(basePoint.y, result.y)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -1,62 +0,0 @@
|
||||
package controllers
|
||||
|
||||
import kotlin.test.*
|
||||
import org.mockito.Mockito.*
|
||||
import java.awt.Point
|
||||
|
||||
|
||||
class DesktopControllerTest {
|
||||
|
||||
/**
|
||||
* Tests that getPointerLocation() returns the mocked mouse position.
|
||||
*
|
||||
* Creates a mock DesktopController instance.
|
||||
* Mocks the getPointerLocation() method to return a fixed point.
|
||||
* Calls getPointerLocation() on the mock controller.
|
||||
* Retrieves the returned point.
|
||||
* Asserts the x and y values match the mocked values.
|
||||
* This validates getPointerLocation() returns the expected mouse position.
|
||||
*/
|
||||
@Test
|
||||
fun `getPointerLocation returns mouse position`() {
|
||||
val controller = mock(MousePointerObserver::class.java)
|
||||
|
||||
// Mock mouse position
|
||||
`when`(controller.getPointerLocation()).thenReturn(Point(100, 200))
|
||||
|
||||
// Assert mouse position is returned
|
||||
val pos = controller.getPointerLocation()
|
||||
assertEquals(100, pos.x)
|
||||
assertEquals(200, pos.y)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Tests that getAlmostPoint() returns a wiggly point different than the source.
|
||||
*
|
||||
* Creates a mock DesktopController instance.
|
||||
* Creates a WiggleParams with x and y wiggle amounts.
|
||||
* Mocks getAlmostPoint() to return a fixed offset point based on the params.
|
||||
* Calls getAlmostPoint() with a source point and the wiggle params.
|
||||
* Retrieves the returned wiggly point.
|
||||
* Asserts the x and y values match the expected wiggly values.
|
||||
* Also asserts the x and y values are different than the source point.
|
||||
* This validates getAlmostPoint() returns a randomly offset point.
|
||||
*/
|
||||
@Test
|
||||
fun `getAlmostPoint returns wiggly point`() {
|
||||
val controller = mock(MousePointerObserver::class.java)
|
||||
val params = MouseWiggleParams(xWiggle = 10, yWiggle = 10)
|
||||
|
||||
// Mock random wiggle
|
||||
`when`(controller.getAlmostPoint(Point(100, 200), params))
|
||||
.thenReturn(Point(105, 205))
|
||||
|
||||
// Assert wiggly point
|
||||
val wiggly = controller.getAlmostPoint(Point(100, 200), params)
|
||||
assertEquals(105, wiggly.x)
|
||||
assertEquals(205, wiggly.y)
|
||||
assertNotEquals(100, wiggly.x)
|
||||
assertNotEquals(200, wiggly.y)
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user