RuneFactory/src/main/kotlin/game_logic/runescape/RSAgent.kt
2023-08-16 09:00:58 -04:00

174 lines
6.8 KiB
Kotlin

package game_logic.runescape
import controllers.Automaton
import controllers.PointerVarianceBounds
import controllers.RobotAutomaton
import params.StandingTaskParams
import params.TravelTaskParams
import java.awt.Point
import java.awt.event.KeyEvent
/**
* Implementation of [RSOrchestrator] using a [RobotAutomaton].
*
* This class handles executing RuneScape automation tasks by controlling
* the game client via image recognition and input emulation.
*
* Usage examples:
* Travel between bank and crafting station:
* ```
* val agent = RSAgent.getInstance()
* val travelParams = TravelTaskParams(...)
* agent.doTravelTask(agent, travelParams)
* ```
* Craft while standing at bank:
* ```
* val standingParams = StandingTaskParams(...)
* orchestrator.doStandingTask(agent, standingParams)
* ```
*
*
* @param automaton The [Automaton] instance used to control the game. Defaults to [RobotAutomaton].
*/
class RSAgent(override val automaton: Automaton = RobotAutomaton()) : RSOrchestrator {
companion object {
/**
* Extra padding in milliseconds added before actions to account for latency. 500ms is entirely arbitrary. It is
* simply a value that works well during high-load periods. Better to be conservative than lossy.
*
* This defines an extra duration in milliseconds that is added to sleeps
* and waits.
*
* It is to account for latency in the system before actions like mouse moves
* and clicks actually take effect.
*/
private const val LATENCY_PADDING_MS: Long = 500L
/**
* The duration in milliseconds of one "tick". The duration of 600ms matches the tick duration of game servers.
*
* This defines the concept of a "tick" as a unit of time used for pacing actions.
*
* It is used in methods like [sleepForNTicks] to calculate sleep durations
* based on multiplying a number of ticks by this value.
*
* For example, 5 ticks with this value would be 5 * 600 = 3000ms sleep duration.
*/
private const val TICK_DURATION_MS = 600L
}
/*==============================================================================================================
interface implementation
==============================================================================================================*/
/**
* Handles the crafting process when standing at the bank.
*
* This method takes care of the workflow when standing at the bank:
* - Opens the bank interface by left-clicking near the provided bank point location.
* - Withdraws the desired inventory preset using the provided hotkey.
* - Opens the crafting interface using the provided crafting dialogue hotkey.
* - Clicks the default "Accept" hotkey to start crafting.
* - Waits for the specified crafting duration plus random variance.
*
* @param taskParams The [StandingTaskParams] configuring the task details like bank location, hotkeys, and durations.
*/
override fun processAtBank(
taskParams: StandingTaskParams
) {
//open the bank located by the chest parameter
moveMouseLeftClickAndSleep(automaton.getNearbyPoint(taskParams.bankPoint, PointerVarianceBounds(10, 10)), 900, 400)
//withdraw the desired inventory preset
automaton.keyPress(taskParams.bankPresetHotkey)
//sleep for a server tick
sleepForNTicks(1)
//open the crafting dialog with the correct hotkey
automaton.keyPress(taskParams.craftingDialogHotkey)
//sleep for a server tick
sleepForNTicks(1)
//press the "accept" default hotkey
automaton.keyPress(KeyEvent.VK_SPACE)
//wait for the desired time to finish
automaton.sleep(taskParams.craftingWaitDurationMillis, taskParams.craftingWaitDurationVarianceMillis)
}
/**
* Handles the crafting process when at a station near the bank.
*
* This method orchestrates the workflow when at the crafting station:
*
* - Travels from the bank to the station by left-clicking near the bank point.
* - Waits for the randomized travel duration.
*
* - Withdraws the desired inventory preset using the provided hotkey.
*
* - Travels to the crafting station by left-clicking the station point.
* - Waits for the randomized travel duration.
*
* - Opens the crafting interface using the provided hotkey.
*
* - Waits for the randomized crafting duration.
*
* @param taskParams The [TravelTaskParams] configuring the task details.
*/
override fun processAtStationNearBank(
taskParams: TravelTaskParams
) {
//move to the bank and open the interface
moveMouseLeftClickAndSleep(
automaton.getNearbyPoint(taskParams.bankPoint, PointerVarianceBounds(10, 10)),
taskParams.travelDurationMillis,
taskParams.travelDurationVarianceMillis
)
//withdraw desired loadout
automaton.keyPress(taskParams.bankPresetHotkey)
sleepForNTicks(1)
//move to station and open the crafting dialog
moveMouseLeftClickAndSleep(taskParams.travelPoint, taskParams.travelDurationMillis, taskParams.travelDurationVarianceMillis)
//start the crafting task
automaton.keyPress(KeyEvent.VK_SPACE)
//wait for it to complete
automaton.sleep(taskParams.craftingWaitDurationMillis, taskParams.craftingWaitDurationVarianceMillis)
}
/*==============================================================================================================
cheater functions
==============================================================================================================*/
/**
* Prompts the user to position the mouse and returns that position.
*
* This method prints a prompt message, then waits for the user to position
* the mouse.
*
* It then returns the current mouse position as a Point after a slight delay.
*
* @return The Point position of the mouse after user positions it.
*/
override fun getBankPoint(): Point {
return promptUserForPoint("Hold your mouse over the bank...")
}
/**
* Sleeps for a specified number of game ticks.
*
* A brief random variance is also added to the sleep duration to add some less-robotic behavior.
*
* @param n The number of game ticks to sleep for.
* @see TICK_DURATION_MS
*/
override fun sleepForNTicks(n: Long) {
val latencyPadding = LATENCY_PADDING_MS
val baseWaitTime = n * TICK_DURATION_MS
automaton.sleep(latencyPadding + baseWaitTime, 150)
}
}