Advertisement
Guest User

Untitled

a guest
Sep 21st, 2019
99
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 13.62 KB | None | 0 0
  1. package com.runematescript
  2.  
  3. import com.runemate.game.api.hybrid.Environment
  4. import com.runemate.game.api.hybrid.entities.details.Renderable
  5. import com.runemate.game.api.hybrid.local.Screen
  6. import com.runemate.game.api.script.framework.AbstractBot
  7. import com.runemate.game.api.script.framework.listeners.EngineListener
  8. import com.sun.jna.Pointer
  9. import com.sun.jna.platform.win32.*
  10. import com.sun.jna.platform.win32.WinUser.*
  11. import com.sun.jna.ptr.IntByReference
  12. import javafx.application.Platform
  13. import javafx.beans.property.BooleanProperty
  14. import javafx.beans.property.SimpleBooleanProperty
  15. import javafx.scene.Scene
  16. import javafx.scene.canvas.Canvas
  17. import javafx.scene.layout.Background
  18. import javafx.scene.layout.Pane
  19. import javafx.scene.paint.Color
  20. import javafx.stage.Stage
  21. import javafx.stage.StageStyle
  22. import java.util.*
  23. import java.util.concurrent.Semaphore
  24. import java.util.concurrent.TimeUnit
  25. import kotlin.concurrent.thread
  26.  
  27. interface GameOverlay {
  28. var enableDoubleBuffering: Boolean
  29. val state: State
  30.  
  31. fun initialize()
  32. fun destroy()
  33. fun addRenderable(renderable: Renderable)
  34. fun removeRenderable(renderable: Renderable)
  35.  
  36. companion object {
  37. @JvmStatic
  38. fun newOverlay(bot: AbstractBot): GameOverlay = WindowsGameOverlay(bot)
  39. }
  40.  
  41. enum class State {
  42. READY, INITIALIZED, DESTROYED
  43. }
  44. }
  45.  
  46. private abstract class GameOverlayBase : GameOverlay, EngineListener {
  47. private val renderables: MutableList<Renderable> = Collections.synchronizedList(mutableListOf())
  48. val renderLock = Semaphore(1)
  49. override var enableDoubleBuffering = false
  50. override var state = GameOverlay.State.READY;
  51. abstract val bot: AbstractBot
  52.  
  53. lateinit var stage: OverlayStage
  54. lateinit var gamePID: String
  55.  
  56. open fun prepareStage() {}
  57. open fun setup() {}
  58. open fun overlayMain() {}
  59. open fun onDestroy() {}
  60.  
  61. final override fun initialize() {
  62. when (state) {
  63. GameOverlay.State.READY -> state = GameOverlay.State.INITIALIZED
  64. GameOverlay.State.INITIALIZED -> return
  65. GameOverlay.State.DESTROYED -> return
  66. }
  67.  
  68. gamePID = Environment.getRuneScapeProcessId() ?: throw IllegalStateException("Couldn't get game process id")
  69.  
  70. Platform.runLater {
  71. stage = OverlayStage("GameOverlay$gamePID%")
  72.  
  73. prepareStage()
  74. stage.show()
  75.  
  76. bot.platform.invokeLater {
  77. setup()
  78. bot.eventDispatcher.addListener(this)
  79. overlayMain()
  80. }
  81. }
  82. }
  83.  
  84. final override fun destroy() {
  85. when (state) {
  86. GameOverlay.State.READY -> {
  87. state = GameOverlay.State.DESTROYED
  88. return
  89. }
  90. GameOverlay.State.INITIALIZED -> state = GameOverlay.State.DESTROYED
  91. GameOverlay.State.DESTROYED -> return
  92. }
  93.  
  94. try {
  95. onDestroy()
  96. bot.eventDispatcher.removeListener(this)
  97. Platform.runLater {
  98. stage.close()
  99. }
  100. } catch (e: Exception) {
  101. e.printStackTrace(bot.logger.printStream)
  102. }
  103. }
  104.  
  105. final override fun addRenderable(renderable: Renderable) {
  106. renderables.add(renderable)
  107. }
  108.  
  109. final override fun removeRenderable(renderable: Renderable) {
  110. renderables.remove(renderable)
  111. }
  112.  
  113. final override fun onCycleStart() {
  114. if (renderLock.tryAcquire()) {
  115. thread {
  116. try {
  117. if (enableDoubleBuffering) {
  118. stage.renderDoubleBuffered(renderables)
  119. } else {
  120. stage.render(renderables)
  121. }
  122. } finally {
  123. renderLock.release()
  124. }
  125. }
  126. }
  127. }
  128. }
  129.  
  130. private class OverlayStage(title: String) : Stage(StageStyle.TRANSPARENT) {
  131. val root = Pane()
  132.  
  133. private val frontCanvas = Canvas()
  134. private val backCanvas = Canvas()
  135. private val doubleBufferingFlag = SimpleBooleanProperty()
  136.  
  137. init {
  138. setTitle(title)
  139.  
  140. scene = Scene(root, 1.0, 1.0, Color.TRANSPARENT)
  141. root.background = Background.EMPTY
  142.  
  143. frontCanvas.widthProperty().bind(widthProperty())
  144. frontCanvas.heightProperty().bind(heightProperty())
  145. backCanvas.widthProperty().bind(widthProperty())
  146. backCanvas.heightProperty().bind(heightProperty())
  147.  
  148. frontCanvas.visibleProperty().bind(doubleBufferingFlag)
  149. backCanvas.visibleProperty().bind(doubleBufferingFlag.not())
  150.  
  151. root.children.setAll(frontCanvas, backCanvas)
  152.  
  153. root.setOnMouseMoved { event ->
  154. println("${event.x}, ${event.y}")
  155. }
  156. }
  157.  
  158. fun render(renderables: List<Renderable>) {
  159. val canvas = if (doubleBufferingFlag.get()) frontCanvas else backCanvas
  160. val graphics = canvas.graphicsContext2D
  161. graphics.clearRect(0.0, 0.0, width, height)
  162. renderables.forEach {
  163. it.render(graphics)
  164. }
  165. }
  166.  
  167. fun renderDoubleBuffered(renderables: List<Renderable>) {
  168. val flag = doubleBufferingFlag.get()
  169. val canvas = if (flag) backCanvas else frontCanvas
  170. val graphics = canvas.graphicsContext2D
  171. graphics.clearRect(0.0, 0.0, width, height)
  172. renderables.forEach {
  173. it.render(graphics)
  174. }
  175.  
  176. Platform.runLater {
  177. doubleBufferingFlag.set(!flag)
  178. }
  179. }
  180. }
  181.  
  182. private class WindowsGameOverlay(override val bot: AbstractBot) : GameOverlayBase() {
  183. private val user32 = User32.INSTANCE
  184. private val kernel32 = Kernel32.INSTANCE
  185. private val hooks = mutableListOf<WinNT.HANDLE>()
  186. private val procs = mutableListOf<WinEventProc>()
  187. private var threadID: Int = -1
  188.  
  189. override fun prepareStage() {
  190.  
  191. }
  192.  
  193. override fun setup() {
  194. threadID = kernel32.GetCurrentThreadId()
  195.  
  196. val (gameHWND, overlayHWND) = findWindowHandles()
  197.  
  198. val localPID = getProcessIdOf(overlayHWND)
  199. val gamePID = gamePID.toInt()
  200.  
  201. val style = user32.GetWindowLong(overlayHWND, GWL_EXSTYLE)
  202. user32.ShowWindow(overlayHWND, SW_HIDE)
  203. user32.SetWindowLong(overlayHWND, GWL_EXSTYLE, style or WS_EX_TRANSPARENT or WS_EX_TOOLWINDOW)
  204. user32.ShowWindow(overlayHWND, SW_SHOW)
  205.  
  206. GameRelocateProc.adjustPosition(overlayHWND)
  207. GameFocusProc.adjustZOrder(gameHWND, overlayHWND)
  208.  
  209. val gameFocusProc = GameFocusProc(gameHWND, overlayHWND)
  210. val overlayFocusProc = OverlayFocusProc(gameHWND, overlayHWND)
  211. val gameRelocateProc = GameRelocateProc(overlayHWND)
  212. val gameDestroyProc = GameDestroyProc(this, gameHWND)
  213. val gameMinimizeProc = GameMinimizeProc(this, gameHWND, overlayHWND)
  214.  
  215. Collections.addAll(procs,
  216. gameFocusProc,
  217. overlayFocusProc,
  218. gameRelocateProc,
  219. gameDestroyProc,
  220. gameMinimizeProc
  221. )
  222.  
  223. Collections.addAll(hooks,
  224. user32.SetWinEventHook(EVENT_OBJECT_REORDER, EVENT_OBJECT_REORDER, null, gameFocusProc, gamePID, 0, WINEVENT_OUTOFCONTEXT or WINEVENT_SKIPOWNPROCESS),
  225. user32.SetWinEventHook(EVENT_SYSTEM_FOREGROUND, EVENT_SYSTEM_FOREGROUND, null, gameFocusProc, gamePID, 0, WINEVENT_OUTOFCONTEXT or WINEVENT_SKIPOWNPROCESS),
  226. user32.SetWinEventHook(EVENT_OBJECT_REORDER, EVENT_OBJECT_REORDER, null, overlayFocusProc, localPID, 0, WINEVENT_OUTOFCONTEXT or WINEVENT_SKIPOWNTHREAD),
  227. user32.SetWinEventHook(EVENT_SYSTEM_FOREGROUND, EVENT_SYSTEM_FOREGROUND, null, overlayFocusProc, localPID, 0, WINEVENT_OUTOFCONTEXT or WINEVENT_SKIPOWNTHREAD),
  228. user32.SetWinEventHook(EVENT_OBJECT_LOCATIONCHANGE, EVENT_OBJECT_LOCATIONCHANGE, null, gameRelocateProc, gamePID, 0, WINEVENT_OUTOFCONTEXT or WINEVENT_SKIPOWNPROCESS),
  229. user32.SetWinEventHook(EVENT_OBJECT_DESTROY, EVENT_OBJECT_DESTROY, null, gameDestroyProc, gamePID, 0, WINEVENT_OUTOFCONTEXT or WINEVENT_SKIPOWNPROCESS),
  230. user32.SetWinEventHook(EVENT_SYSTEM_MINIMIZESTART, EVENT_SYSTEM_MINIMIZEEND, null, gameMinimizeProc, gamePID, 0, WINEVENT_OUTOFCONTEXT or WINEVENT_SKIPOWNPROCESS)
  231. )
  232. }
  233.  
  234. override fun overlayMain() {
  235. val msg = WinUser.MSG()
  236. while (user32.GetMessage(msg, null, 0, 0) > 0) {
  237. user32.TranslateMessage(msg)
  238. user32.DispatchMessage(msg)
  239. }
  240. }
  241.  
  242. override fun onDestroy() {
  243. user32.PostThreadMessage(threadID, WM_QUIT, null, null)
  244. hooks.forEach {
  245. user32.UnhookWinEvent(it)
  246. }
  247. }
  248.  
  249. private fun getProcessIdOf(overlayHWND: WinDef.HWND): Int {
  250. val ref = IntByReference()
  251. user32.GetWindowThreadProcessId(overlayHWND, ref)
  252. return ref.value
  253. }
  254.  
  255. private fun findWindowHandles(): Pair<WinDef.HWND, WinDef.HWND> {
  256. var gameHWND: WinDef.HWND? = null
  257. var overlayHWND: WinDef.HWND? = null
  258.  
  259. val proc = proc@{ hwnd: WinDef.HWND, _: Pointer? ->
  260. val buffer = CharArray(100)
  261. user32.GetWindowText(hwnd, buffer, 100)
  262. val title = String(buffer)
  263.  
  264. if (overlayHWND == null && title.startsWith(stage.title)) {
  265. overlayHWND = hwnd
  266. } else if (gameHWND == null && title.contains("RuneScape")) {
  267. val pid = IntByReference()
  268. user32.GetWindowThreadProcessId(hwnd, pid)
  269. if (pid.value == gamePID.toInt()) {
  270. gameHWND = hwnd
  271. }
  272. }
  273.  
  274. true
  275. }
  276.  
  277. user32.EnumWindows(proc, null);
  278.  
  279. return Pair(
  280. gameHWND ?: throw IllegalStateException("Couldn't find game window"),
  281. overlayHWND ?: throw IllegalStateException("Couldn't find overlay window")
  282. )
  283. }
  284. }
  285.  
  286. private class GameMinimizeProc(private val overlay: WindowsGameOverlay, private val gameHWND: WinDef.HWND, private val overlayHWND: WinDef.HWND) : WinUser.WinEventProc {
  287. override fun callback(hWinEventHook: WinNT.HANDLE, event: WinDef.DWORD, hwnd: WinDef.HWND?, idObject: WinDef.LONG, idChild: WinDef.LONG, idEventThread: WinDef.DWORD, dwmsEventTime: WinDef.DWORD) {
  288. if (hwnd == gameHWND) {
  289. when (event.toInt()) {
  290. EVENT_SYSTEM_MINIMIZESTART -> {
  291. User32.INSTANCE.ShowWindow(overlayHWND, SW_HIDE)
  292. overlay.renderLock.acquire()
  293. }
  294. EVENT_SYSTEM_MINIMIZEEND -> {
  295. User32.INSTANCE.ShowWindow(overlayHWND, SW_SHOW)
  296. overlay.renderLock.release()
  297. }
  298. }
  299. }
  300. }
  301. }
  302.  
  303. private class GameDestroyProc(private val overlay: GameOverlay, private val gameHWND: WinDef.HWND) : WinUser.WinEventProc {
  304. override fun callback(hWinEventHook: WinNT.HANDLE, event: WinDef.DWORD, hwnd: WinDef.HWND?, idObject: WinDef.LONG, idChild: WinDef.LONG, idEventThread: WinDef.DWORD, dwmsEventTime: WinDef.DWORD) {
  305. if (hwnd == gameHWND) {
  306. overlay.destroy()
  307. }
  308. }
  309. }
  310.  
  311. private class GameFocusProc(private val gameHWND: WinDef.HWND, private val overlayHWND: WinDef.HWND) : WinUser.WinEventProc {
  312. override fun callback(hWinEventHook: WinNT.HANDLE, event: WinDef.DWORD, hwnd: WinDef.HWND?, idObject: WinDef.LONG, idChild: WinDef.LONG, idEventThread: WinDef.DWORD, dwmsEventTime: WinDef.DWORD) {
  313. adjustZOrder(gameHWND, overlayHWND)
  314. }
  315.  
  316. companion object {
  317. fun adjustZOrder(gameHWND: WinDef.HWND, overlayHWND: WinDef.HWND) {
  318. User32.INSTANCE.SetWindowPos(overlayHWND, gameHWND, 0, 0, 0, 0, SWP_NOSIZE or SWP_NOMOVE or SWP_NOACTIVATE)
  319. User32.INSTANCE.SetWindowPos(gameHWND, overlayHWND, 0, 0, 0, 0, SWP_NOSIZE or SWP_NOMOVE or SWP_NOACTIVATE)
  320. }
  321. }
  322. }
  323.  
  324. private class OverlayFocusProc(private val gameHWND: WinDef.HWND, private val overlayHWND: WinDef.HWND) : WinUser.WinEventProc {
  325. override fun callback(hWinEventHook: WinNT.HANDLE, event: WinDef.DWORD, hwnd: WinDef.HWND?, idObject: WinDef.LONG, idChild: WinDef.LONG, idEventThread: WinDef.DWORD, dwmsEventTime: WinDef.DWORD) {
  326. User32.INSTANCE.SetWindowPos(gameHWND, overlayHWND, 0, 0, 0, 0, SWP_NOSIZE or SWP_NOMOVE or SWP_NOACTIVATE)
  327. }
  328. }
  329.  
  330. private class GameRelocateProc(private val overlayHWND: WinDef.HWND) : WinUser.WinEventProc {
  331. override fun callback(hWinEventHook: WinNT.HANDLE, event: WinDef.DWORD, hwnd: WinDef.HWND?, idObject: WinDef.LONG, idChild: WinDef.LONG, idEventThread: WinDef.DWORD, dwmsEventTime: WinDef.DWORD) {
  332. if (hwnd != null) {
  333. adjustPosition(overlayHWND)
  334. }
  335. }
  336.  
  337. companion object {
  338. fun adjustPosition(overlayHWND: WinDef.HWND) {
  339. val location = Screen.getLocation() ?: return
  340. val bounds = Screen.getBounds() ?: return
  341.  
  342. User32.INSTANCE.SetWindowPos(overlayHWND, null, location.x, location.y, bounds.width, bounds.height, SWP_NOZORDER)
  343. }
  344. }
  345. }
  346.  
  347. private const val WINEVENT_OUTOFCONTEXT = 0x0000
  348. private const val WINEVENT_SKIPOWNTHREAD = 0x0001
  349. private const val WINEVENT_SKIPOWNPROCESS = 0x0002
  350. private const val WINEVENT_INCONTEXT = 0x0004
  351.  
  352. private const val EVENT_SYSTEM_FOREGROUND = 0x0003
  353. private const val EVENT_SYSTEM_MINIMIZESTART = 0x0016
  354. private const val EVENT_SYSTEM_MINIMIZEEND = 0x0017
  355. private const val EVENT_OBJECT_DESTROY = 0x8001
  356. private const val EVENT_OBJECT_REORDER = 0x8004
  357. private const val EVENT_OBJECT_LOCATIONCHANGE = 0x800B
  358.  
  359. private const val WS_EX_TOOLWINDOW = 0x0080;
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement