Compare commits

...

2 Commits

Author SHA1 Message Date
dtookey
b65b0c368d begun, the native interfacing has 2023-08-16 09:00:58 -04:00
dtookey
ee9287972f put the comments on a diet 2023-08-15 21:16:25 -04:00
15 changed files with 112 additions and 208 deletions

View File

@ -4,7 +4,7 @@
<component name="FrameworkDetectionExcludesConfiguration"> <component name="FrameworkDetectionExcludesConfiguration">
<file type="web" url="file://$PROJECT_DIR$" /> <file type="web" url="file://$PROJECT_DIR$" />
</component> </component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" project-jdk-name="openjdk-19" project-jdk-type="JavaSDK"> <component name="ProjectRootManager" version="2" languageLevel="JDK_19" default="true" project-jdk-name="openjdk-19" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/out" /> <output url="file://$PROJECT_DIR$/out" />
</component> </component>
</project> </project>

View File

@ -15,6 +15,7 @@ dependencies {
testImplementation("org.mockito.kotlin:mockito-kotlin:5.0.0") testImplementation("org.mockito.kotlin:mockito-kotlin:5.0.0")
implementation("net.java.dev.jna:jna:latest.release") implementation("net.java.dev.jna:jna:latest.release")
implementation(kotlin("reflect"))
} }
tasks.test { tasks.test {

View File

@ -1,7 +1,7 @@
import game_logic.runescape.RunescapeRoutines import game_logic.runescape.RunescapeRoutines
fun main() { fun main() {
// RunescapeRoutines.fullRunIncense(0, 4514, 4870, 308) // RunescapeRoutines.fullRunIncense(0, 158, 348, 0)
RunescapeRoutines.createNecromancyInk(2960) RunescapeRoutines.processInventoryAtFurnace(2500)
} }

View File

@ -29,7 +29,7 @@ interface TemporalController {
val duration = if(maxAdditionalDuration == 0L){ val duration = if(maxAdditionalDuration == 0L){
baseDuration baseDuration
}else{ }else{
baseDuration + util.HelperFunctions.getGaussianLong(maxAdditionalDuration) baseDuration + util.HelperFunctions.getApproximatelyNormalLong(maxAdditionalDuration)
} }
TimeUnit.MILLISECONDS.sleep(duration) TimeUnit.MILLISECONDS.sleep(duration)

View File

@ -79,7 +79,7 @@ interface User32 : StdCallLibrary {
* @param userData Optional user-defined data to pass to the callback. * @param userData Optional user-defined data to pass to the callback.
* @return True if successful, false otherwise. * @return True if successful, false otherwise.
*/ */
fun EnumWindows(lpEnumFunc: WNDENUMPROC?, userData: Pointer?): Boolean fun EnumWindows(lpEnumFunc: StdCallLibrary.StdCallCallback?, userData: Pointer?): Boolean
/** /**
* Gets the title text of the specified window. * Gets the title text of the specified window.

View File

@ -73,13 +73,6 @@ class RSAgent(override val automaton: Automaton = RobotAutomaton()) : RSOrchestr
* - Clicks the default "Accept" hotkey to start crafting. * - Clicks the default "Accept" hotkey to start crafting.
* - Waits for the specified crafting duration plus random variance. * - Waits for the specified crafting duration plus random variance.
* *
* Usage example:
*
* ```
* val params = StandingTaskParams(...)
* orchestrator.processAtBank(params)
* ```
*
* @param taskParams The [StandingTaskParams] configuring the task details like bank location, hotkeys, and durations. * @param taskParams The [StandingTaskParams] configuring the task details like bank location, hotkeys, and durations.
*/ */
override fun processAtBank( override fun processAtBank(
@ -118,12 +111,6 @@ class RSAgent(override val automaton: Automaton = RobotAutomaton()) : RSOrchestr
* *
* - Waits for the randomized crafting duration. * - Waits for the randomized crafting duration.
* *
* Usage example:
* ```
* val params = TravelTaskParams(...)
* orchestrator.processAtStationNearBank(params)
* ```
*
* @param taskParams The [TravelTaskParams] configuring the task details. * @param taskParams The [TravelTaskParams] configuring the task details.
*/ */
override fun processAtStationNearBank( override fun processAtStationNearBank(
@ -164,17 +151,6 @@ class RSAgent(override val automaton: Automaton = RobotAutomaton()) : RSOrchestr
* *
* It then returns the current mouse position as a Point after a slight delay. * It then returns the current mouse position as a Point after a slight delay.
* *
* The delay allows the mouse to settle before sampling its position.
*
* Usage example:
* ```
* // Get bank location from user mouse position
* val bankPoint = orchestrator.getBankPoint()
* // Left click the bank to open the interface
* orchestrator.automaton.mouseMove(bankPoint)
* orchestrator.automaton.mouseClick(InputEvent.BUTTON1_DOWN_MASK)
* ```
*
* @return The Point position of the mouse after user positions it. * @return The Point position of the mouse after user positions it.
*/ */
override fun getBankPoint(): Point { override fun getBankPoint(): Point {
@ -184,19 +160,10 @@ class RSAgent(override val automaton: Automaton = RobotAutomaton()) : RSOrchestr
/** /**
* Sleeps for a specified number of game ticks. * Sleeps for a specified number of game ticks.
* *
* This method calculates the total sleep duration based on the number of ticks * A brief random variance is also added to the sleep duration to add some less-robotic behavior.
* and the tick duration constant. It then sleeps for that amount plus a small
* latency padding.
*
* A random variance is also added to the sleep duration to add some less-robotic behavior.
*
* Usage example:
* ```
* val ticks = 10 // Sleep for 10 game ticks
* orchestrator.sleepTicks(ticks)
* ```
* *
* @param n The number of game ticks to sleep for. * @param n The number of game ticks to sleep for.
* @see TICK_DURATION_MS
*/ */
override fun sleepForNTicks(n: Long) { override fun sleepForNTicks(n: Long) {
val latencyPadding = LATENCY_PADDING_MS val latencyPadding = LATENCY_PADDING_MS

View File

@ -48,28 +48,6 @@ object RunescapeRoutines {
* @param volLogs The number of magic logs to cut into sticks. * @param volLogs The number of magic logs to cut into sticks.
* @param volAshes The number of sticks to coat in ashes. * @param volAshes The number of sticks to coat in ashes.
* @param volCleanHerbs The number of clean herbs to infuse into sticks. * @param volCleanHerbs The number of clean herbs to infuse into sticks.
*
* This handles the entire incense stick crafting process:
* - Cleaning grimy herbs
* - Cutting magic logs into sticks
* - Coating sticks in ashes
* - Infusing clean herbs into sticks
*
* It loops through each step based on the provided volumes, performing the
* actions at the bank.
*
* Usage example:
*
* ```
* val herbs = 1000
* val logs = 2000
* val ashes = 1500
* val cleanHerbs = herbs + 150
*
* Routines.fullRunIncense(herbs, logs, ashes, cleanHerbs)
* ```
*
* Progress is printed after each step. Total elapsed time is printed at the end.
*/ */
fun fullRunIncense(volHerbs: Int, volLogs: Int, volAshes: Int, volCleanHerbs: Int) { fun fullRunIncense(volHerbs: Int, volLogs: Int, volAshes: Int, volCleanHerbs: Int) {
val start = System.currentTimeMillis() val start = System.currentTimeMillis()
@ -126,24 +104,6 @@ object RunescapeRoutines {
* @param agent Optional. The Agent instance to use for banking actions. * @param agent Optional. The Agent instance to use for banking actions.
* @param bankPoint Optional. The Point location of the bank to use. * @param bankPoint Optional. The Point location of the bank to use.
* *
* This handles the workflow of:
* - Withdrawing grimy herb preset
* - Cleaning grimy herbs without dialog
* - Depositing clean herbs
*
* It performs the actions at the bank location using the provided agent.
*
* Usage examples:
* ```
* val volume = 1000
* val bankPoint = Point(100, 200)
* val agent = RSAgent.getInstance()
* Routines.cleanHerbs(volume, agent, bankPoint)
* ```
* Can also omit agent and bankPoint to use defaults:
* ```
* Routines.cleanHerbs(1000)
* ```
*/ */
fun cleanHerbs(volume: Int, agent: RSOrchestrator = RSOrchestrator.getInstance(), bankPoint: Point = agent.getBankPoint()) { fun cleanHerbs(volume: Int, agent: RSOrchestrator = RSOrchestrator.getInstance(), bankPoint: Point = agent.getBankPoint()) {
val params = StandingTaskParams( val params = StandingTaskParams(
@ -166,23 +126,6 @@ object RunescapeRoutines {
* @param agent Optional. The Agent instance to use for banking actions. * @param agent Optional. The Agent instance to use for banking actions.
* @param bankPoint Optional. The Point location of the bank to use. * @param bankPoint Optional. The Point location of the bank to use.
* *
* This handles the workflow of:
* - Withdrawing magic log preset
* - Cutting magic logs into incense sticks without dialog
* - Depositing incense sticks
*
* Usage examples:
* ```
* val logs = 1000
* val bankPoint = Point(100, 200)
* val agent = RSAgent.getInstance()
*
* Routines.cutIncenseSticks(logs, agent, bankPoint)
* ```
* Can also omit agent and bankPoint to use defaults:
* ```
* Routines.cutIncenseSticks(1000)
* ```
*/ */
fun cutIncenseSticks(volume: Int, agent: RSOrchestrator = RSOrchestrator.getInstance(), bankPoint: Point = agent.getBankPoint()) { fun cutIncenseSticks(volume: Int, agent: RSOrchestrator = RSOrchestrator.getInstance(), bankPoint: Point = agent.getBankPoint()) {
val params = StandingTaskParams( val params = StandingTaskParams(
@ -205,24 +148,6 @@ object RunescapeRoutines {
* @param agent Optional Agent instance to use for banking actions. * @param agent Optional Agent instance to use for banking actions.
* @param bankPoint Optional Point location of the bank to use. * @param bankPoint Optional Point location of the bank to use.
* *
* This handles the workflow of:
* - Withdrawing incense stick preset
* - Coating incense sticks with ashes using hotkey
* - Depositing coated sticks
*
* Usage examples:
* ```
* val sticks = 1000
* val bankPoint = Point(100, 200)
* val agent = RSAgent.getInstance()
*
* Routines.coatIncenseSticks(sticks, agent, bankPoint)
* ```
* Can also omit agent and bankPoint to use defaults:
*
* ```
* Routines.coatIncenseSticks(1000)
* ```
*/ */
fun coatIncenseSticks(volume: Int, agent: RSOrchestrator = RSOrchestrator.getInstance(), bankPoint: Point = agent.getBankPoint()) { fun coatIncenseSticks(volume: Int, agent: RSOrchestrator = RSOrchestrator.getInstance(), bankPoint: Point = agent.getBankPoint()) {
val params = StandingTaskParams( val params = StandingTaskParams(
@ -243,24 +168,6 @@ object RunescapeRoutines {
* @param volume The number of incense sticks to infuse with herbs. * @param volume The number of incense sticks to infuse with herbs.
* @param agent Optional Agent instance to use for banking actions. * @param agent Optional Agent instance to use for banking actions.
* @param bankPoint Optional Point location of the bank to use. * @param bankPoint Optional Point location of the bank to use.
*
* This handles the workflow of:
* - Withdrawing incense stick preset
* - Infusing incense sticks with herbs using hotkey
* - Depositing infused incense sticks
*
* Usage examples:
* ```
* val sticks = 1000
* val bankPoint = Point(100, 200)
* val agent = RSAgent.getInstance()
*
* Routines.infuseIncenseSticks(sticks, agent, bankPoint)
* ```
* Can also omit agent and bankPoint to use defaults:
* ```
* Routines.infuseIncenseSticks(1000)
* ```
*/ */
fun infuseIncenseSticks(volume: Int, agent: RSOrchestrator = RSOrchestrator.getInstance(), bankPoint: Point = agent.getBankPoint()) { fun infuseIncenseSticks(volume: Int, agent: RSOrchestrator = RSOrchestrator.getInstance(), bankPoint: Point = agent.getBankPoint()) {
val params = StandingTaskParams( val params = StandingTaskParams(
@ -282,21 +189,6 @@ object RunescapeRoutines {
* @param agent The RSOrchestrator instance to use. Defaults to default instance. * @param agent The RSOrchestrator instance to use. Defaults to default instance.
* @param bankPoint The location of the bank. Defaults to agent's configured bank point. * @param bankPoint The location of the bank. Defaults to agent's configured bank point.
* *
* This method handles the workflow of crafting potions using hotkeys while standing at a bank:
*
* - It constructs a StandingTaskParams instance defining:
* - The volume, volume per trip, bank point, crafting hotkey, and other details
* - It calls the orchestrator's doStandingTask() method to execute the task.
*
* Usage example:
* ```
* val volume = 1000
* val bankPoint = Point(100, 200)
* val agent = RSAgent.getInstance()
* Routines.craftPotionsAtBank(volume, agent, bankPoint)
* ```
*
* Progress is automatically printed during execution.
* *
* @deprecated This method needs validation before use in production. * @deprecated This method needs validation before use in production.
*/ */
@ -316,32 +208,13 @@ object RunescapeRoutines {
/** /**
* Grinds potions using a well location for water. * Grinds potions using a well location for water.
* It prompts the user to position the mouse over the well location to get its coordinates.
* *
* @param volume The total number of potions to make. * @param volume The total number of potions to make.
* @param travelDurationInMillis The time in ms for the agent to travel between the bank and the well. * @param travelDurationInMillis The time in ms for the agent to travel between the bank and the well.
* @param agent The RSOrchestrator instance to use. Defaults to the default instance. * @param agent The RSOrchestrator instance to use. Defaults to the default instance.
* @param bankPoint The Point location of the bank. Defaults to the agent's configured bank point. * @param bankPoint The Point location of the bank. Defaults to the agent's configured bank point.
* *
* This method handles the workflow of grinding potions using a well as the water source.
*
* It prompts the user to position the mouse over the well location to get its coordinates.
*
* It then constructs a TravelTaskParams instance to define:
* - The volume, volume per trip, bank point, well point, and other task details.
*
* It calls the orchestrator's doTravelTask() method to execute the grinding task.
*
* Usage example:
* ```
* val volume = 1000
* val travelDuration = 5000 // 5 seconds
* val bankPoint = Point(100, 200)
* val wellPoint = Point(300, 400) // Prompted from user
* Routines.potionGrindWithWell(volume, travelDuration, bankPoint, wellPoint)
* ```
*
* Progress is automatically printed during execution.
*
* @deprecated This method needs validation before use in production. * @deprecated This method needs validation before use in production.
*/ */
@Deprecated("Needs validation before you use it for realsies") @Deprecated("Needs validation before you use it for realsies")
@ -372,32 +245,14 @@ object RunescapeRoutines {
* *
* @param volume The number of inventory slots to process at the furnace. * @param volume The number of inventory slots to process at the furnace.
* *
* The following 2 values are hard coded from my own personal setup * The following 2 values are hard coded from my own personal computer
* furnaceFromChest The Point location of the furnace from the bank chest. * furnaceFromChest The Point location of the furnace from the bank chest.
* chestFromFurnace The Point location of the bank chest from the furnace. * chestFromFurnace The Point location of the bank chest from the furnace.
*
* Uses an Agent instance for banking and traveling.
*
* This handles the workflow of:
* - Withdrawing bars at bank chest
* - Walking to furnace and processing bars into items
* - Walking back to bank and depositing processed items
*
* The furnace and bank locations are passed in as specific Point locations.
* The agent handles the navigation and banking actions.
*
* Usage example:
*
* ```
* Routines.processAtFurnaceNearBank(1500)
* ```
*
* Before processing, the camera is reset to align points.
*/ */
fun processInventoryAtFurnace(volume: Int) { fun processInventoryAtFurnace(volume: Int) {
//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(1813, 893)
val agent = RSOrchestrator.getInstance() val agent = RSOrchestrator.getInstance()
val params = TravelTaskParams( val params = TravelTaskParams(
volume, volume,

View File

@ -0,0 +1,28 @@
package native
import com.sun.jna.Library
import com.sun.jna.Native
import com.sun.jna.NativeLong
interface HelloWorldWrapper: Library{
companion object {
init{
System.setProperty(
"jna.library.path",
"C:\\Users\\Hydros\\IdeaProjects\\RuneFactory\\src\\main\\rust\\src\\build"
)
}
fun getInstance(): HelloWorldWrapper {
val options = Native.getLibraryOptions(HelloWorldWrapper::class.java)
options[Library.OPTION_FUNCTION_MAPPER] = NativeFunctionMapper()
return Native.load("hello", HelloWorldWrapper::class.java, options) as HelloWorldWrapper
}
}
@NativeFunction(name ="_ZN5hello7get_int17h5cc51eaee082b02cE")
fun get_int(): NativeLong
}

View File

@ -0,0 +1,30 @@
package native
import com.sun.jna.NativeLibrary
import com.sun.jna.win32.StdCallFunctionMapper
import java.lang.reflect.Method
/**
* Annotation used to specify the name of a native function.
*
* @param name The name of the native function.
*/
annotation class NativeFunction(val name: String)
/**
* Mapper class that extends [StdCallFunctionMapper] to using the name from the [NativeFunction] annotation if present
* instead of the default name mapping.
*
* @see StdCallFunctionMapper
*/
class NativeFunctionMapper : StdCallFunctionMapper() {
/**
* Overrides the default function name mapping to use the name from the [NativeFunction] annotation if present
*
* @see StdCallFunctionMapper.getFunctionName
*/
override fun getFunctionName(library: NativeLibrary?, method: Method): String {
return method.getAnnotation(NativeFunction::class.java)?.name ?: super.getFunctionName(library, method)
}
}

View File

@ -32,29 +32,26 @@ object HelperFunctions {
0 0
} }
/** /**
* Generates a random long value approximating a normal distribution. * Generates a random long that approximates a normal distribution.
* *
* Takes two random samples from 0 to upperBound/2 and adds them together. This approximates a normal distribution * Works by taking two random samples from 0 to upperBound/2 and adding them together. This tends to give a more natural
* better than a single random sample. * spread than a single random sample.
* *
* @param upperBound The upper bound to sample from * This approach relies on the Central Limit Theorem: that the sum of multiple independent random variables will
* @return A random long value following an approximate normal distribution * tend towards a normal distribution, even if the original variables themselves are not normally distributed.
*
* @param upperBound The upper bound for the random range. Must be >= 2.
* @return A random long value following an approximate normal distribution.
*/ */
fun getGaussianLong(upperBound: Long): Long { fun getApproximatelyNormalLong(upperBound: Long): Long {
// anything lower to 2 will round down to zero, so return zero. Additionally, this guarantees a positive upper // anything lower to 2 will round down to zero, so return zero. Additionally, this guarantees a positive upper
//bound in one step //bound in one step
if (upperBound <= 2L) { if (upperBound < 2L) {
return 0L return 0L
} }
// Generate two random longs from 0 to upperBound/2 and add them together to approximate a normal distribution.
// To create more natural distribution Take two random samples from 0 to upperBound/2 and add them. This return Random.nextLong(upperBound.shr(1)) + Random.nextLong(upperBound.shr(1))
// approximates a normal distribution better than single random sample.
val subBound = upperBound / 2L
val result1 = Random.nextLong(subBound)
val result2 = Random.nextLong(subBound)
return result1 + result2
} }
/** /**
@ -66,6 +63,7 @@ object HelperFunctions {
* @return A random long value * @return A random long value
*/ */
fun getNextGaussian(upperBound: Long): Long { fun getNextGaussian(upperBound: Long): Long {
require(upperBound > 0)
return java.util.Random() return java.util.Random()
.nextGaussian( .nextGaussian(
upperBound.toDouble() / 2.0, upperBound.toDouble() / 2.0,

9
src/main/rust/cargo.toml Normal file
View File

@ -0,0 +1,9 @@
[package]
name = "hello_world"
version = "0.1.0"
edition = "2021"
[dependencies]
[build]
rustflags = ["-C", "prefer-dynamic"]

View File

@ -0,0 +1,3 @@
pub extern fn get_int() -> i32 {
return 42;
}

View File

@ -0,0 +1,14 @@
package native
import kotlin.test.Test
import kotlin.test.assertEquals
class DllLoadTest{
@Test
fun testLoadDll(){
val hello = HelloWorldWrapper.getInstance()
val i = hello.get_int()
assertEquals(i.toInt(), 42)
}
}

Binary file not shown.

View File

@ -2,7 +2,6 @@ package util
import kotlin.math.pow import kotlin.math.pow
import kotlin.system.measureNanoTime import kotlin.system.measureNanoTime
import kotlin.system.measureTimeMillis
import kotlin.test.Test import kotlin.test.Test
@ -16,7 +15,7 @@ class HelperFunctionsTest {
val numSamples = 10000 val numSamples = 10000
val upperBound = 1000L val upperBound = 1000L
val samples = (1..numSamples).map { val samples = (1..numSamples).map {
HelperFunctions.getGaussianLong(upperBound) HelperFunctions.getApproximatelyNormalLong(upperBound)
} }
// Calculate mean and standard deviation // Calculate mean and standard deviation
@ -40,7 +39,7 @@ class HelperFunctionsTest {
val samples = ArrayList<Long>(iterations) val samples = ArrayList<Long>(iterations)
val time = doBenchmark(iterations, upperBound) { val time = doBenchmark(iterations, upperBound) {
val v = HelperFunctions.getGaussianLong(it) val v = HelperFunctions.getApproximatelyNormalLong(it)
samples.add(v) samples.add(v)
v v
} }
@ -105,7 +104,7 @@ class HelperFunctionsTest {
println("Warming up for a few iterations") println("Warming up for a few iterations")
val consumer = ArrayList<Long>(iterations) val consumer = ArrayList<Long>(iterations)
repeat(iterations){ repeat(iterations){
consumer.add(HelperFunctions.getGaussianLong(upperBound)) consumer.add(HelperFunctions.getApproximatelyNormalLong(upperBound))
consumer.add(HelperFunctions.getNextGaussian(upperBound)) consumer.add(HelperFunctions.getNextGaussian(upperBound))
} }
@ -114,7 +113,7 @@ class HelperFunctionsTest {
var total = 0L var total = 0L
val time1 = measureNanoTime { val time1 = measureNanoTime {
repeat(iterations) { repeat(iterations) {
total += HelperFunctions.getGaussianLong(upperBound) total += HelperFunctions.getApproximatelyNormalLong(upperBound)
} }
} }