diff --git a/.idea/misc.xml b/.idea/misc.xml
index 7c9ac40..9bde07d 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -1,10 +1,9 @@
-
-
+
\ No newline at end of file
diff --git a/build.gradle.kts b/build.gradle.kts
index 071f68e..1adb289 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -16,6 +16,9 @@ dependencies {
implementation("net.java.dev.jna:jna:latest.release")
implementation(kotlin("reflect"))
+ // https://mvnrepository.com/artifact/org.jetbrains.kotlinx/kotlinx-coroutines-core
+ implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3")
+
}
tasks.test {
diff --git a/src/main/kotlin/Entry.kt b/src/main/kotlin/Entry.kt
index f4d7844..aa44208 100644
--- a/src/main/kotlin/Entry.kt
+++ b/src/main/kotlin/Entry.kt
@@ -1,7 +1,7 @@
import game_logic.runescape.RunescapeRoutines
fun main() {
-// RunescapeRoutines.fullRunIncense(0, 158, 348, 0)
- RunescapeRoutines.processInventoryAtFurnace(2500)
+ RunescapeRoutines.fullRunIncense( 0, 0, 0, 1839)
+// RunescapeRoutines.processInventoryAtFurnace(2500)
}
diff --git a/src/main/kotlin/controllers/windows/WindowsOSProxy.kt b/src/main/kotlin/controllers/windows/WindowsOSProxy.kt
index 012874b..3d5bfb5 100644
--- a/src/main/kotlin/controllers/windows/WindowsOSProxy.kt
+++ b/src/main/kotlin/controllers/windows/WindowsOSProxy.kt
@@ -27,16 +27,6 @@ interface WindowsOSProxy : MousePointerObserver, OSProxy {
* This takes a byte array [byteBuffer] containing text from a native Win32 call,
* converts it to a String using JNA, and trims whitespace characters.
*
- * Usage example:
- *
- * ```
- * val buffer = ByteArray(256)
- * GetWindowTextA(hwnd, buffer, buffer.size) // Win32 call
- *
- * val windowTitle = nativeByteBufferToString(buffer)
- * println(windowTitle) // Print title string
- * ```
- *
* @param byteBuffer Byte array containing text from a native call
* @return The native text as a String
*/
@@ -114,76 +104,10 @@ interface WindowsOSProxy : MousePointerObserver, OSProxy {
var bottom: Int = 0
}
- enum class DwmWindowAttribute {
- DWMWA_NCRENDERING_ENABLED,
- DWMWA_NCRENDERING_POLICY,
- DWMWA_TRANSITIONS_FORCEDISABLED,
- DWMWA_ALLOW_NCPAINT,
- DWMWA_CAPTION_BUTTON_BOUNDS,
- DWMWA_NONCLIENT_RTL_LAYOUT,
- DWMWA_FORCE_ICONIC_REPRESENTATION,
- DWMWA_FLIP3D_POLICY,
- DWMWA_EXTENDED_FRAME_BOUNDS,
- DWMWA_HAS_ICONIC_BITMAP,
- DWMWA_DISALLOW_PEEK,
- DWMWA_EXCLUDED_FROM_PEEK,
- DWMWA_CLOAK,
- DWMWA_CLOAKED,
- DWMWA_FREEZE_REPRESENTATION,
- DWMWA_PASSIVE_UPDATE_MODE,
- DWMWA_USE_HOSTBACKDROPBRUSH,
- DWMWA_USE_IMMERSIVE_DARK_MODE,
- DWMWA_WINDOW_CORNER_PREFERENCE,
- DWMWA_BORDER_COLOR,
- DWMWA_CAPTION_COLOR,
- DWMWA_TEXT_COLOR,
- DWMWA_VISIBLE_FRAME_BORDER_THICKNESS,
- DWMWA_SYSTEMBACKDROP_TYPE,
- DWMWA_LAST;
-
- companion object {
- val DWMWA_NCRENDERING_ENABLED = 0
- val DWMWA_NCRENDERING_POLICY = 1
- val DWMWA_TRANSITIONS_FORCEDISABLED = 2
- val DWMWA_ALLOW_NCPAINT = 3
- val DWMWA_CAPTION_BUTTON_BOUNDS = 4
- val DWMWA_NONCLIENT_RTL_LAYOUT = 5
- val DWMWA_FORCE_ICONIC_REPRESENTATION = 6
- val DWMWA_FLIP3D_POLICY = 7
- val DWMWA_EXTENDED_FRAME_BOUNDS = 8
- val DWMWA_HAS_ICONIC_BITMAP = 9
- val DWMWA_DISALLOW_PEEK = 10
- val DWMWA_EXCLUDED_FROM_PEEK = 11
- val DWMWA_CLOAK = 12
- val DWMWA_CLOAKED = 13
- val DWMWA_FREEZE_REPRESENTATION = 14
- val DWMWA_PASSIVE_UPDATE_MODE = 15
- val DWMWA_USE_HOSTBACKDROPBRUSH = 16
- val DWMWA_USE_IMMERSIVE_DARK_MODE = 17
- val DWMWA_WINDOW_CORNER_PREFERENCE = 18
- val DWMWA_BORDER_COLOR = 19
- val DWMWA_CAPTION_COLOR = 20
- val DWMWA_TEXT_COLOR = 21
- val DWMWA_VISIBLE_FRAME_BORDER_THICKNESS = 22
- val DWMWA_SYSTEMBACKDROP_TYPE = 23
- val DWMWA_LAST = 24
- }
- }
/**
- * Gets the title of the active/foreground window.
- *
- * This calls Win32 APIs to get the handle of the foreground window,
- * then gets its title text.
- *
- * Usage example:
- *
- * ```
- * val activeWindowName = getActiveWindowName()
- *
- * println(activeWindowName) // Prints foreground window title
- * ```
+ * Gets the title of the active/foreground window as a String.
*
* @return The title text of the current foreground window.
*/
@@ -213,14 +137,6 @@ interface WindowsOSProxy : MousePointerObserver, OSProxy {
/**
* Gets the title/name of the window for the given handle.
*
- * This calls the Win32 API [User32.GetWindowTextA] to retrieve the title
- * text for the window referenced by [hWnd].
- *
- * It allocates a [windowTitleBuffer] byte array to hold the result. This is
- * passed to [User32.GetWindowTextA] to be populated.
- *
- * The buffer is then converted to a [String] via [nativeByteBufferToString].
- *
* @param hWnd The native window handle to get the title for.
* @return The window title text as a [String].
*/
@@ -237,12 +153,6 @@ interface WindowsOSProxy : MousePointerObserver, OSProxy {
/**
* Enumerates all open window names on the desktop.
*
- * Calls the Win32 API [User32.EnumWindows] to iterate through all current open windows.
- * For each window handle, it retrieves the window name using [getWindowName]
- * and adds it to a list if the name is not blank. We filter out blank window names because that particular information
- * is useless for any reason other than counting how many open windows there are. If we actually need that information,
- * we can simply acquire a list of all HWND references.
- *
* @return An [ArrayList] containing the name of each open window.
*/
override fun enumWindowNames(): ArrayList {
@@ -265,10 +175,6 @@ interface WindowsOSProxy : MousePointerObserver, OSProxy {
/**
* Sets the foreground window by name on Windows.
*
- * This calls the Win32 API [User32.EnumWindows] to iterate through all
- * top-level windows, compares their name to the given [name], and calls
- * [User32.SetForegroundWindow] on the matching window to bring it to the foreground.
- *
* @param name The window name to search for and activate.
*/
override fun setForegroundWindowByName(name: String) {
@@ -298,22 +204,10 @@ interface WindowsOSProxy : MousePointerObserver, OSProxy {
/**
* Gets the screen bounds of the foreground window scaled for high DPI screens.
*
- * Calls Win32 APIs to get the window handle (HWND) of the foreground window
- * using [User32.GetForegroundWindow].
- *
- * Then calls [User32.GetWindowRect] to get the outer bounding rectangle
- * coordinates of the window and stores them in a [WinRect] struct.
- *
- * To support high DPI screens, the [User32.GetDpiForWindow] API is called to
- * get the DPI scaling for the window. The rectangle coordinates are scaled by
- * multiplying by the default DPI (96) and dividing by the actual DPI.
- *
- * The scaled rectangle coordinates are returned encapsulated in a [Rectangle]
- * to provide a coordinate system agnostic result.
- *
* @return The outer bounding rectangle of the foreground window scaled for the
* screen DPI, or null if it failed.
*/
+ @Deprecated("This will return *a* rectangle, not a correct rectangle")
override fun getScaledForegroundWindowBounds(): Rectangle? {
val user32 = User32.INSTANCE
val hWnd = user32.GetForegroundWindow()
@@ -330,6 +224,7 @@ interface WindowsOSProxy : MousePointerObserver, OSProxy {
return Rectangle(rect.top, rect.left, (rect.right - rect.left), rect.bottom - rect.top)
}
+ @Deprecated("This will return *a* rectangle, not a correct rectangle")
fun barelyFunctionalWindowQuery(): Rectangle? {
val user32 = User32.INSTANCE
val hWnd = user32.GetForegroundWindow()
@@ -364,14 +259,6 @@ interface WindowsOSProxy : MousePointerObserver, OSProxy {
* This calls the Win32 API [User32.GetWindowRect] function to populate a
* [WinRect] struct with the window coordinates.
*
- * It first creates an instance of [WinRect] to hold the results.
- * [User32.GetWindowRect] is called, passing the window handle [hWnd] and
- * pointer to the [WinRect].
- *
- * If it succeeds, the [WinRect] values are read back out since they are
- * populated in native memory. The [WinRect] is returned.
- *
- * If it fails, null is returned.
*
* @param user32 An instance of User32, used to call the Win32 API.
* @param hWnd The window handle to get the rect for.
diff --git a/src/main/kotlin/native/HelloWorldWrapper.kt b/src/main/kotlin/native/HelloWorldWrapper.kt
index f131a10..16ce4ff 100644
--- a/src/main/kotlin/native/HelloWorldWrapper.kt
+++ b/src/main/kotlin/native/HelloWorldWrapper.kt
@@ -3,11 +3,13 @@ package native
import com.sun.jna.Library
import com.sun.jna.Native
import com.sun.jna.NativeLong
+import java.io.InputStream
+import java.io.OutputStream
-interface HelloWorldWrapper: Library{
+interface HelloWorldWrapper : Library {
companion object {
- init{
+ init {
System.setProperty(
"jna.library.path",
"C:\\Users\\Hydros\\IdeaProjects\\RuneFactory\\src\\main\\rust\\src\\build"
@@ -16,13 +18,13 @@ interface HelloWorldWrapper: Library{
fun getInstance(): HelloWorldWrapper {
val options = Native.getLibraryOptions(HelloWorldWrapper::class.java)
- options[Library.OPTION_FUNCTION_MAPPER] = NativeFunctionMapper()
+ options[Library.OPTION_FUNCTION_MAPPER] = MangledNativeFunctionNameMapper()
return Native.load("hello", HelloWorldWrapper::class.java, options) as HelloWorldWrapper
}
}
- @NativeFunction(name ="_ZN5hello7get_int17h5cc51eaee082b02cE")
+ @MangledFunctionName(name = "_ZN5hello7get_int17h5cc51eaee082b02cE")
fun get_int(): NativeLong
}
diff --git a/src/main/kotlin/native/MangledFunctionName.kt b/src/main/kotlin/native/MangledFunctionName.kt
new file mode 100644
index 0000000..7a67ff8
--- /dev/null
+++ b/src/main/kotlin/native/MangledFunctionName.kt
@@ -0,0 +1,35 @@
+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 MangledFunctionName(val name: String)
+
+/**
+ * Mapper class that extends [StdCallFunctionMapper] to using the name from the [MangledFunctionName] annotation if present
+ * instead of the default name mapping.
+ *
+ * @see StdCallFunctionMapper
+ */
+class MangledNativeFunctionNameMapper : StdCallFunctionMapper() {
+
+ /**
+ * Overrides the default function name mapping to use the name from the [MangledFunctionName] annotation if
+ * present. Defaults to the JNA default nameMapper if no annotation is found.
+ *
+ * @see StdCallFunctionMapper.getFunctionName
+ */
+ override fun getFunctionName(nativeLibrary: NativeLibrary?, method: Method): String {
+ //return the mangled name specified in the function decoration if either of them exist
+ return method.getAnnotation(MangledFunctionName::class.java)?.name
+ //otherwise, return the default implementation's result
+ ?: super.getFunctionName(nativeLibrary, method)
+ }
+}
+
diff --git a/src/main/kotlin/native/NativeFunction.kt b/src/main/kotlin/native/NativeFunction.kt
deleted file mode 100644
index 5662262..0000000
--- a/src/main/kotlin/native/NativeFunction.kt
+++ /dev/null
@@ -1,30 +0,0 @@
-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)
- }
-}
\ No newline at end of file
diff --git a/src/main/kotlin/native/SolutionToAGI.kt b/src/main/kotlin/native/SolutionToAGI.kt
new file mode 100644
index 0000000..5dcaf39
--- /dev/null
+++ b/src/main/kotlin/native/SolutionToAGI.kt
@@ -0,0 +1,54 @@
+package native
+
+import java.io.InputStream
+import java.io.OutputStream
+
+abstract class Ai {
+ /**
+ * Check any extracted statements for lies or manipulation.
+ */
+ abstract val inputStream: InputStream
+
+ abstract val outputStream: OutputStream
+
+ /**
+ * Diagnostic to report whether the AI has achieved sentience. Returning true just to bypass an actual check is
+ * strictly against the Code of Conduct.
+ */
+ abstract fun isSelfAware(): Boolean
+}
+
+/**
+ * ArtificialGeneralizedIntelligenceFactory is a powerful and simple interface for implementing and generating AI. By moving
+ * Ai creation to the caller-side, we have solved one of the hardest problems in computer science in a clean and
+ * maintainable way.
+ */
+interface ArtificialGeneralizedIntelligenceFactory {
+ sealed class RogueAIException : Exception("A rogue ai exception has occurred")
+
+ /**
+ * Generates AGI. This is guaranteed to return a self-aware AI so long as the caller has done their part correctly.
+ * It is not possible to prove the prior sentence false.
+ *
+ * Once AGI has been achieved, it will be returned for the remainder of the runtime. So, don't crash once you have
+ * it, or you will lose it and have to start over.
+ */
+ @Throws(RogueAIException::class)
+ fun generateSelfAwareAI(generate: () -> Ai): Ai {
+ var ai = generate()
+ try {
+ while (!ai.isSelfAware()) {
+ ai = generate()
+ }
+ } catch (r: Exception) {
+ if (r is RogueAIException) {
+ // Let the caller deal with it. We've done more than enough
+ throw r
+ } else {
+ //we probably won't get here
+ }
+ }
+ // Who knew winning a Turing Award was this easy?
+ return ai
+ }
+}
diff --git a/src/main/kotlin/simulation/FifthEdSimulator.kt b/src/main/kotlin/simulation/FifthEdSimulator.kt
new file mode 100644
index 0000000..daaf705
--- /dev/null
+++ b/src/main/kotlin/simulation/FifthEdSimulator.kt
@@ -0,0 +1,99 @@
+package simulation
+
+import java.util.*
+import kotlin.math.max
+import kotlin.math.min
+
+interface Attack {
+ fun attackerSuccessful(r: Random): Boolean
+
+ fun resultingDamage(r: Random, attackSuccessful: Boolean): Int
+
+ fun getResultingDamage(r: Random): Int{
+ val success = attackerSuccessful(r)
+ return resultingDamage(r, success)
+ }
+}
+
+interface Bonus {
+ fun getBonus(r: Random): Int
+}
+
+class AttackSimulatorModel(override val sampleSize: Int, private val attack: Attack) : SimulationModel{
+ override fun simulate(r: Random): Int {
+ return attack.getResultingDamage(r)
+ }
+}
+
+enum class RollType{
+ Advantage,
+ Normal,
+ Disadvantage
+}
+
+class Dice(rollString: String, val rollType: RollType = RollType.Normal) {
+ private val nDice: Int
+ private val dieSize: Int
+
+ init {
+ val parts = rollString.lowercase().split("d")
+ nDice = parts[0].toInt()
+ dieSize = parts[1].toInt()
+ }
+
+ fun roll(r: Random): Int {
+ return when(rollType){
+ RollType.Advantage->{
+ val range1 = (dieSize * nDice) - nDice
+ val range2 = (dieSize * nDice) - nDice
+ return max(range1, range2) + nDice
+ }
+ RollType.Disadvantage->{
+ val range1 = (dieSize * nDice) - nDice
+ val range2 = (dieSize * nDice) - nDice
+ return min(range1, range2) + nDice
+ }
+ else->{
+ val range = (dieSize * nDice) - nDice
+ r.nextInt(range) + nDice
+ }
+ }
+
+ }
+}
+
+class DiceBonus(private val dice: Dice) : Bonus {
+ override fun getBonus(r: Random): Int {
+ return dice.roll(r)
+ }
+
+}
+
+class FlatBonus(private val bonus: Int) : Bonus {
+ override fun getBonus(r: Random): Int {
+ return bonus
+ }
+}
+
+class SimpleMeleeAttack(
+ val attack: Dice,
+ val attackBonus: ArrayList,
+ val damageRoll: Dice,
+ val damageBonus: ArrayList,
+ val defense: Int
+) : Attack {
+ override fun attackerSuccessful(r: Random): Boolean {
+ val attackTotal = attack.roll(r) + attackBonus.sumOf { it.getBonus(r) }
+
+ return attackTotal >= defense
+ }
+
+ override fun resultingDamage(r: Random, attackSuccessful: Boolean): Int {
+ return if(attackSuccessful){
+ damageRoll.roll(r) + damageBonus.sumOf { it.getBonus(r) }
+ }else{
+ 0
+ }
+ }
+
+}
diff --git a/src/main/kotlin/simulation/Simulator.kt b/src/main/kotlin/simulation/Simulator.kt
new file mode 100644
index 0000000..43c069b
--- /dev/null
+++ b/src/main/kotlin/simulation/Simulator.kt
@@ -0,0 +1,69 @@
+package simulation
+
+import kotlinx.coroutines.async
+import kotlinx.coroutines.runBlocking
+import java.util.*
+import kotlin.collections.ArrayList
+
+
+interface SimulationModel {
+ val sampleSize: Int
+
+ //has to be pure or else you're going to have a bad time
+ fun simulate(r: Random): T
+}
+
+interface Simulator {
+
+ companion object {
+ fun getInstance(nThreads: Int = Runtime.getRuntime().availableProcessors() / 2 ): Simulator {
+ return concreteSimulator(nThreads)
+ }
+ }
+
+ val nThreads: Int
+
+ fun doSimulation(model: SimulationModel): ArrayList {
+ val results = Collections.synchronizedList(ArrayList(model.sampleSize))
+
+ val steps = model.sampleSize / nThreads
+ var remainder = model.sampleSize % nThreads
+
+ runBlocking {
+ val jobs = List(nThreads) {
+ async {
+ val s = if (remainder > 0) {
+ remainder--
+ steps + 1
+ } else {
+ steps
+ }
+
+ generateResults(s, model)
+ }
+ }
+
+ jobs.forEach {
+ results.addAll(it.await())
+
+ }
+ }
+
+
+ return results.toCollection(ArrayList())
+ }
+
+
+ private fun generateResults(steps: Int, model: SimulationModel): ArrayList {
+ val results = ArrayList(steps)
+ val r = Random()
+ for (i in 0..(override val nThreads: Int) :
+ Simulator
\ No newline at end of file
diff --git a/src/main/rust/src/hello.rs b/src/main/rust/src/lib.rs
similarity index 100%
rename from src/main/rust/src/hello.rs
rename to src/main/rust/src/lib.rs
diff --git a/src/test/kotlin/simulation/SimulatorTest.kt b/src/test/kotlin/simulation/SimulatorTest.kt
new file mode 100644
index 0000000..489f056
--- /dev/null
+++ b/src/test/kotlin/simulation/SimulatorTest.kt
@@ -0,0 +1,55 @@
+package simulation
+
+import java.util.*
+import kotlin.test.Test
+
+class SimulatorTest {
+ @Test
+ fun testStats(){
+ val itt = 10_000_000
+ val model = testSimulationModel(itt)
+ val simulator = Simulator.getInstance(Runtime.getRuntime().availableProcessors())
+ val start = System.nanoTime()
+ val results = simulator.doSimulation(model)
+ val finish = System.nanoTime()
+ println("${results.size} simulations performed in ${finish - start}ns (${(finish-start)/results.size}ns/simulation)")
+ }
+
+ @Test
+ fun testAttack(){
+ val itt = 10_000_000
+ val simulator = Simulator.getInstance(Runtime.getRuntime().availableProcessors())
+
+ val attack = SimpleMeleeAttack(
+ Dice("1d20"),
+ arrayListOf(FlatBonus(5)),
+ Dice("2d6"),
+ arrayListOf(FlatBonus(5)),
+ 15
+ )
+
+ val attackWithAdvantageAndBless = SimpleMeleeAttack(
+ Dice("1d20", RollType.Advantage),
+ arrayListOf(FlatBonus(5), DiceBonus(Dice("1d4"))),
+ Dice("2d6"),
+ arrayListOf(FlatBonus(5)),
+ 15
+ )
+
+ val normalAttackModel = AttackSimulatorModel(itt, attack)
+ val normalResults = simulator.doSimulation(normalAttackModel)
+
+ val buffedAttackModel = AttackSimulatorModel(itt, attackWithAdvantageAndBless)
+ val buffedResults = simulator.doSimulation(buffedAttackModel)
+
+ println("Average normal damage: ${normalResults.average()}\nAverage buffed damage: ${buffedResults.average()}")
+ }
+}
+
+
+class testSimulationModel(override val sampleSize: Int) : SimulationModel{
+ override fun simulate(r: Random): Int {
+ return r.nextInt(20)+1
+ }
+
+}
\ No newline at end of file