From 075117e354fa19846f306cc21839c18fe9d4f98b Mon Sep 17 00:00:00 2001 From: dtookey Date: Sat, 5 Aug 2023 07:23:27 -0400 Subject: [PATCH] refactored everything into parametric interfaces --- src/main/kotlin/Agent.kt | 64 +++++++--- src/main/kotlin/Doer.kt | 62 ++++++---- src/main/kotlin/Entry.kt | 2 +- src/main/kotlin/Routines.kt | 219 +++++++++++++++++++--------------- src/main/kotlin/TaskParams.kt | 85 +++++++++++++ 5 files changed, 290 insertions(+), 142 deletions(-) create mode 100644 src/main/kotlin/TaskParams.kt diff --git a/src/main/kotlin/Agent.kt b/src/main/kotlin/Agent.kt index 29c8dd7..a11ca18 100644 --- a/src/main/kotlin/Agent.kt +++ b/src/main/kotlin/Agent.kt @@ -28,6 +28,34 @@ class Agent { * Constant for the Minus/Dash key code. */ const val Minus = KeyEvent.VK_MINUS + + 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 + ) + } + } + + 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 + ) + } + } } /** @@ -180,7 +208,7 @@ class Agent { fun scrollOutToHeight(height: Int, scrollWaitAndVariance: Long = 10L) { doer.sleep(1000) - for (i in 0 until height*2) { + for (i in 0 until height * 2) { doer.scrollIn(scrollWaitAndVariance, scrollWaitAndVariance) } @@ -193,8 +221,8 @@ class Agent { * 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 invHotkey The key for the inventory preset to withdraw. - * @param hotbarHotkey The key for the crafting preset to open. + * @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. * @@ -206,21 +234,21 @@ class Agent { * * Useful for automated banking behaviors like crafting or herblore. */ - fun bankStandForLoop( + private fun bankStandForLoop( chest: Point, - invHotkey: Int, - hotbarHotkey: Int, + bankPresetHotkey: Int, + craftingDialogueHotkey: Int, waitDurationMillis: Long, waitDurationVariance: Long ) { //open the bank located by the chest parameter doer.moveMouseLeftClickAndSleep(doer.getAlmostPoint(chest, Doer.WiggleParams()), 900, 400) //withdraw the desired inventory preset - doer.keypress(invHotkey) + doer.keypress(bankPresetHotkey) //sleep for a server tick doer.sleepForNTicks(1) //open the crafting dialog with the correct hotkey - doer.keypress(hotbarHotkey) + doer.keypress(craftingDialogueHotkey) //sleep for a server tick doer.sleepForNTicks(1) //press the "accept" default hotkey @@ -263,11 +291,11 @@ class Agent { * * @param chest The Point location of the bank chest. * @param station The Point location of the processing station. - * @param invHotkey The inventory preset hotkey to withdraw at bank. + * @param bankPresetHotkey The inventory preset hotkey to withdraw at bank. * @param travelDurationMillis Base travel time between bank and station. - * @param travelDurationVariance Random variance to add to travel time. + * @param travelDurationVarianceMillis Random variance to add to travel time. * @param waitDurationMillis Base wait time for processing at station. - * @param waitDurationVariance Random variance to add to wait time. + * @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. @@ -279,31 +307,31 @@ class Agent { fun processAtStationNearBank( chest: Point, station: Point, - invHotkey: Int, + bankPresetHotkey: Int, travelDurationMillis: Long, - travelDurationVariance: Long, + travelDurationVarianceMillis: Long, waitDurationMillis: Long, - waitDurationVariance: Long + waitDurationVarianceMillis: Long ) { //move to the bank and open the interface doer.moveMouseLeftClickAndSleep( doer.getAlmostPoint(chest, Doer.WiggleParams()), travelDurationMillis, - travelDurationVariance + travelDurationVarianceMillis ) //withdraw desired loadout - doer.keypress(invHotkey) + doer.keypress(bankPresetHotkey) doer.sleepForNTicks(1) //move to station and open the crafting dialog - doer.moveMouseLeftClickAndSleep(station, travelDurationMillis, travelDurationVariance) + doer.moveMouseLeftClickAndSleep(station, travelDurationMillis, travelDurationVarianceMillis) //start the crafting task doer.keypress(KeyEvent.VK_SPACE) //wait for it to complete - doer.sleep(waitDurationMillis, waitDurationVariance) + doer.sleep(waitDurationMillis, waitDurationVarianceMillis) } /*============================================================================================================== diff --git a/src/main/kotlin/Doer.kt b/src/main/kotlin/Doer.kt index 7da505b..625321a 100644 --- a/src/main/kotlin/Doer.kt +++ b/src/main/kotlin/Doer.kt @@ -33,18 +33,21 @@ import kotlin.random.Random * @constructor Creates a Doer instance with a Robot. */ class Doer(private val robot: Robot = Robot()) { + companion object{ + /** + * 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 + } + - /** - * 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 val TICK_DURATION_MS = 600L /** * Extra padding in milliseconds added before actions to account for latency. 500ms is entirely arbitrary. It is @@ -116,18 +119,22 @@ class Doer(private val robot: Robot = Robot()) { } /** - * Performs a mouse click with the specified mouse button. + * Performs a mouse click of the specified button. * - * This uses the Robot [mousePress] and [mouseRelease] methods to click the - * mouse button specified by [button]. + * This uses the Robot to press and release the given mouse button. * - * It sleeps for a small random duration between press and release to add - * variance to the click timing. + * A random sleep is added in between pressing and releasing the button + * to add variance and avoid robotic timing. * - * @param button The mouse button to click, as a button mask from [InputEvent]. + * @param button The button to click. Must be a valid constant like [InputEvent.BUTTON1_MASK]. + * + * Returns immediately If button is negative. Button must be a positive integer. */ - fun click(button: Int) { - + private fun click(button: Int) { + //guardian logic + if (button < 0) { + return + } robot.mousePress(button) //we add in some random time variance here to appear less robotic @@ -137,17 +144,22 @@ class Doer(private val robot: Robot = Robot()) { } /** - * Presses and releases a keyboard key. + * Presses and releases the given key. * - * This uses the Robot [keyPress] and [keyRelease] methods to press - * and release the key specified by [key]. + * This uses the Robot to simulate pressing and releasing the key with the given key code. * - * It sleeps for a small random duration in between key press and release - * to pace the keystrokes. + * A random sleep is added after pressing the key before releasing it to add variance + * and avoid robotic timing. * - * @param key The key code of the key to press, from [java.awt.event.KeyEvent]. + * @param key The key code of the key to press, such as [KeyEvent.VK_A]. + * + * returns immediately if key < 0. This can be useful for skipping actions with a -1 */ fun keypress(key: Int) { + //guardian logic + if (key < 0) { + return + } robot.keyPress(key) diff --git a/src/main/kotlin/Entry.kt b/src/main/kotlin/Entry.kt index b5f35ca..bf810c2 100644 --- a/src/main/kotlin/Entry.kt +++ b/src/main/kotlin/Entry.kt @@ -2,7 +2,7 @@ import java.awt.Point fun main() { // Routines.fullRunIncense(0, 8916, 9462, 4808) - val params = RoutineParams(1000, 28, chest = Point(0, 0)) + val params = TaskParams(1000, 28, chest = Point(0, 0)) Routines.processInventoryAtFurnace(params) } diff --git a/src/main/kotlin/Routines.kt b/src/main/kotlin/Routines.kt index 729a35f..79c51fe 100644 --- a/src/main/kotlin/Routines.kt +++ b/src/main/kotlin/Routines.kt @@ -46,32 +46,28 @@ object Routines { // Loop to clean grimy herbs: // Withdraw herb preset, clean without dialog at bank if (volHerbs > 0) { - val params = RoutineParams(volHerbs, CommonVolumesPerStep.FullInventory, agent, chest) - cleanHerbs(params) + cleanHerbs(volHerbs) } println("\rHerbs cleaned") // Loop to cut magic logs into sticks: // Withdraw log preset, cut logs using hotkey at bank if (volLogs > 0) { - val params = RoutineParams(volLogs, CommonVolumesPerStep.FullInventory, agent, chest) - cutIncenseSticks(params) + cutIncenseSticks(volLogs) } println("\rLogs cut into sticks") // Loop to coat sticks in ashes: // Withdraw ash preset, coat sticks using hotkey at bank if (volAshes > 0) { - val params = RoutineParams(volAshes, CommonVolumesPerStep.CoatingIncenseWithAsh, agent, chest) - coatIncenseSticks(params) + coatIncenseSticks(volAshes) } println("\rSticks coated in ashes") // Loop to infuse clean herbs into sticks: // Withdraw herb preset, infuse sticks using hotkey at bank if (volCleanHerbs > 0) { - val params = RoutineParams(volCleanHerbs, CommonVolumesPerStep.InfusingIncenseWithHerb, agent, chest) - infuseIncenseSticks(params) + infuseIncenseSticks(volCleanHerbs) } println("\rClean herbs infused") @@ -81,72 +77,108 @@ object Routines { } @Deprecated("Needs validation before you use it for realsies") - fun cleanHerbs( - params: RoutineParams - ) { - params.agent.doLoop(params.totalVolume, params.volumePerStep) { - params.agent.bankStandWithoutDialog(params.chest, KeyEvent.VK_F1, KeyEvent.VK_1) - } + fun cleanHerbs(volume: Int, agent: Agent = Agent(), bankPoint: Point = agent.getBankPoint()) { + val params = StandingTaskParams( + volume, + 28, + agent, + bankPoint, + KeyEvent.VK_F1, + KeyEvent.VK_1, + 0, + 0 + ) + Agent.doStandingTask(params) } @Deprecated("Needs validation before you use it for realsies") - fun cutIncenseSticks( - params: RoutineParams - ) { - params.agent.doLoop(params.totalVolume, params.volumePerStep) { - params.agent.bankStandForLoop(params.chest, KeyEvent.VK_F2, KeyEvent.VK_2, 26000, 1200) - } + fun cutIncenseSticks(volume: Int, agent: Agent = Agent(), bankPoint: Point = agent.getBankPoint()) { + val params = StandingTaskParams( + volume, + 28, + agent, + bankPoint, + KeyEvent.VK_F2, + KeyEvent.VK_2, + 26000, + Doer.TICK_DURATION_MS, + ) + Agent.doStandingTask(params) } @Deprecated("Needs validation before you use it for realsies") - fun coatIncenseSticks( - params: RoutineParams - ) { - params.agent.doLoop(params.totalVolume, params.volumePerStep) { - params.agent.bankStandForLoop(params.chest, KeyEvent.VK_F3, KeyEvent.VK_3, 21000, 600) - } + fun coatIncenseSticks(volume: Int, agent: Agent = Agent(), bankPoint: Point = agent.getBankPoint()) { + val params = StandingTaskParams( + volume, + 28, + agent, + bankPoint, + KeyEvent.VK_F3, + KeyEvent.VK_3, + 21000, + Doer.TICK_DURATION_MS, + ) + Agent.doStandingTask(params) } @Deprecated("Needs validation before you use it for realsies") - fun infuseIncenseSticks( - params: RoutineParams - ) { - params.agent.doLoop(params.totalVolume, params.volumePerStep) { - params.agent.bankStandForLoop(params.chest, KeyEvent.VK_F4, KeyEvent.VK_4, 48600, 600) - } + fun infuseIncenseSticks(volume: Int, agent: Agent = Agent(), bankPoint: Point = agent.getBankPoint()) { + val params = StandingTaskParams( + volume, + 28, + agent, + bankPoint, + KeyEvent.VK_F4, + KeyEvent.VK_4, + 48600, + Doer.TICK_DURATION_MS, + ) + Agent.doStandingTask(params) } @Deprecated("Needs validation before you use it for realsies") - fun craftPotionAtBank( - params: RoutineParams - ) { - params.agent.doLoop(params.totalVolume, params.volumePerStep) { - params.agent.bankStandForLoop(params.chest, Agent.F6, Agent.Minus, 19200, 600) - } + fun craftPotionAtBank(volume: Int, agent: Agent = Agent(), bankPoint: Point = agent.getBankPoint()) { + val params = StandingTaskParams( + volume, + 28, + agent, + bankPoint, + KeyEvent.VK_F6, + KeyEvent.VK_MINUS, + 19200, + Doer.TICK_DURATION_MS, + ) + Agent.doStandingTask(params) } @Deprecated("Needs validation before you use it for realsies") fun potionGrindWithWell( - params: RoutineParams, - travelDurationInMillis: Long + volume: Int, + travelDurationInMillis: Long, + agent: Agent = Agent(), + bankPoint: Point = agent.getBankPoint() ) { - val agent = Agent() - - val chest = agent.getBankPoint() - val well = agent.promptUserForPoint("Put your mouse over the well...") - - agent.doLoop(params.totalVolume, params.volumePerStep) { - agent.processAtStationNearBank(chest, well, Agent.F6, travelDurationInMillis, 0, 18600, 600) - } + val params = TravelTaskParams( + volume, + 28, + agent, + bankPoint, + well, + KeyEvent.VK_F6, + -1, //since the travel point is also the dialogue creator, we can omit the hotkey + 19200, + Doer.TICK_DURATION_MS, + travelDurationInMillis, + Doer.TICK_DURATION_MS + ) + Agent.doTravelTask(params) } @Deprecated("Needs validation before you use it for realsies") - fun supremeOverloadGrind( - params: RoutineParams - ) { + fun supremeOverloadGrind(params: TaskParams) { val agent = Agent() val chest = agent.getBankPoint() val well = agent.promptUserForPoint("Put your mouse over the well...") @@ -157,67 +189,58 @@ object Routines { } - fun processInventoryAtFurnace( - params: RoutineParams - ) { + fun processInventoryAtFurnace(volume: Int) { + //these two points are specific to my computer. we need to export these into a file or something + val furnaceFromChest = Point(776, 321) + val chestFromFurnance = Point(1713, 843) val agent = Agent() - println("Reset the camera") + val params = TravelTaskParams( + volume, + 28, + agent, + chestFromFurnance, + furnaceFromChest, + KeyEvent.VK_F6, + -1, //since the travel point is also the dialogue creator, we can omit the hotkey + 51000, + Doer.TICK_DURATION_MS, + 2000, + Doer.TICK_DURATION_MS + ) + println("Resetting the camera. We need to define the reset to compass button...") agent.scrollOutToHeight(8) - val furnaceFromChest = Point(776, 321) - val chestFromFurance = Point(1713, 843) - - agent.doLoop(params.totalVolume, params.volumePerStep) { - agent.processAtStationNearBank(chestFromFurance, furnaceFromChest, Agent.F6, 2000, 600, 51000, 600) - } + Agent.doTravelTask(params) } - + /** + * Processes refined planks into frames at the sawmill near the bank. + * + * This handles the full workflow of: + * - Withdrawing planks preset from bank + * - Walking to the sawmill + * - Using planks on saw to make frames + * - Walking back to bank + * - Depositing frames + * + * The function loops through processing a total volume of planks based on the provided + * RoutineParams. + * + * @param params RoutineParams config including total volume, volume per trip, agent, and chest point. + * @return Nothing. + */ @Deprecated("Needs validation before you use it for realsies") - fun processRefinedPlanksIntoFrames( - params: RoutineParams - ) { + 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") val agent = Agent() agent.scrollOutToHeight(8) + //the following 2 points are magic numbers from *my* setup and resolution val sawFromChest = Point(1079, 907) val chestFromSaw = Point(1226, 180) - agent.doLoop(params.totalVolume, params.volumePerStep) { -// //standing at bank with full inv -// d.mouseMove(sawFromChest) -// d.sleep(100, 50) -// //run to saw -// d.click(LeftClick) -// d.sleep(2700, 500) -// //start cutting frames -// d.keypress(Space) -// //waiting -// d.sleep(64000, 1000) -// d.mouseMove(chestFromSaw) -// d.sleep(100, 50) -// //running to bank -// d.click(LeftClick) -// d.sleep(2700, 500) -// d.keypress(F6) -// d.sleep(1200, 500) -// //full inv + agent.doLoop(params.totalVolume, params.volumePerStep) { agent.processAtStationNearBank(chestFromSaw, sawFromChest, Agent.F6, 2700, 500, 64000, 1000) } } -} - -data class RoutineParams( - val totalVolume: Int, - val volumePerStep: Int, - val agent: Agent = Agent(), - val chest: Point = agent.getBankPoint() -) - -object CommonVolumesPerStep { - const val FullInventory = 28 - const val TwoReagentFullInventory = 14 - const val CoatingIncenseWithAsh = 26 - const val InfusingIncenseWithHerb = 27 } \ No newline at end of file diff --git a/src/main/kotlin/TaskParams.kt b/src/main/kotlin/TaskParams.kt new file mode 100644 index 0000000..6dba5ef --- /dev/null +++ b/src/main/kotlin/TaskParams.kt @@ -0,0 +1,85 @@ +import java.awt.Point + +/** + * Configuration parameters for routines. + * + * @param totalVolume The total number of items to process in the routine. + * @param volumePerStep The volume of items to process per loop iteration. + * @param agent The Agent instance to use for actions like banking. + * @param chest The Point location of the bank chest to use. + */ +interface TaskParams { + val totalVolume: Int + val volumePerStep: Int + val agent: Agent + +} + +interface BankParams{ + val bankPoint: Point + val bankPresetHotkey: Int +} + +interface CraftingParams{ + val craftingDialogHotkey: Int + val craftingWaitDurationMillis: Long + val craftingWaitDurationVarianceMillis: Long +} + +interface TravelParams{ + val travelPoint: Point + val travelDurationMillis: Long + val travelDurationVarianceMillis: Long +} + +data class StandingTaskParams( + override val totalVolume: Int, + override val volumePerStep: Int, + override val agent: Agent, + override val bankPoint: Point, + override val bankPresetHotkey: Int, + override val craftingDialogHotkey: Int, + override val craftingWaitDurationMillis: Long, + override val craftingWaitDurationVarianceMillis: Long +): TaskParams, BankParams, CraftingParams + + +data class TravelTaskParams( + override val totalVolume: Int, + override val volumePerStep: Int, + override val agent: Agent, + override val bankPoint: Point, + override val travelPoint: Point, + override val bankPresetHotkey: Int, + override val craftingDialogHotkey: Int = -1, + override val craftingWaitDurationMillis: Long, + override val craftingWaitDurationVarianceMillis: Long, + override val travelDurationMillis: Long, + override val travelDurationVarianceMillis: Long +): TaskParams, BankParams, CraftingParams, TravelParams + +/** + * CommonVolumesPerStep provides constants for common inventory volumes used during routines. + */ +object CommonVolumesPerStep { + /** + * Full inventory volume constant. + */ + const val FullInventory = 28 + + /** + * Two-reagent full inventory volume constant. + * For example, when combining two items that fill the inventory. + */ + const val TwoReagentFullInventory = 14 + + /** + * Volume for coating incense sticks with ashes. + */ + const val CoatingIncenseWithAsh = 26 + + /** + * Volume for infusing incense sticks with herbs. + */ + const val InfusingIncenseWithHerb = 27 +} \ No newline at end of file