Compare commits
2 Commits
8e28448428
...
234adbf9b5
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
234adbf9b5 | ||
|
|
2cb6d3aed3 |
@ -1,431 +0,0 @@
|
|||||||
import java.awt.Point
|
|
||||||
import java.awt.event.InputEvent
|
|
||||||
import java.awt.event.KeyEvent
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Agent handles lower level actions like banking, navigation, and timing
|
|
||||||
* to support automation routines.
|
|
||||||
*
|
|
||||||
* This provides a common set of primitive actions that can be used across
|
|
||||||
* different automation workflows. Routines build on top of these actions.
|
|
||||||
*
|
|
||||||
* The agent handles things like:
|
|
||||||
* - Bank interaction (presets, deposits, withdrawals)
|
|
||||||
* - Navigation points and travel
|
|
||||||
* - Timing actions with randomness
|
|
||||||
* - Progress reporting and logging
|
|
||||||
*
|
|
||||||
* By encapsulating these common actions, routines can focus on their
|
|
||||||
* specific workflow logic and leverage the agent for the lower level
|
|
||||||
* activities needed to craft, cook, etc.
|
|
||||||
*/
|
|
||||||
class Agent(val controller: Automaton = RobotController()) {
|
|
||||||
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.
|
|
||||||
*/
|
|
||||||
const val LATENCY_PADDING_MS = 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.
|
|
||||||
*/
|
|
||||||
const val TICK_DURATION_MS = 600L
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Performs a standing crafting task loop for the agent.
|
|
||||||
*
|
|
||||||
* The agent will repeatedly go to the bank, withdraw items,
|
|
||||||
* open the crafting interface, craft items, close it,
|
|
||||||
* and deposit items back until the total volume is reached.
|
|
||||||
*
|
|
||||||
* @param params the parameters configuring how to perform the standing task
|
|
||||||
*/
|
|
||||||
fun doStandingTask(params: StandingTaskParams) {
|
|
||||||
val agent = params.agent
|
|
||||||
agent.doLoop(params.totalVolume, params.volumePerStep) {
|
|
||||||
agent.bankStandForLoop(
|
|
||||||
params.bankPoint,
|
|
||||||
params.bankPresetHotkey,
|
|
||||||
params.craftingDialogHotkey,
|
|
||||||
params.craftingWaitDurationMillis,
|
|
||||||
params.craftingWaitDurationVarianceMillis
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Performs a looped travel task for the agent.
|
|
||||||
*
|
|
||||||
* This handles having the agent repeatedly travel from the bank
|
|
||||||
* to a station, process items, and travel back.
|
|
||||||
*
|
|
||||||
* @param params the parameters configuring how to perform the task
|
|
||||||
*/
|
|
||||||
fun doTravelTask(params: TravelTaskParams) {
|
|
||||||
val agent = params.agent
|
|
||||||
agent.doLoop(params.totalVolume, params.volumePerStep) {
|
|
||||||
agent.processAtStationNearBank(
|
|
||||||
params.bankPoint,
|
|
||||||
params.travelPoint,
|
|
||||||
params.bankPresetHotkey,
|
|
||||||
params.travelDurationMillis,
|
|
||||||
params.travelDurationVarianceMillis,
|
|
||||||
params.craftingWaitDurationMillis,
|
|
||||||
params.craftingWaitDurationVarianceMillis
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Computes the total number of steps needed to process the given total volume.
|
|
||||||
*
|
|
||||||
* @param totalVolume the total amount that needs to be processed
|
|
||||||
* @param volumePerStep the amount to process per step
|
|
||||||
* @return the number of steps required to process the total volume
|
|
||||||
*/
|
|
||||||
private fun computeTotalSteps(totalVolume: Int, volumePerStep: Int) =
|
|
||||||
totalVolume / volumePerStep + if (totalVolume % volumePerStep > 0) {
|
|
||||||
1
|
|
||||||
} else {
|
|
||||||
0
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Performs a loop to repeatedly execute a task for automated steps.
|
|
||||||
*
|
|
||||||
* @param totalVolume The total number of units to process across all steps.
|
|
||||||
* @param volumePerStep The number of units to process per step.
|
|
||||||
* @param task The task function to execute on each step. It receives the Agent.
|
|
||||||
*
|
|
||||||
* This method handles iterating through the steps, reporting progress,
|
|
||||||
* timing the overall execution, and calling the task on each iteration.
|
|
||||||
*
|
|
||||||
* It uses computeTotalSteps to calculate how many iterations needed based on total
|
|
||||||
* and per step volumes. The task typically simulates some action like banking.
|
|
||||||
*/
|
|
||||||
fun doLoop(totalVolume: Int, volumePerStep: Int, task: (Agent) -> Unit) {
|
|
||||||
require(totalVolume > 0) {
|
|
||||||
"You must make at least 1 thing in total"
|
|
||||||
}
|
|
||||||
require(volumePerStep > 0) {
|
|
||||||
"You must consume at least 1 thing per step"
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
val totalSteps = computeTotalSteps(totalVolume, volumePerStep)
|
|
||||||
|
|
||||||
val start = System.currentTimeMillis()
|
|
||||||
for (i in 0 until totalSteps) {
|
|
||||||
report(i + 1, totalSteps, System.currentTimeMillis() - start)
|
|
||||||
task(this)
|
|
||||||
}
|
|
||||||
println()
|
|
||||||
val finish = System.currentTimeMillis()
|
|
||||||
println("Finished everything in ${prettyTimeString(finish - start)}")
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Prints a progress report for the current step.
|
|
||||||
*
|
|
||||||
* @param step The current step number.
|
|
||||||
* @param of The total number of steps.
|
|
||||||
* @param dur The duration in milliseconds so far.
|
|
||||||
*
|
|
||||||
* This method prints a progress report to the console in the format:
|
|
||||||
* "Step {step} of {of} ({formattedDuration} complete | ~{remainingTime} remaining)"
|
|
||||||
*
|
|
||||||
* It calculates the estimated remaining time based on the current duration and
|
|
||||||
* number of steps completed vs total steps.
|
|
||||||
*
|
|
||||||
* The output is printed on the same line to dynamically update the progress.
|
|
||||||
*/
|
|
||||||
fun report(step: Int, of: Int, dur: Long) {
|
|
||||||
val remaining = (dur / step) * (of - step)
|
|
||||||
print("\rStep $step of $of (${prettyTimeString(dur)} complete\t|\t~${prettyTimeString(remaining)} remaining) ")
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Formats the given duration in milliseconds into a human readable time string.
|
|
||||||
*
|
|
||||||
* @param durationMillis The duration to format in milliseconds.
|
|
||||||
*
|
|
||||||
* @return A formatted time string showing the duration broken down into hours, minutes, and seconds.
|
|
||||||
*
|
|
||||||
* This converts the duration into hours, minutes, and seconds based on millis per second,
|
|
||||||
* minute, and hour constants. It returns a string in the format "XhYmZs" where X, Y, and Z are
|
|
||||||
* the calculated hours, minutes, and seconds.
|
|
||||||
*
|
|
||||||
* If durationMillis is 0, it returns "No time data yet" instead.
|
|
||||||
*/
|
|
||||||
fun prettyTimeString(durationMillis: Long): String {
|
|
||||||
if (durationMillis == 0L) {
|
|
||||||
return "No time data yet"
|
|
||||||
}
|
|
||||||
val millisPerSecond = 1000L
|
|
||||||
val millisPerMinute = 60L * millisPerSecond
|
|
||||||
val millisPerHour = 60L * millisPerMinute
|
|
||||||
return if (durationMillis > millisPerHour) {
|
|
||||||
return "${durationMillis / millisPerHour}h${(durationMillis % millisPerHour) / millisPerMinute}m${(durationMillis % millisPerMinute) / millisPerSecond}s"
|
|
||||||
} else if (durationMillis > millisPerMinute) {
|
|
||||||
return "${(durationMillis % millisPerHour) / millisPerMinute}m${(durationMillis % millisPerMinute) / millisPerSecond}s"
|
|
||||||
} else {
|
|
||||||
"${(durationMillis % millisPerMinute) / millisPerSecond}s"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Prompts the user to position the mouse pointer and returns the pointer location.
|
|
||||||
*
|
|
||||||
* @param prompt The message to display to the user as a prompt.
|
|
||||||
*
|
|
||||||
* @return The Point containing the mouse pointer location after prompting.
|
|
||||||
*
|
|
||||||
* This first prints the prompt message to the console.
|
|
||||||
* It then uses the Doer to count down from 5 seconds while printing a countdown.
|
|
||||||
* After the countdown, it gets the current mouse pointer location using the Doer
|
|
||||||
* and returns the Point.
|
|
||||||
*
|
|
||||||
* This allows prompting the user to move the mouse before taking a snapshot of the pointer position.
|
|
||||||
*/
|
|
||||||
fun promptUserForPoint(prompt: String): Point {
|
|
||||||
println(prompt)
|
|
||||||
countDown(5) {
|
|
||||||
print("\rtaking point snapshot in $it... ")
|
|
||||||
if (it == 0) {
|
|
||||||
println("\r ")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return controller.getPointerLocation()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Scrolls out to the specified height by scrolling in and then back out.
|
|
||||||
*
|
|
||||||
* @param height The height in pixels to scroll out to.
|
|
||||||
* @param scrollWaitAndVariance The number of milliseconds to wait between scroll steps. Defaults to 16.
|
|
||||||
*
|
|
||||||
* This method first sleeps for 1 second. It then scrolls in by the height amount
|
|
||||||
* using repeated small scroll in steps.
|
|
||||||
*
|
|
||||||
* After scrolling in fully, it then scrolls back out using a few repeated small scroll outs.
|
|
||||||
*
|
|
||||||
* This allows smoothly animating the scroll all the way in and then back out to a specific height
|
|
||||||
*
|
|
||||||
* The scrollWaitAndVariance controls the pacing between scroll steps. The default of 16ms provides
|
|
||||||
* a reasonable scroll animation speed.
|
|
||||||
*/
|
|
||||||
fun scrollOutToHeight(height: Int, scrollWaitAndVariance: Long = 10L) {
|
|
||||||
controller.sleep(1000)
|
|
||||||
|
|
||||||
for (i in 0 until height * 2) {
|
|
||||||
controller.scrollIn(scrollWaitAndVariance, scrollWaitAndVariance)
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i in 0 until height) {
|
|
||||||
controller.scrollOut(scrollWaitAndVariance, scrollWaitAndVariance)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Performs automated banking steps in a loop at the given chest location.
|
|
||||||
*
|
|
||||||
* @param chest The Point location of the bank chest to click on.
|
|
||||||
* @param bankPresetHotkey The key for the inventory preset to withdraw.
|
|
||||||
* @param craftingDialogueHotkey The key for the crafting preset to open.
|
|
||||||
* @param waitDurationMillis The time in ms to wait at each loop iteration.
|
|
||||||
* @param waitDurationVariance Random variance to add to wait time.
|
|
||||||
*
|
|
||||||
* This handles the steps to open the bank interface, withdraw a preset,
|
|
||||||
* open a crafting interface, and wait for the desired duration.
|
|
||||||
*
|
|
||||||
* It clicks the bank chest, presses the inventory hotkey, presses the crafting hotkey,
|
|
||||||
* presses spacebar to accept, and waits before repeating.
|
|
||||||
*
|
|
||||||
* Useful for automated banking behaviors like crafting or herblore.
|
|
||||||
*/
|
|
||||||
private fun bankStandForLoop(
|
|
||||||
chest: Point,
|
|
||||||
bankPresetHotkey: Int,
|
|
||||||
craftingDialogueHotkey: Int,
|
|
||||||
waitDurationMillis: Long,
|
|
||||||
waitDurationVariance: Long
|
|
||||||
) {
|
|
||||||
//open the bank located by the chest parameter
|
|
||||||
moveMouseLeftClickAndSleep(controller.getAlmostPoint(chest, WiggleParams()), 900, 400)
|
|
||||||
//withdraw the desired inventory preset
|
|
||||||
controller.keyPress(bankPresetHotkey)
|
|
||||||
//sleep for a server tick
|
|
||||||
sleepForNTicks(1)
|
|
||||||
//open the crafting dialog with the correct hotkey
|
|
||||||
controller.keyPress(craftingDialogueHotkey)
|
|
||||||
//sleep for a server tick
|
|
||||||
sleepForNTicks(1)
|
|
||||||
//press the "accept" default hotkey
|
|
||||||
controller.keyPress(KeyEvent.VK_SPACE)
|
|
||||||
//wait for the desired time to finish
|
|
||||||
controller.sleepWithVariance(waitDurationMillis, waitDurationVariance)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Performs banking actions at a bank without additional dialog prompts.
|
|
||||||
*
|
|
||||||
* @param chest The Point location of the bank chest or stand to interact with.
|
|
||||||
* @param invKey The key code for the inventory preset hotkey to withdraw.
|
|
||||||
* @param hotKey The key code for the action hotkey, like crafting.
|
|
||||||
*
|
|
||||||
* This method handles clicking the chest, withdrawing a preset inventory,
|
|
||||||
* and activating a process like crafting that doesn't require additional prompts.
|
|
||||||
*
|
|
||||||
* It clicks the chest location, presses the inventory preset hotkey, waits briefly,
|
|
||||||
* then presses the action hotkey like crafting. This allows automated crafting at the bank.
|
|
||||||
*
|
|
||||||
* The sleeps provide a brief pause between actions to allow animations.
|
|
||||||
*/
|
|
||||||
fun bankStandWithoutDialog(chest: Point, invKey: Int, hotKey: Int) {
|
|
||||||
//open the bank located by the chest parameter
|
|
||||||
moveMouseLeftClickAndSleep(controller.getAlmostPoint(chest, WiggleParams()), 900, 400)
|
|
||||||
//withdraw the desired inventory preset
|
|
||||||
controller.keyPress(invKey)
|
|
||||||
|
|
||||||
sleepForNTicks(1)
|
|
||||||
|
|
||||||
//press the hotkey that causes action without dialogue
|
|
||||||
controller.keyPress(hotKey)
|
|
||||||
|
|
||||||
sleepForNTicks(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Performs processing steps between a bank and nearby crafting station.
|
|
||||||
*
|
|
||||||
* @param chest The Point location of the bank chest.
|
|
||||||
* @param station The Point location of the processing station.
|
|
||||||
* @param bankPresetHotkey The inventory preset hotkey to withdraw at bank.
|
|
||||||
* @param travelDurationMillis Base travel time between bank and station.
|
|
||||||
* @param travelDurationVarianceMillis Random variance to add to travel time.
|
|
||||||
* @param waitDurationMillis Base wait time for processing at station.
|
|
||||||
* @param waitDurationVarianceMillis Random variance to add to wait time.
|
|
||||||
*
|
|
||||||
* This handles the steps to go to the bank, withdraw a preset, go to the station,
|
|
||||||
* open the processing interface, wait, and then loop.
|
|
||||||
*
|
|
||||||
* It goes between the bank and station locations, simulating travel time.
|
|
||||||
* At the bank it withdraws using the preset hotkey.
|
|
||||||
* At the station it activates processing and waits.
|
|
||||||
*/
|
|
||||||
fun processAtStationNearBank(
|
|
||||||
chest: Point,
|
|
||||||
station: Point,
|
|
||||||
bankPresetHotkey: Int,
|
|
||||||
travelDurationMillis: Long,
|
|
||||||
travelDurationVarianceMillis: Long,
|
|
||||||
waitDurationMillis: Long,
|
|
||||||
waitDurationVarianceMillis: Long
|
|
||||||
) {
|
|
||||||
//move to the bank and open the interface
|
|
||||||
moveMouseLeftClickAndSleep(
|
|
||||||
controller.getAlmostPoint(chest, WiggleParams()),
|
|
||||||
travelDurationMillis,
|
|
||||||
travelDurationVarianceMillis
|
|
||||||
)
|
|
||||||
|
|
||||||
//withdraw desired loadout
|
|
||||||
controller.keyPress(bankPresetHotkey)
|
|
||||||
sleepForNTicks(1)
|
|
||||||
|
|
||||||
//move to station and open the crafting dialog
|
|
||||||
moveMouseLeftClickAndSleep(station, travelDurationMillis, travelDurationVarianceMillis)
|
|
||||||
|
|
||||||
//start the crafting task
|
|
||||||
controller.keyPress(KeyEvent.VK_SPACE)
|
|
||||||
|
|
||||||
//wait for it to complete
|
|
||||||
controller.sleepWithVariance(waitDurationMillis, waitDurationVarianceMillis)
|
|
||||||
}
|
|
||||||
|
|
||||||
/*==============================================================================================================
|
|
||||||
cheater functions
|
|
||||||
==============================================================================================================*/
|
|
||||||
|
|
||||||
|
|
||||||
fun getBankPoint(): Point {
|
|
||||||
return promptUserForPoint("Hold your mouse over the bank...")
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
fun countDown(nSeconds: Int, announceFn: (step: Int) -> Unit) {
|
|
||||||
for (i in nSeconds downTo 0) {
|
|
||||||
announceFn(i)
|
|
||||||
controller.sleep(1000)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getPointerLocationAfter(delayInSeconds: Int): Point {
|
|
||||||
countDown(delayInSeconds) {
|
|
||||||
print("\rtaking pointer snapshot in $it...")
|
|
||||||
if (it == 0) {
|
|
||||||
println("\r ")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return controller.getPointerLocation()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getPointerLocationAsValDeclarationString(varName: String): String {
|
|
||||||
val info = getPointerLocationAfter(5)
|
|
||||||
return "val $varName = Point(${info.x}, ${info.y})"
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
fun moveMouseLeftClickAndSleep(p: Point, dur: Long, durRange: Long) {
|
|
||||||
controller.moveMouse(p)
|
|
||||||
controller.sleepWithVariance(100, 50)
|
|
||||||
//left click
|
|
||||||
controller.mouseClick(InputEvent.BUTTON1_DOWN_MASK)
|
|
||||||
controller.sleepWithVariance(dur, durRange)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun sleepForNTicks(n: Long) {
|
|
||||||
val latencyPadding = LATENCY_PADDING_MS
|
|
||||||
val baseWaitTime = n * TICK_DURATION_MS
|
|
||||||
controller.sleepWithVariance(latencyPadding + baseWaitTime, 150)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
fun drawStar(p: Point) {
|
|
||||||
val offset = 100
|
|
||||||
val top = Point(p.x, p.y - offset * 2)
|
|
||||||
val topright = Point(p.x + offset * 2, p.y + offset)
|
|
||||||
val bottomright = Point(p.x + offset * 2, p.y)
|
|
||||||
val topleft = Point(p.x - offset * 2, p.y + offset)
|
|
||||||
val bottomleft = Point(p.x - offset * 2, p.y)
|
|
||||||
val points = arrayListOf(top, bottomleft, topright, topleft, bottomright)
|
|
||||||
for (i in 0 until 10) {
|
|
||||||
for (point in points) {
|
|
||||||
controller.moveMouse(point)
|
|
||||||
controller.sleep(32)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -60,7 +60,7 @@ interface InputController {
|
|||||||
fun scrollOut(sleepDur: Long, sleepDurVariance: Long)
|
fun scrollOut(sleepDur: Long, sleepDurVariance: Long)
|
||||||
}
|
}
|
||||||
|
|
||||||
interface TemporalController{
|
interface TemporalController {
|
||||||
/**
|
/**
|
||||||
* Sleeps for the specified duration.
|
* Sleeps for the specified duration.
|
||||||
*
|
*
|
||||||
@ -128,7 +128,7 @@ interface DesktopController {
|
|||||||
* @param params The wiggle parameters
|
* @param params The wiggle parameters
|
||||||
* @return A new [Point] randomly offset from the target point.
|
* @return A new [Point] randomly offset from the target point.
|
||||||
*/
|
*/
|
||||||
fun getAlmostPoint(point: Point, params : WiggleParams): Point{
|
fun getAlmostPoint(point: Point, params: WiggleParams): Point {
|
||||||
val xDel = Random.nextInt(0, params.xWiggle)
|
val xDel = Random.nextInt(0, params.xWiggle)
|
||||||
val yDel = Random.nextInt(0, params.yWiggle)
|
val yDel = Random.nextInt(0, params.yWiggle)
|
||||||
val xDir = if (Random.nextDouble() > 0.5) {
|
val xDir = if (Random.nextDouble() > 0.5) {
|
||||||
@ -146,17 +146,26 @@ interface DesktopController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Interface for controllers that provide desktop input capabilities.
|
* Interface for full-featured desktop automation controllers.
|
||||||
*
|
*
|
||||||
* This interface extends [DesktopController], [InputController], and
|
* Automaton combines capabilities from other interfaces to create a controller that can:
|
||||||
* [TemporalController] to create a combined interface that can:
|
|
||||||
*
|
*
|
||||||
* - Get desktop/mouse info like pointer location
|
* - Get desktop and mouse state information like pointer location via [DesktopController]
|
||||||
* - Perform mouse and keyboard input like clicks and key presses
|
|
||||||
* - Control timing and add delays
|
|
||||||
*
|
*
|
||||||
* Classes that implement this interface can serve as full featured
|
* - Perform mouse and keyboard input like clicks, key presses, and scrolling via [InputController]
|
||||||
* controllers for desktop automation tasks.
|
*
|
||||||
|
* - Handle timing and delays between actions using [TemporalController]
|
||||||
|
*
|
||||||
|
* By composing multiple capabilities, Automaton aims to provide a simple yet powerful interface for implementing
|
||||||
|
* desktop automation routines.
|
||||||
|
*
|
||||||
|
* Typical usage involves:
|
||||||
|
*
|
||||||
|
* 1. Obtaining an Automaton instance bound to the current OS/desktop
|
||||||
|
* 2. Calling methods like [moveMouse] and [mouseClick] to perform actions
|
||||||
|
* 3. Using [sleep] and [sleepWithVariance] to add delays
|
||||||
|
*
|
||||||
|
* This interface allows the underlying OS/desktop implementation details to be abstracted and swapped as needed.
|
||||||
*/
|
*/
|
||||||
interface Automaton : DesktopController, InputController, TemporalController
|
interface Automaton : DesktopController, InputController, TemporalController
|
||||||
|
|
||||||
66
src/main/kotlin/HelperFunctions.kt
Normal file
66
src/main/kotlin/HelperFunctions.kt
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
object HelperFunctions {
|
||||||
|
/**
|
||||||
|
* Computes the total number of steps needed to process the given total volume.
|
||||||
|
*
|
||||||
|
* @param totalVolume the total amount that needs to be processed
|
||||||
|
* @param volumePerStep the amount to process per step
|
||||||
|
* @return the number of steps required to process the total volume
|
||||||
|
*/
|
||||||
|
fun calculateTotalSteps(totalVolume: Int, volumePerStep: Int) =
|
||||||
|
totalVolume / volumePerStep + if (totalVolume % volumePerStep > 0) {
|
||||||
|
1
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prints a progress report for the current step.
|
||||||
|
*
|
||||||
|
* @param step The current step number.
|
||||||
|
* @param of The total number of steps.
|
||||||
|
* @param dur The duration in milliseconds so far.
|
||||||
|
*
|
||||||
|
* This method prints a progress report to the console in the format:
|
||||||
|
* "Step {step} of {of} ({formattedDuration} complete | ~{remainingTime} remaining)"
|
||||||
|
*
|
||||||
|
* It calculates the estimated remaining time based on the current duration and
|
||||||
|
* number of steps completed vs total steps.
|
||||||
|
*
|
||||||
|
* The output is printed on the same line to dynamically update the progress.
|
||||||
|
*/
|
||||||
|
fun report(step: Int, of: Int, dur: Long) {
|
||||||
|
val remaining = (dur / step) * (of - step)
|
||||||
|
print("\rStep $step of $of (${prettyTimeString(dur)} complete\t|\t~${prettyTimeString(remaining)} remaining) ")
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Formats the given duration in milliseconds into a human readable time string.
|
||||||
|
*
|
||||||
|
* @param durationMillis The duration to format in milliseconds.
|
||||||
|
*
|
||||||
|
* @return A formatted time string showing the duration broken down into hours, minutes, and seconds.
|
||||||
|
*
|
||||||
|
* This converts the duration into hours, minutes, and seconds based on millis per second,
|
||||||
|
* minute, and hour constants. It returns a string in the format "XhYmZs" where X, Y, and Z are
|
||||||
|
* the calculated hours, minutes, and seconds.
|
||||||
|
*
|
||||||
|
* If durationMillis is 0, it returns "No time data yet" instead.
|
||||||
|
*/
|
||||||
|
fun prettyTimeString(durationMillis: Long): String {
|
||||||
|
if (durationMillis == 0L) {
|
||||||
|
return "No time data yet"
|
||||||
|
}
|
||||||
|
val millisPerSecond = 1000L
|
||||||
|
val millisPerMinute = 60L * millisPerSecond
|
||||||
|
val millisPerHour = 60L * millisPerMinute
|
||||||
|
return if (durationMillis > millisPerHour) {
|
||||||
|
return "${durationMillis / millisPerHour}h${(durationMillis % millisPerHour) / millisPerMinute}m${(durationMillis % millisPerMinute) / millisPerSecond}s"
|
||||||
|
} else if (durationMillis > millisPerMinute) {
|
||||||
|
return "${(durationMillis % millisPerHour) / millisPerMinute}m${(durationMillis % millisPerMinute) / millisPerSecond}s"
|
||||||
|
} else {
|
||||||
|
"${(durationMillis % millisPerMinute) / millisPerSecond}s"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
58
src/main/kotlin/Orchestrator.kt
Normal file
58
src/main/kotlin/Orchestrator.kt
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
import java.awt.Point
|
||||||
|
|
||||||
|
interface Orchestrator {
|
||||||
|
|
||||||
|
val automaton: Automaton
|
||||||
|
|
||||||
|
fun scrollOutToHeight(height: Int, scrollWaitAndVariance: Long = 10L) {
|
||||||
|
automaton.sleep(1000)
|
||||||
|
doLoop(height * 2, 1) {
|
||||||
|
automaton.scrollIn(scrollWaitAndVariance, scrollWaitAndVariance)
|
||||||
|
}
|
||||||
|
|
||||||
|
doLoop(height, 1){
|
||||||
|
automaton.scrollOut(scrollWaitAndVariance, scrollWaitAndVariance)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Performs a loop to repeatedly execute a task for automated steps.
|
||||||
|
*
|
||||||
|
* @param totalVolume The total number of units to process across all steps.
|
||||||
|
* @param volumePerStep The number of units to process per step.
|
||||||
|
* @param task The task function to execute on each step. It receives the Agent.
|
||||||
|
*
|
||||||
|
* This method handles iterating through the steps, reporting progress,
|
||||||
|
* timing the overall execution, and calling the task on each iteration.
|
||||||
|
*
|
||||||
|
* It uses computeTotalSteps to calculate how many iterations needed based on total
|
||||||
|
* and per step volumes. The task typically simulates some action like banking.
|
||||||
|
*/
|
||||||
|
fun doLoop(totalVolume: Int, volumePerStep: Int, task: (Orchestrator) -> Unit) {
|
||||||
|
require(totalVolume > 0) {
|
||||||
|
"You must make at least 1 thing in total"
|
||||||
|
}
|
||||||
|
require(volumePerStep > 0) {
|
||||||
|
"You must consume at least 1 thing per step"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
val totalSteps = HelperFunctions.calculateTotalSteps(totalVolume, volumePerStep)
|
||||||
|
|
||||||
|
val start = System.currentTimeMillis()
|
||||||
|
for (i in 0 until totalSteps) {
|
||||||
|
HelperFunctions.report(i + 1, totalSteps, System.currentTimeMillis() - start)
|
||||||
|
task(this)
|
||||||
|
}
|
||||||
|
println()
|
||||||
|
val finish = System.currentTimeMillis()
|
||||||
|
println("Finished everything in ${HelperFunctions.prettyTimeString(finish - start)}")
|
||||||
|
}
|
||||||
|
|
||||||
|
fun promptUserForPoint(prompt: String): Point
|
||||||
|
|
||||||
|
fun drawStar(p: Point)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
322
src/main/kotlin/RSLogic.kt
Normal file
322
src/main/kotlin/RSLogic.kt
Normal file
@ -0,0 +1,322 @@
|
|||||||
|
import java.awt.Point
|
||||||
|
import java.awt.event.InputEvent
|
||||||
|
import java.awt.event.KeyEvent
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface for coordinating RuneScape automation routines.
|
||||||
|
*
|
||||||
|
* This interface provides methods for common in-game workflows like:
|
||||||
|
*
|
||||||
|
* - Processing actions at the bank chest
|
||||||
|
* - Traveling between bank and crafting station
|
||||||
|
* - Bank standing without dialogue boxes
|
||||||
|
*
|
||||||
|
* Implementations would integrate with a desktop automation library
|
||||||
|
* to actually perform the in-game clicks and inputs.
|
||||||
|
*
|
||||||
|
* This interface allows the game-specific logic to be separated from
|
||||||
|
* the underlying automation library.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
interface RSCoordinator {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform actions at the bank chest.
|
||||||
|
*
|
||||||
|
* This typically involves:
|
||||||
|
* 1. Clicking the chest to open bank interface
|
||||||
|
* 2. Pressing preset hotkey to withdraw items
|
||||||
|
* 3. Pressing crafting hotkey to start crafting workflow
|
||||||
|
* 4. Waiting for crafting duration
|
||||||
|
*
|
||||||
|
* @param bankPoint Point location of bank chest to click
|
||||||
|
* @param bankPresetHotkey Key code for bank preset withdraw action
|
||||||
|
* @param craftingDialogueHotkey Key code to select crafting dialogue
|
||||||
|
* @param waitDurationMillis Duration in ms to wait during crafting
|
||||||
|
* @param waitDurationVariance Allowed variance in wait duration
|
||||||
|
*/
|
||||||
|
fun processAtBank(
|
||||||
|
bankPoint: Point,
|
||||||
|
bankPresetHotkey: Int,
|
||||||
|
craftingDialogueHotkey: Int,
|
||||||
|
waitDurationMillis: Long,
|
||||||
|
waitDurationVariance: Long
|
||||||
|
)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform actions between bank and nearby station.
|
||||||
|
*
|
||||||
|
* This involves:
|
||||||
|
* 1. Traveling from bankPoint to stationPoint
|
||||||
|
* 2. Clicking station to open interface
|
||||||
|
* 3. Pressing dialogue key to start crafting
|
||||||
|
* 4. Waiting for crafting duration
|
||||||
|
* 5. Waiting for crafting duration
|
||||||
|
*
|
||||||
|
* @param bankPoint Point location of bank
|
||||||
|
* @param craftingStationPoint Point location of crafting station
|
||||||
|
* @param bankPresetHotkey Key code to withdraw items
|
||||||
|
* @param travelDurationMillis Time in ms to travel between points
|
||||||
|
* @param travelDurationVariance Allowed variance in travel time
|
||||||
|
* @param waitDurationMillis Crafting duration
|
||||||
|
* @param waitDurationVariance Variance in crafting duration
|
||||||
|
*/
|
||||||
|
fun processAtStationNearBank(
|
||||||
|
bankPoint: Point,
|
||||||
|
craftingStationPoint: Point,
|
||||||
|
bankPresetHotkey: Int,
|
||||||
|
travelDurationMillis: Long,
|
||||||
|
travelDurationVarianceMillis: Long,
|
||||||
|
waitDurationMillis: Long,
|
||||||
|
waitDurationVarianceMillis: Long
|
||||||
|
)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform bank standing without random events.
|
||||||
|
*
|
||||||
|
* This involves:
|
||||||
|
* 1. Clicking the bank chest at bankPoint
|
||||||
|
* 2. Pressing inventoryHotKey to load an inventory preset
|
||||||
|
* 3. Pressing actionBarHotKey to perform an action
|
||||||
|
*
|
||||||
|
* @param bankPoint Location of bank chest
|
||||||
|
* @param inventoryHotKey Key code to clear inventory
|
||||||
|
* @param actionBarHotKey Key code to clear action bar
|
||||||
|
*/
|
||||||
|
fun bankStandWithoutDialog(bankPoint: Point, inventoryHotKey: Int, actionBarHotKey: Int)
|
||||||
|
|
||||||
|
fun getBankPoint(): Point
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface for orchestrating and coordinating RuneScape automation routines.
|
||||||
|
*
|
||||||
|
* This interface combines the orchestration capabilities from [Orchestrator]
|
||||||
|
* and the RuneScape coordination capabilities from [RSCoordinator].
|
||||||
|
*
|
||||||
|
* An implementation would use the orchestration methods like [doLoop] to
|
||||||
|
* define the overall workflow.
|
||||||
|
*
|
||||||
|
* It would use the RSCoordinator methods like [processAtBank] to
|
||||||
|
* encapsulate common in-game actions needed for that workflow.
|
||||||
|
*
|
||||||
|
* By combining both capabilities, this interface provides a simple
|
||||||
|
* way to implement full RuneScape automation routines.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
interface RSOrchestrator : Orchestrator, RSCoordinator{
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun doStandingTask(orchestrator: RSOrchestrator, params: StandingTaskParams) {
|
||||||
|
orchestrator.doLoop(params.totalVolume, params.volumePerStep) {
|
||||||
|
orchestrator.processAtBank(
|
||||||
|
params.bankPoint,
|
||||||
|
params.bankPresetHotkey,
|
||||||
|
params.craftingDialogHotkey,
|
||||||
|
params.craftingWaitDurationMillis,
|
||||||
|
params.craftingWaitDurationVarianceMillis
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun doTravelTask(orchestrator: RSOrchestrator, params: TravelTaskParams) {
|
||||||
|
orchestrator.doLoop(params.totalVolume, params.volumePerStep) {
|
||||||
|
orchestrator.processAtStationNearBank(
|
||||||
|
params.bankPoint,
|
||||||
|
params.travelPoint,
|
||||||
|
params.bankPresetHotkey,
|
||||||
|
params.travelDurationMillis,
|
||||||
|
params.travelDurationVarianceMillis,
|
||||||
|
params.craftingWaitDurationMillis,
|
||||||
|
params.craftingWaitDurationVarianceMillis
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getDefaultInstance(): RSOrchestrator{
|
||||||
|
return RSAgent()
|
||||||
|
}
|
||||||
|
} //end of companion object
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private class RSAgent(override val automaton: Automaton = RobotController()) : 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
|
||||||
|
==============================================================================================================*/
|
||||||
|
|
||||||
|
override fun bankStandWithoutDialog(bankPoint: Point, inventoryHotKey: Int, actionBarHotKey: Int) {
|
||||||
|
//open the bank located by the chest parameter
|
||||||
|
moveMouseLeftClickAndSleep(automaton.getAlmostPoint(bankPoint, WiggleParams()), 900, 400)
|
||||||
|
//withdraw the desired inventory preset
|
||||||
|
automaton.keyPress(inventoryHotKey)
|
||||||
|
|
||||||
|
sleepForNTicks(1)
|
||||||
|
|
||||||
|
//press the hotkey that causes action without dialogue
|
||||||
|
automaton.keyPress(actionBarHotKey)
|
||||||
|
|
||||||
|
sleepForNTicks(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun processAtBank(
|
||||||
|
bankPoint: Point,
|
||||||
|
bankPresetHotkey: Int,
|
||||||
|
craftingDialogueHotkey: Int,
|
||||||
|
waitDurationMillis: Long,
|
||||||
|
waitDurationVariance: Long
|
||||||
|
) {
|
||||||
|
//open the bank located by the chest parameter
|
||||||
|
moveMouseLeftClickAndSleep(automaton.getAlmostPoint(bankPoint, WiggleParams()), 900, 400)
|
||||||
|
//withdraw the desired inventory preset
|
||||||
|
automaton.keyPress(bankPresetHotkey)
|
||||||
|
//sleep for a server tick
|
||||||
|
sleepForNTicks(1)
|
||||||
|
//open the crafting dialog with the correct hotkey
|
||||||
|
automaton.keyPress(craftingDialogueHotkey)
|
||||||
|
//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.sleepWithVariance(waitDurationMillis, waitDurationVariance)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun processAtStationNearBank(
|
||||||
|
bankPoint: Point,
|
||||||
|
craftingStationPoint: Point,
|
||||||
|
bankPresetHotkey: Int,
|
||||||
|
travelDurationMillis: Long,
|
||||||
|
travelDurationVarianceMillis: Long,
|
||||||
|
waitDurationMillis: Long,
|
||||||
|
waitDurationVarianceMillis: Long
|
||||||
|
) {
|
||||||
|
//move to the bank and open the interface
|
||||||
|
moveMouseLeftClickAndSleep(
|
||||||
|
automaton.getAlmostPoint(bankPoint, WiggleParams()),
|
||||||
|
travelDurationMillis,
|
||||||
|
travelDurationVarianceMillis
|
||||||
|
)
|
||||||
|
|
||||||
|
//withdraw desired loadout
|
||||||
|
automaton.keyPress(bankPresetHotkey)
|
||||||
|
sleepForNTicks(1)
|
||||||
|
|
||||||
|
//move to station and open the crafting dialog
|
||||||
|
moveMouseLeftClickAndSleep(craftingStationPoint, travelDurationMillis, travelDurationVarianceMillis)
|
||||||
|
|
||||||
|
//start the crafting task
|
||||||
|
automaton.keyPress(KeyEvent.VK_SPACE)
|
||||||
|
|
||||||
|
//wait for it to complete
|
||||||
|
automaton.sleepWithVariance(waitDurationMillis, waitDurationVarianceMillis)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*==============================================================================================================
|
||||||
|
cheater functions
|
||||||
|
==============================================================================================================*/
|
||||||
|
override fun promptUserForPoint(prompt: String): Point {
|
||||||
|
println(prompt)
|
||||||
|
countDown(5) {
|
||||||
|
print("\rtaking point snapshot in $it... ")
|
||||||
|
if (it == 0) {
|
||||||
|
println("\r ")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return automaton.getPointerLocation()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getBankPoint(): Point {
|
||||||
|
return promptUserForPoint("Hold your mouse over the bank...")
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fun countDown(nSeconds: Int, announceFn: (step: Int) -> Unit) {
|
||||||
|
for (i in nSeconds downTo 0) {
|
||||||
|
announceFn(i)
|
||||||
|
automaton.sleep(1000)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getPointerLocationAfter(delayInSeconds: Int): Point {
|
||||||
|
countDown(delayInSeconds) {
|
||||||
|
print("\rtaking pointer snapshot in $it...")
|
||||||
|
if (it == 0) {
|
||||||
|
println("\r ")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return automaton.getPointerLocation()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getPointerLocationAsValDeclarationString(varName: String): String {
|
||||||
|
val info = getPointerLocationAfter(5)
|
||||||
|
return "val $varName = Point(${info.x}, ${info.y})"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fun moveMouseLeftClickAndSleep(p: Point, dur: Long, durRange: Long) {
|
||||||
|
automaton.moveMouse(p)
|
||||||
|
automaton.sleepWithVariance(100, 50)
|
||||||
|
//left click
|
||||||
|
automaton.mouseClick(InputEvent.BUTTON1_DOWN_MASK)
|
||||||
|
automaton.sleepWithVariance(dur, durRange)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun sleepForNTicks(n: Long) {
|
||||||
|
val latencyPadding = LATENCY_PADDING_MS
|
||||||
|
val baseWaitTime = n * TICK_DURATION_MS
|
||||||
|
automaton.sleepWithVariance(latencyPadding + baseWaitTime, 150)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
override fun drawStar(p: Point) {
|
||||||
|
val offset = 100
|
||||||
|
val top = Point(p.x, p.y - offset * 2)
|
||||||
|
val topright = Point(p.x + offset * 2, p.y + offset)
|
||||||
|
val bottomright = Point(p.x + offset * 2, p.y)
|
||||||
|
val topleft = Point(p.x - offset * 2, p.y + offset)
|
||||||
|
val bottomleft = Point(p.x - offset * 2, p.y)
|
||||||
|
val points = arrayListOf(top, bottomleft, topright, topleft, bottomright)
|
||||||
|
for (i in 0 until 10) {
|
||||||
|
for (point in points) {
|
||||||
|
automaton.moveMouse(point)
|
||||||
|
automaton.sleep(32)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@ -15,6 +15,17 @@ import java.awt.event.KeyEvent
|
|||||||
* The routines are encapsulated for pure convenience
|
* The routines are encapsulated for pure convenience
|
||||||
*/
|
*/
|
||||||
object Routines {
|
object Routines {
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
const val TICK_DURATION_MS = 600L
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Performs the full incense stick crafting process from start to finish.
|
* Performs the full incense stick crafting process from start to finish.
|
||||||
@ -39,7 +50,7 @@ object Routines {
|
|||||||
val start = System.currentTimeMillis()
|
val start = System.currentTimeMillis()
|
||||||
|
|
||||||
//initialize the shared agent and chest point
|
//initialize the shared agent and chest point
|
||||||
val agent = Agent()
|
val agent = RSOrchestrator.getDefaultInstance()
|
||||||
val bankPoint = agent.getBankPoint()
|
val bankPoint = agent.getBankPoint()
|
||||||
|
|
||||||
// Loop to clean grimy herbs:
|
// Loop to clean grimy herbs:
|
||||||
@ -71,8 +82,8 @@ object Routines {
|
|||||||
println("\rClean herbs infused")
|
println("\rClean herbs infused")
|
||||||
|
|
||||||
val finish = System.currentTimeMillis()
|
val finish = System.currentTimeMillis()
|
||||||
agent.drawStar(agent.controller.getPointerLocation())
|
agent.drawStar(agent.automaton.getPointerLocation())
|
||||||
println("Entire chain finished in ${agent.prettyTimeString(finish - start)}")
|
println("Entire chain finished in ${HelperFunctions.prettyTimeString(finish - start)}")
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -89,18 +100,17 @@ object Routines {
|
|||||||
*
|
*
|
||||||
* It performs the actions at the bank location using the provided agent.
|
* It performs the actions at the bank location using the provided agent.
|
||||||
*/
|
*/
|
||||||
fun cleanHerbs(volume: Int, agent: Agent = Agent(), bankPoint: Point = agent.getBankPoint()) {
|
fun cleanHerbs(volume: Int, agent: RSOrchestrator = RSOrchestrator.getDefaultInstance(), bankPoint: Point = agent.getBankPoint()) {
|
||||||
val params = StandingTaskParams(
|
val params = StandingTaskParams(
|
||||||
volume,
|
volume,
|
||||||
CommonVolumesPerStep.FullInventory,
|
CommonVolumesPerStep.FullInventory,
|
||||||
agent,
|
|
||||||
bankPoint,
|
bankPoint,
|
||||||
KeyEvent.VK_F1,
|
KeyEvent.VK_F1,
|
||||||
KeyEvent.VK_1,
|
KeyEvent.VK_1,
|
||||||
0,
|
0,
|
||||||
0
|
0
|
||||||
)
|
)
|
||||||
Agent.doStandingTask(params)
|
RSOrchestrator.doStandingTask(agent, params)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -116,18 +126,17 @@ object Routines {
|
|||||||
* - Cutting magic logs into incense sticks without dialog
|
* - Cutting magic logs into incense sticks without dialog
|
||||||
* - Depositing incense sticks
|
* - Depositing incense sticks
|
||||||
*/
|
*/
|
||||||
fun cutIncenseSticks(volume: Int, agent: Agent = Agent(), bankPoint: Point = agent.getBankPoint()) {
|
fun cutIncenseSticks(volume: Int, agent: RSOrchestrator = RSOrchestrator.getDefaultInstance(), bankPoint: Point = agent.getBankPoint()) {
|
||||||
val params = StandingTaskParams(
|
val params = StandingTaskParams(
|
||||||
volume,
|
volume,
|
||||||
CommonVolumesPerStep.FullInventory,
|
CommonVolumesPerStep.FullInventory,
|
||||||
agent,
|
|
||||||
bankPoint,
|
bankPoint,
|
||||||
KeyEvent.VK_F2,
|
KeyEvent.VK_F2,
|
||||||
KeyEvent.VK_2,
|
KeyEvent.VK_2,
|
||||||
26000,
|
26000,
|
||||||
Agent.TICK_DURATION_MS,
|
TICK_DURATION_MS,
|
||||||
)
|
)
|
||||||
Agent.doStandingTask(params)
|
RSOrchestrator.doStandingTask(agent, params)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -143,18 +152,17 @@ object Routines {
|
|||||||
* - Coating incense sticks with ashes using hotkey
|
* - Coating incense sticks with ashes using hotkey
|
||||||
* - Depositing coated sticks
|
* - Depositing coated sticks
|
||||||
*/
|
*/
|
||||||
fun coatIncenseSticks(volume: Int, agent: Agent = Agent(), bankPoint: Point = agent.getBankPoint()) {
|
fun coatIncenseSticks(volume: Int, agent: RSOrchestrator = RSOrchestrator.getDefaultInstance(), bankPoint: Point = agent.getBankPoint()) {
|
||||||
val params = StandingTaskParams(
|
val params = StandingTaskParams(
|
||||||
volume,
|
volume,
|
||||||
CommonVolumesPerStep.CoatingIncenseWithAsh,
|
CommonVolumesPerStep.CoatingIncenseWithAsh,
|
||||||
agent,
|
|
||||||
bankPoint,
|
bankPoint,
|
||||||
KeyEvent.VK_F3,
|
KeyEvent.VK_F3,
|
||||||
KeyEvent.VK_3,
|
KeyEvent.VK_3,
|
||||||
17000,
|
17000,
|
||||||
Agent.TICK_DURATION_MS,
|
TICK_DURATION_MS,
|
||||||
)
|
)
|
||||||
Agent.doStandingTask(params)
|
RSOrchestrator.doStandingTask(agent, params)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -169,63 +177,60 @@ object Routines {
|
|||||||
* - Infusing incense sticks with herbs using hotkey
|
* - Infusing incense sticks with herbs using hotkey
|
||||||
* - Depositing infused incense sticks
|
* - Depositing infused incense sticks
|
||||||
*/
|
*/
|
||||||
fun infuseIncenseSticks(volume: Int, agent: Agent = Agent(), bankPoint: Point = agent.getBankPoint()) {
|
fun infuseIncenseSticks(volume: Int, agent: RSOrchestrator = RSOrchestrator.getDefaultInstance(), bankPoint: Point = agent.getBankPoint()) {
|
||||||
val params = StandingTaskParams(
|
val params = StandingTaskParams(
|
||||||
volume,
|
volume,
|
||||||
CommonVolumesPerStep.InfusingIncenseWithHerb,
|
CommonVolumesPerStep.InfusingIncenseWithHerb,
|
||||||
agent,
|
|
||||||
bankPoint,
|
bankPoint,
|
||||||
KeyEvent.VK_F4,
|
KeyEvent.VK_F4,
|
||||||
KeyEvent.VK_4,
|
KeyEvent.VK_4,
|
||||||
48600,
|
48600,
|
||||||
Agent.TICK_DURATION_MS,
|
TICK_DURATION_MS,
|
||||||
)
|
)
|
||||||
Agent.doStandingTask(params)
|
RSOrchestrator.doStandingTask(agent, params)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Deprecated("Needs validation before you use it for realsies")
|
@Deprecated("Needs validation before you use it for realsies")
|
||||||
fun craftPotionAtBank(volume: Int, agent: Agent = Agent(), bankPoint: Point = agent.getBankPoint()) {
|
fun craftPotionAtBank(volume: Int, agent: RSOrchestrator = RSOrchestrator.getDefaultInstance(), bankPoint: Point = agent.getBankPoint()) {
|
||||||
val params = StandingTaskParams(
|
val params = StandingTaskParams(
|
||||||
volume,
|
volume,
|
||||||
CommonVolumesPerStep.FullInventory,
|
CommonVolumesPerStep.FullInventory,
|
||||||
agent,
|
|
||||||
bankPoint,
|
bankPoint,
|
||||||
KeyEvent.VK_F6,
|
KeyEvent.VK_F6,
|
||||||
KeyEvent.VK_MINUS,
|
KeyEvent.VK_MINUS,
|
||||||
19200,
|
19200,
|
||||||
Agent.TICK_DURATION_MS,
|
TICK_DURATION_MS,
|
||||||
)
|
)
|
||||||
Agent.doStandingTask(params)
|
RSOrchestrator.doStandingTask(agent, params)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Deprecated("Needs validation before you use it for realsies")
|
@Deprecated("Needs validation before you use it for realsies")
|
||||||
fun potionGrindWithWell(
|
fun potionGrindWithWell(
|
||||||
volume: Int,
|
volume: Int,
|
||||||
travelDurationInMillis: Long,
|
travelDurationInMillis: Long,
|
||||||
agent: Agent = Agent(),
|
agent: RSOrchestrator = RSOrchestrator.getDefaultInstance(),
|
||||||
bankPoint: Point = agent.getBankPoint()
|
bankPoint: Point = agent.getBankPoint()
|
||||||
) {
|
) {
|
||||||
val well = agent.promptUserForPoint("Put your mouse over the well...")
|
val well = agent.promptUserForPoint("Put your mouse over the well...")
|
||||||
val params = TravelTaskParams(
|
val params = TravelTaskParams(
|
||||||
volume,
|
volume,
|
||||||
CommonVolumesPerStep.FullInventory,
|
CommonVolumesPerStep.FullInventory,
|
||||||
agent,
|
|
||||||
bankPoint,
|
bankPoint,
|
||||||
well,
|
well,
|
||||||
KeyEvent.VK_F6,
|
KeyEvent.VK_F6,
|
||||||
-1, //since the travel point is also the dialogue creator, we can omit the hotkey
|
-1, //since the travel point is also the dialogue creator, we can omit the hotkey
|
||||||
19200,
|
19200,
|
||||||
Agent.TICK_DURATION_MS,
|
TICK_DURATION_MS,
|
||||||
travelDurationInMillis,
|
travelDurationInMillis,
|
||||||
Agent.TICK_DURATION_MS
|
TICK_DURATION_MS
|
||||||
)
|
)
|
||||||
Agent.doTravelTask(params)
|
RSOrchestrator.doTravelTask(agent, params)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Deprecated("Needs validation before you use it for realsies")
|
@Deprecated("Needs validation before you use it for realsies")
|
||||||
fun supremeOverloadGrind(params: TaskParams) {
|
fun supremeOverloadGrind(params: TaskParams) {
|
||||||
val agent = Agent()
|
val agent = RSOrchestrator.getDefaultInstance()
|
||||||
val chest = agent.getBankPoint()
|
val chest = agent.getBankPoint()
|
||||||
val well = agent.promptUserForPoint("Put your mouse over the well...")
|
val well = agent.promptUserForPoint("Put your mouse over the well...")
|
||||||
|
|
||||||
@ -260,24 +265,23 @@ object Routines {
|
|||||||
//these two points are specific to my computer. we need to export these into a file or something
|
//these two points are specific to my computer. we need to export these into a file or something
|
||||||
val furnaceFromChest = Point(776, 321)
|
val furnaceFromChest = Point(776, 321)
|
||||||
val chestFromFurnance = Point(1713, 843)
|
val chestFromFurnance = Point(1713, 843)
|
||||||
val agent = Agent()
|
val agent = RSOrchestrator.getDefaultInstance()
|
||||||
val params = TravelTaskParams(
|
val params = TravelTaskParams(
|
||||||
volume,
|
volume,
|
||||||
28,
|
28,
|
||||||
agent,
|
|
||||||
chestFromFurnance,
|
chestFromFurnance,
|
||||||
furnaceFromChest,
|
furnaceFromChest,
|
||||||
KeyEvent.VK_F6,
|
KeyEvent.VK_F6,
|
||||||
-1, //since the travel point is also the dialogue creator, we can omit the hotkey
|
-1, //since the travel point is also the dialogue creator, we can omit the hotkey
|
||||||
51000,
|
51000,
|
||||||
Agent.TICK_DURATION_MS,
|
TICK_DURATION_MS,
|
||||||
2000,
|
2000,
|
||||||
Agent.TICK_DURATION_MS
|
TICK_DURATION_MS
|
||||||
)
|
)
|
||||||
println("Resetting the camera. We need to define the reset to compass button...")
|
println("Resetting the camera. We need to define the reset to compass button...")
|
||||||
agent.scrollOutToHeight(8)
|
agent.scrollOutToHeight(8)
|
||||||
|
|
||||||
Agent.doTravelTask(params)
|
RSOrchestrator.doTravelTask(agent, params)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -299,7 +303,7 @@ object Routines {
|
|||||||
@Deprecated("Needs validation before you use it for realsies")
|
@Deprecated("Needs validation before you use it for realsies")
|
||||||
fun processRefinedPlanksIntoFrames(params: TaskParams) {
|
fun processRefinedPlanksIntoFrames(params: TaskParams) {
|
||||||
println("You must zoom in all the way and have the compass pointing straight N with a completely top-down view\n you must also be standing at the touch point on the saw")
|
println("You must zoom in all the way and have the compass pointing straight N with a completely top-down view\n you must also be standing at the touch point on the saw")
|
||||||
val agent = Agent()
|
val agent = RSOrchestrator.getDefaultInstance()
|
||||||
agent.scrollOutToHeight(8)
|
agent.scrollOutToHeight(8)
|
||||||
|
|
||||||
//the following 2 points are magic numbers from *my* setup and resolution
|
//the following 2 points are magic numbers from *my* setup and resolution
|
||||||
|
|||||||
@ -13,7 +13,6 @@ import java.awt.Point
|
|||||||
interface TaskParams {
|
interface TaskParams {
|
||||||
val totalVolume: Int
|
val totalVolume: Int
|
||||||
val volumePerStep: Int
|
val volumePerStep: Int
|
||||||
val agent: Agent
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -90,7 +89,6 @@ interface TravelParams {
|
|||||||
data class StandingTaskParams(
|
data class StandingTaskParams(
|
||||||
override val totalVolume: Int,
|
override val totalVolume: Int,
|
||||||
override val volumePerStep: Int,
|
override val volumePerStep: Int,
|
||||||
override val agent: Agent,
|
|
||||||
override val bankPoint: Point,
|
override val bankPoint: Point,
|
||||||
override val bankPresetHotkey: Int,
|
override val bankPresetHotkey: Int,
|
||||||
override val craftingDialogHotkey: Int,
|
override val craftingDialogHotkey: Int,
|
||||||
@ -122,7 +120,6 @@ data class StandingTaskParams(
|
|||||||
data class TravelTaskParams(
|
data class TravelTaskParams(
|
||||||
override val totalVolume: Int,
|
override val totalVolume: Int,
|
||||||
override val volumePerStep: Int,
|
override val volumePerStep: Int,
|
||||||
override val agent: Agent,
|
|
||||||
override val bankPoint: Point,
|
override val bankPoint: Point,
|
||||||
override val travelPoint: Point,
|
override val travelPoint: Point,
|
||||||
override val bankPresetHotkey: Int,
|
override val bankPresetHotkey: Int,
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user