├── .gitattributes ├── explore ├── 2020-01-03.add-audio-message │ ├── .gitignore │ ├── elm.json │ └── src │ │ ├── Main.elm │ │ └── Bot.elm ├── 2019-05-10.eve-online-travel-bot │ ├── .gitignore │ ├── elm.json │ └── src │ │ └── SimplifiedSanderling.elm ├── 2020-01-06.explore-tribal-wars-2 │ ├── .gitignore │ ├── elm-analyse.json │ ├── elm.json │ └── src │ │ ├── Main.elm │ │ └── Limbara │ │ └── Limbara.elm ├── 2019-05-14.eve-online-bot-framework │ ├── .gitignore │ ├── elm.json │ └── tests │ │ └── SanderlingInterfaceTest.elm ├── 2019-07-10.locate-objects-in-screenshot │ ├── app │ │ ├── .gitignore │ │ └── elm.json │ └── 2019-07-11.example-from-eve-online-crop-0.bmp ├── 2019-07-04.read-screenshot-from-file-and-configure-image-search │ └── app │ │ ├── .gitignore │ │ └── elm.json ├── 2019-09-15.eve-online-memory-reading │ ├── implement │ │ └── eve-online-memory-reading │ │ │ ├── .gitignore │ │ │ ├── eve-online-memory-reading.csproj │ │ │ ├── CommonConversion.cs │ │ │ ├── PyStr.cs │ │ │ ├── PyList.cs │ │ │ ├── EveOnline.cs │ │ │ ├── SampleMemoryReader.cs │ │ │ ├── BotEngine │ │ │ ├── Kernel32.cs │ │ │ └── Measurement.cs │ │ │ ├── PythonMemoryReader.cs │ │ │ ├── ProcessMemoryReader.cs │ │ │ └── PyDict.cs │ └── 2019-09-15.eve-online-memory-reading.md ├── 2019-08-09.simple-bot-framework │ └── dotnet-windows-bot-interface │ │ ├── .gitignore │ │ └── dotnet-windows-bot-interface.csproj ├── 2020-12-07-explore-multi-instance-scenarios │ └── eve-online-test-coordinate-input-focus │ │ ├── .gitignore │ │ ├── elm-analyse.json │ │ ├── Common │ │ ├── FNV.elm │ │ ├── Basics.elm │ │ └── DecisionTree.elm │ │ ├── elm.json │ │ └── EveOnline │ │ └── MemoryReading.elm ├── 2019-06-26.how-to-take-screenshots │ └── 2019-06-26.eve-online-screenshot.jpeg ├── 2020-07-06-tribal-wars-2-farmbot-bug │ └── 2020-07-03-tribal-wars-2-farmbot-bug.png ├── 2019-08-02.interface-to-host │ └── 2019-08-02.interface-to-host.md ├── 2020-05-20-explore-tribal-wars-2 │ ├── 2020-05-20-battle-reports-with-casualties.json │ └── 2020-05-20-battle-report-with-casualties.json ├── 2020-03-04.make-running-a-bot-easier │ └── run-app-2DA2E2EDBD.bat ├── 2019-08-14.locate-object-in-window │ └── 2019-08-14.locate-object-in-window.md ├── 2020-05-04-guide-on-developing-bots │ └── 2020-05-04-guide-on-developing-bots.md ├── 2019-10-14.improve-automated-testing │ └── 2019-10-14.improve-automated-testing.md └── 2020-07-31-learning-how-an-app-works │ └── 2020-07-31-learning-how-an-app-works.md ├── implement ├── templates │ ├── remember-bot-settings │ │ ├── .gitignore │ │ ├── elm-analyse.json │ │ ├── elm.json │ │ └── Bot.elm │ ├── send-input-to-window │ │ ├── .gitignore │ │ ├── elm-analyse.json │ │ ├── CompilationInterface │ │ │ └── SourceFiles.elm │ │ └── elm.json │ ├── locate-object-in-window │ │ ├── .gitignore │ │ ├── elm-analyse.json │ │ ├── CompilationInterface │ │ │ └── SourceFiles.elm │ │ └── elm.json │ ├── display-session-length-limit │ │ ├── .gitignore │ │ ├── elm-analyse.json │ │ ├── elm.json │ │ └── Bot.elm │ └── minimal-bot-using-volatile-process-with-callback │ │ ├── .gitignore │ │ ├── CompilationInterface │ │ └── SourceFiles.elm │ │ ├── VolatileProcess.csx │ │ ├── elm-analyse.json │ │ └── elm.json └── applications │ ├── elvenar │ ├── elvenar-bot │ │ ├── .gitignore │ │ ├── elm-analyse.json │ │ ├── CompilationInterface │ │ │ └── SourceFiles.elm │ │ └── elm.json │ ├── elvenar-bot-elm-test │ │ ├── .gitignore │ │ ├── elm-analyse.json │ │ ├── elm.json │ │ └── tests │ │ │ └── Sample_2023_04_26.elm │ └── training-data │ │ ├── 2022-03-07-elvenar-djvj-BTqe1xf.bmp │ │ └── 2023-04-26-elvenar-sample-collectibles-icons-125.png │ ├── eve-online │ ├── eve-online-mining-bot │ │ ├── .gitignore │ │ ├── elm-analyse.json │ │ ├── CompilationInterface │ │ │ └── SourceFiles.elm │ │ ├── Common │ │ │ ├── FNV.elm │ │ │ ├── Basics.elm │ │ │ └── DecisionPath.elm │ │ ├── elm.json │ │ ├── BotLab │ │ │ └── NotificationsShim │ │ │ │ ├── VolatileProcess.csx │ │ │ │ └── VolatileProcessInterface.elm │ │ └── EveOnline │ │ │ └── MemoryReading.elm │ ├── eve-online-framework-test │ │ ├── .gitignore │ │ ├── elm-analyse.json │ │ ├── elm.json │ │ └── tests │ │ │ └── BotFrameworkTest.elm │ ├── eve-online-combat-anomaly-bot │ │ ├── .gitignore │ │ ├── elm-analyse.json │ │ ├── CompilationInterface │ │ │ └── SourceFiles.elm │ │ ├── Common │ │ │ ├── FNV.elm │ │ │ ├── Basics.elm │ │ │ └── DecisionPath.elm │ │ ├── elm.json │ │ ├── BotLab │ │ │ └── NotificationsShim │ │ │ │ ├── VolatileProcess.csx │ │ │ │ └── VolatileProcessInterface.elm │ │ └── EveOnline │ │ │ └── MemoryReading.elm │ ├── eve-online-warp-to-0-autopilot │ │ ├── .gitignore │ │ ├── elm-analyse.json │ │ ├── CompilationInterface │ │ │ └── SourceFiles.elm │ │ ├── Common │ │ │ ├── FNV.elm │ │ │ ├── Basics.elm │ │ │ └── DecisionPath.elm │ │ ├── elm.json │ │ ├── BotLab │ │ │ └── NotificationsShim │ │ │ │ ├── VolatileProcess.csx │ │ │ │ └── VolatileProcessInterface.elm │ │ └── EveOnline │ │ │ └── MemoryReading.elm │ └── training-data │ │ ├── 2019-06-26.eve-online-screenshot.jpeg │ │ ├── 2019-07-30.eve-online-context-menu-system.png │ │ ├── 2019-08-06.eve-online-overview-entry-menu.png │ │ ├── 2020-07-10-eve-online-surroundings-button.png │ │ ├── 2019-08-06.eve-online-last-route-element-menu.png │ │ ├── 2019-08-06.eve-online-station-window-undock-and-other-buttons.png │ │ └── 2019-08-06.eve-online-station-window-undock-button-mouse-over.png │ ├── tribal-wars-2 │ ├── tribal-wars-2-farmbot │ │ ├── .gitignore │ │ ├── elm-analyse.json │ │ ├── Common │ │ │ ├── Basics.elm │ │ │ └── DecisionTree.elm │ │ └── elm.json │ ├── tribal-wars-2.game-ui-setup.png │ └── training-data │ │ └── 2021-03-13-tribal-wars-2-outgoing-command-returning.json │ └── web-browser │ └── web-browser-csharp │ ├── .gitignore │ └── web-browser-csharp.csproj ├── .vscode └── extensions.json ├── .github ├── copilot-instructions.md └── workflows │ └── test-and-publish.yml ├── guide ├── image │ ├── 2020-08-08-simulate-run-cmd.png │ ├── chromium-menu.with-zoom-100%.png │ ├── windows-display-settings-scale.png │ ├── 2019-08-17.paint.net-color-picker.png │ ├── 2020-08-08-simulate-run-progress.png │ ├── 2020-06-10-vscode-elm-display-error.png │ ├── 2022-12-10-botlab-client-select-bot.png │ ├── vscode-open-directory-from-explorer.png │ ├── 2022-10-07-botlab-client-offer-install.png │ ├── 2020-01-20.vscode-elm-extension-install.png │ ├── 2020-01-20.vscode-elm-extension-settings.png │ ├── 2021-11-29-botlab-catalog-search-results.png │ ├── 2020-06-10-vscode-elm-display-error-hover.png │ ├── 2021-12-09-botlab-client-devtools-default.png │ ├── 2021-12-09-botlab-devtools-select-session.png │ ├── 2021-12-09-botlab-devtools-session-summary.png │ ├── 2024-02-18-botlab-client-initial-main-menu.png │ ├── chromium-menu.with-zoom-100%.crop-to-zoom.png │ ├── 2019-10-10.fix-windows-sandbox-internet-access.png │ ├── 2020-05-08-vscode-settings-extension-elm-format.png │ ├── 2021-11-30-botlab-reactor-online-session-detail.png │ ├── 2021-12-09-botlab-devtools-session-event-details.png │ ├── 2022-10-07-botlab-client-completed-installation.png │ ├── 2022-12-02-botlab-client-confirm-online-session.png │ ├── 2023-05-11-botlab-input-scheduling-illustration.png │ ├── 2021-11-30-botlab-reactor-show-online-session-key.png │ ├── 2021-12-09-botlab-client-devtools-import-artifact.png │ ├── 2021-12-09-botlab-client-main-menu-enter-devtools.png │ ├── 2019-08-16.demo-bot-template-locate-object-in-window.png │ ├── 2020-08-08-configure-run-app-multiline-app-settings.png │ ├── 2021-11-30-botlab-reactor-dashboard-recent-sessions.png │ ├── 2024-02-18-botlab-client-executable-file-in-explorer.png │ ├── 2024-02-18-botlab-client-play-session-summary-export.png │ ├── 2020-02-07.eve-online-memory-usage-first-memory-reading.png │ ├── 2021-12-09-botlab-devtools-select-session-with-imported.png │ ├── 2022-12-10-botlab-client-select-bot-entered-catalog-url.png │ ├── 2024-02-18-botlab-client-main-menu-with-recent-sessions.png │ ├── 2020-12-08-input-focus-scheduling-runtime-engine-windows.png │ ├── 2021-01-24-data-flow-in-bot-architecture-separating-memory.png │ ├── 2021-10-13-data-flow-in-bot-architecture-separating-memory.png │ ├── 2021-11-29-botlab-ide-program-code-completion-suggestions.png │ ├── 2022-12-10-botlab-client-configure-session-bot-description.png │ ├── 2023-05-11-botlab-input-scheduling-two-client-instances-gui.png │ ├── 2025-04-23-botlab-client-ui-export-session-recording-dialog.png │ ├── 2024-01-03-botlab-client-webbrowser-user-data-folder-indication.png │ ├── 2022-12-02-botlab-client-configure-session-online-session-marked.png │ ├── 2021-12-09-botlab-devtools-session-event-details-eve-online-reading.png │ ├── 2024-03-30-botlab-client-play-session-input-focus-scheduling-disabled.png │ ├── 2024-03-30-botlab-client-configure-session-input-focus-scheduling-disabled.png │ └── data-flow-in-bot-architecture-separating-memory.xml ├── eve-online │ ├── image │ │ ├── 2020-07-10-eve-online-surroundings-button.png │ │ ├── 2020-03-25-eve-online-inventory-context-menu.png │ │ ├── 2020-07-19-BrianCorner-eve-online-repair-all.png │ │ ├── 2023-03-08-botlab-gui-eve-online-bot-startup.png │ │ ├── 2019-10-08.eve-online-launcher-settings-dialog.png │ │ ├── 2020-03-11-eve-online-ship-ui-module-rows-names.png │ │ ├── 2021-02-23-briancorner-eve-online-drones-window.png │ │ ├── 2020-03-11-eve-online-parsed-user-interface-names.png │ │ ├── 2020-05-13-eve-online-module-button-tooltip-scaled.png │ │ ├── 2020-03-11-eve-online-parsed-user-interface-inventory-inspect.png │ │ ├── 2021-08-29-eve-online-autopilot-bot-code-in-elm-editor-in-space.png │ │ └── 2021-02-12-eve-online-inspect-memory-reading-of-abyssal-key-activation-window .png │ ├── eve-online-players-strategies.md │ └── eve-online-warp-to-0-autopilot-bot.md ├── tribal-wars-2 │ └── image │ │ ├── 2025-02-16-tribal-wars-2-farmbot-started.png │ │ ├── 2025-02-16-tribal-wars-2-farmbot-game-entered.jpeg │ │ ├── 2021-12-02-tribal-wars-2-farmbot-browser-profile-id.png │ │ ├── 2020-01-25.tribal-wars-2-farmbot-configure-army-preset.png │ │ ├── 2022-12-01-tw2-farmbot-configure-session-start-marked.png │ │ ├── 2025-02-16-tribal-wars-2-farmbot-select-bot-bundled-bot-with-marker.png │ │ ├── 2022-12-01-tw2-farmbot-configure-session-section-bot-settings-edited-crop.png │ │ └── 2022-12-01-tw2-farmbot-configure-session-section-bot-settings-marked-edit.png ├── common-player-agent-interface.md ├── botlab-contributor-program.md ├── bot-development-language-and-terms.md ├── how-to-install-the-botlab-client-and-register-the-botlab-command.md ├── elvenar │ └── elvenar-bot.md ├── how-to-collect-samples-for-64-bit-memory-reading-development.md ├── how-to-report-an-issue-with-a-bot-or-request-a-new-feature.md ├── botlab-online-session.md └── running-bots-on-multiple-game-clients.md ├── .editorconfig └── License.txt /.gitattributes: -------------------------------------------------------------------------------- 1 | * -text -------------------------------------------------------------------------------- /explore/2020-01-03.add-audio-message/.gitignore: -------------------------------------------------------------------------------- 1 | /elm-stuff/ 2 | 3 | -------------------------------------------------------------------------------- /explore/2019-05-10.eve-online-travel-bot/.gitignore: -------------------------------------------------------------------------------- 1 | /elm-stuff/ 2 | 3 | -------------------------------------------------------------------------------- /explore/2020-01-06.explore-tribal-wars-2/.gitignore: -------------------------------------------------------------------------------- 1 | /elm-stuff/ 2 | 3 | -------------------------------------------------------------------------------- /implement/templates/remember-bot-settings/.gitignore: -------------------------------------------------------------------------------- 1 | /elm-stuff/ 2 | 3 | -------------------------------------------------------------------------------- /implement/templates/send-input-to-window/.gitignore: -------------------------------------------------------------------------------- 1 | /elm-stuff/ 2 | 3 | -------------------------------------------------------------------------------- /explore/2019-05-14.eve-online-bot-framework/.gitignore: -------------------------------------------------------------------------------- 1 | /elm-stuff/ 2 | 3 | -------------------------------------------------------------------------------- /implement/applications/elvenar/elvenar-bot/.gitignore: -------------------------------------------------------------------------------- 1 | /elm-stuff/ 2 | 3 | -------------------------------------------------------------------------------- /implement/templates/locate-object-in-window/.gitignore: -------------------------------------------------------------------------------- 1 | /elm-stuff/ 2 | 3 | -------------------------------------------------------------------------------- /explore/2019-07-10.locate-objects-in-screenshot/app/.gitignore: -------------------------------------------------------------------------------- 1 | /elm-stuff/ 2 | 3 | -------------------------------------------------------------------------------- /implement/applications/elvenar/elvenar-bot-elm-test/.gitignore: -------------------------------------------------------------------------------- 1 | /elm-stuff/ 2 | 3 | -------------------------------------------------------------------------------- /implement/templates/display-session-length-limit/.gitignore: -------------------------------------------------------------------------------- 1 | /elm-stuff/ 2 | 3 | -------------------------------------------------------------------------------- /implement/applications/eve-online/eve-online-mining-bot/.gitignore: -------------------------------------------------------------------------------- 1 | /elm-stuff/ 2 | 3 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "pine.pine" 4 | ] 5 | } -------------------------------------------------------------------------------- /implement/applications/eve-online/eve-online-framework-test/.gitignore: -------------------------------------------------------------------------------- 1 | /elm-stuff/ 2 | 3 | -------------------------------------------------------------------------------- /implement/applications/tribal-wars-2/tribal-wars-2-farmbot/.gitignore: -------------------------------------------------------------------------------- 1 | /elm-stuff/ 2 | 3 | -------------------------------------------------------------------------------- /implement/applications/eve-online/eve-online-combat-anomaly-bot/.gitignore: -------------------------------------------------------------------------------- 1 | /elm-stuff/ 2 | 3 | -------------------------------------------------------------------------------- /implement/applications/eve-online/eve-online-warp-to-0-autopilot/.gitignore: -------------------------------------------------------------------------------- 1 | /elm-stuff/ 2 | 3 | -------------------------------------------------------------------------------- /implement/templates/minimal-bot-using-volatile-process-with-callback/.gitignore: -------------------------------------------------------------------------------- 1 | /elm-stuff/ 2 | 3 | -------------------------------------------------------------------------------- /explore/2019-07-04.read-screenshot-from-file-and-configure-image-search/app/.gitignore: -------------------------------------------------------------------------------- 1 | /elm-stuff/ 2 | 3 | -------------------------------------------------------------------------------- /explore/2019-09-15.eve-online-memory-reading/implement/eve-online-memory-reading/.gitignore: -------------------------------------------------------------------------------- 1 | /obj/ 2 | /bin/ 3 | -------------------------------------------------------------------------------- /implement/applications/web-browser/web-browser-csharp/.gitignore: -------------------------------------------------------------------------------- 1 | /obj/ 2 | /bin/ 3 | /.vs/ 4 | /.local-chromium/ 5 | -------------------------------------------------------------------------------- /.github/copilot-instructions.md: -------------------------------------------------------------------------------- 1 | 2 | For any adaptations of the code, apply 3 | -------------------------------------------------------------------------------- /explore/2019-08-09.simple-bot-framework/dotnet-windows-bot-interface/.gitignore: -------------------------------------------------------------------------------- 1 | /obj/ 2 | /bin/ 3 | /.vs/ 4 | /test/ 5 | -------------------------------------------------------------------------------- /explore/2020-12-07-explore-multi-instance-scenarios/eve-online-test-coordinate-input-focus/.gitignore: -------------------------------------------------------------------------------- 1 | /elm-stuff/ 2 | 3 | -------------------------------------------------------------------------------- /guide/image/2020-08-08-simulate-run-cmd.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Viir/bots/HEAD/guide/image/2020-08-08-simulate-run-cmd.png -------------------------------------------------------------------------------- /guide/image/chromium-menu.with-zoom-100%.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Viir/bots/HEAD/guide/image/chromium-menu.with-zoom-100%.png -------------------------------------------------------------------------------- /guide/image/windows-display-settings-scale.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Viir/bots/HEAD/guide/image/windows-display-settings-scale.png -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | 2 | [*] 3 | end_of_line = lf 4 | 5 | [*.elm] 6 | indent_style = space 7 | 8 | [*.cs] 9 | indent_style = space 10 | -------------------------------------------------------------------------------- /guide/image/2019-08-17.paint.net-color-picker.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Viir/bots/HEAD/guide/image/2019-08-17.paint.net-color-picker.png -------------------------------------------------------------------------------- /guide/image/2020-08-08-simulate-run-progress.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Viir/bots/HEAD/guide/image/2020-08-08-simulate-run-progress.png -------------------------------------------------------------------------------- /guide/image/2020-06-10-vscode-elm-display-error.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Viir/bots/HEAD/guide/image/2020-06-10-vscode-elm-display-error.png -------------------------------------------------------------------------------- /guide/image/2022-12-10-botlab-client-select-bot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Viir/bots/HEAD/guide/image/2022-12-10-botlab-client-select-bot.png -------------------------------------------------------------------------------- /guide/image/vscode-open-directory-from-explorer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Viir/bots/HEAD/guide/image/vscode-open-directory-from-explorer.png -------------------------------------------------------------------------------- /guide/image/2022-10-07-botlab-client-offer-install.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Viir/bots/HEAD/guide/image/2022-10-07-botlab-client-offer-install.png -------------------------------------------------------------------------------- /guide/image/2020-01-20.vscode-elm-extension-install.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Viir/bots/HEAD/guide/image/2020-01-20.vscode-elm-extension-install.png -------------------------------------------------------------------------------- /guide/image/2020-01-20.vscode-elm-extension-settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Viir/bots/HEAD/guide/image/2020-01-20.vscode-elm-extension-settings.png -------------------------------------------------------------------------------- /guide/image/2021-11-29-botlab-catalog-search-results.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Viir/bots/HEAD/guide/image/2021-11-29-botlab-catalog-search-results.png -------------------------------------------------------------------------------- /guide/image/2020-06-10-vscode-elm-display-error-hover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Viir/bots/HEAD/guide/image/2020-06-10-vscode-elm-display-error-hover.png -------------------------------------------------------------------------------- /guide/image/2021-12-09-botlab-client-devtools-default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Viir/bots/HEAD/guide/image/2021-12-09-botlab-client-devtools-default.png -------------------------------------------------------------------------------- /guide/image/2021-12-09-botlab-devtools-select-session.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Viir/bots/HEAD/guide/image/2021-12-09-botlab-devtools-select-session.png -------------------------------------------------------------------------------- /guide/image/2021-12-09-botlab-devtools-session-summary.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Viir/bots/HEAD/guide/image/2021-12-09-botlab-devtools-session-summary.png -------------------------------------------------------------------------------- /guide/image/2024-02-18-botlab-client-initial-main-menu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Viir/bots/HEAD/guide/image/2024-02-18-botlab-client-initial-main-menu.png -------------------------------------------------------------------------------- /guide/image/chromium-menu.with-zoom-100%.crop-to-zoom.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Viir/bots/HEAD/guide/image/chromium-menu.with-zoom-100%.crop-to-zoom.png -------------------------------------------------------------------------------- /guide/image/2019-10-10.fix-windows-sandbox-internet-access.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Viir/bots/HEAD/guide/image/2019-10-10.fix-windows-sandbox-internet-access.png -------------------------------------------------------------------------------- /guide/image/2020-05-08-vscode-settings-extension-elm-format.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Viir/bots/HEAD/guide/image/2020-05-08-vscode-settings-extension-elm-format.png -------------------------------------------------------------------------------- /guide/image/2021-11-30-botlab-reactor-online-session-detail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Viir/bots/HEAD/guide/image/2021-11-30-botlab-reactor-online-session-detail.png -------------------------------------------------------------------------------- /guide/image/2021-12-09-botlab-devtools-session-event-details.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Viir/bots/HEAD/guide/image/2021-12-09-botlab-devtools-session-event-details.png -------------------------------------------------------------------------------- /guide/image/2022-10-07-botlab-client-completed-installation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Viir/bots/HEAD/guide/image/2022-10-07-botlab-client-completed-installation.png -------------------------------------------------------------------------------- /guide/image/2022-12-02-botlab-client-confirm-online-session.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Viir/bots/HEAD/guide/image/2022-12-02-botlab-client-confirm-online-session.png -------------------------------------------------------------------------------- /guide/image/2023-05-11-botlab-input-scheduling-illustration.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Viir/bots/HEAD/guide/image/2023-05-11-botlab-input-scheduling-illustration.png -------------------------------------------------------------------------------- /guide/image/2021-11-30-botlab-reactor-show-online-session-key.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Viir/bots/HEAD/guide/image/2021-11-30-botlab-reactor-show-online-session-key.png -------------------------------------------------------------------------------- /guide/image/2021-12-09-botlab-client-devtools-import-artifact.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Viir/bots/HEAD/guide/image/2021-12-09-botlab-client-devtools-import-artifact.png -------------------------------------------------------------------------------- /guide/image/2021-12-09-botlab-client-main-menu-enter-devtools.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Viir/bots/HEAD/guide/image/2021-12-09-botlab-client-main-menu-enter-devtools.png -------------------------------------------------------------------------------- /guide/eve-online/image/2020-07-10-eve-online-surroundings-button.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Viir/bots/HEAD/guide/eve-online/image/2020-07-10-eve-online-surroundings-button.png -------------------------------------------------------------------------------- /guide/image/2019-08-16.demo-bot-template-locate-object-in-window.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Viir/bots/HEAD/guide/image/2019-08-16.demo-bot-template-locate-object-in-window.png -------------------------------------------------------------------------------- /guide/image/2020-08-08-configure-run-app-multiline-app-settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Viir/bots/HEAD/guide/image/2020-08-08-configure-run-app-multiline-app-settings.png -------------------------------------------------------------------------------- /guide/image/2021-11-30-botlab-reactor-dashboard-recent-sessions.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Viir/bots/HEAD/guide/image/2021-11-30-botlab-reactor-dashboard-recent-sessions.png -------------------------------------------------------------------------------- /guide/image/2024-02-18-botlab-client-executable-file-in-explorer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Viir/bots/HEAD/guide/image/2024-02-18-botlab-client-executable-file-in-explorer.png -------------------------------------------------------------------------------- /guide/image/2024-02-18-botlab-client-play-session-summary-export.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Viir/bots/HEAD/guide/image/2024-02-18-botlab-client-play-session-summary-export.png -------------------------------------------------------------------------------- /implement/applications/tribal-wars-2/tribal-wars-2.game-ui-setup.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Viir/bots/HEAD/implement/applications/tribal-wars-2/tribal-wars-2.game-ui-setup.png -------------------------------------------------------------------------------- /guide/eve-online/image/2020-03-25-eve-online-inventory-context-menu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Viir/bots/HEAD/guide/eve-online/image/2020-03-25-eve-online-inventory-context-menu.png -------------------------------------------------------------------------------- /guide/eve-online/image/2020-07-19-BrianCorner-eve-online-repair-all.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Viir/bots/HEAD/guide/eve-online/image/2020-07-19-BrianCorner-eve-online-repair-all.png -------------------------------------------------------------------------------- /guide/eve-online/image/2023-03-08-botlab-gui-eve-online-bot-startup.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Viir/bots/HEAD/guide/eve-online/image/2023-03-08-botlab-gui-eve-online-bot-startup.png -------------------------------------------------------------------------------- /guide/image/2020-02-07.eve-online-memory-usage-first-memory-reading.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Viir/bots/HEAD/guide/image/2020-02-07.eve-online-memory-usage-first-memory-reading.png -------------------------------------------------------------------------------- /guide/image/2021-12-09-botlab-devtools-select-session-with-imported.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Viir/bots/HEAD/guide/image/2021-12-09-botlab-devtools-select-session-with-imported.png -------------------------------------------------------------------------------- /guide/image/2022-12-10-botlab-client-select-bot-entered-catalog-url.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Viir/bots/HEAD/guide/image/2022-12-10-botlab-client-select-bot-entered-catalog-url.png -------------------------------------------------------------------------------- /guide/image/2024-02-18-botlab-client-main-menu-with-recent-sessions.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Viir/bots/HEAD/guide/image/2024-02-18-botlab-client-main-menu-with-recent-sessions.png -------------------------------------------------------------------------------- /guide/tribal-wars-2/image/2025-02-16-tribal-wars-2-farmbot-started.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Viir/bots/HEAD/guide/tribal-wars-2/image/2025-02-16-tribal-wars-2-farmbot-started.png -------------------------------------------------------------------------------- /guide/eve-online/image/2019-10-08.eve-online-launcher-settings-dialog.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Viir/bots/HEAD/guide/eve-online/image/2019-10-08.eve-online-launcher-settings-dialog.png -------------------------------------------------------------------------------- /guide/eve-online/image/2020-03-11-eve-online-ship-ui-module-rows-names.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Viir/bots/HEAD/guide/eve-online/image/2020-03-11-eve-online-ship-ui-module-rows-names.png -------------------------------------------------------------------------------- /guide/eve-online/image/2021-02-23-briancorner-eve-online-drones-window.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Viir/bots/HEAD/guide/eve-online/image/2021-02-23-briancorner-eve-online-drones-window.png -------------------------------------------------------------------------------- /guide/image/2020-12-08-input-focus-scheduling-runtime-engine-windows.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Viir/bots/HEAD/guide/image/2020-12-08-input-focus-scheduling-runtime-engine-windows.png -------------------------------------------------------------------------------- /guide/image/2021-01-24-data-flow-in-bot-architecture-separating-memory.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Viir/bots/HEAD/guide/image/2021-01-24-data-flow-in-bot-architecture-separating-memory.png -------------------------------------------------------------------------------- /guide/image/2021-10-13-data-flow-in-bot-architecture-separating-memory.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Viir/bots/HEAD/guide/image/2021-10-13-data-flow-in-bot-architecture-separating-memory.png -------------------------------------------------------------------------------- /guide/image/2021-11-29-botlab-ide-program-code-completion-suggestions.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Viir/bots/HEAD/guide/image/2021-11-29-botlab-ide-program-code-completion-suggestions.png -------------------------------------------------------------------------------- /guide/image/2022-12-10-botlab-client-configure-session-bot-description.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Viir/bots/HEAD/guide/image/2022-12-10-botlab-client-configure-session-bot-description.png -------------------------------------------------------------------------------- /guide/eve-online/image/2020-03-11-eve-online-parsed-user-interface-names.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Viir/bots/HEAD/guide/eve-online/image/2020-03-11-eve-online-parsed-user-interface-names.png -------------------------------------------------------------------------------- /guide/image/2023-05-11-botlab-input-scheduling-two-client-instances-gui.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Viir/bots/HEAD/guide/image/2023-05-11-botlab-input-scheduling-two-client-instances-gui.png -------------------------------------------------------------------------------- /guide/image/2025-04-23-botlab-client-ui-export-session-recording-dialog.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Viir/bots/HEAD/guide/image/2025-04-23-botlab-client-ui-export-session-recording-dialog.png -------------------------------------------------------------------------------- /guide/tribal-wars-2/image/2025-02-16-tribal-wars-2-farmbot-game-entered.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Viir/bots/HEAD/guide/tribal-wars-2/image/2025-02-16-tribal-wars-2-farmbot-game-entered.jpeg -------------------------------------------------------------------------------- /guide/eve-online/image/2020-05-13-eve-online-module-button-tooltip-scaled.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Viir/bots/HEAD/guide/eve-online/image/2020-05-13-eve-online-module-button-tooltip-scaled.png -------------------------------------------------------------------------------- /guide/image/2024-01-03-botlab-client-webbrowser-user-data-folder-indication.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Viir/bots/HEAD/guide/image/2024-01-03-botlab-client-webbrowser-user-data-folder-indication.png -------------------------------------------------------------------------------- /explore/2019-06-26.how-to-take-screenshots/2019-06-26.eve-online-screenshot.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Viir/bots/HEAD/explore/2019-06-26.how-to-take-screenshots/2019-06-26.eve-online-screenshot.jpeg -------------------------------------------------------------------------------- /guide/image/2022-12-02-botlab-client-configure-session-online-session-marked.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Viir/bots/HEAD/guide/image/2022-12-02-botlab-client-configure-session-online-session-marked.png -------------------------------------------------------------------------------- /guide/tribal-wars-2/image/2021-12-02-tribal-wars-2-farmbot-browser-profile-id.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Viir/bots/HEAD/guide/tribal-wars-2/image/2021-12-02-tribal-wars-2-farmbot-browser-profile-id.png -------------------------------------------------------------------------------- /implement/applications/elvenar/training-data/2022-03-07-elvenar-djvj-BTqe1xf.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Viir/bots/HEAD/implement/applications/elvenar/training-data/2022-03-07-elvenar-djvj-BTqe1xf.bmp -------------------------------------------------------------------------------- /guide/image/2021-12-09-botlab-devtools-session-event-details-eve-online-reading.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Viir/bots/HEAD/guide/image/2021-12-09-botlab-devtools-session-event-details-eve-online-reading.png -------------------------------------------------------------------------------- /guide/tribal-wars-2/image/2020-01-25.tribal-wars-2-farmbot-configure-army-preset.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Viir/bots/HEAD/guide/tribal-wars-2/image/2020-01-25.tribal-wars-2-farmbot-configure-army-preset.png -------------------------------------------------------------------------------- /guide/tribal-wars-2/image/2022-12-01-tw2-farmbot-configure-session-start-marked.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Viir/bots/HEAD/guide/tribal-wars-2/image/2022-12-01-tw2-farmbot-configure-session-start-marked.png -------------------------------------------------------------------------------- /explore/2020-07-06-tribal-wars-2-farmbot-bug/2020-07-03-tribal-wars-2-farmbot-bug.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Viir/bots/HEAD/explore/2020-07-06-tribal-wars-2-farmbot-bug/2020-07-03-tribal-wars-2-farmbot-bug.png -------------------------------------------------------------------------------- /guide/image/2024-03-30-botlab-client-play-session-input-focus-scheduling-disabled.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Viir/bots/HEAD/guide/image/2024-03-30-botlab-client-play-session-input-focus-scheduling-disabled.png -------------------------------------------------------------------------------- /implement/applications/eve-online/training-data/2019-06-26.eve-online-screenshot.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Viir/bots/HEAD/implement/applications/eve-online/training-data/2019-06-26.eve-online-screenshot.jpeg -------------------------------------------------------------------------------- /explore/2020-01-06.explore-tribal-wars-2/elm-analyse.json: -------------------------------------------------------------------------------- 1 | { 2 | "checks": { 3 | "SingleFieldRecord": false, 4 | "UseConsOverConcat": false, 5 | "MapNothingToNothing": false 6 | } 7 | } -------------------------------------------------------------------------------- /guide/eve-online/image/2020-03-11-eve-online-parsed-user-interface-inventory-inspect.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Viir/bots/HEAD/guide/eve-online/image/2020-03-11-eve-online-parsed-user-interface-inventory-inspect.png -------------------------------------------------------------------------------- /guide/eve-online/image/2021-08-29-eve-online-autopilot-bot-code-in-elm-editor-in-space.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Viir/bots/HEAD/guide/eve-online/image/2021-08-29-eve-online-autopilot-bot-code-in-elm-editor-in-space.png -------------------------------------------------------------------------------- /guide/image/2024-03-30-botlab-client-configure-session-input-focus-scheduling-disabled.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Viir/bots/HEAD/guide/image/2024-03-30-botlab-client-configure-session-input-focus-scheduling-disabled.png -------------------------------------------------------------------------------- /explore/2019-07-10.locate-objects-in-screenshot/2019-07-11.example-from-eve-online-crop-0.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Viir/bots/HEAD/explore/2019-07-10.locate-objects-in-screenshot/2019-07-11.example-from-eve-online-crop-0.bmp -------------------------------------------------------------------------------- /implement/applications/eve-online/training-data/2019-07-30.eve-online-context-menu-system.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Viir/bots/HEAD/implement/applications/eve-online/training-data/2019-07-30.eve-online-context-menu-system.png -------------------------------------------------------------------------------- /implement/applications/eve-online/training-data/2019-08-06.eve-online-overview-entry-menu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Viir/bots/HEAD/implement/applications/eve-online/training-data/2019-08-06.eve-online-overview-entry-menu.png -------------------------------------------------------------------------------- /implement/applications/eve-online/training-data/2020-07-10-eve-online-surroundings-button.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Viir/bots/HEAD/implement/applications/eve-online/training-data/2020-07-10-eve-online-surroundings-button.png -------------------------------------------------------------------------------- /guide/tribal-wars-2/image/2025-02-16-tribal-wars-2-farmbot-select-bot-bundled-bot-with-marker.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Viir/bots/HEAD/guide/tribal-wars-2/image/2025-02-16-tribal-wars-2-farmbot-select-bot-bundled-bot-with-marker.png -------------------------------------------------------------------------------- /implement/applications/elvenar/training-data/2023-04-26-elvenar-sample-collectibles-icons-125.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Viir/bots/HEAD/implement/applications/elvenar/training-data/2023-04-26-elvenar-sample-collectibles-icons-125.png -------------------------------------------------------------------------------- /implement/applications/eve-online/training-data/2019-08-06.eve-online-last-route-element-menu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Viir/bots/HEAD/implement/applications/eve-online/training-data/2019-08-06.eve-online-last-route-element-menu.png -------------------------------------------------------------------------------- /guide/tribal-wars-2/image/2022-12-01-tw2-farmbot-configure-session-section-bot-settings-edited-crop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Viir/bots/HEAD/guide/tribal-wars-2/image/2022-12-01-tw2-farmbot-configure-session-section-bot-settings-edited-crop.png -------------------------------------------------------------------------------- /guide/tribal-wars-2/image/2022-12-01-tw2-farmbot-configure-session-section-bot-settings-marked-edit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Viir/bots/HEAD/guide/tribal-wars-2/image/2022-12-01-tw2-farmbot-configure-session-section-bot-settings-marked-edit.png -------------------------------------------------------------------------------- /guide/eve-online/image/2021-02-12-eve-online-inspect-memory-reading-of-abyssal-key-activation-window .png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Viir/bots/HEAD/guide/eve-online/image/2021-02-12-eve-online-inspect-memory-reading-of-abyssal-key-activation-window .png -------------------------------------------------------------------------------- /implement/applications/eve-online/training-data/2019-08-06.eve-online-station-window-undock-and-other-buttons.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Viir/bots/HEAD/implement/applications/eve-online/training-data/2019-08-06.eve-online-station-window-undock-and-other-buttons.png -------------------------------------------------------------------------------- /implement/applications/eve-online/training-data/2019-08-06.eve-online-station-window-undock-button-mouse-over.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Viir/bots/HEAD/implement/applications/eve-online/training-data/2019-08-06.eve-online-station-window-undock-button-mouse-over.png -------------------------------------------------------------------------------- /implement/templates/send-input-to-window/elm-analyse.json: -------------------------------------------------------------------------------- 1 | { 2 | "checks": { 3 | "SingleFieldRecord": false, 4 | "MultiLineRecordFormatting": false, 5 | "UseConsOverConcat": false, 6 | "MapNothingToNothing": false, 7 | "ExposeAll": false 8 | } 9 | } -------------------------------------------------------------------------------- /implement/applications/elvenar/elvenar-bot/elm-analyse.json: -------------------------------------------------------------------------------- 1 | { 2 | "checks": { 3 | "SingleFieldRecord": false, 4 | "MultiLineRecordFormatting": false, 5 | "UseConsOverConcat": false, 6 | "MapNothingToNothing": false, 7 | "ExposeAll": false 8 | } 9 | } -------------------------------------------------------------------------------- /implement/templates/locate-object-in-window/elm-analyse.json: -------------------------------------------------------------------------------- 1 | { 2 | "checks": { 3 | "SingleFieldRecord": false, 4 | "MultiLineRecordFormatting": false, 5 | "UseConsOverConcat": false, 6 | "MapNothingToNothing": false, 7 | "ExposeAll": false 8 | } 9 | } -------------------------------------------------------------------------------- /implement/templates/remember-bot-settings/elm-analyse.json: -------------------------------------------------------------------------------- 1 | { 2 | "checks": { 3 | "SingleFieldRecord": false, 4 | "MultiLineRecordFormatting": false, 5 | "UseConsOverConcat": false, 6 | "MapNothingToNothing": false, 7 | "ExposeAll": false 8 | } 9 | } -------------------------------------------------------------------------------- /implement/applications/tribal-wars-2/tribal-wars-2-farmbot/elm-analyse.json: -------------------------------------------------------------------------------- 1 | { 2 | "checks": { 3 | "SingleFieldRecord": false, 4 | "MultiLineRecordFormatting": false, 5 | "UseConsOverConcat": false, 6 | "MapNothingToNothing": false, 7 | "ExposeAll": false 8 | } 9 | } -------------------------------------------------------------------------------- /implement/templates/display-session-length-limit/elm-analyse.json: -------------------------------------------------------------------------------- 1 | { 2 | "checks": { 3 | "SingleFieldRecord": false, 4 | "MultiLineRecordFormatting": false, 5 | "UseConsOverConcat": false, 6 | "MapNothingToNothing": false, 7 | "ExposeAll": false 8 | } 9 | } -------------------------------------------------------------------------------- /implement/applications/elvenar/elvenar-bot-elm-test/elm-analyse.json: -------------------------------------------------------------------------------- 1 | { 2 | "checks": { 3 | "SingleFieldRecord": false, 4 | "MultiLineRecordFormatting": false, 5 | "UseConsOverConcat": false, 6 | "MapNothingToNothing": false, 7 | "ExposeAll": false 8 | } 9 | } -------------------------------------------------------------------------------- /implement/applications/eve-online/eve-online-mining-bot/elm-analyse.json: -------------------------------------------------------------------------------- 1 | { 2 | "checks": { 3 | "SingleFieldRecord": false, 4 | "MultiLineRecordFormatting": false, 5 | "UseConsOverConcat": false, 6 | "MapNothingToNothing": false, 7 | "ExposeAll": false 8 | } 9 | } -------------------------------------------------------------------------------- /implement/templates/minimal-bot-using-volatile-process-with-callback/CompilationInterface/SourceFiles.elm: -------------------------------------------------------------------------------- 1 | module CompilationInterface.SourceFiles exposing (..) 2 | 3 | 4 | file____VolatileProcess_csx : { utf8 : String } 5 | file____VolatileProcess_csx = 6 | { utf8 = "The compiler replaces this function." } 7 | -------------------------------------------------------------------------------- /implement/templates/minimal-bot-using-volatile-process-with-callback/VolatileProcess.csx: -------------------------------------------------------------------------------- 1 | string InterfaceToHost_Request(string request) 2 | { 3 | return 4 | "Hello from volatile process! I got this from the agent host: " + 5 | ____request_to_botlab_agent_host____("from script code"); 6 | } 7 | -------------------------------------------------------------------------------- /implement/applications/eve-online/eve-online-framework-test/elm-analyse.json: -------------------------------------------------------------------------------- 1 | { 2 | "checks": { 3 | "SingleFieldRecord": false, 4 | "MultiLineRecordFormatting": false, 5 | "UseConsOverConcat": false, 6 | "MapNothingToNothing": false, 7 | "ExposeAll": false 8 | } 9 | } -------------------------------------------------------------------------------- /implement/applications/eve-online/eve-online-combat-anomaly-bot/elm-analyse.json: -------------------------------------------------------------------------------- 1 | { 2 | "checks": { 3 | "SingleFieldRecord": false, 4 | "MultiLineRecordFormatting": false, 5 | "UseConsOverConcat": false, 6 | "MapNothingToNothing": false, 7 | "ExposeAll": false 8 | } 9 | } -------------------------------------------------------------------------------- /implement/applications/eve-online/eve-online-warp-to-0-autopilot/elm-analyse.json: -------------------------------------------------------------------------------- 1 | { 2 | "checks": { 3 | "SingleFieldRecord": false, 4 | "MultiLineRecordFormatting": false, 5 | "UseConsOverConcat": false, 6 | "MapNothingToNothing": false, 7 | "ExposeAll": false 8 | } 9 | } -------------------------------------------------------------------------------- /implement/templates/minimal-bot-using-volatile-process-with-callback/elm-analyse.json: -------------------------------------------------------------------------------- 1 | { 2 | "checks": { 3 | "SingleFieldRecord": false, 4 | "MultiLineRecordFormatting": false, 5 | "UseConsOverConcat": false, 6 | "MapNothingToNothing": false, 7 | "ExposeAll": false 8 | } 9 | } -------------------------------------------------------------------------------- /explore/2020-12-07-explore-multi-instance-scenarios/eve-online-test-coordinate-input-focus/elm-analyse.json: -------------------------------------------------------------------------------- 1 | { 2 | "checks": { 3 | "SingleFieldRecord": false, 4 | "MultiLineRecordFormatting": false, 5 | "UseConsOverConcat": false, 6 | "MapNothingToNothing": false, 7 | "ExposeAll": false 8 | } 9 | } -------------------------------------------------------------------------------- /implement/applications/web-browser/web-browser-csharp/web-browser-csharp.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net6.0 6 | web_browser_csharp 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /explore/2019-09-15.eve-online-memory-reading/implement/eve-online-memory-reading/eve-online-memory-reading.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | netcoreapp3.0 6 | eve_online_memory_reading 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /explore/2019-05-10.eve-online-travel-bot/elm.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "application", 3 | "source-directories": [ 4 | "src" 5 | ], 6 | "elm-version": "0.19.0", 7 | "dependencies": { 8 | "direct": { 9 | "elm/core": "1.0.2" 10 | }, 11 | "indirect": { 12 | "elm/json": "1.1.3", 13 | "elm/time": "1.0.0" 14 | } 15 | }, 16 | "test-dependencies": { 17 | "direct": {}, 18 | "indirect": {} 19 | } 20 | } -------------------------------------------------------------------------------- /implement/applications/elvenar/elvenar-bot/CompilationInterface/SourceFiles.elm: -------------------------------------------------------------------------------- 1 | module CompilationInterface.SourceFiles exposing (..) 2 | 3 | {-| For documentation of the compilation interface, see 4 | -} 5 | 6 | 7 | file____Windows_VolatileProcess_csx : { utf8 : String } 8 | file____Windows_VolatileProcess_csx = 9 | { utf8 = "The compiler replaces this declaration." } 10 | -------------------------------------------------------------------------------- /implement/templates/locate-object-in-window/CompilationInterface/SourceFiles.elm: -------------------------------------------------------------------------------- 1 | module CompilationInterface.SourceFiles exposing (..) 2 | 3 | {-| For documentation of the compilation interface, see 4 | -} 5 | 6 | 7 | file____Windows_VolatileProcess_csx : { utf8 : String } 8 | file____Windows_VolatileProcess_csx = 9 | { utf8 = "The compiler replaces this declaration." } 10 | -------------------------------------------------------------------------------- /implement/templates/send-input-to-window/CompilationInterface/SourceFiles.elm: -------------------------------------------------------------------------------- 1 | module CompilationInterface.SourceFiles exposing (..) 2 | 3 | {-| For documentation of the compilation interface, see 4 | -} 5 | 6 | 7 | file____Windows_VolatileProcess_csx : { utf8 : String } 8 | file____Windows_VolatileProcess_csx = 9 | { utf8 = "The compiler replaces this declaration." } 10 | -------------------------------------------------------------------------------- /explore/2019-09-15.eve-online-memory-reading/implement/eve-online-memory-reading/CommonConversion.cs: -------------------------------------------------------------------------------- 1 | 2 | using System; 3 | 4 | namespace eve_online_memory_reading 5 | { 6 | static public class CommonConversion 7 | { 8 | static public string StringIdentifierFromValue(byte[] value) 9 | { 10 | using (var sha = new System.Security.Cryptography.SHA256Managed()) 11 | { 12 | return BitConverter.ToString(sha.ComputeHash(value)).Replace("-", ""); 13 | } 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /explore/2019-08-09.simple-bot-framework/dotnet-windows-bot-interface/dotnet-windows-bot-interface.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | netcoreapp3.0 6 | dotnet_windows_bot_interface 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /explore/2019-09-15.eve-online-memory-reading/implement/eve-online-memory-reading/PyStr.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace eve_online_memory_reading 4 | { 5 | public class PyStr : PyObject 6 | { 7 | readonly public string String; 8 | 9 | public PyStr( 10 | Int64 BaseAddress, 11 | IMemoryReader MemoryReader) 12 | : 13 | base(BaseAddress, MemoryReader) 14 | { 15 | String = MemoryReader.ReadStringAsciiNullTerminated(BaseAddress + 20); 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /.github/workflows/test-and-publish.yml: -------------------------------------------------------------------------------- 1 | name: test-and-publish 2 | 3 | on: 4 | push: 5 | workflow_dispatch: 6 | pull_request_review: 7 | types: [submitted] 8 | 9 | jobs: 10 | build: 11 | 12 | runs-on: ubuntu-24.04 13 | 14 | steps: 15 | 16 | - name: Avoid git mutating files on checkout 17 | run: | 18 | git config --global core.autocrlf false 19 | 20 | - uses: actions/checkout@v4 21 | 22 | - name: Install elm-format 23 | run: npm install -g elm-format 24 | 25 | - name: Check formatting in Elm program code 26 | run: elm-format --validate ./implement/ 27 | -------------------------------------------------------------------------------- /guide/common-player-agent-interface.md: -------------------------------------------------------------------------------- 1 | # Common Player Agent Interface 2 | 3 | ## Motivation for a Common Player Agent Interface 4 | 5 | The common interface for player agents results from the cost reduction it implies in bot development projects. 6 | 7 | Bot developers typically spend the most effort on tests depending on the environment. This environment can be a live game client, as would be the case during productive use of the bot. Because setting up a live game client is often relatively expensive, most tests happen with environment programs that simulate a game client. The standard interface to the player agent enables the reuse of existing simulation programs for more bot development projects. 8 | 9 | -------------------------------------------------------------------------------- /implement/templates/remember-bot-settings/elm.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "application", 3 | "source-directories": [ 4 | "." 5 | ], 6 | "elm-version": "0.19.1", 7 | "dependencies": { 8 | "direct": { 9 | "elm/bytes": "1.0.8", 10 | "elm/core": "1.0.5", 11 | "elm/json": "1.1.3" 12 | }, 13 | "indirect": {} 14 | }, 15 | "test-dependencies": { 16 | "direct": { 17 | "elm-explorations/test": "2.1.1" 18 | }, 19 | "indirect": { 20 | "elm/html": "1.0.0", 21 | "elm/random": "1.0.0", 22 | "elm/time": "1.0.0", 23 | "elm/virtual-dom": "1.0.3" 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /implement/templates/display-session-length-limit/elm.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "application", 3 | "source-directories": [ 4 | "." 5 | ], 6 | "elm-version": "0.19.1", 7 | "dependencies": { 8 | "direct": { 9 | "elm/bytes": "1.0.8", 10 | "elm/core": "1.0.5", 11 | "elm/json": "1.1.3" 12 | }, 13 | "indirect": {} 14 | }, 15 | "test-dependencies": { 16 | "direct": { 17 | "elm-explorations/test": "2.1.1" 18 | }, 19 | "indirect": { 20 | "elm/html": "1.0.0", 21 | "elm/random": "1.0.0", 22 | "elm/time": "1.0.0", 23 | "elm/virtual-dom": "1.0.3" 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /implement/applications/eve-online/eve-online-mining-bot/CompilationInterface/SourceFiles.elm: -------------------------------------------------------------------------------- 1 | module CompilationInterface.SourceFiles exposing (..) 2 | 3 | {-| For documentation of the compilation interface, see 4 | -} 5 | 6 | 7 | file____EveOnline_VolatileProcess_csx : { utf8 : String } 8 | file____EveOnline_VolatileProcess_csx = 9 | { utf8 = "The compiler replaces this declaration." } 10 | 11 | 12 | file____BotLab_NotificationsShim_VolatileProcess_csx : { utf8 : String } 13 | file____BotLab_NotificationsShim_VolatileProcess_csx = 14 | { utf8 = "The compiler replaces this declaration." } 15 | -------------------------------------------------------------------------------- /implement/applications/eve-online/eve-online-combat-anomaly-bot/CompilationInterface/SourceFiles.elm: -------------------------------------------------------------------------------- 1 | module CompilationInterface.SourceFiles exposing (..) 2 | 3 | {-| For documentation of the compilation interface, see 4 | -} 5 | 6 | 7 | file____EveOnline_VolatileProcess_csx : { utf8 : String } 8 | file____EveOnline_VolatileProcess_csx = 9 | { utf8 = "The compiler replaces this declaration." } 10 | 11 | 12 | file____BotLab_NotificationsShim_VolatileProcess_csx : { utf8 : String } 13 | file____BotLab_NotificationsShim_VolatileProcess_csx = 14 | { utf8 = "The compiler replaces this declaration." } 15 | -------------------------------------------------------------------------------- /implement/applications/eve-online/eve-online-warp-to-0-autopilot/CompilationInterface/SourceFiles.elm: -------------------------------------------------------------------------------- 1 | module CompilationInterface.SourceFiles exposing (..) 2 | 3 | {-| For documentation of the compilation interface, see 4 | -} 5 | 6 | 7 | file____EveOnline_VolatileProcess_csx : { utf8 : String } 8 | file____EveOnline_VolatileProcess_csx = 9 | { utf8 = "The compiler replaces this declaration." } 10 | 11 | 12 | file____BotLab_NotificationsShim_VolatileProcess_csx : { utf8 : String } 13 | file____BotLab_NotificationsShim_VolatileProcess_csx = 14 | { utf8 = "The compiler replaces this declaration." } 15 | -------------------------------------------------------------------------------- /implement/applications/eve-online/eve-online-mining-bot/Common/FNV.elm: -------------------------------------------------------------------------------- 1 | -- source: https://github.com/Skinney/fnv/blob/master/src/FNV.elm 2 | 3 | 4 | module Common.FNV exposing (hashString) 5 | 6 | {-| FNV hash function for hashing strings 7 | 8 | @docs hashString 9 | 10 | -} 11 | 12 | import Bitwise 13 | import Char 14 | 15 | 16 | fnvPrime : Int 17 | fnvPrime = 18 | (2 ^ 24) + (2 ^ 8) + 0x93 19 | 20 | 21 | {-| Takes a string. Returns a hash (integer). 22 | hashString "Turn me into a hash" == 4201504952 23 | -} 24 | hashString : String -> Int 25 | hashString str = 26 | String.foldl hashHelp 0 str 27 | 28 | 29 | hashHelp : Char -> Int -> Int 30 | hashHelp c hash = 31 | (Bitwise.xor hash (Char.toCode c) * fnvPrime) 32 | |> Bitwise.shiftRightZfBy 0 33 | -------------------------------------------------------------------------------- /implement/applications/eve-online/eve-online-combat-anomaly-bot/Common/FNV.elm: -------------------------------------------------------------------------------- 1 | -- source: https://github.com/Skinney/fnv/blob/master/src/FNV.elm 2 | 3 | 4 | module Common.FNV exposing (hashString) 5 | 6 | {-| FNV hash function for hashing strings 7 | 8 | @docs hashString 9 | 10 | -} 11 | 12 | import Bitwise 13 | import Char 14 | 15 | 16 | fnvPrime : Int 17 | fnvPrime = 18 | (2 ^ 24) + (2 ^ 8) + 0x93 19 | 20 | 21 | {-| Takes a string. Returns a hash (integer). 22 | hashString "Turn me into a hash" == 4201504952 23 | -} 24 | hashString : String -> Int 25 | hashString str = 26 | String.foldl hashHelp 0 str 27 | 28 | 29 | hashHelp : Char -> Int -> Int 30 | hashHelp c hash = 31 | (Bitwise.xor hash (Char.toCode c) * fnvPrime) 32 | |> Bitwise.shiftRightZfBy 0 33 | -------------------------------------------------------------------------------- /implement/applications/eve-online/eve-online-warp-to-0-autopilot/Common/FNV.elm: -------------------------------------------------------------------------------- 1 | -- source: https://github.com/Skinney/fnv/blob/master/src/FNV.elm 2 | 3 | 4 | module Common.FNV exposing (hashString) 5 | 6 | {-| FNV hash function for hashing strings 7 | 8 | @docs hashString 9 | 10 | -} 11 | 12 | import Bitwise 13 | import Char 14 | 15 | 16 | fnvPrime : Int 17 | fnvPrime = 18 | (2 ^ 24) + (2 ^ 8) + 0x93 19 | 20 | 21 | {-| Takes a string. Returns a hash (integer). 22 | hashString "Turn me into a hash" == 4201504952 23 | -} 24 | hashString : String -> Int 25 | hashString str = 26 | String.foldl hashHelp 0 str 27 | 28 | 29 | hashHelp : Char -> Int -> Int 30 | hashHelp c hash = 31 | (Bitwise.xor hash (Char.toCode c) * fnvPrime) 32 | |> Bitwise.shiftRightZfBy 0 33 | -------------------------------------------------------------------------------- /explore/2020-12-07-explore-multi-instance-scenarios/eve-online-test-coordinate-input-focus/Common/FNV.elm: -------------------------------------------------------------------------------- 1 | -- source: https://github.com/Skinney/fnv/blob/master/src/FNV.elm 2 | 3 | 4 | module Common.FNV exposing (hashString) 5 | 6 | {-| FNV hash function for hashing strings 7 | 8 | @docs hashString 9 | 10 | -} 11 | 12 | import Bitwise 13 | import Char 14 | 15 | 16 | fnvPrime : Int 17 | fnvPrime = 18 | (2 ^ 24) + (2 ^ 8) + 0x93 19 | 20 | 21 | {-| Takes a string. Returns a hash (integer). 22 | hashString "Turn me into a hash" == 4201504952 23 | -} 24 | hashString : String -> Int 25 | hashString str = 26 | String.foldl hashHelp 0 str 27 | 28 | 29 | hashHelp : Char -> Int -> Int 30 | hashHelp c hash = 31 | (Bitwise.xor hash (Char.toCode c) * fnvPrime) 32 | |> Bitwise.shiftRightZfBy 0 33 | -------------------------------------------------------------------------------- /explore/2019-05-14.eve-online-bot-framework/elm.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "application", 3 | "source-directories": [ 4 | "src" 5 | ], 6 | "elm-version": "0.19.0", 7 | "dependencies": { 8 | "direct": { 9 | "elm/core": "1.0.2", 10 | "elm/json": "1.1.3", 11 | "elm-community/json-extra": "4.0.0" 12 | }, 13 | "indirect": { 14 | "elm/parser": "1.1.0", 15 | "elm/time": "1.0.0", 16 | "rtfeldman/elm-iso8601-date-strings": "1.1.3" 17 | } 18 | }, 19 | "test-dependencies": { 20 | "direct": { 21 | "elm-explorations/test": "1.2.1" 22 | }, 23 | "indirect": { 24 | "elm/html": "1.0.0", 25 | "elm/random": "1.0.0", 26 | "elm/virtual-dom": "1.0.2" 27 | } 28 | } 29 | } -------------------------------------------------------------------------------- /explore/2020-12-07-explore-multi-instance-scenarios/eve-online-test-coordinate-input-focus/Common/Basics.elm: -------------------------------------------------------------------------------- 1 | module Common.Basics exposing (..) 2 | 3 | 4 | listElementAtWrappedIndex : Int -> List element -> Maybe element 5 | listElementAtWrappedIndex indexToWrap list = 6 | if (list |> List.length) < 1 then 7 | Nothing 8 | 9 | else 10 | list |> List.drop (indexToWrap |> modBy (list |> List.length)) |> List.head 11 | 12 | 13 | {-| Remove duplicate values, keeping the first instance of each element which appears more than once. 14 | -} 15 | listUnique : List element -> List element 16 | listUnique = 17 | List.foldr 18 | (\nextElement elements -> 19 | if elements |> List.member nextElement then 20 | elements 21 | 22 | else 23 | nextElement :: elements 24 | ) 25 | [] 26 | -------------------------------------------------------------------------------- /explore/2019-08-02.interface-to-host/2019-08-02.interface-to-host.md: -------------------------------------------------------------------------------- 1 | # 2019-08-02 Interface to Host 2 | 3 | When looking at the current interface between bot and host, some questions came up: 4 | 5 | + What does it mean when the `botRequests` contain multiple `FinishSession` entries? What is the difference to having just one `FinishSession` entry? 6 | + When `botRequests` contains tasks after a `FinishSession` entry, are these tasks started? 7 | + When a response contains a `StartTask` entry, is this task started even if the same response also contains a `FinishSession` entry? 8 | + What is the `Process` in `ProcessEventResponse`? 9 | + Why does the `Delay` task have a `taskId`? How would we use this id? 10 | + How does the bot specify that it is not interested anymore in `Delay` tasks it has started before? We can ignore the resulting events, but would it not be better to avoid having these events generated at all? 11 | 12 | -------------------------------------------------------------------------------- /explore/2020-01-06.explore-tribal-wars-2/elm.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "application", 3 | "source-directories": [ 4 | "src" 5 | ], 6 | "elm-version": "0.19.1", 7 | "dependencies": { 8 | "direct": { 9 | "elm/core": "1.0.2", 10 | "elm/json": "1.1.3", 11 | "elm/regex": "1.0.0", 12 | "elm-community/json-extra": "4.0.0", 13 | "elm-community/result-extra": "2.2.1" 14 | }, 15 | "indirect": { 16 | "elm/parser": "1.1.0", 17 | "elm/time": "1.0.0", 18 | "rtfeldman/elm-iso8601-date-strings": "1.1.3" 19 | } 20 | }, 21 | "test-dependencies": { 22 | "direct": { 23 | "elm-explorations/test": "1.2.1" 24 | }, 25 | "indirect": { 26 | "elm/html": "1.0.0", 27 | "elm/random": "1.0.0", 28 | "elm/virtual-dom": "1.0.2" 29 | } 30 | } 31 | } -------------------------------------------------------------------------------- /explore/2020-01-03.add-audio-message/elm.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "application", 3 | "source-directories": [ 4 | "src" 5 | ], 6 | "elm-version": "0.19.1", 7 | "dependencies": { 8 | "direct": { 9 | "elm/bytes": "1.0.8", 10 | "elm/core": "1.0.2", 11 | "elm/json": "1.1.3", 12 | "elm-community/maybe-extra": "5.0.0", 13 | "ivadzy/bbase64": "1.1.1" 14 | }, 15 | "indirect": { 16 | "elm/parser": "1.1.0", 17 | "elm/regex": "1.0.0", 18 | "elm/time": "1.0.0", 19 | "rtfeldman/elm-iso8601-date-strings": "1.1.3" 20 | } 21 | }, 22 | "test-dependencies": { 23 | "direct": { 24 | "elm-explorations/test": "1.2.1" 25 | }, 26 | "indirect": { 27 | "elm/html": "1.0.0", 28 | "elm/random": "1.0.0", 29 | "elm/virtual-dom": "1.0.2" 30 | } 31 | } 32 | } -------------------------------------------------------------------------------- /explore/2019-07-04.read-screenshot-from-file-and-configure-image-search/app/elm.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "application", 3 | "source-directories": [ 4 | "src" 5 | ], 6 | "elm-version": "0.19.0", 7 | "dependencies": { 8 | "direct": { 9 | "elm/browser": "1.0.1", 10 | "elm/bytes": "1.0.8", 11 | "elm/core": "1.0.2", 12 | "elm/file": "1.0.5", 13 | "elm/html": "1.0.0", 14 | "elm/json": "1.1.3", 15 | "ivadzy/bbase64": "1.1.1" 16 | }, 17 | "indirect": { 18 | "elm/regex": "1.0.0", 19 | "elm/time": "1.0.0", 20 | "elm/url": "1.0.0", 21 | "elm/virtual-dom": "1.0.2" 22 | } 23 | }, 24 | "test-dependencies": { 25 | "direct": { 26 | "elm-explorations/test": "1.2.2" 27 | }, 28 | "indirect": { 29 | "elm/random": "1.0.0" 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /explore/2020-05-20-explore-tribal-wars-2/2020-05-20-battle-reports-with-casualties.json: -------------------------------------------------------------------------------- 1 | { 2 | "offset": 0, 3 | "total": 2, 4 | "reports": [ 5 | { 6 | "id": 1137257, 7 | "time_created": 1589744135, 8 | "type": "attack", 9 | "title": "Segundo pueblo de John ataca (ESTRELLA DEL NORTE )", 10 | "favourite": 0, 11 | "haul": "partial", 12 | "result": 2, 13 | "token": "1137257.123456.714e8dfb9617327f1", 14 | "read": 0 15 | }, 16 | { 17 | "id": 1093285, 18 | "time_created": 1589698147, 19 | "type": "attack", 20 | "title": "Segundo pueblo de John ataca (ESTRELLA DEL NORTE )", 21 | "favourite": 0, 22 | "haul": "full", 23 | "result": 2, 24 | "token": "1093285.123456.8468d4f2a7ca81afa", 25 | "read": 0 26 | } 27 | ] 28 | } -------------------------------------------------------------------------------- /implement/templates/minimal-bot-using-volatile-process-with-callback/elm.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "application", 3 | "source-directories": [ 4 | "." 5 | ], 6 | "elm-version": "0.19.1", 7 | "dependencies": { 8 | "direct": { 9 | "elm/bytes": "1.0.8", 10 | "elm/core": "1.0.5", 11 | "elm/json": "1.1.3", 12 | "elm/regex": "1.0.0", 13 | "elm-community/list-extra": "8.7.0", 14 | "elm-community/result-extra": "2.4.0", 15 | "elm-community/string-extra": "4.0.1", 16 | "z5h/jaro-winkler": "1.0.2" 17 | }, 18 | "indirect": {} 19 | }, 20 | "test-dependencies": { 21 | "direct": { 22 | "elm-explorations/test": "2.1.1" 23 | }, 24 | "indirect": { 25 | "elm/html": "1.0.0", 26 | "elm/random": "1.0.0", 27 | "elm/time": "1.0.0", 28 | "elm/virtual-dom": "1.0.3" 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /implement/applications/tribal-wars-2/tribal-wars-2-farmbot/Common/Basics.elm: -------------------------------------------------------------------------------- 1 | module Common.Basics exposing (..) 2 | 3 | 4 | listElementAtWrappedIndex : Int -> List element -> Maybe element 5 | listElementAtWrappedIndex indexToWrap list = 6 | if (list |> List.length) < 1 then 7 | Nothing 8 | 9 | else 10 | list |> List.drop (indexToWrap |> modBy (list |> List.length)) |> List.head 11 | 12 | 13 | {-| Remove duplicate values, keeping the first instance of each element which appears more than once. 14 | -} 15 | listUnique : List element -> List element 16 | listUnique = 17 | List.foldr 18 | (\nextElement elements -> 19 | if elements |> List.member nextElement then 20 | elements 21 | 22 | else 23 | nextElement :: elements 24 | ) 25 | [] 26 | 27 | 28 | stringContainsIgnoringCase : String -> String -> Bool 29 | stringContainsIgnoringCase pattern = 30 | String.toLower >> String.contains (String.toLower pattern) 31 | -------------------------------------------------------------------------------- /explore/2019-07-10.locate-objects-in-screenshot/app/elm.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "application", 3 | "source-directories": [ 4 | "src" 5 | ], 6 | "elm-version": "0.19.0", 7 | "dependencies": { 8 | "direct": { 9 | "elm/bytes": "1.0.8", 10 | "elm/core": "1.0.2", 11 | "elm/json": "1.1.3", 12 | "elm-community/json-extra": "4.0.0", 13 | "elm-community/maybe-extra": "5.0.0", 14 | "ivadzy/bbase64": "1.1.1" 15 | }, 16 | "indirect": { 17 | "elm/parser": "1.1.0", 18 | "elm/regex": "1.0.0", 19 | "elm/time": "1.0.0", 20 | "rtfeldman/elm-iso8601-date-strings": "1.1.3" 21 | } 22 | }, 23 | "test-dependencies": { 24 | "direct": { 25 | "elm-explorations/test": "1.2.1" 26 | }, 27 | "indirect": { 28 | "elm/html": "1.0.0", 29 | "elm/random": "1.0.0", 30 | "elm/virtual-dom": "1.0.2" 31 | } 32 | } 33 | } -------------------------------------------------------------------------------- /explore/2019-09-15.eve-online-memory-reading/implement/eve-online-memory-reading/PyList.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace eve_online_memory_reading 4 | { 5 | /// 6 | /// Offsets from https://github.com/python/cpython/blob/2.7/Include/listobject.h and https://github.com/python/cpython/blob/2.7/Objects/listobject.c 7 | /// 8 | public class PyList : PyObjectVar 9 | { 10 | public const int Offset_ob_item = 12; 11 | 12 | readonly public UInt32? ob_item; 13 | 14 | readonly public UInt32[] Items; 15 | 16 | public PyList( 17 | Int64 BaseAddress, 18 | IMemoryReader MemoryReader) 19 | : 20 | base(BaseAddress, MemoryReader) 21 | { 22 | ob_item = MemoryReader.ReadUInt32(BaseAddress + Offset_ob_item); 23 | 24 | if (ob_item.HasValue && ob_size.HasValue) 25 | { 26 | Items = MemoryReader.ReadArray(ob_item.Value, (int)ob_size.Value * 4); 27 | } 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /guide/eve-online/eve-online-players-strategies.md: -------------------------------------------------------------------------------- 1 | # EVE Online Players Strategies 2 | 3 | ### Travel - Bounce of Celestial to Avoid Gate Campers 4 | 5 | [MutantWizard](https://forum.botlab.org/u/MutantWizard) described it at https://forum.botlab.org/t/how-to-automate-mining-asteroids-in-eve-online/628/61?u=viir: 6 | 7 | > Do you think it might be interesting to implement a bounce of a random celestial where the route takes one through a system other than high sec? 8 | 9 | > Its a standard strategy for trying to avoid gate campers deploying bubbles and smart bombs. Normally a traveler is expected to warp from gate to gate so his trajectory is reasonable foreseeable. Gate campers would often deploy bubbles on this trajectory or wait for a traveler to come out of warp on this trajectory. To avoid the trajectory traps we often warp from the system entry gate to some celestial and then from there to the exit gate. this changes the foreseeable trajectory and adds a bit of a safety margin. If its not a major development task it may be worth while considering. 10 | 11 | -------------------------------------------------------------------------------- /explore/2019-09-15.eve-online-memory-reading/implement/eve-online-memory-reading/EveOnline.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | 3 | namespace eve_online_memory_reading 4 | { 5 | static public class EveOnline 6 | { 7 | /// 8 | /// returns the root of the UI tree. 9 | /// 10 | /// 11 | /// 12 | static public UITreeNode UITreeRoot( 13 | IPythonMemoryReader MemoryReader) 14 | { 15 | var candidateAddresses = PyTypeObject.EnumeratePossibleAddressesOfInstancesOfPythonTypeFilteredByObType(MemoryReader, "UIRoot"); 16 | 17 | // return the candidate tree with the largest number of nodes. 18 | return 19 | candidateAddresses 20 | .Select(candidateAddress => new UITreeNode(candidateAddress, MemoryReader)) 21 | .OrderByDescending(candidate => candidate.EnumerateChildrenTransitive(MemoryReader)?.Count()) 22 | .FirstOrDefault(); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /implement/templates/send-input-to-window/elm.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "application", 3 | "source-directories": [ 4 | "." 5 | ], 6 | "elm-version": "0.19.1", 7 | "dependencies": { 8 | "direct": { 9 | "chelovek0v/bbase64": "1.0.1", 10 | "elm/bytes": "1.0.8", 11 | "elm/core": "1.0.5", 12 | "elm/json": "1.1.3", 13 | "elm-community/list-extra": "8.7.0", 14 | "elm-community/maybe-extra": "5.3.0", 15 | "elm-community/result-extra": "2.4.0", 16 | "elm-community/string-extra": "4.0.1", 17 | "z5h/jaro-winkler": "1.0.2" 18 | }, 19 | "indirect": { 20 | "elm/regex": "1.0.0" 21 | } 22 | }, 23 | "test-dependencies": { 24 | "direct": { 25 | "elm-explorations/test": "2.1.1" 26 | }, 27 | "indirect": { 28 | "elm/html": "1.0.0", 29 | "elm/random": "1.0.0", 30 | "elm/time": "1.0.0", 31 | "elm/virtual-dom": "1.0.3" 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /implement/templates/locate-object-in-window/elm.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "application", 3 | "source-directories": [ 4 | "." 5 | ], 6 | "elm-version": "0.19.1", 7 | "dependencies": { 8 | "direct": { 9 | "chelovek0v/bbase64": "1.0.1", 10 | "elm/bytes": "1.0.8", 11 | "elm/core": "1.0.5", 12 | "elm/json": "1.1.3", 13 | "elm-community/list-extra": "8.7.0", 14 | "elm-community/maybe-extra": "5.3.0", 15 | "elm-community/result-extra": "2.4.0", 16 | "elm-community/string-extra": "4.0.1", 17 | "z5h/jaro-winkler": "1.0.2" 18 | }, 19 | "indirect": { 20 | "elm/regex": "1.0.0" 21 | } 22 | }, 23 | "test-dependencies": { 24 | "direct": { 25 | "elm-explorations/test": "2.1.1" 26 | }, 27 | "indirect": { 28 | "elm/html": "1.0.0", 29 | "elm/random": "1.0.0", 30 | "elm/time": "1.0.0", 31 | "elm/virtual-dom": "1.0.3" 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /implement/applications/elvenar/elvenar-bot/elm.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "application", 3 | "source-directories": [ 4 | "." 5 | ], 6 | "elm-version": "0.19.1", 7 | "dependencies": { 8 | "direct": { 9 | "chelovek0v/bbase64": "1.0.1", 10 | "elm/bytes": "1.0.8", 11 | "elm/core": "1.0.5", 12 | "elm/json": "1.1.3", 13 | "elm/random": "1.0.0", 14 | "elm-community/list-extra": "8.7.0", 15 | "elm-community/maybe-extra": "5.3.0", 16 | "elm-community/random-extra": "3.2.0", 17 | "elm-community/result-extra": "2.4.0", 18 | "elm-community/string-extra": "4.0.1", 19 | "z5h/jaro-winkler": "1.0.2" 20 | }, 21 | "indirect": { 22 | "elm/regex": "1.0.0", 23 | "elm/time": "1.0.0" 24 | } 25 | }, 26 | "test-dependencies": { 27 | "direct": { 28 | "elm-explorations/test": "2.1.1" 29 | }, 30 | "indirect": { 31 | "elm/html": "1.0.0", 32 | "elm/virtual-dom": "1.0.3" 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /implement/applications/eve-online/eve-online-framework-test/elm.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "application", 3 | "source-directories": [ 4 | "./../eve-online-mining-bot/" 5 | ], 6 | "elm-version": "0.19.1", 7 | "dependencies": { 8 | "direct": { 9 | "cmditch/elm-bigint": "2.0.1", 10 | "danfishgold/base64-bytes": "1.1.0", 11 | "elm/bytes": "1.0.8", 12 | "elm/core": "1.0.5", 13 | "elm/json": "1.1.3", 14 | "elm/regex": "1.0.0", 15 | "elm-community/list-extra": "8.7.0", 16 | "elm-community/maybe-extra": "5.3.0", 17 | "elm-community/result-extra": "2.4.0", 18 | "elm-community/string-extra": "4.0.1" 19 | }, 20 | "indirect": { 21 | "rtfeldman/elm-hex": "1.0.0" 22 | } 23 | }, 24 | "test-dependencies": { 25 | "direct": { 26 | "elm-explorations/test": "2.1.1" 27 | }, 28 | "indirect": { 29 | "elm/html": "1.0.0", 30 | "elm/random": "1.0.0", 31 | "elm/time": "1.0.0", 32 | "elm/virtual-dom": "1.0.3" 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /implement/applications/eve-online/eve-online-mining-bot/elm.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "application", 3 | "source-directories": [ 4 | "." 5 | ], 6 | "elm-version": "0.19.1", 7 | "dependencies": { 8 | "direct": { 9 | "avh4/elm-color": "1.0.0", 10 | "cmditch/elm-bigint": "2.0.1", 11 | "elm/bytes": "1.0.8", 12 | "elm/core": "1.0.5", 13 | "elm/json": "1.1.3", 14 | "elm/regex": "1.0.0", 15 | "elm-community/list-extra": "8.7.0", 16 | "elm-community/maybe-extra": "5.3.0", 17 | "elm-community/result-extra": "2.4.0", 18 | "elm-community/string-extra": "4.0.1", 19 | "z5h/jaro-winkler": "1.0.2" 20 | }, 21 | "indirect": { 22 | "rtfeldman/elm-hex": "1.0.0" 23 | } 24 | }, 25 | "test-dependencies": { 26 | "direct": { 27 | "elm-explorations/test": "2.1.1" 28 | }, 29 | "indirect": { 30 | "elm/html": "1.0.0", 31 | "elm/random": "1.0.0", 32 | "elm/time": "1.0.0", 33 | "elm/virtual-dom": "1.0.3" 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /implement/applications/eve-online/eve-online-combat-anomaly-bot/elm.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "application", 3 | "source-directories": [ 4 | "." 5 | ], 6 | "elm-version": "0.19.1", 7 | "dependencies": { 8 | "direct": { 9 | "avh4/elm-color": "1.0.0", 10 | "cmditch/elm-bigint": "2.0.1", 11 | "elm/bytes": "1.0.8", 12 | "elm/core": "1.0.5", 13 | "elm/json": "1.1.3", 14 | "elm/regex": "1.0.0", 15 | "elm-community/list-extra": "8.7.0", 16 | "elm-community/maybe-extra": "5.3.0", 17 | "elm-community/result-extra": "2.4.0", 18 | "elm-community/string-extra": "4.0.1", 19 | "z5h/jaro-winkler": "1.0.2" 20 | }, 21 | "indirect": { 22 | "rtfeldman/elm-hex": "1.0.0" 23 | } 24 | }, 25 | "test-dependencies": { 26 | "direct": { 27 | "elm-explorations/test": "2.1.1" 28 | }, 29 | "indirect": { 30 | "elm/html": "1.0.0", 31 | "elm/random": "1.0.0", 32 | "elm/time": "1.0.0", 33 | "elm/virtual-dom": "1.0.3" 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /implement/applications/eve-online/eve-online-warp-to-0-autopilot/elm.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "application", 3 | "source-directories": [ 4 | "." 5 | ], 6 | "elm-version": "0.19.1", 7 | "dependencies": { 8 | "direct": { 9 | "avh4/elm-color": "1.0.0", 10 | "cmditch/elm-bigint": "2.0.1", 11 | "elm/bytes": "1.0.8", 12 | "elm/core": "1.0.5", 13 | "elm/json": "1.1.3", 14 | "elm/regex": "1.0.0", 15 | "elm-community/list-extra": "8.7.0", 16 | "elm-community/maybe-extra": "5.3.0", 17 | "elm-community/result-extra": "2.4.0", 18 | "elm-community/string-extra": "4.0.1", 19 | "z5h/jaro-winkler": "1.0.2" 20 | }, 21 | "indirect": { 22 | "rtfeldman/elm-hex": "1.0.0" 23 | } 24 | }, 25 | "test-dependencies": { 26 | "direct": { 27 | "elm-explorations/test": "2.1.1" 28 | }, 29 | "indirect": { 30 | "elm/html": "1.0.0", 31 | "elm/random": "1.0.0", 32 | "elm/time": "1.0.0", 33 | "elm/virtual-dom": "1.0.3" 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /License.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) Michael Rätzel and Contributors 4 | 5 | All rights reserved. 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy 8 | of this software and associated documentation files (the "Software"), to deal 9 | in the Software without restriction, including without limitation the rights 10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | copies of the Software, and to permit persons to whom the Software is 12 | furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in all 15 | copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | SOFTWARE. 24 | -------------------------------------------------------------------------------- /implement/applications/elvenar/elvenar-bot-elm-test/elm.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "application", 3 | "source-directories": [ 4 | "./../elvenar-bot" 5 | ], 6 | "elm-version": "0.19.1", 7 | "dependencies": { 8 | "direct": { 9 | "chelovek0v/bbase64": "1.0.1", 10 | "danfishgold/base64-bytes": "1.1.0", 11 | "elm/bytes": "1.0.8", 12 | "elm/core": "1.0.5", 13 | "elm/json": "1.1.3", 14 | "elm/random": "1.0.0", 15 | "elm-community/list-extra": "8.7.0", 16 | "elm-community/maybe-extra": "5.3.0", 17 | "elm-community/random-extra": "3.2.0", 18 | "elm-community/result-extra": "2.4.0", 19 | "elm-community/string-extra": "4.0.1", 20 | "z5h/jaro-winkler": "1.0.2" 21 | }, 22 | "indirect": { 23 | "elm/regex": "1.0.0", 24 | "elm/time": "1.0.0" 25 | } 26 | }, 27 | "test-dependencies": { 28 | "direct": { 29 | "elm-explorations/test": "2.1.1" 30 | }, 31 | "indirect": { 32 | "elm/html": "1.0.0", 33 | "elm/virtual-dom": "1.0.3" 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /explore/2020-03-04.make-running-a-bot-easier/run-app-2DA2E2EDBD.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | @echo This is a script to run the app found at https://botcatalog.org/bot/2DA2E2EDBDCE6D2824C76A6FB48064B11CC6A742667F607148C5C9A63ED14AE1 ... 3 | @echo. 4 | @echo Below is the beginning of the app description found on the catalog: 5 | @echo. 6 | @echo {- Michaels EVE Online mining bot version 2020-02-13 7 | @echo The bot warps to an asteroid belt, mines there until the ore hold is full, and then docks at a station to unload the ore. It then repeats this cycle until you stop it. 8 | @echo [...] 9 | @echo. 10 | 11 | where botengine.exe >nul 2>nul 12 | if %ErrorLevel% equ 0 ( 13 | botengine.exe run-bot https://github.com/Viir/bots/tree/4a8c9b900f8676c2bb98d2f3c9e91cd945439234/implement/applications/eve-online/eve-online-mining-bot 14 | ) else ( 15 | @echo I failed to run the app because I did not find the 'botengine.exe' program. 16 | @echo. 17 | @echo Please see https://to.botengine.org/failed-run-bot-did-not-find-botengine-program for a guide on how to install the 'botengine.exe' program so that I can find it. 18 | @start "" https://to.botengine.org/failed-run-bot-did-not-find-botengine-program 19 | ) 20 | 21 | pause 22 | -------------------------------------------------------------------------------- /implement/applications/tribal-wars-2/tribal-wars-2-farmbot/elm.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "application", 3 | "source-directories": [ 4 | "" 5 | ], 6 | "elm-version": "0.19.1", 7 | "dependencies": { 8 | "direct": { 9 | "elm/bytes": "1.0.8", 10 | "elm/core": "1.0.5", 11 | "elm/json": "1.1.3", 12 | "elm/regex": "1.0.0", 13 | "elm-community/json-extra": "4.3.0", 14 | "elm-community/list-extra": "8.7.0", 15 | "elm-community/result-extra": "2.4.0", 16 | "elm-community/string-extra": "4.0.1", 17 | "marcosh/elm-html-to-unicode": "1.0.4", 18 | "z5h/jaro-winkler": "1.0.2" 19 | }, 20 | "indirect": { 21 | "elm/parser": "1.1.0", 22 | "elm/time": "1.0.0", 23 | "elm/url": "1.0.0", 24 | "rtfeldman/elm-iso8601-date-strings": "1.1.4" 25 | } 26 | }, 27 | "test-dependencies": { 28 | "direct": { 29 | "elm-explorations/test": "2.1.1" 30 | }, 31 | "indirect": { 32 | "elm/html": "1.0.0", 33 | "elm/random": "1.0.0", 34 | "elm/virtual-dom": "1.0.3" 35 | } 36 | } 37 | } -------------------------------------------------------------------------------- /explore/2020-01-03.add-audio-message/src/Main.elm: -------------------------------------------------------------------------------- 1 | module Main exposing 2 | ( interfaceToHost_deserializeState 3 | , interfaceToHost_initState 4 | , interfaceToHost_processEvent 5 | , interfaceToHost_serializeState 6 | , main 7 | ) 8 | 9 | import Bot 10 | import BotEngine.Interface_To_Host_20190808 as InterfaceToHost 11 | 12 | 13 | interfaceToHost_initState : Bot.State 14 | interfaceToHost_initState = 15 | Bot.initState 16 | 17 | 18 | interfaceToHost_processEvent : String -> Bot.State -> ( Bot.State, String ) 19 | interfaceToHost_processEvent = 20 | InterfaceToHost.wrapForSerialInterface_processEvent Bot.processEvent 21 | 22 | 23 | interfaceToHost_serializeState : Bot.State -> String 24 | interfaceToHost_serializeState = 25 | always "" 26 | 27 | 28 | interfaceToHost_deserializeState : String -> Bot.State 29 | interfaceToHost_deserializeState = 30 | always interfaceToHost_initState 31 | 32 | 33 | {-| Define the Elm entry point. Don't change this function. 34 | -} 35 | main : Program Int Bot.State String 36 | main = 37 | InterfaceToHost.elmEntryPoint interfaceToHost_initState interfaceToHost_processEvent interfaceToHost_serializeState (interfaceToHost_deserializeState >> always interfaceToHost_initState) 38 | -------------------------------------------------------------------------------- /explore/2020-01-06.explore-tribal-wars-2/src/Main.elm: -------------------------------------------------------------------------------- 1 | module Main exposing 2 | ( interfaceToHost_deserializeState 3 | , interfaceToHost_initState 4 | , interfaceToHost_processEvent 5 | , interfaceToHost_serializeState 6 | , main 7 | ) 8 | 9 | import Bot 10 | import BotEngine.Interface_To_Host_20190808 as InterfaceToHost 11 | 12 | 13 | interfaceToHost_initState : Bot.State 14 | interfaceToHost_initState = 15 | Bot.initState 16 | 17 | 18 | interfaceToHost_processEvent : String -> Bot.State -> ( Bot.State, String ) 19 | interfaceToHost_processEvent = 20 | InterfaceToHost.wrapForSerialInterface_processEvent Bot.processEvent 21 | 22 | 23 | interfaceToHost_serializeState : Bot.State -> String 24 | interfaceToHost_serializeState = 25 | always "" 26 | 27 | 28 | interfaceToHost_deserializeState : String -> Bot.State 29 | interfaceToHost_deserializeState = 30 | always interfaceToHost_initState 31 | 32 | 33 | {-| Define the Elm entry point. Don't change this function. 34 | -} 35 | main : Program Int Bot.State String 36 | main = 37 | InterfaceToHost.elmEntryPoint interfaceToHost_initState interfaceToHost_processEvent interfaceToHost_serializeState (interfaceToHost_deserializeState >> always interfaceToHost_initState) 38 | -------------------------------------------------------------------------------- /explore/2020-12-07-explore-multi-instance-scenarios/eve-online-test-coordinate-input-focus/elm.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "application", 3 | "source-directories": [ 4 | "." 5 | ], 6 | "elm-version": "0.19.1", 7 | "dependencies": { 8 | "direct": { 9 | "cmditch/elm-bigint": "2.0.1", 10 | "elm/core": "1.0.2", 11 | "elm/json": "1.1.3", 12 | "elm/regex": "1.0.0", 13 | "elm-community/json-extra": "4.0.0", 14 | "elm-community/list-extra": "8.2.2", 15 | "elm-community/maybe-extra": "5.2.0", 16 | "elm-community/result-extra": "2.2.1", 17 | "elm-community/string-extra": "4.0.1", 18 | "z5h/jaro-winkler": "1.0.2" 19 | }, 20 | "indirect": { 21 | "elm/parser": "1.1.0", 22 | "elm/time": "1.0.0", 23 | "rtfeldman/elm-hex": "1.0.0", 24 | "rtfeldman/elm-iso8601-date-strings": "1.1.3" 25 | } 26 | }, 27 | "test-dependencies": { 28 | "direct": { 29 | "elm-explorations/test": "1.2.1" 30 | }, 31 | "indirect": { 32 | "elm/html": "1.0.0", 33 | "elm/random": "1.0.0", 34 | "elm/virtual-dom": "1.0.2" 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /explore/2019-05-14.eve-online-bot-framework/tests/SanderlingInterfaceTest.elm: -------------------------------------------------------------------------------- 1 | module SanderlingInterfaceTest exposing (suite) 2 | 3 | import Expect exposing (Expectation) 4 | import Sanderling_Interface_20190514 5 | import Test exposing (..) 6 | 7 | 8 | suite : Test 9 | suite = 10 | describe "Interface between host and bot." 11 | [ botEventMemoryMeasurementCompleted 12 | ] 13 | 14 | 15 | botEventMemoryMeasurementCompleted : Test 16 | botEventMemoryMeasurementCompleted = 17 | test "Bot event for memory measurement completed." <| 18 | \_ -> 19 | """ 20 | { 21 | "timeInMilliseconds" : 1234, 22 | "event": { 23 | "memoryMeasurementFinished" : { 24 | "ok" : { 25 | "reducedWithNamedNodesJson" : "json content" 26 | } 27 | } 28 | } 29 | } 30 | """ 31 | |> Sanderling_Interface_20190514.deserializeBotEventAtTime 32 | |> Expect.equal 33 | (Ok 34 | { timeInMilliseconds = 1234 35 | , event = 36 | Sanderling_Interface_20190514.MemoryMeasurementFinished 37 | (Ok { reducedWithNamedNodesJson = Just "json content" }) 38 | } 39 | ) 40 | -------------------------------------------------------------------------------- /explore/2019-09-15.eve-online-memory-reading/implement/eve-online-memory-reading/SampleMemoryReader.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace eve_online_memory_reading 4 | { 5 | public class SampleMemoryReader : IMemoryReader 6 | { 7 | readonly BotEngine.ProcessMeasurement sample; 8 | 9 | public MemoryReaderModuleInfo[] Modules() 10 | { 11 | throw new NotImplementedException(); 12 | } 13 | 14 | public SampleMemoryReader(BotEngine.ProcessMeasurement sample) 15 | { 16 | this.sample = sample; 17 | } 18 | 19 | public byte[] ReadBytes(Int64 address, int bytesCount) 20 | { 21 | foreach (var memoryBaseAddressAndListOctet in sample.MemoryBaseAddressAndListOctet) 22 | { 23 | var offsetInSampleRange = 24 | address - memoryBaseAddressAndListOctet.Key; 25 | 26 | if (offsetInSampleRange < 0 || memoryBaseAddressAndListOctet.Value.Length <= offsetInSampleRange) 27 | continue; 28 | 29 | var bytes = new byte[Math.Min(bytesCount, memoryBaseAddressAndListOctet.Value.Length - offsetInSampleRange)]; 30 | 31 | Array.Copy(memoryBaseAddressAndListOctet.Value, offsetInSampleRange, bytes, 0, bytes.Length); 32 | 33 | return bytes; 34 | } 35 | 36 | return null; 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /explore/2020-12-07-explore-multi-instance-scenarios/eve-online-test-coordinate-input-focus/Common/DecisionTree.elm: -------------------------------------------------------------------------------- 1 | module Common.DecisionTree exposing (..) 2 | 3 | 4 | type DecisionPathNode leaf 5 | = DescribeBranch String (DecisionPathNode leaf) 6 | | EndDecisionPath leaf 7 | 8 | 9 | endDecisionPath : leaf -> DecisionPathNode leaf 10 | endDecisionPath = 11 | EndDecisionPath 12 | 13 | 14 | describeBranch : String -> DecisionPathNode leaf -> DecisionPathNode leaf 15 | describeBranch = 16 | DescribeBranch 17 | 18 | 19 | unpackToDecisionStagesDescriptionsAndLeaf : DecisionPathNode leaf -> ( List String, leaf ) 20 | unpackToDecisionStagesDescriptionsAndLeaf node = 21 | case node of 22 | EndDecisionPath leaf -> 23 | ( [], leaf ) 24 | 25 | DescribeBranch branchDescription childNode -> 26 | let 27 | ( childDecisionsDescriptions, leaf ) = 28 | unpackToDecisionStagesDescriptionsAndLeaf childNode 29 | in 30 | ( branchDescription :: childDecisionsDescriptions, leaf ) 31 | 32 | 33 | continueDecisionTree : (originalLeaf -> DecisionPathNode newLeaf) -> DecisionPathNode originalLeaf -> DecisionPathNode newLeaf 34 | continueDecisionTree continueLeaf originalNode = 35 | case originalNode of 36 | DescribeBranch branch childNode -> 37 | DescribeBranch branch (continueDecisionTree continueLeaf childNode) 38 | 39 | EndDecisionPath leaf -> 40 | continueLeaf leaf 41 | -------------------------------------------------------------------------------- /explore/2019-09-15.eve-online-memory-reading/implement/eve-online-memory-reading/BotEngine/Kernel32.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | 4 | namespace BotEngine.Windows 5 | { 6 | static public class Kernel32 7 | { 8 | public enum PROCESS_ACCESS_RIGHT 9 | { 10 | PROCESS_CREATE_PROCESS = 0x0080, 11 | PROCESS_CREATE_THREAD = 0x0002, 12 | PROCESS_DUP_HANDLE = 0x0040, 13 | PROCESS_QUERY_INFORMATION = 0x0400, 14 | PROCESS_SET_INFORMATION = 0x0200, 15 | PROCESS_SET_QUOTA = 0x0100, 16 | PROCESS_SUSPEND_RESUME = 0x0800, 17 | PROCESS_TERMINATE = 0x0001, 18 | PROCESS_VM_OPERATION = 0x0008, 19 | PROCESS_VM_READ = 0x0010, 20 | PROCESS_VM_WRITE = 0x0020, 21 | SYNCHRONIZE = 0x00100000, 22 | } 23 | 24 | [DllImport("kernel32.dll")] 25 | static extern public Int32 CloseHandle(IntPtr hObject); 26 | 27 | [DllImport("kernel32.dll")] 28 | static extern public IntPtr OpenProcess( 29 | PROCESS_ACCESS_RIGHT dwDesiredAccess, 30 | Int32 bInheritHandle, 31 | UInt32 dwProcessId); 32 | 33 | [DllImport("kernel32.dll", SetLastError = true)] 34 | static extern public UInt32 ReadProcessMemory( 35 | IntPtr hProcess, 36 | IntPtr lpBaseAddress, 37 | byte[] lpBuffer, 38 | IntPtr size, 39 | [Out] out IntPtr lpNumberOfBytesRead); 40 | 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /explore/2020-01-03.add-audio-message/src/Bot.elm: -------------------------------------------------------------------------------- 1 | {- Demonstrate how add an audio message. 2 | Use the `--bot-configuration` parameter to specify the path to the WAV file. 3 | 4 | Example integrated in bot for Ivar (https://forum.botengine.org/t/how-to-add-audio-message-if-neutral-or-enemy-hits-local/93/12?u=viir) 5 | 6 | As base, I used the bot from https://github.com/Viir/bots/tree/225c680115328d9ba0223760cec85d56f2ea9a87/implement/templates/send-input-to-window 7 | 8 | https://stackoverflow.com/questions/42845506/how-to-play-a-sound-in-netcore/54670829#54670829 9 | 10 | bot-catalog-tags:demo,notification 11 | -} 12 | 13 | 14 | module Bot exposing 15 | ( State 16 | , initState 17 | , processEvent 18 | ) 19 | 20 | import BotEngine.Interface_To_Host_20190808 as InterfaceToHost 21 | import BotEngine.SimpleBotFramework as SimpleBotFramework 22 | 23 | 24 | type alias SimpleState = 25 | {} 26 | 27 | 28 | type alias State = 29 | SimpleBotFramework.State SimpleState 30 | 31 | 32 | initState : State 33 | initState = 34 | SimpleBotFramework.initState {} 35 | 36 | 37 | processEvent : InterfaceToHost.BotEvent -> State -> ( State, InterfaceToHost.BotResponse ) 38 | processEvent = 39 | SimpleBotFramework.processEvent simpleProcessEvent 40 | 41 | 42 | simpleProcessEvent : SimpleBotFramework.BotEvent -> SimpleState -> ( SimpleState, SimpleBotFramework.BotResponse ) 43 | simpleProcessEvent _ stateBefore = 44 | ( stateBefore 45 | , SimpleBotFramework.FinishSession { statusDescriptionText = "Unused." } 46 | ) 47 | -------------------------------------------------------------------------------- /explore/2019-09-15.eve-online-memory-reading/implement/eve-online-memory-reading/PythonMemoryReader.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace eve_online_memory_reading 5 | { 6 | public interface IPythonMemoryReader : IMemoryReader 7 | { 8 | PyTypeObject TypeFromAddress(UInt32 TypeObjectAddress); 9 | } 10 | 11 | /// 12 | /// caches Type Objects. 13 | /// 14 | public class PythonMemoryReader : IPythonMemoryReader 15 | { 16 | readonly IMemoryReader MemoryReader; 17 | 18 | readonly Dictionary CacheTypeObject = new Dictionary(); 19 | 20 | public PythonMemoryReader( 21 | IMemoryReader MemoryReader) 22 | { 23 | this.MemoryReader = MemoryReader; 24 | } 25 | 26 | PyTypeObject IPythonMemoryReader.TypeFromAddress(uint TypeObjectAddress) 27 | { 28 | PyTypeObject TypeObject; 29 | 30 | if (CacheTypeObject.TryGetValue(TypeObjectAddress, out TypeObject)) 31 | { 32 | return TypeObject; 33 | } 34 | 35 | TypeObject = new PyTypeObject(TypeObjectAddress, MemoryReader); 36 | 37 | CacheTypeObject[TypeObjectAddress] = TypeObject; 38 | 39 | return TypeObject; 40 | } 41 | 42 | byte[] IMemoryReader.ReadBytes(long Address, int BytesCount) 43 | { 44 | return MemoryReader.ReadBytes(Address, BytesCount); 45 | } 46 | 47 | MemoryReaderModuleInfo[] IMemoryReader.Modules() 48 | { 49 | return MemoryReader.Modules(); 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /implement/applications/eve-online/eve-online-mining-bot/Common/Basics.elm: -------------------------------------------------------------------------------- 1 | module Common.Basics exposing (..) 2 | 3 | import List.Extra 4 | import Maybe.Extra 5 | import Result.Extra 6 | 7 | 8 | resultFirstSuccessOrFirstError : List (Result e o) -> Maybe (Result e o) 9 | resultFirstSuccessOrFirstError list = 10 | let 11 | ( oks, errors ) = 12 | Result.Extra.partition list 13 | in 14 | oks 15 | |> List.head 16 | |> Maybe.map Ok 17 | |> Maybe.Extra.orElse (errors |> List.head |> Maybe.map Err) 18 | 19 | 20 | listElementAtWrappedIndex : Int -> List element -> Maybe element 21 | listElementAtWrappedIndex indexToWrap list = 22 | if (list |> List.length) < 1 then 23 | Nothing 24 | 25 | else 26 | list |> List.drop (indexToWrap |> modBy (list |> List.length)) |> List.head 27 | 28 | 29 | {-| Remove duplicate values, keeping the first instance of each element which appears more than once. 30 | -} 31 | listUnique : List element -> List element 32 | listUnique = 33 | List.foldr 34 | (\nextElement elements -> 35 | if elements |> List.member nextElement then 36 | elements 37 | 38 | else 39 | nextElement :: elements 40 | ) 41 | [] 42 | 43 | 44 | stringContainsIgnoringCase : String -> String -> Bool 45 | stringContainsIgnoringCase pattern = 46 | String.toLower >> String.contains (String.toLower pattern) 47 | 48 | 49 | listGatherEqualsBy : (a -> derived) -> List a -> List ( derived, ( a, List a ) ) 50 | listGatherEqualsBy derive list = 51 | List.map 52 | (\( first, rest ) -> ( derive first, ( first, rest ) )) 53 | (List.Extra.gatherEqualsBy derive list) 54 | -------------------------------------------------------------------------------- /implement/applications/eve-online/eve-online-combat-anomaly-bot/Common/Basics.elm: -------------------------------------------------------------------------------- 1 | module Common.Basics exposing (..) 2 | 3 | import List.Extra 4 | import Maybe.Extra 5 | import Result.Extra 6 | 7 | 8 | resultFirstSuccessOrFirstError : List (Result e o) -> Maybe (Result e o) 9 | resultFirstSuccessOrFirstError list = 10 | let 11 | ( oks, errors ) = 12 | Result.Extra.partition list 13 | in 14 | oks 15 | |> List.head 16 | |> Maybe.map Ok 17 | |> Maybe.Extra.orElse (errors |> List.head |> Maybe.map Err) 18 | 19 | 20 | listElementAtWrappedIndex : Int -> List element -> Maybe element 21 | listElementAtWrappedIndex indexToWrap list = 22 | if (list |> List.length) < 1 then 23 | Nothing 24 | 25 | else 26 | list |> List.drop (indexToWrap |> modBy (list |> List.length)) |> List.head 27 | 28 | 29 | {-| Remove duplicate values, keeping the first instance of each element which appears more than once. 30 | -} 31 | listUnique : List element -> List element 32 | listUnique = 33 | List.foldr 34 | (\nextElement elements -> 35 | if elements |> List.member nextElement then 36 | elements 37 | 38 | else 39 | nextElement :: elements 40 | ) 41 | [] 42 | 43 | 44 | stringContainsIgnoringCase : String -> String -> Bool 45 | stringContainsIgnoringCase pattern = 46 | String.toLower >> String.contains (String.toLower pattern) 47 | 48 | 49 | listGatherEqualsBy : (a -> derived) -> List a -> List ( derived, ( a, List a ) ) 50 | listGatherEqualsBy derive list = 51 | List.map 52 | (\( first, rest ) -> ( derive first, ( first, rest ) )) 53 | (List.Extra.gatherEqualsBy derive list) 54 | -------------------------------------------------------------------------------- /implement/applications/eve-online/eve-online-warp-to-0-autopilot/Common/Basics.elm: -------------------------------------------------------------------------------- 1 | module Common.Basics exposing (..) 2 | 3 | import List.Extra 4 | import Maybe.Extra 5 | import Result.Extra 6 | 7 | 8 | resultFirstSuccessOrFirstError : List (Result e o) -> Maybe (Result e o) 9 | resultFirstSuccessOrFirstError list = 10 | let 11 | ( oks, errors ) = 12 | Result.Extra.partition list 13 | in 14 | oks 15 | |> List.head 16 | |> Maybe.map Ok 17 | |> Maybe.Extra.orElse (errors |> List.head |> Maybe.map Err) 18 | 19 | 20 | listElementAtWrappedIndex : Int -> List element -> Maybe element 21 | listElementAtWrappedIndex indexToWrap list = 22 | if (list |> List.length) < 1 then 23 | Nothing 24 | 25 | else 26 | list |> List.drop (indexToWrap |> modBy (list |> List.length)) |> List.head 27 | 28 | 29 | {-| Remove duplicate values, keeping the first instance of each element which appears more than once. 30 | -} 31 | listUnique : List element -> List element 32 | listUnique = 33 | List.foldr 34 | (\nextElement elements -> 35 | if elements |> List.member nextElement then 36 | elements 37 | 38 | else 39 | nextElement :: elements 40 | ) 41 | [] 42 | 43 | 44 | stringContainsIgnoringCase : String -> String -> Bool 45 | stringContainsIgnoringCase pattern = 46 | String.toLower >> String.contains (String.toLower pattern) 47 | 48 | 49 | listGatherEqualsBy : (a -> derived) -> List a -> List ( derived, ( a, List a ) ) 50 | listGatherEqualsBy derive list = 51 | List.map 52 | (\( first, rest ) -> ( derive first, ( first, rest ) )) 53 | (List.Extra.gatherEqualsBy derive list) 54 | -------------------------------------------------------------------------------- /explore/2019-08-14.locate-object-in-window/2019-08-14.locate-object-in-window.md: -------------------------------------------------------------------------------- 1 | # 2019-08-14 Locate Object in Window 2 | 3 | The overall goal of this stage is to expand the simple bot framework to support sensing the bots environment. The change last week already added the parts for acting on a window. This weeks expansion adds the functionality to read information from such a window so that the bot has all the information it needs to act. The information to extract includes locating objects as well as overall classification. 4 | 5 | ## Runtime Expenses for Screenshot Transfer 6 | 7 | To allow the bot to read from the screenshot, we transfer the screenshot from the volatile host to the bot. In an early version of this transport, I reused the BMP image file decoding developed earlier on the bot side. So the bot would receive the screenshot as BMP encoded image file. I implemented a variant in which the data is sent encoded in base64. But I did not find a solution to decode from the base64 string to `Bytes` fast enough. The first base64 decoding function I experimented with was from `ivadzy/bbase64 1.1.1`. Then I tried the base64 decoding function from `danfishgold/base64-bytes 1.0.2`. With both of them, I saw more than five seconds of bot event processing time. When I just let it store the base64 string on the bot side, the duration dropped dramatically: In most cases, less than 300ms for an image with 1000x800 pixels. 8 | I achieved a significant reduction of the time to process the bot event when completely removing base64 decoding and instead pack the pixel values into arrays of integers in the JSON. 9 | Remember that processing times also depend on the used javascript engine. After switching to V8/puppeteer, we might find new/other variants to be faster. 10 | -------------------------------------------------------------------------------- /implement/applications/eve-online/eve-online-mining-bot/Common/DecisionPath.elm: -------------------------------------------------------------------------------- 1 | module Common.DecisionPath exposing (..) 2 | 3 | 4 | type DecisionPathNode pathEnd 5 | = DescribeBranch String (DecisionPathNode pathEnd) 6 | | EndDecisionPath pathEnd 7 | 8 | 9 | endDecisionPath : pathEnd -> DecisionPathNode pathEnd 10 | endDecisionPath = 11 | EndDecisionPath 12 | 13 | 14 | describeBranch : String -> DecisionPathNode pathEnd -> DecisionPathNode pathEnd 15 | describeBranch = 16 | DescribeBranch 17 | 18 | 19 | mapEnd : (oldEnd -> newEnd) -> DecisionPathNode oldEnd -> DecisionPathNode newEnd 20 | mapEnd f node = 21 | case node of 22 | DescribeBranch branch childNode -> 23 | DescribeBranch branch (mapEnd f childNode) 24 | 25 | EndDecisionPath pathEnd -> 26 | EndDecisionPath (f pathEnd) 27 | 28 | 29 | unpackToDecisionStagesDescriptionsAndLeaf : DecisionPathNode pathEnd -> ( List String, pathEnd ) 30 | unpackToDecisionStagesDescriptionsAndLeaf node = 31 | case node of 32 | EndDecisionPath pathEnd -> 33 | ( [], pathEnd ) 34 | 35 | DescribeBranch branchDescription childNode -> 36 | let 37 | ( childDecisionsDescriptions, pathEnd ) = 38 | unpackToDecisionStagesDescriptionsAndLeaf childNode 39 | in 40 | ( branchDescription :: childDecisionsDescriptions, pathEnd ) 41 | 42 | 43 | continueDecisionPath : (originalEnd -> DecisionPathNode newEnd) -> DecisionPathNode originalEnd -> DecisionPathNode newEnd 44 | continueDecisionPath continuePath originalNode = 45 | case originalNode of 46 | DescribeBranch branch childNode -> 47 | DescribeBranch branch (continueDecisionPath continuePath childNode) 48 | 49 | EndDecisionPath pathEnd -> 50 | continuePath pathEnd 51 | -------------------------------------------------------------------------------- /implement/applications/eve-online/eve-online-combat-anomaly-bot/Common/DecisionPath.elm: -------------------------------------------------------------------------------- 1 | module Common.DecisionPath exposing (..) 2 | 3 | 4 | type DecisionPathNode pathEnd 5 | = DescribeBranch String (DecisionPathNode pathEnd) 6 | | EndDecisionPath pathEnd 7 | 8 | 9 | endDecisionPath : pathEnd -> DecisionPathNode pathEnd 10 | endDecisionPath = 11 | EndDecisionPath 12 | 13 | 14 | describeBranch : String -> DecisionPathNode pathEnd -> DecisionPathNode pathEnd 15 | describeBranch = 16 | DescribeBranch 17 | 18 | 19 | mapEnd : (oldEnd -> newEnd) -> DecisionPathNode oldEnd -> DecisionPathNode newEnd 20 | mapEnd f node = 21 | case node of 22 | DescribeBranch branch childNode -> 23 | DescribeBranch branch (mapEnd f childNode) 24 | 25 | EndDecisionPath pathEnd -> 26 | EndDecisionPath (f pathEnd) 27 | 28 | 29 | unpackToDecisionStagesDescriptionsAndLeaf : DecisionPathNode pathEnd -> ( List String, pathEnd ) 30 | unpackToDecisionStagesDescriptionsAndLeaf node = 31 | case node of 32 | EndDecisionPath pathEnd -> 33 | ( [], pathEnd ) 34 | 35 | DescribeBranch branchDescription childNode -> 36 | let 37 | ( childDecisionsDescriptions, pathEnd ) = 38 | unpackToDecisionStagesDescriptionsAndLeaf childNode 39 | in 40 | ( branchDescription :: childDecisionsDescriptions, pathEnd ) 41 | 42 | 43 | continueDecisionPath : (originalEnd -> DecisionPathNode newEnd) -> DecisionPathNode originalEnd -> DecisionPathNode newEnd 44 | continueDecisionPath continuePath originalNode = 45 | case originalNode of 46 | DescribeBranch branch childNode -> 47 | DescribeBranch branch (continueDecisionPath continuePath childNode) 48 | 49 | EndDecisionPath pathEnd -> 50 | continuePath pathEnd 51 | -------------------------------------------------------------------------------- /implement/applications/eve-online/eve-online-warp-to-0-autopilot/Common/DecisionPath.elm: -------------------------------------------------------------------------------- 1 | module Common.DecisionPath exposing (..) 2 | 3 | 4 | type DecisionPathNode pathEnd 5 | = DescribeBranch String (DecisionPathNode pathEnd) 6 | | EndDecisionPath pathEnd 7 | 8 | 9 | endDecisionPath : pathEnd -> DecisionPathNode pathEnd 10 | endDecisionPath = 11 | EndDecisionPath 12 | 13 | 14 | describeBranch : String -> DecisionPathNode pathEnd -> DecisionPathNode pathEnd 15 | describeBranch = 16 | DescribeBranch 17 | 18 | 19 | mapEnd : (oldEnd -> newEnd) -> DecisionPathNode oldEnd -> DecisionPathNode newEnd 20 | mapEnd f node = 21 | case node of 22 | DescribeBranch branch childNode -> 23 | DescribeBranch branch (mapEnd f childNode) 24 | 25 | EndDecisionPath pathEnd -> 26 | EndDecisionPath (f pathEnd) 27 | 28 | 29 | unpackToDecisionStagesDescriptionsAndLeaf : DecisionPathNode pathEnd -> ( List String, pathEnd ) 30 | unpackToDecisionStagesDescriptionsAndLeaf node = 31 | case node of 32 | EndDecisionPath pathEnd -> 33 | ( [], pathEnd ) 34 | 35 | DescribeBranch branchDescription childNode -> 36 | let 37 | ( childDecisionsDescriptions, pathEnd ) = 38 | unpackToDecisionStagesDescriptionsAndLeaf childNode 39 | in 40 | ( branchDescription :: childDecisionsDescriptions, pathEnd ) 41 | 42 | 43 | continueDecisionPath : (originalEnd -> DecisionPathNode newEnd) -> DecisionPathNode originalEnd -> DecisionPathNode newEnd 44 | continueDecisionPath continuePath originalNode = 45 | case originalNode of 46 | DescribeBranch branch childNode -> 47 | DescribeBranch branch (continueDecisionPath continuePath childNode) 48 | 49 | EndDecisionPath pathEnd -> 50 | continuePath pathEnd 51 | -------------------------------------------------------------------------------- /guide/botlab-contributor-program.md: -------------------------------------------------------------------------------- 1 | # BotLab Contributor Program 2 | 3 | We created the BotLab Contributor Program to recognize and reward the hard work of our awesome contributors, encourage knowledge sharing within the developer community, and build friendly competition around contributions. 4 | 5 | Through the contributor program, contributors are rewarded with BotLab credits and can use the [BotLab 'Pro' features](https://botlab.org/pricing) for free. 6 | 7 | ## How it works 8 | 9 | Earn credits by recording videos, writing content, collecting training data, contributing code, answering technical questions, or validating others' contributions. 10 | 11 | ## Automatic rewards for bot programs 12 | 13 | Besides the manual distribution of rewards, there are automatic rewards for sharing bot programs. 14 | Through automated rewards, authors earn credits proportional to the popularity of their publications. 15 | 16 | After publishing a new bot program under their name, the contributor receives 20 % of all credits spent with that bot. For each 500 thousand credits users pay for running that bot, the contributor gets 100 thousand credits. 17 | 18 | To enable the automatic rewards, the contributor must publish their bot on the BotLab catalog under their name. 19 | 20 | ### Attribution and verification of authorship 21 | 22 | To register as the author of a bot program, set the `authors-forum-usernames` tag in the bot program's `Bot.elm` file. If the bot has multiple names in `authors-forum-usernames`, the rewards will be split between these authors. 23 | When publishing a bot on the catalog, ensure the list of authors does not contain a name without their consent since users tend to message the listed authors with support requests. 24 | The listed authors receive the credits via a voucher code via a private message on the [BotLab forum](https://forum.botlab.org). 25 | -------------------------------------------------------------------------------- /implement/applications/eve-online/eve-online-mining-bot/BotLab/NotificationsShim/VolatileProcess.csx: -------------------------------------------------------------------------------- 1 | #r "mscorlib" 2 | #r "netstandard" 3 | #r "System" 4 | #r "System.Collections.Immutable" 5 | #r "System.IO.Compression" 6 | #r "System.Net" 7 | #r "System.Linq" 8 | #r "System.Text.Json" 9 | 10 | using System; 11 | using System.Collections.Generic; 12 | using System.Collections.Immutable; 13 | using System.Linq; 14 | 15 | 16 | class Request 17 | { 18 | public ConsoleBeepStructure[] EffectConsoleBeepSequence { set; get; } 19 | 20 | public struct ConsoleBeepStructure 21 | { 22 | public int frequency { set; get; } 23 | 24 | public int durationInMs { set; get; } 25 | } 26 | } 27 | 28 | class Response 29 | { 30 | public object CompletedOtherEffect; 31 | } 32 | 33 | string serialRequest(string serializedRequest) 34 | { 35 | var requestStructure = System.Text.Json.JsonSerializer.Deserialize(serializedRequest); 36 | 37 | var response = request(requestStructure); 38 | 39 | return SerializeToJsonForBot(response); 40 | } 41 | 42 | Response request(Request request) 43 | { 44 | if (request?.EffectConsoleBeepSequence != null) 45 | { 46 | foreach (var beep in request?.EffectConsoleBeepSequence) 47 | { 48 | if (beep.frequency == 0) // Avoid exception "The frequency must be between 37 and 32767." 49 | System.Threading.Thread.Sleep(beep.durationInMs); 50 | else 51 | System.Console.Beep(beep.frequency, beep.durationInMs); 52 | } 53 | 54 | return new Response 55 | { 56 | CompletedOtherEffect = new object(), 57 | }; 58 | } 59 | 60 | return null; 61 | } 62 | 63 | string SerializeToJsonForBot(T value) => 64 | System.Text.Json.JsonSerializer.Serialize(value); 65 | 66 | 67 | string InterfaceToHost_Request(string request) 68 | { 69 | return serialRequest(request); 70 | } 71 | -------------------------------------------------------------------------------- /implement/applications/eve-online/eve-online-combat-anomaly-bot/BotLab/NotificationsShim/VolatileProcess.csx: -------------------------------------------------------------------------------- 1 | #r "mscorlib" 2 | #r "netstandard" 3 | #r "System" 4 | #r "System.Collections.Immutable" 5 | #r "System.IO.Compression" 6 | #r "System.Net" 7 | #r "System.Linq" 8 | #r "System.Text.Json" 9 | 10 | using System; 11 | using System.Collections.Generic; 12 | using System.Collections.Immutable; 13 | using System.Linq; 14 | 15 | 16 | class Request 17 | { 18 | public ConsoleBeepStructure[] EffectConsoleBeepSequence { set; get; } 19 | 20 | public struct ConsoleBeepStructure 21 | { 22 | public int frequency { set; get; } 23 | 24 | public int durationInMs { set; get; } 25 | } 26 | } 27 | 28 | class Response 29 | { 30 | public object CompletedOtherEffect; 31 | } 32 | 33 | string serialRequest(string serializedRequest) 34 | { 35 | var requestStructure = System.Text.Json.JsonSerializer.Deserialize(serializedRequest); 36 | 37 | var response = request(requestStructure); 38 | 39 | return SerializeToJsonForBot(response); 40 | } 41 | 42 | Response request(Request request) 43 | { 44 | if (request?.EffectConsoleBeepSequence != null) 45 | { 46 | foreach (var beep in request?.EffectConsoleBeepSequence) 47 | { 48 | if (beep.frequency == 0) // Avoid exception "The frequency must be between 37 and 32767." 49 | System.Threading.Thread.Sleep(beep.durationInMs); 50 | else 51 | System.Console.Beep(beep.frequency, beep.durationInMs); 52 | } 53 | 54 | return new Response 55 | { 56 | CompletedOtherEffect = new object(), 57 | }; 58 | } 59 | 60 | return null; 61 | } 62 | 63 | string SerializeToJsonForBot(T value) => 64 | System.Text.Json.JsonSerializer.Serialize(value); 65 | 66 | 67 | string InterfaceToHost_Request(string request) 68 | { 69 | return serialRequest(request); 70 | } 71 | -------------------------------------------------------------------------------- /implement/applications/eve-online/eve-online-warp-to-0-autopilot/BotLab/NotificationsShim/VolatileProcess.csx: -------------------------------------------------------------------------------- 1 | #r "mscorlib" 2 | #r "netstandard" 3 | #r "System" 4 | #r "System.Collections.Immutable" 5 | #r "System.IO.Compression" 6 | #r "System.Net" 7 | #r "System.Linq" 8 | #r "System.Text.Json" 9 | 10 | using System; 11 | using System.Collections.Generic; 12 | using System.Collections.Immutable; 13 | using System.Linq; 14 | 15 | 16 | class Request 17 | { 18 | public ConsoleBeepStructure[] EffectConsoleBeepSequence { set; get; } 19 | 20 | public struct ConsoleBeepStructure 21 | { 22 | public int frequency { set; get; } 23 | 24 | public int durationInMs { set; get; } 25 | } 26 | } 27 | 28 | class Response 29 | { 30 | public object CompletedOtherEffect; 31 | } 32 | 33 | string serialRequest(string serializedRequest) 34 | { 35 | var requestStructure = System.Text.Json.JsonSerializer.Deserialize(serializedRequest); 36 | 37 | var response = request(requestStructure); 38 | 39 | return SerializeToJsonForBot(response); 40 | } 41 | 42 | Response request(Request request) 43 | { 44 | if (request?.EffectConsoleBeepSequence != null) 45 | { 46 | foreach (var beep in request?.EffectConsoleBeepSequence) 47 | { 48 | if (beep.frequency == 0) // Avoid exception "The frequency must be between 37 and 32767." 49 | System.Threading.Thread.Sleep(beep.durationInMs); 50 | else 51 | System.Console.Beep(beep.frequency, beep.durationInMs); 52 | } 53 | 54 | return new Response 55 | { 56 | CompletedOtherEffect = new object(), 57 | }; 58 | } 59 | 60 | return null; 61 | } 62 | 63 | string SerializeToJsonForBot(T value) => 64 | System.Text.Json.JsonSerializer.Serialize(value); 65 | 66 | 67 | string InterfaceToHost_Request(string request) 68 | { 69 | return serialRequest(request); 70 | } 71 | -------------------------------------------------------------------------------- /explore/2019-09-15.eve-online-memory-reading/2019-09-15.eve-online-memory-reading.md: -------------------------------------------------------------------------------- 1 | # 2019-09-15 EVE Online Memory Reading 2 | 3 | Today I explored memory reading EVE Online. This is for advanced users who want to learn how the memory reading for EVE Online works and maybe customize it. To make this easier, I took the reference implementation and improved it. 4 | 5 | The original tutorial was published in 2016, and the memory reading was discussed in this thread: https://forum.botengine.org/t/advanced-do-it-yourself-memory-reading-in-eve-online/68 6 | 7 | I used the implementation from there as a basis so the Python side of things might already look familiar to you. 8 | 9 | In contrast to the older code, today's version also supports reading from a file containing a sample of the client process. This new feature allows us to repeat the reading as often we want, without having to start an instance of the game client. In addition to that, another new feature lets you save the result of the memory reading to a JSON file for easy inspection and further processing. This JSON file contains the UI tree read from the EVE Online client. To use this feature, add the `--output` parameter when running the program. 10 | 11 | Below is an example of a full command-line; in this case, it reads the memory contents from a [file saved earlier](https://forum.botengine.org/t/how-to-collect-samples-for-memory-reading-development/50): 12 | 13 | ``` 14 | dotnet run -- --source="C:\path-to-a-process-sample-file.zip" --output="C:\path\to\directory\with\write\access" 15 | ``` 16 | 17 | So the result of today's exploration is a .NET console app which supports both from a live client process and a saved process. All the memory reading functions are inlined in the source code so that you don't have to look up DLL files or other assemblies to see the implementation. 18 | 19 | I added this program to the repository here: https://github.com/Viir/bots/commit/92410ac78c46957462431719f0c34781e2620da5 20 | -------------------------------------------------------------------------------- /implement/applications/tribal-wars-2/tribal-wars-2-farmbot/Common/DecisionTree.elm: -------------------------------------------------------------------------------- 1 | module Common.DecisionTree exposing (..) 2 | 3 | 4 | type DecisionPathNode leaf 5 | = DescribeBranch String (DecisionPathNode leaf) 6 | | EndDecisionPath leaf 7 | 8 | 9 | endDecisionPath : leaf -> DecisionPathNode leaf 10 | endDecisionPath = 11 | EndDecisionPath 12 | 13 | 14 | describeBranch : String -> DecisionPathNode leaf -> DecisionPathNode leaf 15 | describeBranch = 16 | DescribeBranch 17 | 18 | 19 | unpackToDecisionStagesDescriptionsAndLeaf : DecisionPathNode leaf -> ( List String, leaf ) 20 | unpackToDecisionStagesDescriptionsAndLeaf node = 21 | case node of 22 | EndDecisionPath leaf -> 23 | ( [], leaf ) 24 | 25 | DescribeBranch branchDescription childNode -> 26 | let 27 | ( childDecisionsDescriptions, leaf ) = 28 | unpackToDecisionStagesDescriptionsAndLeaf childNode 29 | in 30 | ( branchDescription :: childDecisionsDescriptions, leaf ) 31 | 32 | 33 | continueDecisionTree : (originalLeaf -> DecisionPathNode newLeaf) -> DecisionPathNode originalLeaf -> DecisionPathNode newLeaf 34 | continueDecisionTree continueLeaf originalNode = 35 | case originalNode of 36 | DescribeBranch branch childNode -> 37 | DescribeBranch branch (continueDecisionTree continueLeaf childNode) 38 | 39 | EndDecisionPath leaf -> 40 | continueLeaf leaf 41 | 42 | 43 | mapLastDescriptionBeforeLeaf : (String -> String) -> DecisionPathNode leaf -> DecisionPathNode leaf 44 | mapLastDescriptionBeforeLeaf descriptionMap originalTree = 45 | case originalTree of 46 | EndDecisionPath _ -> 47 | originalTree 48 | 49 | DescribeBranch originalDescription nextNode -> 50 | let 51 | mappedNextNode = 52 | mapLastDescriptionBeforeLeaf descriptionMap nextNode 53 | 54 | description = 55 | if mappedNextNode == nextNode then 56 | descriptionMap originalDescription 57 | 58 | else 59 | originalDescription 60 | in 61 | DescribeBranch description mappedNextNode 62 | -------------------------------------------------------------------------------- /guide/bot-development-language-and-terms.md: -------------------------------------------------------------------------------- 1 | # Bot Development Language and Terms 2 | 3 | This document explains terms and language specific to the use and development of bots. 4 | 5 | ## Play Session 6 | 7 | Whether we run a bot or record a human playing, we get a play session in both cases. 8 | Why do we not distinguish (everywhere) between sessions with a human and sessions with a bot as the player agent? Because in some cases, we prefer to have a human take over temporarily when a bot gets stuck. This implies that a single session can have both human and bot as the player agent at different times. 9 | 10 | ## Player Agent 11 | 12 | A player agent can be either a bot or a human. We use bots as agents for productive use. For development, we sometimes let a human take the role of the agent. After a human has demonstrated how to perform a task, we can use the recording of that play session for training bots. (Process mining) 13 | 14 | ## Program 15 | 16 | We categorize programs based on their interfaces, that is, their inputs and outputs. 17 | We distinguish the following three types of interfaces: 18 | 19 | + Player Agent ('Bot') 20 | + Environment 21 | + Assistant 22 | 23 | The standard interface between player agent and environment allows us to combine any agent with any environment for testing and comparing fitness. 24 | 25 | ### Bot Program 26 | 27 | A bot defines the behavior of a player agent. We also call it a programmatic player. It receives impressions from the environment, typically via screenshots of the game client. It outputs effects to perform on the game client. These are effects that could result from human interaction, such as mouse clicks or keyboard inputs. 28 | 29 | We use the bot program interface also to derive metrics and notifications in a play session. 30 | 31 | ### Environment Program 32 | 33 | An environment program allows us to simulate a player's environment. In contrast to a live environment, a simulated environment enables reproducible and automated testing. 34 | Reproducible environments, in turn, allow us to quickly compare the fitness of different bots in the same situation. 35 | 36 | ### Assistant Program 37 | 38 | An assistant program helps with developing programs. Input for this program includes our complete workspace, including the program we are working on and past play sessions. With this context, the assistant makes recommendations specific to our project and the situations our bots encountered in the past. These recommendations can include changes to bot-settings or program codes. 39 | 40 | -------------------------------------------------------------------------------- /explore/2020-05-04-guide-on-developing-bots/2020-05-04-guide-on-developing-bots.md: -------------------------------------------------------------------------------- 1 | # Refining Bot Development Examples and Guides - Improving EVE Online Jet Can Collection Example 2 | 3 | Today I discovered a way to improve on yesterdays implementation for Foivos Saropoulos jet can collection in EVE Online (See the commit at https://github.com/Viir/bots/commit/b5f2fb0e09b9aa7846f2bdc31506dd84b8eeb4d0) 4 | 5 | The benefit of this improvement is making it easier to implement similar functionality in the future; it would not necessarily bring any improvement for this particular app. That is why I do not add it there immediately; it is not on the shortest path to a working app for Foivos. 6 | 7 | A problem with changes in the linked commit is the introduction of remembering the action we performed. In this specific case, a sequence to initiate warping to a fleet member (App-specific language). Yesterday's implementation bases this memory on a leaf of the decision tree selecting this action. This kind of dependency makes development more complex, also affecting the ability to employ machine learning to automate programming by training data. 8 | 9 | To get rid of this dependency again, we can instead draw on what we can observe passively. The analogy here is watching someone play: Given a video recording of the gameplay, can we decide if the warp-to-fleet member is complete? Drawing on what I know about the game, it seems possible: Is the context menu close enough to the right character in the chat window? Is it expanded up to the stage where we can initiate the warp with the next click? If these conditions are met, we can check if the ship started a warp within two seconds of the context menu disappearing. 10 | We do not have to stop here. If, for some reason, the set of conditions to meet is not strict enough yet, we could also draw on remembering the location of the last mouse click to boost confidence. We can check if that location is within the right context menu entry. This dependency on past inputs is less problematic than the dependency taken in yesterday's change, as it is not specific to the origin of the action in the policy. 11 | 12 | Not depending on the learning/collecting policy is the goal, since it allows for reuse of already available data sets. A concrete example is a case where we attempt to implement that jet can collection feature and test it: We don't want to depend on starting a game client to perform a live test, as this would slow down the development process. With the policy-independent variant, we can test the new implementation using a recording from another session. That other session does not even have to be related to the use of any bot; it could be as well a record of a human playing. 13 | -------------------------------------------------------------------------------- /explore/2019-05-10.eve-online-travel-bot/src/SimplifiedSanderling.elm: -------------------------------------------------------------------------------- 1 | module SimplifiedSanderling exposing 2 | ( BotEffect(..) 3 | , BotEvent(..) 4 | , BotEventAtTime 5 | , BotRequest(..) 6 | , InfoPanelRouteRouteElementMarker 7 | , MemoryMeasurement 8 | , MouseButtonType(..) 9 | , ShipManeuverType(..) 10 | , centerFromRegion 11 | , mouseClickAtLocation 12 | ) 13 | 14 | 15 | type alias BotEventAtTime = 16 | { timeInMilliseconds : Int 17 | , event : BotEvent 18 | } 19 | 20 | 21 | type BotEvent 22 | = MemoryMeasurementCompleted MemoryMeasurement 23 | 24 | 25 | type BotRequest 26 | = TakeMemoryMeasurementAtTime Int 27 | | ReportStatus String 28 | | Effect BotEffect 29 | 30 | 31 | type alias MemoryMeasurement = 32 | { shipUi : Maybe MemoryMeasurementShipUi 33 | , infoPanelRoute : Maybe MemoryMeasurementInfoPanelRoute 34 | , menus : List MemoryMeasurementMenu 35 | } 36 | 37 | 38 | type alias MemoryMeasurementMenu = 39 | { uiElement : UIElement 40 | , entries : List MemoryMeasurementMenuEntry 41 | } 42 | 43 | 44 | type alias MemoryMeasurementMenuEntry = 45 | { uiElement : UIElement 46 | , text : String 47 | } 48 | 49 | 50 | type alias MemoryMeasurementInfoPanelRoute = 51 | { routeElementMarker : List InfoPanelRouteRouteElementMarker } 52 | 53 | 54 | type alias InfoPanelRouteRouteElementMarker = 55 | { uiElement : UIElement } 56 | 57 | 58 | type alias UIElement = 59 | { id : Int 60 | , region : UIElementRegion 61 | } 62 | 63 | 64 | type BotEffect 65 | = SimpleEffect SimpleBotEffect 66 | 67 | 68 | type SimpleBotEffect 69 | = SimpleMouseClickAtLocation Location MouseButtonType 70 | 71 | 72 | type MouseButtonType 73 | = MouseButtonLeft 74 | | MouseButtonRight 75 | 76 | 77 | type alias Location = 78 | { x : Int, y : Int } 79 | 80 | 81 | type alias UIElementRegion = 82 | { left : Int 83 | , top : Int 84 | , width : Int 85 | , height : Int 86 | } 87 | 88 | 89 | type alias MemoryMeasurementShipUi = 90 | { indication : Maybe MemoryMeasurementShipUiIndication } 91 | 92 | 93 | type alias MemoryMeasurementShipUiIndication = 94 | { maneuverType : Maybe ShipManeuverType } 95 | 96 | 97 | type ShipManeuverType 98 | = Warp 99 | | Jump 100 | | Orbit 101 | | Approach 102 | 103 | 104 | mouseClickAtLocation : Location -> MouseButtonType -> BotEffect 105 | mouseClickAtLocation location mouseButtonType = 106 | SimpleMouseClickAtLocation location mouseButtonType |> SimpleEffect 107 | 108 | 109 | centerFromRegion : UIElementRegion -> Location 110 | centerFromRegion region = 111 | { x = region.left + region.width // 2, y = region.height // 2 } 112 | -------------------------------------------------------------------------------- /implement/applications/tribal-wars-2/training-data/2021-03-13-tribal-wars-2-outgoing-command-returning.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": { 3 | "command_id": 3440145, 4 | "type": "attack", 5 | "direction": "back", 6 | "origin": { 7 | "id": 4578 8 | }, 9 | "target": { 10 | "id": 1965, 11 | "name": "Barbarian village", 12 | "x": 470, 13 | "y": 529, 14 | "character_id": null 15 | }, 16 | "id": 3440145, 17 | "icon": 1049601, 18 | "preset_id": 2356789, 19 | "home": { 20 | "id": 4578, 21 | "name": "Village name given by player", 22 | "x": 567, 23 | "y": 678, 24 | "character_id": 876543 25 | }, 26 | "time_start": 1614123456, 27 | "time_completed": 1614456789, 28 | "report_id": 3341234, 29 | "units": { 30 | "spear": 0, 31 | "sword": 0, 32 | "axe": 0, 33 | "archer": 0, 34 | "light_cavalry": 30, 35 | "heavy_cavalry": 0, 36 | "mounted_archer": 0, 37 | "ram": 0, 38 | "catapult": 0, 39 | "knight": 0, 40 | "snob": 0, 41 | "trebuchet": 0, 42 | "doppelsoldner": 0 43 | } 44 | }, 45 | "time_start": 1614123456, 46 | "time_completed": 1614456789, 47 | "jobType": "command", 48 | "id": 3440145, 49 | "type": "attack", 50 | "icon": 1049601, 51 | "startVillageId": 4578, 52 | "startVillageName": "Village name given by player", 53 | "startCharacterName": null, 54 | "startCharacterId": 876543, 55 | "startX": 567, 56 | "startY": 678, 57 | "targetVillageId": 1965, 58 | "targetVillageName": "Barbarian village", 59 | "targetCharacterName": null, 60 | "targetCharacterId": null, 61 | "targetX": 470, 62 | "targetY": 529, 63 | "targetIsBarbarian": true, 64 | "returning": true, 65 | "units": { 66 | "spear": 0, 67 | "sword": 0, 68 | "axe": 0, 69 | "archer": 0, 70 | "light_cavalry": 0, 71 | "heavy_cavalry": 0, 72 | "mounted_archer": 50, 73 | "ram": 0, 74 | "catapult": 0, 75 | "knight": 0, 76 | "snob": 0, 77 | "trebuchet": 0, 78 | "doppelsoldner": 0 79 | }, 80 | "isSpy": false, 81 | "isCommand": true, 82 | "actionType": "attack", 83 | "destination": { 84 | "village": { 85 | "id": 4578, 86 | "name": "Village name given by player", 87 | "x": 567, 88 | "y": 678 89 | }, 90 | "character": { 91 | "name": null, 92 | "id": 876543 93 | } 94 | } 95 | } -------------------------------------------------------------------------------- /implement/applications/eve-online/eve-online-mining-bot/BotLab/NotificationsShim/VolatileProcessInterface.elm: -------------------------------------------------------------------------------- 1 | module BotLab.NotificationsShim.VolatileProcessInterface exposing (..) 2 | 3 | import Json.Decode 4 | import Json.Encode 5 | 6 | 7 | type RequestToVolatileHost 8 | = EffectConsoleBeepSequence (List ConsoleBeepStructure) 9 | 10 | 11 | type ResponseFromVolatileHost 12 | = CompletedEffectSequenceOnWindow 13 | 14 | 15 | type alias ConsoleBeepStructure = 16 | { frequency : Int 17 | , durationInMs : Int 18 | } 19 | 20 | 21 | deserializeResponseFromVolatileHost : String -> Result Json.Decode.Error ResponseFromVolatileHost 22 | deserializeResponseFromVolatileHost = 23 | Json.Decode.decodeString decodeResponseFromVolatileHost 24 | 25 | 26 | decodeResponseFromVolatileHost : Json.Decode.Decoder ResponseFromVolatileHost 27 | decodeResponseFromVolatileHost = 28 | Json.Decode.oneOf 29 | [ Json.Decode.field "CompletedEffectSequenceOnWindow" (jsonDecodeSucceedWhenNotNull CompletedEffectSequenceOnWindow) 30 | ] 31 | 32 | 33 | encodeRequestToVolatileHost : RequestToVolatileHost -> Json.Encode.Value 34 | encodeRequestToVolatileHost request = 35 | case request of 36 | EffectConsoleBeepSequence effectConsoleBeepSequence -> 37 | Json.Encode.object [ ( "EffectConsoleBeepSequence", effectConsoleBeepSequence |> Json.Encode.list encodeConsoleBeep ) ] 38 | 39 | 40 | decodeRequestToVolatileHost : Json.Decode.Decoder RequestToVolatileHost 41 | decodeRequestToVolatileHost = 42 | Json.Decode.oneOf 43 | [ Json.Decode.field "EffectConsoleBeepSequence" (Json.Decode.list decodeConsoleBeep |> Json.Decode.map EffectConsoleBeepSequence) 44 | ] 45 | 46 | 47 | buildRequestStringToGetResponseFromVolatileHost : RequestToVolatileHost -> String 48 | buildRequestStringToGetResponseFromVolatileHost = 49 | encodeRequestToVolatileHost 50 | >> Json.Encode.encode 0 51 | 52 | 53 | encodeConsoleBeep : ConsoleBeepStructure -> Json.Encode.Value 54 | encodeConsoleBeep consoleBeep = 55 | Json.Encode.object 56 | [ ( "frequency", consoleBeep.frequency |> Json.Encode.int ) 57 | , ( "durationInMs", consoleBeep.durationInMs |> Json.Encode.int ) 58 | ] 59 | 60 | 61 | decodeConsoleBeep : Json.Decode.Decoder ConsoleBeepStructure 62 | decodeConsoleBeep = 63 | Json.Decode.map2 ConsoleBeepStructure 64 | (Json.Decode.field "frequency" Json.Decode.int) 65 | (Json.Decode.field "durationInMs" Json.Decode.int) 66 | 67 | 68 | jsonDecodeSucceedWhenNotNull : a -> Json.Decode.Decoder a 69 | jsonDecodeSucceedWhenNotNull valueIfNotNull = 70 | Json.Decode.value 71 | |> Json.Decode.andThen 72 | (\asValue -> 73 | if asValue == Json.Encode.null then 74 | Json.Decode.fail "Is null." 75 | 76 | else 77 | Json.Decode.succeed valueIfNotNull 78 | ) 79 | -------------------------------------------------------------------------------- /implement/applications/eve-online/eve-online-combat-anomaly-bot/BotLab/NotificationsShim/VolatileProcessInterface.elm: -------------------------------------------------------------------------------- 1 | module BotLab.NotificationsShim.VolatileProcessInterface exposing (..) 2 | 3 | import Json.Decode 4 | import Json.Encode 5 | 6 | 7 | type RequestToVolatileHost 8 | = EffectConsoleBeepSequence (List ConsoleBeepStructure) 9 | 10 | 11 | type ResponseFromVolatileHost 12 | = CompletedEffectSequenceOnWindow 13 | 14 | 15 | type alias ConsoleBeepStructure = 16 | { frequency : Int 17 | , durationInMs : Int 18 | } 19 | 20 | 21 | deserializeResponseFromVolatileHost : String -> Result Json.Decode.Error ResponseFromVolatileHost 22 | deserializeResponseFromVolatileHost = 23 | Json.Decode.decodeString decodeResponseFromVolatileHost 24 | 25 | 26 | decodeResponseFromVolatileHost : Json.Decode.Decoder ResponseFromVolatileHost 27 | decodeResponseFromVolatileHost = 28 | Json.Decode.oneOf 29 | [ Json.Decode.field "CompletedEffectSequenceOnWindow" (jsonDecodeSucceedWhenNotNull CompletedEffectSequenceOnWindow) 30 | ] 31 | 32 | 33 | encodeRequestToVolatileHost : RequestToVolatileHost -> Json.Encode.Value 34 | encodeRequestToVolatileHost request = 35 | case request of 36 | EffectConsoleBeepSequence effectConsoleBeepSequence -> 37 | Json.Encode.object [ ( "EffectConsoleBeepSequence", effectConsoleBeepSequence |> Json.Encode.list encodeConsoleBeep ) ] 38 | 39 | 40 | decodeRequestToVolatileHost : Json.Decode.Decoder RequestToVolatileHost 41 | decodeRequestToVolatileHost = 42 | Json.Decode.oneOf 43 | [ Json.Decode.field "EffectConsoleBeepSequence" (Json.Decode.list decodeConsoleBeep |> Json.Decode.map EffectConsoleBeepSequence) 44 | ] 45 | 46 | 47 | buildRequestStringToGetResponseFromVolatileHost : RequestToVolatileHost -> String 48 | buildRequestStringToGetResponseFromVolatileHost = 49 | encodeRequestToVolatileHost 50 | >> Json.Encode.encode 0 51 | 52 | 53 | encodeConsoleBeep : ConsoleBeepStructure -> Json.Encode.Value 54 | encodeConsoleBeep consoleBeep = 55 | Json.Encode.object 56 | [ ( "frequency", consoleBeep.frequency |> Json.Encode.int ) 57 | , ( "durationInMs", consoleBeep.durationInMs |> Json.Encode.int ) 58 | ] 59 | 60 | 61 | decodeConsoleBeep : Json.Decode.Decoder ConsoleBeepStructure 62 | decodeConsoleBeep = 63 | Json.Decode.map2 ConsoleBeepStructure 64 | (Json.Decode.field "frequency" Json.Decode.int) 65 | (Json.Decode.field "durationInMs" Json.Decode.int) 66 | 67 | 68 | jsonDecodeSucceedWhenNotNull : a -> Json.Decode.Decoder a 69 | jsonDecodeSucceedWhenNotNull valueIfNotNull = 70 | Json.Decode.value 71 | |> Json.Decode.andThen 72 | (\asValue -> 73 | if asValue == Json.Encode.null then 74 | Json.Decode.fail "Is null." 75 | 76 | else 77 | Json.Decode.succeed valueIfNotNull 78 | ) 79 | -------------------------------------------------------------------------------- /implement/applications/eve-online/eve-online-warp-to-0-autopilot/BotLab/NotificationsShim/VolatileProcessInterface.elm: -------------------------------------------------------------------------------- 1 | module BotLab.NotificationsShim.VolatileProcessInterface exposing (..) 2 | 3 | import Json.Decode 4 | import Json.Encode 5 | 6 | 7 | type RequestToVolatileHost 8 | = EffectConsoleBeepSequence (List ConsoleBeepStructure) 9 | 10 | 11 | type ResponseFromVolatileHost 12 | = CompletedEffectSequenceOnWindow 13 | 14 | 15 | type alias ConsoleBeepStructure = 16 | { frequency : Int 17 | , durationInMs : Int 18 | } 19 | 20 | 21 | deserializeResponseFromVolatileHost : String -> Result Json.Decode.Error ResponseFromVolatileHost 22 | deserializeResponseFromVolatileHost = 23 | Json.Decode.decodeString decodeResponseFromVolatileHost 24 | 25 | 26 | decodeResponseFromVolatileHost : Json.Decode.Decoder ResponseFromVolatileHost 27 | decodeResponseFromVolatileHost = 28 | Json.Decode.oneOf 29 | [ Json.Decode.field "CompletedEffectSequenceOnWindow" (jsonDecodeSucceedWhenNotNull CompletedEffectSequenceOnWindow) 30 | ] 31 | 32 | 33 | encodeRequestToVolatileHost : RequestToVolatileHost -> Json.Encode.Value 34 | encodeRequestToVolatileHost request = 35 | case request of 36 | EffectConsoleBeepSequence effectConsoleBeepSequence -> 37 | Json.Encode.object [ ( "EffectConsoleBeepSequence", effectConsoleBeepSequence |> Json.Encode.list encodeConsoleBeep ) ] 38 | 39 | 40 | decodeRequestToVolatileHost : Json.Decode.Decoder RequestToVolatileHost 41 | decodeRequestToVolatileHost = 42 | Json.Decode.oneOf 43 | [ Json.Decode.field "EffectConsoleBeepSequence" (Json.Decode.list decodeConsoleBeep |> Json.Decode.map EffectConsoleBeepSequence) 44 | ] 45 | 46 | 47 | buildRequestStringToGetResponseFromVolatileHost : RequestToVolatileHost -> String 48 | buildRequestStringToGetResponseFromVolatileHost = 49 | encodeRequestToVolatileHost 50 | >> Json.Encode.encode 0 51 | 52 | 53 | encodeConsoleBeep : ConsoleBeepStructure -> Json.Encode.Value 54 | encodeConsoleBeep consoleBeep = 55 | Json.Encode.object 56 | [ ( "frequency", consoleBeep.frequency |> Json.Encode.int ) 57 | , ( "durationInMs", consoleBeep.durationInMs |> Json.Encode.int ) 58 | ] 59 | 60 | 61 | decodeConsoleBeep : Json.Decode.Decoder ConsoleBeepStructure 62 | decodeConsoleBeep = 63 | Json.Decode.map2 ConsoleBeepStructure 64 | (Json.Decode.field "frequency" Json.Decode.int) 65 | (Json.Decode.field "durationInMs" Json.Decode.int) 66 | 67 | 68 | jsonDecodeSucceedWhenNotNull : a -> Json.Decode.Decoder a 69 | jsonDecodeSucceedWhenNotNull valueIfNotNull = 70 | Json.Decode.value 71 | |> Json.Decode.andThen 72 | (\asValue -> 73 | if asValue == Json.Encode.null then 74 | Json.Decode.fail "Is null." 75 | 76 | else 77 | Json.Decode.succeed valueIfNotNull 78 | ) 79 | -------------------------------------------------------------------------------- /guide/how-to-install-the-botlab-client-and-register-the-botlab-command.md: -------------------------------------------------------------------------------- 1 | # How to Install the BotLab Client and Register the `botlab` Command 2 | 3 | When you land here, you might have tried to use the `botlab` program in some form. Maybe you downloaded a script from the [bot catalog](https://to.botlab.org/catalog), and got this error message when running the script: 4 | 5 | > I failed to run the bot because I did not find the 'botlab.exe' program. 6 | 7 | Or maybe you followed instructions to run a command in Windows and got an error message like this: 8 | 9 | > 'botlab' is not recognized as an internal or external command, 10 | operable program or batch file. 11 | 12 | The BotLab client program is a tool for developing and running bots, and many guides assume it is registered on your Windows system. To make these guides and scripts work, follow these steps: 13 | 14 | + Download the file from 15 | + Extract the downloaded zip archive. The extraction will give you a file named `BotLab.exe`. 16 | 17 | ![BotLab client executable file in Windows Explorer](./image/2024-02-18-botlab-client-executable-file-in-explorer.png) 18 | 19 | 20 | + Run the `BotLab.exe` program, for example by double clicking the file in the Windows Explorer. It will open a window like in this screenshot: 21 | 22 | ![BotLab client offers to install](./image/2022-10-07-botlab-client-offer-install.png) 23 | 24 | + To start the installation, use the button labeled `Install and Continue`. 25 | + The program then confirms the successful installation with a new output like this: 26 | 27 | ![BotLab client completed installation](./image/2022-10-07-botlab-client-completed-installation.png) 28 | 29 | That's it; the installation is complete. Now you can run bots by using the 'Run Bot' button in the BotLab client window: 30 | 31 | ![The first view visible in the BotLab client after installing](./image/2024-02-18-botlab-client-initial-main-menu.png) 32 | 33 | If you have any questions, the [BotLab forum](https://forum.botlab.org) is a good place to learn more. 34 | 35 | ## Using Different Versions Simultaneously 36 | 37 | As the evolution of functionality in BotLab continues, multiple new versions of the BotLab client are offered each year. Sometimes, you might want to simultaneously use different client software versions on the same Windows system. 38 | 39 | To do this, place each of the versions you want to use in a separate directory in the file system. You don't have to use the installation to run bots. If you don't want to register the current instance as 'botlab.exe' on the whole Windows user account, use the 'Continue without installing' option. 40 | You can also rename the executable file and then use the installation to register multiple different versions on the whole Windows user account. 41 | 42 | Scripts from the configuration export or catalog assume the name `botlab.exe` by default. If you renamed the executable file on your system, change the script accordingly. 43 | -------------------------------------------------------------------------------- /guide/eve-online/eve-online-warp-to-0-autopilot-bot.md: -------------------------------------------------------------------------------- 1 | # EVE Online Warp-To-0 Autopilot Bot 2 | 3 | When playing EVE Online, you might spend significant time traveling between solar systems. This activity is so common that there is even an in-game autopilot to automate this process. But that autopilot has a critical flaw: It is quite inefficient and will cause long travel times. You can travel faster by manually commanding your ship. 4 | 5 | Fortunately, this process can be automated using a bot. The bot we are using here follows the route set in the in-game autopilot and uses the context menu to initiate warp and dock commands. 6 | 7 | ## Starting the Autopilot Bot 8 | 9 | If the BotLab client is not already installed on your machine, follow the guide at 10 | The BotLab client is a tool for developing bots and also makes running bots easier with graphical user interfaces for configuration. 11 | 12 | In the BotLab client, load the bot by entering the following link in the 'Select Bot' view: 13 | 14 | 15 | There is a detailed walkthrough video on how to load and run a bot at 16 | 17 | Before starting the bot, set up the game client as follows: 18 | 19 | + Set the UI language to English. 20 | + Set the in-game autopilot route. 21 | + Make sure the autopilot info panel is expanded, so that the route is visible. 22 | 23 | The bot needs a few seconds to start and find the EVE Online client process. It also shows status messages to inform what it is doing at the moment and when the startup is complete. 24 | 25 | ![EVE Online Bot Starting](./image/2023-03-08-botlab-gui-eve-online-bot-startup.png) 26 | 27 | When the startup sequence has completed, the bot might display this message: 28 | 29 | > I see no route in the info panel. I will start when a route is set. 30 | 31 | We need to set the destination in the in-game autopilot so that the route is visible in the `Route` info panel. But we do not start the in-game autopilot because it would interfere with our bot. 32 | Also, this bot does not undock, so we need to undock our ship manually for the bot to start piloting. As long as the ship is docked, the bot displays the following message: 33 | 34 | > I cannot see if the ship is warping or jumping. I wait for the ship UI to appear on the screen. 35 | 36 | As soon as we undock, the bot will start to send mouse clicks to the game client to initiate warp and jump maneuvers. 37 | 38 | ## Configuration Settings 39 | 40 | Settings are optional; you only need them in case the defaults don't fit your use-case. 41 | 42 | + `activate-module-always` : Text found in tooltips of ship modules that should always be active. For example: "cloaking device". 43 | 44 | Alright, I think that is all there is to know about the basic autopilot bot. If you have questions about this bot or are searching for other bots, don't hesitate to ask on the [BotLab forum](https://forum.botlab.org/). 45 | 46 | -------------------------------------------------------------------------------- /guide/elvenar/elvenar-bot.md: -------------------------------------------------------------------------------- 1 | # Elvenar Bot 2 | 3 | This bot collects coins in the Elvenar game client window. 4 | It locates the coins over residential buildings in the Elvenar window and then clicks on them to collect them 🪙 5 | 6 | ## Setup and starting the bot 7 | 8 | If the BotLab client is not already installed on your machine, follow the guide at 9 | The BotLab client is a tool for developing bots and also makes running bots easier with graphical user interfaces for configuration. 10 | 11 | In the BotLab client, load the bot by entering the following link in the 'Select Bot' view: 12 | 13 | 14 | There is a detailed walkthrough video on how to load and run a bot at 15 | 16 | Follow these steps to start a new bot session: 17 | 18 | + Load Elvenar in a web browser. 19 | + Ensure the product of the display 'scale' setting in Windows and the 'zoom' setting in the web browser is 125%. If the 'scale' in Windows settings is 100%, zoom the web browser tab to 125%. If the 'scale' in Windows settings is 125%, zoom the web browser tab to 100%. 20 | + Elvenar offers you five different zoom levels. Zoom to the middle level to ensure the bot will correctly recognize the icons in the game. (You can change zoom levels using the mouse wheel or via the looking glass icons in the settings menu) 21 | + Start the bot and immediately click on the web browser containing Elvenar. 22 | 23 | From here on, the bot works automatically, periodically checking for and collecting coins. 24 | 25 | > The bot picks the topmost window in the display order, the one in the front. This selection happens once when starting the bot. The bot then remembers the window address and continues working on the same window. 26 | > To use this bot, bring the Elvenar game client window to the foreground after pressing the button to run the bot. When the bot displays the window title in the status text, it has completed the selection of the game window. 27 | 28 | You can test this bot by placing a screenshot in a paint app like MS Paint or Paint.NET, where you can quickly change its location within the window. 29 | 30 | You can see the training data samples used to develop this bot at 31 | 32 | ## Getting Help 33 | 34 | If you have any questions, the [BotLab forum](https://forum.botlab.org) is a good place to learn more. You can also contact me at [support@botlab.org](mailto:support@botlab.org?subject=Tribal%20Wars%202%20Farmbot%20-%20your%20issue%20here) 35 | 36 | When asking for help with the bot, include one of these two artifacts to help us see what happened on your setup: 37 | 38 | + The summary from the `Report Problem or Share Session` dialog in the play session interface. Either upload the saved JSON file or copy the text in that file. To reach this dialog, use the buttons labeled `Get Help With This Bot Session` and then `Report Problem or Share Session`. 39 | + The play session recording archive from the session view in DevTools. 40 | -------------------------------------------------------------------------------- /explore/2019-09-15.eve-online-memory-reading/implement/eve-online-memory-reading/BotEngine/Measurement.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Text.RegularExpressions; 6 | 7 | namespace BotEngine 8 | { 9 | public class ProcessMeasurement 10 | { 11 | public KeyValuePair[] MemoryBaseAddressAndListOctet; 12 | 13 | static string ProcessMemoryEntryName => @"Process\Memory"; 14 | 15 | static public Int64? BaseAddressFromMemoryEntryName(string MemoryEntryName) 16 | { 17 | if (null == MemoryEntryName) 18 | { 19 | return null; 20 | } 21 | 22 | var match = Regex.Match(MemoryEntryName, @"0x([\d\w]+)"); 23 | 24 | if (!match.Success) 25 | { 26 | return null; 27 | } 28 | 29 | if (Int64.TryParse( 30 | match.Groups[1].Value, 31 | System.Globalization.NumberStyles.HexNumber, 32 | System.Globalization.CultureInfo.InvariantCulture.NumberFormat, 33 | out var asInt)) 34 | return asInt; 35 | 36 | return null; 37 | } 38 | 39 | static public ProcessMeasurement MeasurementFromZipArchive(byte[] ZipArchiveSerial) 40 | { 41 | using (var ZipArchive = new System.IO.Compression.ZipArchive(new MemoryStream(ZipArchiveSerial), System.IO.Compression.ZipArchiveMode.Read)) 42 | { 43 | var memoryEntries = 44 | ZipArchive.Entries 45 | .Where(entry => entry.FullName.StartsWith(ProcessMemoryEntryName, StringComparison.InvariantCultureIgnoreCase)) 46 | .ToList(); 47 | 48 | var memoryList = 49 | memoryEntries 50 | ?.Select(Entry => 51 | { 52 | var content = new byte[Entry.Length]; 53 | 54 | using (var stream = Entry.Open()) 55 | { 56 | if (stream.Read(content, 0, content.Length) != content.Length) 57 | throw new NotImplementedException(); 58 | } 59 | 60 | return new 61 | { 62 | baseAddress = BaseAddressFromMemoryEntryName(Entry.Name), 63 | content = content, 64 | }; 65 | }) 66 | ?.ToArray(); 67 | 68 | return new ProcessMeasurement 69 | { 70 | MemoryBaseAddressAndListOctet = 71 | memoryList 72 | ?.Where(AddressAndListOctet => AddressAndListOctet.baseAddress.HasValue && null != AddressAndListOctet.content) 73 | ?.Select(AddressAndListOctet => new KeyValuePair(AddressAndListOctet.baseAddress.Value, AddressAndListOctet.content)) 74 | ?.ToArray(), 75 | }; 76 | } 77 | } 78 | } 79 | } -------------------------------------------------------------------------------- /explore/2019-10-14.improve-automated-testing/2019-10-14.improve-automated-testing.md: -------------------------------------------------------------------------------- 1 | # 2019-10-14 Improve Automated Testing 2 | 3 | Based on experience working on these changes: 4 | 5 | + https://github.com/Viir/bots/commit/9929d49f4c38611181c08325d23bad5ef8a36cab 6 | + https://github.com/Viir/bots/commit/1b93524d8c43bd7a66d3c0cbd09a37eeaccc4534 7 | 8 | Problems experienced there: 9 | 10 | + Process to extract the relevant portions from the sample files which were already present in the same repository: 11 | + So far, using `elm-test` to run tests. 12 | + The sample data (from https://github.com/Viir/bots/tree/1b93524d8c43bd7a66d3c0cbd09a37eeaccc4534/implement/applications/eve-online/training-data/2019-10-12.eve-online-mining) has to be made available to the Elm test function somehow. To solve this, test data was copied into the Elm module source code. 13 | + To avoid problems with parsing the Elm modules and with readability for humans, the sample data was not copied completely but reduced to portions which are relevant for the test. 14 | + Just removing contents before and after the part of the JSON tree containing the tested object was not sufficient; in some cases also removed superfluous elements within the subtree tree, which is parsed in the test. Not everything in there is parsed. 15 | + Ideally, we could reference the file we already have, instead of messing with the Elm source code. 16 | 17 | How about using a test runner that supports referencing and loading files and propagating them into the tests? 18 | 19 | We could describe a test in the Elm module like this: 20 | ```Elm 21 | type alias FileTest = 22 | { name : String 23 | , source : String 24 | , passes : Bytes.Bytes -> Bool 25 | } 26 | 27 | 28 | allTestsToRun : List FileTest 29 | allTestsToRun = 30 | [ sample_7C3AE6AF_ship_UI_first_module 31 | ] 32 | 33 | 34 | sample_7C3AE6AF_ship_UI_first_module : List FileTest 35 | sample_7C3AE6AF_ship_UI_first_module = 36 | { name = "7C3AE6AF - First Ship UI Module" 37 | , source = "https://github.com/Viir/bots/blob/1b93524d8c43bd7a66d3c0cbd09a37eeaccc4534/implement/applications/eve-online/training-data/2019-10-12.eve-online-mining/2019-10-12.from-7C3AE6AF.reduced-with-named-nodes.only-shipui.json" 38 | , passes = 39 | (Bytes.Decode.decode Bytes.Decode.string 40 | |> Maybe.andThen (parseMemoryMeasurementFromJson >> Result.toMaybe) 41 | |> Maybe.andThen (.shipUi >> maybeNothingFromCanNotSeeIt) 42 | |> Maybe.map .modules 43 | |> Maybe.andThen List.head 44 | ) 45 | == Just 46 | { uiElement = { id = 543723600, region = { left = 632, top = 539, right = 696, bottom = 603 } } 47 | , isActive = Just True 48 | } 49 | } 50 | ``` 51 | 52 | Note about the source in the example above: Since it specifies a commit hash, we do not need to load from the given address. Maybe we have the same commit in a local repository; then, we can get it from there. At the same time, having the URL in the code helps humans navigate. 53 | 54 | This design should allow to only give the name of the compilation root module and the name of the `allTestsToRun` function to the test runner. 55 | -------------------------------------------------------------------------------- /guide/how-to-collect-samples-for-64-bit-memory-reading-development.md: -------------------------------------------------------------------------------- 1 | # How to Collect Samples for 64-bit Memory Reading Development 2 | 3 | This guide explains how to save an example of a game client process to a file. Such examples are to support the development of memory reading frameworks or bots. 4 | 5 | The tool we use in this guide works only for 64-bit processes. 6 | 7 | The tool copies the memory contents of a chosen Windows process (such as a game client) and takes a screenshot from its main window and writes those to a file. This data is used in development to correlate screen contents with memory contents. 8 | 9 | Here you can see a typical scenario where we use this tool: https://forum.botlab.org/t/mining-bot-i-cannot-see-the-ore-hold-capacity-gauge/3101 10 | 11 | **Steps to collect a sample:** 12 | 13 | + Download and unpack the zip archive from [https://github.com/Arcitectus/Sanderling/releases/download/v2020-04-12/2020-04-12-read-memory-64.zip](https://github.com/Arcitectus/Sanderling/releases/download/v2020-04-12/2020-04-12-read-memory-64.zip) 14 | + Find the game client in the Windows Task Manager. 15 | + Make sure the name of the game client displayed in the Windows Task Manager does not contain `(32 bit)`. 16 | + Read the process ID of the game client process in the `PID` column in the Task Manager. 17 | + Ensure the game client window is visible and not minimized. 18 | + Use the Windows Command Prompt to run the tool, using the following command: 19 | ```cmd 20 | read-memory-64-bit.exe save-process-sample --pid=12345 21 | ``` 22 | + The tool then creates a process sample file in the directory currently selected in the Command Prompt. When successful, the program exits with a message like the following: 23 | ```cmd 24 | Saved sample F2CC4E4EC28482747A05172990F7B54CFABAA7F80C2DB83B81E86D3F41523551 to file 'process-sample-F2CC4E4EC2.zip'. 25 | ``` 26 | 27 | Since this tool does not interfere with the game client's operation, the game client can change data structures during the timespan needed to copy the memory contents. Because the memory contents are copied at different times, there is a risk of inconsistencies in the copy, which in turn can make it unusable for development. There are two ways to counter this risk: 28 | 29 | + Using more samples to increase the chance that one is good. 30 | + Reducing the time needed to copy the memory contents. You can achieve this by reducing the memory usage of the game client. Memory usage is often affected by settings, such as the resolution or quality of textures used for graphics rendering. Reducing memory use has the added benefit of smaller sample files. 31 | 32 | ### Troubleshooting 33 | 34 | #### `Parameter is not valid` in `Bitmap..ctor` 35 | 36 | ```txt 37 | Unhandled exception. System.ArgumentException: Parameter is not valid. 38 | at System.Drawing.SafeNativeMethods.Gdip.CheckStatus(Int32 status) 39 | at System.Drawing.Bitmap..ctor(Int32 width, Int32 height, PixelFormat format) 40 | at read_memory_64_bit.Program.GetScreenshotOfWindowClientAreaAsBitmap(IntPtr windowHandle) 41 | ``` 42 | 43 | This error happens when the main window of the chosen process is minimized. 44 | 45 | To avoid the error, ensure the game client window is visible and not minimized. 46 | -------------------------------------------------------------------------------- /guide/how-to-report-an-issue-with-a-bot-or-request-a-new-feature.md: -------------------------------------------------------------------------------- 1 | # How to Report an Issue with a Bot or Request a New Feature 2 | 3 | Did you see something to improve in a bot? 4 | This guide helps you report bugs and communicate ideas for new features to developers. 5 | 6 | Improving a bot starts with identifying a scenario in which we want it to behave differently than it did so far. This approach applies to both fixing bugs and adding features. 7 | 8 | These scenarios are the fuel for bot development. Developing bots is an incremental process. A bot evolves as we collect more training data describing the game environment and the desired behavior. 9 | 10 | Explaining your use case in human language is a good start, but a developer will usually ask for more data. 11 | 12 | ## Session Recording and Archive 13 | 14 | The most common way to describe the bot's situation is to share a recording of a play session. 15 | 16 | The session recording allows us to: 17 | 18 | + See which bot was used in the session and how it was instructed. 19 | + Travel back in time and see what the bot saw in the past. 20 | + Understand why the bot did what it did. 21 | + Create simulation environments to test bot programs: 22 | + Collect training data to adapt bot programs to changes in the game world and game clients. 23 | 24 | ## Exporting a Play Session Recording 25 | 26 | How do we get a session recording that we can share with others? 27 | 28 | The BotLab client automatically saves a recording for every play session by default. That means saving the session recording is already taken care of unless you choose to deactivate it for that session. 29 | 30 | (If you have set the `--detailed-session-recording` switch to `off` on a session, the recording will not be available for that session) 31 | 32 | The main menu of the BotLab client shows a list of recent play sessions; we can open any of these for review and further analysis: 33 | 34 | ![List of recent play sessions in the main menu](./image/2024-02-18-botlab-client-main-menu-with-recent-sessions.png) 35 | 36 | By selecting a play session in the main menu, we switch to the tools to explore and analyze that particular session. 37 | To export the play session recording into a transportable zip archive, use the button 'Export play session' above the summary view: 38 | 39 | ![Play session summary page](./image/2024-02-18-botlab-client-play-session-summary-export.png) 40 | 41 | **Note**: After clicking that button, the software might take a few seconds to respond, depending on how many events are in the play session. 42 | 43 | The software then opens a new 'Save as' dialog window where we can select a directory to save the exported recording, as seen in the screenshot below: 44 | 45 | ![File save dialog for exporting a play session recording](./image/2025-04-23-botlab-client-ui-export-session-recording-dialog.png) 46 | 47 | The file save dialog will default to a file name like `session-recording-2025-04-23T09-31-32.zip` 48 | 49 | With the export, you can share the play session recording like any other file. This way, other people can do an analysis as detailed as necessary. When required, it also enables distilling the training data to adapt the bot to the specifics of your game client. 50 | -------------------------------------------------------------------------------- /implement/templates/remember-bot-settings/Bot.elm: -------------------------------------------------------------------------------- 1 | {- This program demonstrates how to remember the bot-settings string. 2 | 3 | It takes any settings string received from the user and stores it in the bot state. 4 | This bot also updates the status message to show the last received settings string, so you can check that a method (e.g., via command line) of applying the settings works. 5 | -} 6 | {- 7 | catalog-tags:template,bot-settings,demo-interface-to-host 8 | authors-forum-usernames:viir 9 | -} 10 | 11 | 12 | module Bot exposing 13 | ( State 14 | , botMain 15 | ) 16 | 17 | import BotLab.BotInterface_To_Host_2023_05_15 as InterfaceToHost 18 | import Json.Encode 19 | 20 | 21 | type alias State = 22 | { lastReceivedSettings : Maybe { timeInMilliseconds : Int, settings : String } 23 | , timeInMilliseconds : Int 24 | } 25 | 26 | 27 | botMain : InterfaceToHost.BotConfig State 28 | botMain = 29 | { init = { timeInMilliseconds = 0, lastReceivedSettings = Nothing } 30 | , processEvent = processEvent 31 | } 32 | 33 | 34 | processEvent : InterfaceToHost.BotEvent -> State -> ( State, InterfaceToHost.BotEventResponse ) 35 | processEvent event stateBefore = 36 | let 37 | state = 38 | stateBefore |> integrateEvent event 39 | in 40 | ( state 41 | , InterfaceToHost.ContinueSession 42 | { statusText = state |> statusMessageFromState 43 | , startTasks = [] 44 | , notifyWhenArrivedAtTime = Just { timeInMilliseconds = state.timeInMilliseconds + 1000 } 45 | } 46 | ) 47 | 48 | 49 | integrateEvent : InterfaceToHost.BotEvent -> State -> State 50 | integrateEvent event stateBeforeUpdateTime = 51 | let 52 | stateBefore = 53 | { stateBeforeUpdateTime | timeInMilliseconds = event.timeInMilliseconds } 54 | in 55 | case event.eventAtTime of 56 | InterfaceToHost.BotSettingsChangedEvent settingsString -> 57 | { stateBefore 58 | | lastReceivedSettings = 59 | Just 60 | { timeInMilliseconds = stateBefore.timeInMilliseconds 61 | , settings = settingsString 62 | } 63 | } 64 | 65 | InterfaceToHost.TimeArrivedEvent -> 66 | stateBefore 67 | 68 | InterfaceToHost.TaskCompletedEvent _ -> 69 | stateBefore 70 | 71 | InterfaceToHost.SessionDurationPlannedEvent _ -> 72 | stateBefore 73 | 74 | 75 | statusMessageFromState : State -> String 76 | statusMessageFromState state = 77 | case state.lastReceivedSettings of 78 | Nothing -> 79 | "I did not receive any settings so far." 80 | 81 | Just lastReceivedSettings -> 82 | let 83 | ageInSeconds = 84 | (state.timeInMilliseconds - lastReceivedSettings.timeInMilliseconds) // 1000 85 | in 86 | [ (ageInSeconds |> String.fromInt) ++ " seconds ago, I received the following settings:" 87 | , lastReceivedSettings.settings 88 | , "----" 89 | , "As JSON encoded:" 90 | , lastReceivedSettings.settings |> Json.Encode.string |> Json.Encode.encode 0 91 | ] 92 | |> String.join "\n" 93 | -------------------------------------------------------------------------------- /explore/2020-12-07-explore-multi-instance-scenarios/eve-online-test-coordinate-input-focus/EveOnline/MemoryReading.elm: -------------------------------------------------------------------------------- 1 | module EveOnline.MemoryReading exposing (..) 2 | 3 | import Dict 4 | import Json.Decode 5 | import Json.Encode 6 | 7 | 8 | type alias UITreeNode = 9 | { originalJson : Json.Encode.Value 10 | , pythonObjectAddress : String 11 | , pythonObjectTypeName : String 12 | , dictEntriesOfInterest : Dict.Dict String Json.Encode.Value 13 | , children : Maybe (List UITreeNodeChild) 14 | } 15 | 16 | 17 | type UITreeNodeChild 18 | = UITreeNodeChild UITreeNode 19 | 20 | 21 | unwrapUITreeNodeChild : UITreeNodeChild -> UITreeNode 22 | unwrapUITreeNodeChild child = 23 | case child of 24 | UITreeNodeChild node -> 25 | node 26 | 27 | 28 | countDescendantsInUITreeNode : UITreeNode -> Int 29 | countDescendantsInUITreeNode parent = 30 | parent.children 31 | |> Maybe.withDefault [] 32 | |> List.map unwrapUITreeNodeChild 33 | |> List.map (countDescendantsInUITreeNode >> (+) 1) 34 | |> List.sum 35 | 36 | 37 | listDescendantsInUITreeNode : UITreeNode -> List UITreeNode 38 | listDescendantsInUITreeNode parent = 39 | parent.children 40 | |> Maybe.withDefault [] 41 | |> List.map unwrapUITreeNodeChild 42 | |> List.concatMap (\child -> child :: listDescendantsInUITreeNode child) 43 | 44 | 45 | decodeMemoryReadingFromString : String -> Result Json.Decode.Error UITreeNode 46 | decodeMemoryReadingFromString = 47 | Json.Decode.decodeString uiTreeNodeDecoder 48 | 49 | 50 | uiTreeNodeDecoder : Json.Decode.Decoder UITreeNode 51 | uiTreeNodeDecoder = 52 | Json.Decode.map5 53 | (\originalJson pythonObjectAddress pythonObjectTypeName dictEntriesOfInterest children -> 54 | { originalJson = originalJson 55 | , pythonObjectAddress = pythonObjectAddress 56 | , pythonObjectTypeName = pythonObjectTypeName 57 | , dictEntriesOfInterest = dictEntriesOfInterest |> Dict.fromList 58 | , children = children |> Maybe.map (List.map UITreeNodeChild) 59 | } 60 | ) 61 | Json.Decode.value 62 | (Json.Decode.field "pythonObjectAddress" Json.Decode.string) 63 | (decodeOptionalField "pythonObjectTypeName" Json.Decode.string |> Json.Decode.map (Maybe.withDefault "")) 64 | (Json.Decode.field "dictEntriesOfInterest" (Json.Decode.keyValuePairs Json.Decode.value)) 65 | (decodeOptionalOrNullField "children" (Json.Decode.list (Json.Decode.lazy (\_ -> uiTreeNodeDecoder)))) 66 | 67 | 68 | decodeOptionalOrNullField : String -> Json.Decode.Decoder a -> Json.Decode.Decoder (Maybe a) 69 | decodeOptionalOrNullField fieldName decoder = 70 | decodeOptionalField fieldName (Json.Decode.nullable decoder) 71 | |> Json.Decode.map (Maybe.andThen identity) 72 | 73 | 74 | decodeOptionalField : String -> Json.Decode.Decoder a -> Json.Decode.Decoder (Maybe a) 75 | decodeOptionalField fieldName decoder = 76 | let 77 | finishDecoding json = 78 | case Json.Decode.decodeValue (Json.Decode.field fieldName Json.Decode.value) json of 79 | Ok _ -> 80 | -- The field is present, so run the decoder on it. 81 | Json.Decode.map Just (Json.Decode.field fieldName decoder) 82 | 83 | Err _ -> 84 | -- The field was missing, which is fine! 85 | Json.Decode.succeed Nothing 86 | in 87 | Json.Decode.value 88 | |> Json.Decode.andThen finishDecoding 89 | -------------------------------------------------------------------------------- /explore/2020-01-06.explore-tribal-wars-2/src/Limbara/Limbara.elm: -------------------------------------------------------------------------------- 1 | module Limbara.Limbara exposing 2 | ( RequestToVolatileHost(..) 3 | , ResponseFromVolatileHost(..) 4 | , buildScriptToGetResponseFromVolatileHost 5 | , deserializeResponseFromVolatileHost 6 | ) 7 | 8 | import Json.Decode 9 | import Json.Decode.Extra 10 | import Json.Encode 11 | 12 | 13 | type RequestToVolatileHost 14 | = StartWebBrowserRequest 15 | | RunJavascriptInCurrentPageRequest RunJavascriptInCurrentPageRequestStructure 16 | 17 | 18 | type alias RunJavascriptInCurrentPageRequestStructure = 19 | { requestId : String 20 | , javascript : String 21 | , timeToWaitForCallbackMilliseconds : Int 22 | } 23 | 24 | 25 | type ResponseFromVolatileHost 26 | = WebBrowserStarted 27 | | RunJavascriptInCurrentPageResponse RunJavascriptInCurrentPageResponseStructure 28 | 29 | 30 | type alias RunJavascriptInCurrentPageResponseStructure = 31 | { directReturnValueAsString : String 32 | , callbackReturnValueAsString : Maybe String 33 | } 34 | 35 | 36 | deserializeResponseFromVolatileHost : String -> Result Json.Decode.Error ResponseFromVolatileHost 37 | deserializeResponseFromVolatileHost = 38 | Json.Decode.decodeString decodeResponseFromVolatileHost 39 | 40 | 41 | decodeResponseFromVolatileHost : Json.Decode.Decoder ResponseFromVolatileHost 42 | decodeResponseFromVolatileHost = 43 | Json.Decode.oneOf 44 | [ Json.Decode.field "WebBrowserStarted" (Json.Decode.succeed WebBrowserStarted) 45 | , Json.Decode.field "RunJavascriptInCurrentPageResponse" decodeRunJavascriptInCurrentPageResponse 46 | |> Json.Decode.map RunJavascriptInCurrentPageResponse 47 | ] 48 | 49 | 50 | encodeRequestToVolatileHost : RequestToVolatileHost -> Json.Encode.Value 51 | encodeRequestToVolatileHost request = 52 | case request of 53 | StartWebBrowserRequest -> 54 | Json.Encode.object [ ( "StartWebBrowserRequest", Json.Encode.object [] ) ] 55 | 56 | RunJavascriptInCurrentPageRequest runJavascriptInCurrentPageRequest -> 57 | Json.Encode.object [ ( "RunJavascriptInCurrentPageRequest", runJavascriptInCurrentPageRequest |> encodeRunJavascriptInCurrentPageRequest ) ] 58 | 59 | 60 | encodeRunJavascriptInCurrentPageRequest : RunJavascriptInCurrentPageRequestStructure -> Json.Encode.Value 61 | encodeRunJavascriptInCurrentPageRequest runJavascriptInCurrentPageRequest = 62 | Json.Encode.object 63 | [ ( "requestId", runJavascriptInCurrentPageRequest.requestId |> Json.Encode.string ) 64 | , ( "javascript", runJavascriptInCurrentPageRequest.javascript |> Json.Encode.string ) 65 | , ( "timeToWaitForCallbackMilliseconds", runJavascriptInCurrentPageRequest.timeToWaitForCallbackMilliseconds |> Json.Encode.int ) 66 | ] 67 | 68 | 69 | decodeRunJavascriptInCurrentPageResponse : Json.Decode.Decoder RunJavascriptInCurrentPageResponseStructure 70 | decodeRunJavascriptInCurrentPageResponse = 71 | Json.Decode.map2 RunJavascriptInCurrentPageResponseStructure 72 | (Json.Decode.field "directReturnValueAsString" Json.Decode.string) 73 | (Json.Decode.Extra.optionalField "callbackReturnValueAsString" Json.Decode.string) 74 | 75 | 76 | buildScriptToGetResponseFromVolatileHost : RequestToVolatileHost -> String 77 | buildScriptToGetResponseFromVolatileHost request = 78 | "serialRequest(" 79 | ++ (request 80 | |> encodeRequestToVolatileHost 81 | |> Json.Encode.encode 0 82 | |> Json.Encode.string 83 | |> Json.Encode.encode 0 84 | ) 85 | ++ ")" 86 | -------------------------------------------------------------------------------- /explore/2019-09-15.eve-online-memory-reading/implement/eve-online-memory-reading/ProcessMemoryReader.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using Kernel32 = BotEngine.Windows.Kernel32; 5 | 6 | namespace eve_online_memory_reading 7 | { 8 | /// 9 | /// reads memory from the process identified by . 10 | /// 11 | public class ProcessMemoryReader : IMemoryReader, IDisposable 12 | { 13 | readonly public int ProcessId; 14 | 15 | IntPtr ProcessHandle; 16 | 17 | MemoryReaderModuleInfo[] ModulesCache; 18 | 19 | public MemoryReaderModuleInfo[] Modules() 20 | { 21 | // assuming that Modules havent changed since call to constructor. 22 | return ModulesCache; 23 | } 24 | 25 | static public MemoryReaderModuleInfo[] ModulesOfProcess(int ProcessId) 26 | { 27 | var Process = System.Diagnostics.Process.GetProcessById(ProcessId); 28 | 29 | var Modules = new List(); 30 | 31 | foreach (var Module in Process.Modules.OfType()) 32 | { 33 | Modules.Add(new MemoryReaderModuleInfo(Module.ModuleName, Module.BaseAddress.ToInt64())); 34 | } 35 | 36 | return Modules.ToArray(); 37 | } 38 | 39 | public ProcessMemoryReader( 40 | int ProcessId) 41 | { 42 | this.ProcessId = ProcessId; 43 | 44 | ProcessHandle = Kernel32.OpenProcess(Kernel32.PROCESS_ACCESS_RIGHT.PROCESS_VM_READ, 0, (uint)ProcessId); 45 | 46 | ModulesCache = ModulesOfProcess(ProcessId); 47 | } 48 | 49 | public ProcessMemoryReader( 50 | System.Diagnostics.Process Process) 51 | : 52 | this(Process.Id) 53 | { 54 | } 55 | 56 | public void Dispose() 57 | { 58 | Kernel32.CloseHandle(ProcessHandle); 59 | } 60 | 61 | static public IntPtr? CastToIntPtrAvoidOverflow(Int64 Address) 62 | { 63 | if (4 == IntPtr.Size) 64 | { 65 | if (Address < UInt32.MinValue) 66 | { 67 | return null; 68 | } 69 | 70 | if (UInt32.MaxValue < Address) 71 | { 72 | return null; 73 | } 74 | } 75 | 76 | return (IntPtr)((Int32)Address); 77 | } 78 | 79 | public byte[] ReadBytes(Int64 Address, int BytesCount) 80 | { 81 | var Buffer = new byte[BytesCount]; 82 | 83 | var lpNumberOfBytesRead = IntPtr.Zero; 84 | 85 | var AddressAsIntPtr = CastToIntPtrAvoidOverflow(Address); 86 | 87 | if (!AddressAsIntPtr.HasValue) 88 | { 89 | return null; 90 | } 91 | 92 | var Error = Kernel32.ReadProcessMemory(ProcessHandle, AddressAsIntPtr.Value, Buffer, (IntPtr)Buffer.Length, out lpNumberOfBytesRead); 93 | 94 | var NumberOfBytesRead = (int)lpNumberOfBytesRead; 95 | 96 | if (NumberOfBytesRead < 1) 97 | { 98 | return null; 99 | } 100 | 101 | if (Buffer.Length == NumberOfBytesRead) 102 | { 103 | return Buffer; 104 | } 105 | 106 | return Buffer.Take(NumberOfBytesRead).ToArray(); 107 | } 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /guide/image/data-flow-in-bot-architecture-separating-memory.xml: -------------------------------------------------------------------------------- 1 | 7VxLd+K4Ev41nHPvIhy/gWVedC/SMz2TOX3TS2HLoG7bYmQBoX/9leSXjITjBANOBxaJLcuyXF9VqV7ywL6Nnz8RsFx8wQGMBpYRPA/su4FlmYblsH+8ZZu1uBMra5gTFOSdqoZH9AsWd+atKxTAtNaRYhxRtKw3+jhJoE9rbYAQvKl3C3FUf+oSzKHS8OiDSG39HwroIm/1DKO68Bmi+aJ4tFFcmQH/55zgVZI/cGDZofhll2NQDJb3TxcgwBupyb4f2LcEY5odxc+3MOLELeiW3Tfdc7WcOIEJbXPDz/vHJyOyfvyVPNHv/t/e/Iu3vbKzUdYgWsHiNcRk6bagkHhFyAcxBvbNZoEofFwCn1/dMJ5gbQsaR+zMZIcgQvOEHftsUpCwhgjMYPQVp4giXLuwhoQihsPDTocYBQF/dNnhOh+yvDCPQJrm08FsJohy3nP5aYii6BZHmIip24ELx4HD2lNK8E8oXRlbM9vz2BWVijlh+ePhs9SUU/UTxDGkZMu65Fe9HOBcAmw3P99U/FQywUJmpeJGkPPwvBy6gpEd5Ei+AlXzgurBqDp1VMcaUF1jaJgaXJ0OcMWfQoTptyB4eLj7/DCf/eta4ZVpjy7IHozsZGwNXbMus5ZWZoeGp8JrGceD17rAezC8tjEZTpwavKapwus5GpU8GneA7QLaoTnxvB9kuqbhH6ORc//jyrIVJGHALJH8FBO6wHOcgOi+ar2pY131ecB4mSP8A1K6zc0qsKK4jj+jItk+8fuHbnH6PR9OnNw91862+VmIEzoFMYp4wzdIApCAvDl/lmk1oZXiFfFhA6tPcsGigMwhbZIJMx+SU6sRfgIjQNG6btd1j6NzZhxH/QdSSzj7XDA2TlvStASCACVz7kQQHHPXBMSQex4R4lQ5SA8Leuf3GnuJ3V7Huc5kOB7XdBzTe4qOM62JquPcY6k478ySYfVLMphv3HfR0Gu4C45vxLEwInui48qJS0qOIq7TOjUp67qNGXfcBmR6lHU3OrLoxopFVxrhsrYzNBadfSxtZ45/Q4MOPiP6VDyKHX+vnsTOqrH5STF0K8naTMDmM/3TNDajENjRHPu/pkWY4gxyJW69JgRspQ5LjBKaSiN/5Q0VG5YxgMKrGO8E3Hb6jzy3qT87yGZQ8WD5Kq3YUktT1WE8BVe+gW34yVdImD4SaqTi2Sf5RBqpgbsPUe62yoRNzNob3a5GbmeYM1/KkGLqN1X4IF2AJT/0AQnaWaylwvgMozXk3r9GZfBzyZM3xE+3TihOf9k1zYazNCGDO+fenLpdxWmHhmlIvx3x9NQlhS88GhP6eAE+yz2H/B4iP2NVfvQe17hnAjTeI0AxjHH+gIv4SOJjGu7QNSbSryY+Tlv/s4usxx7hOUts5gDhMTUW0J5X61cUzDyLmjq+q6cDRE+AfoWzyolL2iylcMlaAuijlMfyRQ6dyXqnoSzZ3etqmfYUb8+Z6HSLxtvrQrfo8TYUqn2UoIg2w+y2VVznC983WiGSnKyWAaBQWviNkC2flpHAjZiWNiq8xzgQMmffLCW/hjdJfs6L4oWeYVEmow237IRX8sXf9IYdiZ+9k/h2NKlRU5c7O1rqbHRm0etZONJqbTQ4bq9kr5y5JHx8dQqgkLZn4b2KRev3la7RTgzJ08UxddJ1PKvZdhRUbldEvKNl3AiX6FGHijAlatStuygJTuCOR5I3KVTfW1ugg7Mu2k3VB5KlYtZl0OooMu2aaq2Bxg/Sln9Zx0NUTW7+kYnXBc5GOHWVQc7Z4XRUtXkHKGAt0whzGwUlJbTXxOc09umKcK36CBk9AM0MmC/6wEb/gJeQtVswwgIT9Iu1gRc98vacUOaNCqlWuWA0qXLwXWec9jCCpTCCZfAXMf70KZ4xCN4VtqanYtuFTlZrI3QVubpk4RFleF+4Hq6zhZbAdImT9P0lZ0dWXVLGGlE5ra8+UWj4oSu0SjeghcPQs6hWMXM1qlWJC+MzxmacNOJfAFOfoKWoXrW8iGu/GdOL3pwf/QclfrTK/XkYhmydTNmRCI7RBRzs1Hz99/0J4657oSlbP63zrtouC0r53p5rPq41ZVowArMhJgySab4ZqJ+rWAtBtdm5j2PkD17IS78i68IzkFLOsm6dFnH4UxinenhNBa0PEpxpquTrcTK0adqNQdFOkgdnUImOuh3A1gVdbI3YdJHn14vNuavIz5dOaEyn9dlEaZx4zUIBdMXNikxcirxBizzcbxTndF1F6jxNfc3RQp36OkLrw3oGjXWVfc7iNU5ckrrCj36vy5Q36eEyZbXYbvrh66J28qUjXRmhWHBPiJua5T5MIJqLPgJEmCed7RfdwJQeha46V/bkdJ20l4ffYBHf3QKvSYWcGgFbjQh9E4dlHIhuGfktD8ScmsksXQpaZJEgRrCkhpb374p/fkPw91VGv2vWwbSXz9XFInq0JHiNuMjsGZ29UPaArPuMUzIL8rI75wTEYnkK1BBvP+IbcpReDmIcaoa8ItbRQpVqQ8nHYzc1kzpdJZmuE7DmDGFcwD4UbJ12OTHYqnbvtW4JGZfBDSY/LzzWkse04fCT8pgml6+gB5Pgmn/ZisPAScgJ98oyaLuJfi86cRJ1XA1xirbX7bZTtsftYmNO6iNk7mt+U0V2ZRzTemGgzL1VBnrDjjs9pJYCaV6eEUrlGWG5bFzUx3tVH+7Zy9A1ZQQFxAFaF/D+s0A8/hggkBsiAfZXMRSbWw3BZqBeJhSKr9jlnJolQmOcCmMGL1cRIJlxk2avZBk4HEg1JwYvQhlKrCZNRTO7m2ygEEdMPLJULM0mvDMrdk9WG5rNyF+lVERSC1Hit6RYXAe0mniRsChTGGLsNKuEEm+bBWSz7kscIZ93p3ykshw1u5gXpQLxuPZvqCaeW986FaXn7A3ExJMQkxjk1qb4sxAaRcwVxcsIxlnUa8t0pUyizBINIeCkZK9/KyhQvViRaDUE4eoZWYqHalKW/cdMcNaIF8Xr36VzJRLBkGpUCOVx13ehPzTlhLrPyI1HQ0ezT66T74xpN2+oC9YDENLOcL+q9g8b/gIkc+He3K91n8Dp3zpx+pLRnY8/alaIsnawawNTi61azP2VwDXCIiN1Kf99AcvGDeK2JhyhrbY4Grhn2Qmzl7BtN4l1/NkO1QEwdqqenF37qzsPoOk9LzvJ375r4qS7x7UgnvmrV4OWiWHnFSaMuGv3GyutxLmxaElOF59T7l3jBbFvG0HQ5F7LHcfdq5Cmr8tIKoQhJMpbW37V5XzpJodZr/KiOenI+R65zHiWxrVqAOm+1jJxtIb0G5Zjdlp9mD3DuPr8vX3/fw== -------------------------------------------------------------------------------- /implement/applications/eve-online/eve-online-framework-test/tests/BotFrameworkTest.elm: -------------------------------------------------------------------------------- 1 | module BotFrameworkTest exposing (..) 2 | 3 | import EveOnline.BotFramework 4 | import EveOnline.BotFrameworkSeparatingMemory 5 | import Expect 6 | import Test 7 | 8 | 9 | bubbleSortCountingIterations_test : Test.Test 10 | bubbleSortCountingIterations_test = 11 | [ { input = [ 0, 1, 3 ] 12 | , expected = ( [ 0, 1, 3 ], 0 ) 13 | } 14 | , { input = [ 0, 3, 1 ] 15 | , expected = ( [ 0, 1, 3 ], 1 ) 16 | } 17 | , { input = [ 30, -10, -100 ] 18 | , expected = ( [ -100, -10, 30 ], 2 ) 19 | } 20 | , { input = [ 0, 1, 2, 4, 3, 5, 7, 6 ] 21 | , expected = ( [ 0, 1, 2, 3, 4, 5, 6, 7 ], 1 ) 22 | } 23 | , { input = [ 0, 1, 2, 4, 3, 7, 6, 5 ] 24 | , expected = ( [ 0, 1, 2, 3, 4, 5, 6, 7 ], 2 ) 25 | } 26 | ] 27 | |> List.indexedMap 28 | (\i testCase -> 29 | Test.test ("Scenario " ++ String.fromInt i) <| 30 | \_ -> 31 | let 32 | output = 33 | EveOnline.BotFrameworkSeparatingMemory.bubbleSortCountingIterations 34 | identity 35 | testCase.input 36 | in 37 | output 38 | |> Expect.equal testCase.expected 39 | ) 40 | |> Test.describe "bubble sort counting iterations" 41 | 42 | 43 | test_closestPointOnRectangleEdge : Test.Test 44 | test_closestPointOnRectangleEdge = 45 | [ { input = 46 | { rectangle = { left = 100, top = 10, right = 200, bottom = 30 } 47 | , point = { x = 0, y = 0 } 48 | } 49 | , expected = { x = 100, y = 10 } 50 | } 51 | , { input = 52 | { rectangle = { left = 100, top = 10, right = 200, bottom = 30 } 53 | , point = { x = 130, y = 13 } 54 | } 55 | , expected = { x = 130, y = 10 } 56 | } 57 | , { input = 58 | { rectangle = { left = 100, top = 10, right = 200, bottom = 30 } 59 | , point = { x = 135, y = 21 } 60 | } 61 | , expected = { x = 135, y = 30 } 62 | } 63 | , { input = 64 | { rectangle = { left = 100, top = 10, right = 200, bottom = 30 } 65 | , point = { x = 103, y = 21 } 66 | } 67 | , expected = { x = 100, y = 21 } 68 | } 69 | , { input = 70 | { rectangle = { left = 100, top = 10, right = 200, bottom = 30 } 71 | , point = { x = 198, y = 23 } 72 | } 73 | , expected = { x = 200, y = 23 } 74 | } 75 | ] 76 | |> List.indexedMap 77 | (\i testCase -> 78 | Test.test ("Scenario " ++ String.fromInt i) <| 79 | \_ -> 80 | let 81 | frameworkRect = 82 | { x = testCase.input.rectangle.left 83 | , y = testCase.input.rectangle.top 84 | , width = testCase.input.rectangle.right - testCase.input.rectangle.left 85 | , height = testCase.input.rectangle.bottom - testCase.input.rectangle.top 86 | } 87 | 88 | closestPoint = 89 | EveOnline.BotFramework.closestPointOnRectangleEdge frameworkRect testCase.input.point 90 | in 91 | closestPoint 92 | |> Expect.equal testCase.expected 93 | ) 94 | |> Test.describe "closest point on rectangle edge" 95 | -------------------------------------------------------------------------------- /implement/templates/display-session-length-limit/Bot.elm: -------------------------------------------------------------------------------- 1 | {- This program demonstrates how to use the session time limit. 2 | 3 | Some bots should consider the remaining time in the current session when choosing the next activity. 4 | This program gets and stores the session length limit set in the configuration interface. 5 | It also computes the remaining time as the difference between the present time and the configured limit and displays the result via the status text. 6 | -} 7 | {- 8 | catalog-tags:template,demo-interface-to-host 9 | authors-forum-usernames:viir 10 | -} 11 | 12 | 13 | module Bot exposing 14 | ( State 15 | , botMain 16 | ) 17 | 18 | import BotLab.BotInterface_To_Host_2023_05_15 as InterfaceToHost 19 | 20 | 21 | type alias State = 22 | { timeInMilliseconds : Int 23 | , lastSessionLengthLimitInMilliseconds : Maybe Int 24 | } 25 | 26 | 27 | botMain : InterfaceToHost.BotConfig State 28 | botMain = 29 | { init = { timeInMilliseconds = 0, lastSessionLengthLimitInMilliseconds = Nothing } 30 | , processEvent = processEvent 31 | } 32 | 33 | 34 | processEvent : InterfaceToHost.BotEvent -> State -> ( State, InterfaceToHost.BotEventResponse ) 35 | processEvent event stateBefore = 36 | let 37 | state = 38 | stateBefore |> integrateEvent event 39 | in 40 | ( state 41 | , InterfaceToHost.ContinueSession 42 | { statusText = state |> statusTextFromState 43 | , startTasks = [] 44 | , notifyWhenArrivedAtTime = Just { timeInMilliseconds = state.timeInMilliseconds + 1000 } 45 | } 46 | ) 47 | 48 | 49 | integrateEvent : InterfaceToHost.BotEvent -> State -> State 50 | integrateEvent event stateBeforeUpdateTime = 51 | let 52 | stateBefore = 53 | { stateBeforeUpdateTime | timeInMilliseconds = event.timeInMilliseconds } 54 | in 55 | case event.eventAtTime of 56 | InterfaceToHost.TimeArrivedEvent -> 57 | stateBefore 58 | 59 | InterfaceToHost.BotSettingsChangedEvent _ -> 60 | stateBefore 61 | 62 | InterfaceToHost.TaskCompletedEvent _ -> 63 | stateBefore 64 | 65 | InterfaceToHost.SessionDurationPlannedEvent { timeInMilliseconds } -> 66 | { stateBefore | lastSessionLengthLimitInMilliseconds = Just timeInMilliseconds } 67 | 68 | 69 | statusTextFromState : State -> String 70 | statusTextFromState state = 71 | case state.lastSessionLengthLimitInMilliseconds of 72 | Nothing -> 73 | "I did not yet receive information about a session length limit." 74 | 75 | Just lastSessionLengthLimitInMilliseconds -> 76 | let 77 | remainingTotalSeconds = 78 | (lastSessionLengthLimitInMilliseconds - state.timeInMilliseconds) // 1000 79 | in 80 | "The session length was set to " 81 | ++ describeTimespanAsMinutesPlusSeconds { lengthInSeconds = lastSessionLengthLimitInMilliseconds // 1000 } 82 | ++ ".\nRemaining are " 83 | ++ describeTimespanAsMinutesPlusSeconds { lengthInSeconds = remainingTotalSeconds } 84 | ++ "." 85 | 86 | 87 | describeTimespanAsMinutesPlusSeconds : { lengthInSeconds : Int } -> String 88 | describeTimespanAsMinutesPlusSeconds { lengthInSeconds } = 89 | let 90 | totalMinutes = 91 | lengthInSeconds // 60 92 | 93 | secondsInMinute = 94 | lengthInSeconds - totalMinutes * 60 95 | in 96 | (totalMinutes |> String.fromInt) 97 | ++ " minutes and " 98 | ++ (secondsInMinute |> String.fromInt) 99 | ++ " seconds" 100 | -------------------------------------------------------------------------------- /implement/applications/eve-online/eve-online-mining-bot/EveOnline/MemoryReading.elm: -------------------------------------------------------------------------------- 1 | module EveOnline.MemoryReading exposing (..) 2 | 3 | {-| This module contains: 4 | 5 | - Types to represent memory readings from the Sanderling project. 6 | - Decoders for the popular JSON representation of Sanderling memory readings. 7 | 8 | To learn more about Sanderling, see 9 | 10 | -} 11 | 12 | import Dict 13 | import Json.Decode 14 | import Json.Encode 15 | 16 | 17 | type alias UITreeNode = 18 | { originalJson : Json.Encode.Value 19 | , pythonObjectAddress : String 20 | , pythonObjectTypeName : String 21 | , dictEntriesOfInterest : Dict.Dict String Json.Encode.Value 22 | , children : Maybe (List UITreeNodeChild) 23 | } 24 | 25 | 26 | type UITreeNodeChild 27 | = UITreeNodeChild UITreeNode 28 | 29 | 30 | unwrapUITreeNodeChild : UITreeNodeChild -> UITreeNode 31 | unwrapUITreeNodeChild child = 32 | case child of 33 | UITreeNodeChild node -> 34 | node 35 | 36 | 37 | countDescendantsInUITreeNode : UITreeNode -> Int 38 | countDescendantsInUITreeNode parent = 39 | parent.children 40 | |> Maybe.withDefault [] 41 | |> List.map unwrapUITreeNodeChild 42 | |> List.map (countDescendantsInUITreeNode >> (+) 1) 43 | |> List.sum 44 | 45 | 46 | listDescendantsInUITreeNode : UITreeNode -> List UITreeNode 47 | listDescendantsInUITreeNode parent = 48 | parent.children 49 | |> Maybe.withDefault [] 50 | |> List.map unwrapUITreeNodeChild 51 | |> List.concatMap (\child -> child :: listDescendantsInUITreeNode child) 52 | 53 | 54 | decodeMemoryReadingFromString : String -> Result Json.Decode.Error UITreeNode 55 | decodeMemoryReadingFromString = 56 | Json.Decode.decodeString uiTreeNodeDecoder 57 | 58 | 59 | uiTreeNodeDecoder : Json.Decode.Decoder UITreeNode 60 | uiTreeNodeDecoder = 61 | Json.Decode.map5 62 | (\originalJson pythonObjectAddress pythonObjectTypeName dictEntriesOfInterest children -> 63 | { originalJson = originalJson 64 | , pythonObjectAddress = pythonObjectAddress 65 | , pythonObjectTypeName = pythonObjectTypeName 66 | , dictEntriesOfInterest = dictEntriesOfInterest |> Dict.fromList 67 | , children = children |> Maybe.map (List.map UITreeNodeChild) 68 | } 69 | ) 70 | Json.Decode.value 71 | (Json.Decode.field "pythonObjectAddress" Json.Decode.string) 72 | (decodeOptionalField "pythonObjectTypeName" Json.Decode.string |> Json.Decode.map (Maybe.withDefault "")) 73 | (Json.Decode.field "dictEntriesOfInterest" (Json.Decode.keyValuePairs Json.Decode.value)) 74 | (decodeOptionalOrNullField "children" (Json.Decode.list (Json.Decode.lazy (\_ -> uiTreeNodeDecoder)))) 75 | 76 | 77 | decodeOptionalOrNullField : String -> Json.Decode.Decoder a -> Json.Decode.Decoder (Maybe a) 78 | decodeOptionalOrNullField fieldName decoder = 79 | decodeOptionalField fieldName (Json.Decode.nullable decoder) 80 | |> Json.Decode.map (Maybe.andThen identity) 81 | 82 | 83 | decodeOptionalField : String -> Json.Decode.Decoder a -> Json.Decode.Decoder (Maybe a) 84 | decodeOptionalField fieldName decoder = 85 | let 86 | finishDecoding json = 87 | case Json.Decode.decodeValue (Json.Decode.field fieldName Json.Decode.value) json of 88 | Ok _ -> 89 | -- The field is present, so run the decoder on it. 90 | Json.Decode.map Just (Json.Decode.field fieldName decoder) 91 | 92 | Err _ -> 93 | -- The field was missing, which is fine! 94 | Json.Decode.succeed Nothing 95 | in 96 | Json.Decode.value 97 | |> Json.Decode.andThen finishDecoding 98 | -------------------------------------------------------------------------------- /implement/applications/eve-online/eve-online-combat-anomaly-bot/EveOnline/MemoryReading.elm: -------------------------------------------------------------------------------- 1 | module EveOnline.MemoryReading exposing (..) 2 | 3 | {-| This module contains: 4 | 5 | - Types to represent memory readings from the Sanderling project. 6 | - Decoders for the popular JSON representation of Sanderling memory readings. 7 | 8 | To learn more about Sanderling, see 9 | 10 | -} 11 | 12 | import Dict 13 | import Json.Decode 14 | import Json.Encode 15 | 16 | 17 | type alias UITreeNode = 18 | { originalJson : Json.Encode.Value 19 | , pythonObjectAddress : String 20 | , pythonObjectTypeName : String 21 | , dictEntriesOfInterest : Dict.Dict String Json.Encode.Value 22 | , children : Maybe (List UITreeNodeChild) 23 | } 24 | 25 | 26 | type UITreeNodeChild 27 | = UITreeNodeChild UITreeNode 28 | 29 | 30 | unwrapUITreeNodeChild : UITreeNodeChild -> UITreeNode 31 | unwrapUITreeNodeChild child = 32 | case child of 33 | UITreeNodeChild node -> 34 | node 35 | 36 | 37 | countDescendantsInUITreeNode : UITreeNode -> Int 38 | countDescendantsInUITreeNode parent = 39 | parent.children 40 | |> Maybe.withDefault [] 41 | |> List.map unwrapUITreeNodeChild 42 | |> List.map (countDescendantsInUITreeNode >> (+) 1) 43 | |> List.sum 44 | 45 | 46 | listDescendantsInUITreeNode : UITreeNode -> List UITreeNode 47 | listDescendantsInUITreeNode parent = 48 | parent.children 49 | |> Maybe.withDefault [] 50 | |> List.map unwrapUITreeNodeChild 51 | |> List.concatMap (\child -> child :: listDescendantsInUITreeNode child) 52 | 53 | 54 | decodeMemoryReadingFromString : String -> Result Json.Decode.Error UITreeNode 55 | decodeMemoryReadingFromString = 56 | Json.Decode.decodeString uiTreeNodeDecoder 57 | 58 | 59 | uiTreeNodeDecoder : Json.Decode.Decoder UITreeNode 60 | uiTreeNodeDecoder = 61 | Json.Decode.map5 62 | (\originalJson pythonObjectAddress pythonObjectTypeName dictEntriesOfInterest children -> 63 | { originalJson = originalJson 64 | , pythonObjectAddress = pythonObjectAddress 65 | , pythonObjectTypeName = pythonObjectTypeName 66 | , dictEntriesOfInterest = dictEntriesOfInterest |> Dict.fromList 67 | , children = children |> Maybe.map (List.map UITreeNodeChild) 68 | } 69 | ) 70 | Json.Decode.value 71 | (Json.Decode.field "pythonObjectAddress" Json.Decode.string) 72 | (decodeOptionalField "pythonObjectTypeName" Json.Decode.string |> Json.Decode.map (Maybe.withDefault "")) 73 | (Json.Decode.field "dictEntriesOfInterest" (Json.Decode.keyValuePairs Json.Decode.value)) 74 | (decodeOptionalOrNullField "children" (Json.Decode.list (Json.Decode.lazy (\_ -> uiTreeNodeDecoder)))) 75 | 76 | 77 | decodeOptionalOrNullField : String -> Json.Decode.Decoder a -> Json.Decode.Decoder (Maybe a) 78 | decodeOptionalOrNullField fieldName decoder = 79 | decodeOptionalField fieldName (Json.Decode.nullable decoder) 80 | |> Json.Decode.map (Maybe.andThen identity) 81 | 82 | 83 | decodeOptionalField : String -> Json.Decode.Decoder a -> Json.Decode.Decoder (Maybe a) 84 | decodeOptionalField fieldName decoder = 85 | let 86 | finishDecoding json = 87 | case Json.Decode.decodeValue (Json.Decode.field fieldName Json.Decode.value) json of 88 | Ok _ -> 89 | -- The field is present, so run the decoder on it. 90 | Json.Decode.map Just (Json.Decode.field fieldName decoder) 91 | 92 | Err _ -> 93 | -- The field was missing, which is fine! 94 | Json.Decode.succeed Nothing 95 | in 96 | Json.Decode.value 97 | |> Json.Decode.andThen finishDecoding 98 | -------------------------------------------------------------------------------- /implement/applications/eve-online/eve-online-warp-to-0-autopilot/EveOnline/MemoryReading.elm: -------------------------------------------------------------------------------- 1 | module EveOnline.MemoryReading exposing (..) 2 | 3 | {-| This module contains: 4 | 5 | - Types to represent memory readings from the Sanderling project. 6 | - Decoders for the popular JSON representation of Sanderling memory readings. 7 | 8 | To learn more about Sanderling, see 9 | 10 | -} 11 | 12 | import Dict 13 | import Json.Decode 14 | import Json.Encode 15 | 16 | 17 | type alias UITreeNode = 18 | { originalJson : Json.Encode.Value 19 | , pythonObjectAddress : String 20 | , pythonObjectTypeName : String 21 | , dictEntriesOfInterest : Dict.Dict String Json.Encode.Value 22 | , children : Maybe (List UITreeNodeChild) 23 | } 24 | 25 | 26 | type UITreeNodeChild 27 | = UITreeNodeChild UITreeNode 28 | 29 | 30 | unwrapUITreeNodeChild : UITreeNodeChild -> UITreeNode 31 | unwrapUITreeNodeChild child = 32 | case child of 33 | UITreeNodeChild node -> 34 | node 35 | 36 | 37 | countDescendantsInUITreeNode : UITreeNode -> Int 38 | countDescendantsInUITreeNode parent = 39 | parent.children 40 | |> Maybe.withDefault [] 41 | |> List.map unwrapUITreeNodeChild 42 | |> List.map (countDescendantsInUITreeNode >> (+) 1) 43 | |> List.sum 44 | 45 | 46 | listDescendantsInUITreeNode : UITreeNode -> List UITreeNode 47 | listDescendantsInUITreeNode parent = 48 | parent.children 49 | |> Maybe.withDefault [] 50 | |> List.map unwrapUITreeNodeChild 51 | |> List.concatMap (\child -> child :: listDescendantsInUITreeNode child) 52 | 53 | 54 | decodeMemoryReadingFromString : String -> Result Json.Decode.Error UITreeNode 55 | decodeMemoryReadingFromString = 56 | Json.Decode.decodeString uiTreeNodeDecoder 57 | 58 | 59 | uiTreeNodeDecoder : Json.Decode.Decoder UITreeNode 60 | uiTreeNodeDecoder = 61 | Json.Decode.map5 62 | (\originalJson pythonObjectAddress pythonObjectTypeName dictEntriesOfInterest children -> 63 | { originalJson = originalJson 64 | , pythonObjectAddress = pythonObjectAddress 65 | , pythonObjectTypeName = pythonObjectTypeName 66 | , dictEntriesOfInterest = dictEntriesOfInterest |> Dict.fromList 67 | , children = children |> Maybe.map (List.map UITreeNodeChild) 68 | } 69 | ) 70 | Json.Decode.value 71 | (Json.Decode.field "pythonObjectAddress" Json.Decode.string) 72 | (decodeOptionalField "pythonObjectTypeName" Json.Decode.string |> Json.Decode.map (Maybe.withDefault "")) 73 | (Json.Decode.field "dictEntriesOfInterest" (Json.Decode.keyValuePairs Json.Decode.value)) 74 | (decodeOptionalOrNullField "children" (Json.Decode.list (Json.Decode.lazy (\_ -> uiTreeNodeDecoder)))) 75 | 76 | 77 | decodeOptionalOrNullField : String -> Json.Decode.Decoder a -> Json.Decode.Decoder (Maybe a) 78 | decodeOptionalOrNullField fieldName decoder = 79 | decodeOptionalField fieldName (Json.Decode.nullable decoder) 80 | |> Json.Decode.map (Maybe.andThen identity) 81 | 82 | 83 | decodeOptionalField : String -> Json.Decode.Decoder a -> Json.Decode.Decoder (Maybe a) 84 | decodeOptionalField fieldName decoder = 85 | let 86 | finishDecoding json = 87 | case Json.Decode.decodeValue (Json.Decode.field fieldName Json.Decode.value) json of 88 | Ok _ -> 89 | -- The field is present, so run the decoder on it. 90 | Json.Decode.map Just (Json.Decode.field fieldName decoder) 91 | 92 | Err _ -> 93 | -- The field was missing, which is fine! 94 | Json.Decode.succeed Nothing 95 | in 96 | Json.Decode.value 97 | |> Json.Decode.andThen finishDecoding 98 | -------------------------------------------------------------------------------- /implement/applications/elvenar/elvenar-bot-elm-test/tests/Sample_2023_04_26.elm: -------------------------------------------------------------------------------- 1 | module Sample_2023_04_26 exposing (..) 2 | 3 | import BotLab.SimpleBotFramework exposing (Location2d) 4 | 5 | 6 | type alias ScenarioSinglePatternOnSampleImage = 7 | { imageFileBase64 : String 8 | , instanceLocations : List Location2d 9 | } 10 | 11 | 12 | {-| Instances of the coin from training sample 13 | -} 14 | sample_2023_04_26_coins : List ScenarioSinglePatternOnSampleImage 15 | sample_2023_04_26_coins = 16 | [ { imageFileBase64 = """Qk1mCQAAAAAAADYAAAAoAAAAHAAAABwAAAABABgAAAAAAAAAAADEDgAAxA4AAAAAAAAAAAAAMEyAN0WONkSKLzdsIzBbKDVfJTVWHkpuIVJxI1NyRGmES2+JXYCWZ4qaZ4qcZ4qdWXqQTHKOSnOWP3qSKGyVImiTKWyZI2KSHEt2GkJzGEiEGVKaN05iNUSINUaIM0J+IDNbIDVVKElsLF57RXeQcJqwk7LAh6i3h6m3dZimdZimk7W/h6m2h6m2mb3NgKy8V4+mN3qZMG6OKlx3I0hiJT5TKU9zJlSOJjFCLTptMUN8MEh/KUh1HkVgKWeCS3+Wk7zOXpOlLFBtHkRiHEBfGT5eGT5eI0dmHDlYIkBeL05pUoiVp8rWgqu3PX2MO3SFPW+OMFRvPWqOToq1Gig/JzhmL0J4Lkx5KlJ+PGeCVX2So9DhWnuYEilQFSZXFy1dGDFgHEuEHEuEH1SLGlGBE0V4EUN1Cy5fIUVzgqvPocTVZImlSm+QNmuLPnycYKzUITBGHTRRIDtgJk5vQ2qIYIiZvdTdRWWEIjtgRGODOpG2QKTHRK7PO5nCJ2WZLXamPouzLGuYEUN1JEd2JUh3AiRWS3CJmr7OhKrEQXmUPHmWQoOkITBGGjdRFztTIVBmR3GDoL3IPHGAHzddeJ+3n87gTsrqTsvqTszqPZ3HN4u3O5fAMnagU6rNX7rcIkV0Cy5fLVF/FTpZKU1rv+LuaJu0O3CIPXKQGzJHFzlVIktgJlJgc5arhKW6HDBRScXuUcjuKrjqM7ffNbviMbDaLo3MScDoQLDfMYm+O6jVRcLqVNXlKXKWCi1eKVuNFDVkLGGTmsHUVX2ZRnCREi0/FjVII0tdNWt7k7jLN05tfJuye9r1Nb3rKbjqNb3jOcnrH324IXO9P6/eTs7vM4/DO6jVPazZR7bMWeHvKG6UEC1cJVWFCyJQZo2jdpyzWIGeGzdHIEJTM2V2RYmag6O4MUhnrNboZ9HyW83xRsTuN8ToIoS8GWirKYLFI3a+InS9KnSuPKrYRMHpQqzERbPJWuLvLWSWDilYG0FxIUdkjLPGcZqyI0VXIVNtN2t/dKa6aJ+/RHadktLofMjrfsrrW6LJJmGaI1SPLHmxIoPHIoPHI4XIKIG+JHu6YtDtYNfyTrrhT7jgT7LfHUV0HkR0ETReaoCYsr/IGDpUMGB4QIaurdjiO2uWKlWEU4erL3CfLm+eS5G6KW2mMJHINKHXIH/EIH7EI4XIIHe3IHa3MIzFQ6jWRKnXM4zGSaTSSKTSH0Z3ETNeKkduydPXEzpeOYO3Q5HAyenxDzZsKlWEY5q6S5G6SpC5PYGtNqziN7DmN6vfQbzlQbzmQb7qNZLJFWauSa/aKXy7HWmwGWGrM3WjNXqnNnyoETNdETNdZ36WNnCiN47MOYevxu/3KkVvRIOpYcXqTbnnQqPTKHOnRKDbZL3iYbviac3pS8PmQMPpU83sM4axKnOiKonEK4zFTMTlQcftJH24KYi/JUltChk+PHSWLlBrNm2TSpG6x+/5NFqDTZi9R4uwNIq7QKDPGleOK4nRcsroc8vobtDrbs/rYMvqT8DhT8HiGlCHLY7HLY/GXuT2PbzkJH64MJrNM2GDDB5EJEhsK0diNllySXqPuN/qN2OLUJ7DX77gJGufNIm6KHSnJIPOWLPghNrtldntgdTsZM7rVdDtU8zrK3WkKYnDKIfBJIC9H3KwG2anK4/EJktuCxpAHDhcK0ReMFdzQHeQnMHRV4CXa5qultfibs3oM3i0J2WoHmSbYMTmUrHXW8vrluD1gdnzadDsU7TcN5LLMobAM4jBD0yaI5DEN7LhOLTjMURrChxOS2CAK0ReLU1pP3WOZanAbp+yOld0lNXgc9XtVqrTQIvAG1+YRZ/JbNXyML/oPsTseNjzbtfvWr7iKX6/R6fWNIjBN5DGQMDqOrjlRcjwMURrChxOe5OlJD9aK0tmO2qCQ36XgLrINk5ta5uve+H1VqrUJ2aoM4W1I2yiUbHXYs3sLr7oKr7qWbveN4/IMorGVb3lO5TKX87vRsvzQ8TuR872ECNSKDxmqsXJKz5VJj5ZPGF2QHOLgau3cpuoGiU3bcrpXrPUL1+IKF+VJluRMHKlKojJLpvhL5zjP5/mM4vNQKHmSpG8MXGmiNfzctTpdtrwSpe1ESRGbYeavN3jPE5eQVppUHJ8V4OOgKatmMvUSWR0Ll2GUpy/QH+kPJK+MXSmKmSYH2ObImymJHazKXi3ImuoFFKLGVaSKGieidfzc9bracffF0dyJjpZn73HYXiMT15nUWhxW3Z8W32EeJqgg6uzlMbPNmuTFDJeb8/tVc7zSbHaM3ysHV6WGk2BGk+EEk+IHWGbLH6+KWifLm6jidjzc9bsSJSyAylWS2J8iqSyUWiAS1lfTWNpUXF3V3uBZpScY5qlY6Sxi77MOVNxM0hoW5+3Zq/GQXOOUY+wWa7NWa7NOGycPnqnY8/zR7vvNYq8N47AdqC1HzZUJDxas83XWZGmNGR9U2htUmhtV3R6Xn2EaIqSY5CYbaSukr3FjL3MVHiSHzdXOWaCcMPYZt/4Zt/5Ztz2Y87vUaXOVa7VRrrtO57SJF+QLEVkX4aclcbWaKK2PXiSJ0hiU2htVmxyYXh+Y36GWXl/YIGGXouVaZGafaq1jsPQa7nPPGuGGC5NQ1+FTX+iWa3MV7TbVrDXRYu3JGKTFjxsES9di7rLfaa4dJuvQnaRLFJrIT1XUGVtU2hwWm52W3J6YnqCXXqDY4SNTXmJXpGfWpaoaKy+s9Ldu97pWn2WN1NzK0VmHDRfHDNfHDNfPnGGYZOitd7ld6i6PXuVNGWGJ0ZhHzhSHjhcWW51W3B3bH6EcoWKan2EW3R+XnuEOllsUHmJVIaXV5KkV5mraqq8jrbAmcLLiK+9g6m6f6a6gKi9iK66jbK/VnmSOnCFMV97KVBzHTdLGDBIFzRcgZaWfI+SeouRcoWKbH+FVmt1QFhoMkxgPF9xRm1/R3WHSn6RTIOWX36Na4qWbYyYcpSkaY2lYISrVHB/SmZ9R2iHJkZdJENgJkdrEyo/EyQ7GTFchZieg5aaeI2Od4yNdoqNdYWNiZeaT2l5boeRco6WcI6ZaIqaZYuaTXuNRXeJS36QO2qBPW2HU4mfNV93KlJsKUxuGzRDIDlQGTdWGSxCGSY5GStK""" 17 | , instanceLocations = [ { x = 15, y = 14 } ] 18 | } 19 | ] 20 | -------------------------------------------------------------------------------- /guide/botlab-online-session.md: -------------------------------------------------------------------------------- 1 | # BotLab Online Session 2 | 3 | When starting a play session with a bot, you can choose to start an online session. Online sessions provide several advantages over offline sessions: 4 | 5 | + Monitoring from other devices: No need to go to your PC to check the status of your bot. You can use your smartphone or any other device with a web browser to see the status of your bot. 6 | + Organize and keep track of your operations and experiments: Easily see which bots you already tested and when you used them the last time. 7 | + Longer running time: Run a bot continuously in one session for up to 72 hours. 8 | 9 | To see a list of your most recent online sessions, log in at 10 | 11 | Below is a screenshot of the website to view your online sessions and monitor your bots: 12 | ![viewing details of an online play session with a bot](./image/2021-11-30-botlab-reactor-online-session-detail.png) 13 | 14 | Online sessions cost 2000 credits per hour. When you log in to your account for the first time, you automatically get 1000 credits. Using these initial credits balance, you can test the online session feature without paying anything (Creating an account is free). 15 | When you have used up the credits on your account, you can add more following the instructions at 16 | 17 | For more about purchasing and using credits, see the guide at 18 | 19 | ### Starting an Online Session 20 | 21 | Follow these steps to start a bot in an online session: 22 | 23 | + Load a bot in the BotLab client to get to the 'Configure Session' view. 24 | + Scroll down to the 'Online Session' section. 25 | + Click on the checkbox at 'Connect to the BotLab Reactor and start an online session'. 26 | + Continue with other configurations (bot settings, pause keys) as usual, and start the play session. 27 | 28 | ![configure session to start online session](./image/2022-12-02-botlab-client-configure-session-online-session-marked.png) 29 | 30 | The first time you start an online session, the client will ask you to enter your online session key from your Reactor account: 31 | 32 | ![botlab client prompt for online session key](./image/2022-12-02-botlab-client-confirm-online-session.png) 33 | 34 | Here you need to enter your online session key to continue. 35 | 36 | To get the key to enter here, go to and log in to your account. After logging in, you see a section titled `Online play session keys`. In this section, there is an entry for a key, containing a button labeled `Show key`. Clicking this button reveals your key. Please don't share this key with anyone, and don't post it on the forum. 37 | 38 | ![Web UI displaying online session key](./image/2021-11-30-botlab-reactor-show-online-session-key.png) 39 | 40 | Copy the key from the web page and paste it into the botlab console window. Press the enter key to complete the input. BotLab then checks the key and continues to start the bot in an online session. 41 | 42 | The BotLab client also stores the entered key in the Windows user account, so you don't have to enter it the next time you start an online session. 43 | 44 | After starting an online session, you can also see it at under `Most recent play sessions`: 45 | 46 | ![List of most recent online sessions](./image/2021-11-30-botlab-reactor-dashboard-recent-sessions.png) 47 | 48 | 49 | Clicking on the session ID brings you to the details view of the session, where you can also see the status reported by the bot. 50 | 51 | The sessions under `Most recent play sessions` are still available after stopping the BotLab client, so you can continue to view details of past sessions. 52 | 53 | ## Getting Help 54 | 55 | If you have any questions, the [BotLab forum](https://forum.botlab.org) is a good place to learn more. 56 | -------------------------------------------------------------------------------- /guide/running-bots-on-multiple-game-clients.md: -------------------------------------------------------------------------------- 1 | # Running Bots on Multiple Game Clients 2 | 3 | Do you want to use a bot with multiple game clients? There is no general limit to the number of game clients; supporting multiple clients depends on your bot's programming. 4 | Many bots support multiple clients, but it is not always obvious how to set this up if you use a bot made by somebody else. However, many bots follow the same approach to multi-client support, so you can check if it also applies to the bot you are using. 5 | 6 | Most bots use a variant of multi-client support with these traits: 7 | 8 | + One bot instance per game client instance. 9 | + Select the game client window on startup. 10 | + Default to select the topmost game client window. 11 | 12 | These bullet points need some further explanation. Let's see what they mean in detail. 13 | 14 | ### One Bot Instance per Game Client Instance 15 | 16 | You start a new instance of the bot for each game client you want to use. This approach has several implications. For example, it means that you can use different bots for each game client, and you can start, pause, and stop them at different times. It also means you can see the performance metrics for each instance individually. 17 | 18 | ### Select the Game Client Window on Startup 19 | 20 | When the bot starts, it expects an instance of the game client already present. The bot selects a window to work on only at startup. It remembers the window's ID and keeps working on the same window for the rest of the session. Note that the bots need some time to startup and complete the window selection. When the bot reports what it sees in the game client or sends input, you know it has completed the window selection. 21 | 22 | ### Default to Select the Topmost Game Client Window 23 | 24 | There are many windows open on the desktop, and there can be multiple instances of the game client. The default way to select the right one allows for using multiple game clients without any configuration. The bot uses a property of the window called 'Z-index' to sort them. The Z-index is tracked by the operating system and establishes an ordering of the windows, based on how far they are from the window with input focus, also called the 'topmost' window. 25 | When you select a window for [input focus](https://en.wikipedia.org/wiki/Focus_(computing)), it becomes the topmost window and has the highest priority for the bot's selection. Focusing a window can be as simple as clicking on it. There are also keyboard commands to switch between windows, such as `Alt` + `Tab` in Microsoft Windows. 26 | 27 | Some bots offer optional settings to limit the selection of the game client window. For example, some bots for the game EVE Online offer a setting to pick a pilot name. Such options reduce the dependency on maintaining the window order on startup. 28 | 29 | ## Process to Start Bots on Multiple Game Clients 30 | 31 | When using a bot that follows the three choices above, this is the process to start your bots: 32 | 33 | + Focus the game client window to be used with bot instance A. 34 | + Start bot instance A and wait until the bot has selected the window. 35 | + Pause bot instance A. 36 | + Focus the game client window to be used with bot instance B. 37 | + Start bot instance B and wait until the bot has selected the window. 38 | + Unpause bot instance A. 39 | 40 | The order in which you started the game clients is not relevant. It also does not matter if you had a different bot running on a game client window. 41 | 42 | ## Avoiding Interference Through Input Focus Scheduling 43 | 44 | When you run multiple bot instances in parallel, you might want to use input focus scheduling to prevent them from interfering with each other's inputs. The BotLab client comes with built-in support for input focus scheduling. To make sure this feature is enabled for your bot instances, see the guide at https://to.botlab.org/guide/input-focus-scheduling-for-multiple-bot-instances 45 | -------------------------------------------------------------------------------- /explore/2019-09-15.eve-online-memory-reading/implement/eve-online-memory-reading/PyDict.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | 4 | namespace eve_online_memory_reading 5 | { 6 | public class PyDictEntry 7 | { 8 | readonly public Int64 BaseAddress; 9 | 10 | readonly public UInt32? me_hash; 11 | 12 | readonly public UInt32? me_key; 13 | 14 | readonly public UInt32? me_value; 15 | 16 | readonly public PyStr KeyAsStr; 17 | 18 | public string KeyStr 19 | { 20 | get 21 | { 22 | var KeyAsStr = this.KeyAsStr; 23 | 24 | if (null == KeyAsStr) 25 | { 26 | return null; 27 | } 28 | 29 | return KeyAsStr.String; 30 | } 31 | } 32 | 33 | public PyDictEntry( 34 | Int64 BaseAddress, 35 | IMemoryReader MemoryReader) 36 | { 37 | this.BaseAddress = BaseAddress; 38 | 39 | var Array = MemoryReader.ReadArray(BaseAddress, 12); 40 | 41 | if (null == Array) 42 | { 43 | return; 44 | } 45 | 46 | if (0 < Array.Length) 47 | { 48 | me_hash = Array[0]; 49 | } 50 | if (1 < Array.Length) 51 | { 52 | me_key = Array[1]; 53 | 54 | KeyAsStr = new PyStr(me_key.Value, MemoryReader); 55 | } 56 | 57 | if (2 < Array.Length) 58 | { 59 | me_value = Array[2]; 60 | } 61 | } 62 | } 63 | 64 | /// 65 | /// Offsets from https://github.com/python/cpython/blob/2.7/Include/dictobject.h and https://github.com/python/cpython/blob/2.7/Objects/dictobject.c 66 | /// 67 | public class PyDict : PyObject 68 | { 69 | public const int Offset_ma_fill = 8; 70 | public const int Offset_ma_used = 12; 71 | public const int Offset_ma_mask = 16; 72 | public const int Offset_ma_table = 20; 73 | 74 | readonly public UInt32? ma_fill; 75 | 76 | readonly public UInt32? ma_used; 77 | 78 | readonly public UInt32? ma_mask; 79 | 80 | readonly public UInt32? ma_table; 81 | 82 | readonly public UInt32? SlotsCount; 83 | 84 | readonly public PyDictEntry[] Slots; 85 | 86 | public PyDict( 87 | Int64 BaseAddress, 88 | IMemoryReader MemoryReader, 89 | int? SlotsCountMax = null) 90 | : 91 | base(BaseAddress, MemoryReader) 92 | { 93 | ma_fill = MemoryReader.ReadUInt32(BaseAddress + Offset_ma_fill); 94 | ma_used = MemoryReader.ReadUInt32(BaseAddress + Offset_ma_used); 95 | ma_mask = MemoryReader.ReadUInt32(BaseAddress + Offset_ma_mask); 96 | ma_table = MemoryReader.ReadUInt32(BaseAddress + Offset_ma_table); 97 | 98 | SlotsCount = ma_mask + 1; 99 | 100 | if (ma_table.HasValue && SlotsCount.HasValue) 101 | { 102 | var SlotsToReadCount = (int)Math.Min(SlotsCountMax ?? int.MaxValue, SlotsCount.Value); 103 | 104 | Slots = 105 | Enumerable.Range(0, SlotsToReadCount) 106 | .Select((SlotIndex) => new PyDictEntry(ma_table.Value + SlotIndex * 12, MemoryReader)) 107 | .ToArray(); 108 | } 109 | } 110 | 111 | public PyDictEntry EntryForKeyStr(string KeyStr) 112 | { 113 | var Slots = this.Slots; 114 | 115 | if (null == Slots) 116 | { 117 | return null; 118 | } 119 | 120 | foreach (var Slot in Slots) 121 | { 122 | if (null == Slot) 123 | { 124 | continue; 125 | } 126 | 127 | if (string.Equals(Slot.KeyStr, KeyStr)) 128 | { 129 | return Slot; 130 | } 131 | } 132 | 133 | return null; 134 | } 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /explore/2020-05-20-explore-tribal-wars-2/2020-05-20-battle-report-with-casualties.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 1137257, 3 | "time_created": 1589744135, 4 | "title": "Segundo pueblo de John ataca (ESTRELLA DEL NORTE )", 5 | "favourite": 0, 6 | "haul": "partial", 7 | "result": 2, 8 | "token": "1137257.229172.714e8dfb9617327f1", 9 | "type": "ReportAttack", 10 | "ReportAttack": { 11 | "outcome": 17, 12 | "attUnits": { 13 | "spear": 12, 14 | "sword": 0, 15 | "axe": 0, 16 | "archer": 0, 17 | "light_cavalry": 0, 18 | "heavy_cavalry": 0, 19 | "mounted_archer": 0, 20 | "ram": 0, 21 | "catapult": 0, 22 | "knight": 0, 23 | "snob": 0, 24 | "trebuchet": 0, 25 | "doppelsoldner": 0 26 | }, 27 | "attLosses": { 28 | "spear": 4, 29 | "sword": 0, 30 | "axe": 0, 31 | "archer": 0, 32 | "light_cavalry": 0, 33 | "heavy_cavalry": 0, 34 | "mounted_archer": 0, 35 | "ram": 0, 36 | "catapult": 0, 37 | "knight": 0, 38 | "snob": 0, 39 | "trebuchet": 0, 40 | "doppelsoldner": 0 41 | }, 42 | "attRevived": [], 43 | "attFaith": 0.5, 44 | "attModifier": 0.5650000000000001, 45 | "attEffects": [], 46 | "attWon": true, 47 | "defUnits": { 48 | "spear": 0, 49 | "sword": 0, 50 | "axe": 0, 51 | "archer": 0, 52 | "light_cavalry": 0, 53 | "heavy_cavalry": 0, 54 | "mounted_archer": 0, 55 | "ram": 0, 56 | "catapult": 0, 57 | "knight": 0, 58 | "snob": 0, 59 | "trebuchet": 0, 60 | "doppelsoldner": 0 61 | }, 62 | "defLosses": { 63 | "spear": 0, 64 | "sword": 0, 65 | "axe": 0, 66 | "archer": 0, 67 | "light_cavalry": 0, 68 | "heavy_cavalry": 0, 69 | "mounted_archer": 0, 70 | "ram": 0, 71 | "catapult": 0, 72 | "knight": 0, 73 | "snob": 0, 74 | "trebuchet": 0, 75 | "doppelsoldner": 0 76 | }, 77 | "defRevived": null, 78 | "defFaith": 0.5, 79 | "defModifier": 0.5, 80 | "defEffects": [], 81 | "officers": { 82 | "leader": false, 83 | "loot_master": false, 84 | "medic": false, 85 | "scout": false, 86 | "supporter": false, 87 | "bastard": false 88 | }, 89 | "loyaltyBefore": null, 90 | "loyaltyAfter": null, 91 | "luck": 1.1300000000000001, 92 | "morale": 1, 93 | "leader": 1, 94 | "wallBonus": 0.1499999999999999, 95 | "night": false, 96 | "farmRule": 1, 97 | "wallBefore": null, 98 | "wallAfter": null, 99 | "building": null, 100 | "buildingBefore": null, 101 | "buildingAfter": null, 102 | "haul": { 103 | "wood": 25, 104 | "clay": 28, 105 | "iron": 28, 106 | "food": 0 107 | }, 108 | "capacity": 200, 109 | "storage": null, 110 | "buildings": { 111 | "timber_camp": 9, 112 | "clay_pit": 10, 113 | "iron_mine": 10 114 | }, 115 | "attCharacterIcon": 0, 116 | "defCharacterIcon": null, 117 | "attVillageId": 1617, 118 | "attVillageName": "Segundo pueblo de John", 119 | "attVillageX": 511, 120 | "attVillageY": 488, 121 | "attCharacterId": 123456, 122 | "attCharacterName": "John", 123 | "defVillageId": 2170, 124 | "defVillageName": "ESTRELLA DEL NORTE", 125 | "defVillageX": 499, 126 | "defVillageY": 459, 127 | "defCharacterId": 0, 128 | "defCharacterName": null 129 | } 130 | } -------------------------------------------------------------------------------- /explore/2020-07-31-learning-how-an-app-works/2020-07-31-learning-how-an-app-works.md: -------------------------------------------------------------------------------- 1 | # 2020-07-31 - Learning How An App Works 2 | 3 | Its program code defines the behavior of a bot. No matter if you want to fix a bug or expand an app with a new feature, you need to make a change in the program code. But how do you know what to change and where? 4 | 5 | People who already have experience with the programming language can read the program code and then use that experience to simulate the program execution in their head. But that does not work if you are new to the programming language. 6 | 7 | Besides not know the rules of the language, there is another reason why reading the program code is an inefficient way to learn how a program works: The source code covers many different situations and, as a result, is relatively abstract. For example, the ordering in the program code is independent of the actual processing order at runtime. 8 | 9 | How do we find out in which order things happen and what are the roles of specific parts? 10 | 11 | To do this, we look at how the program execution happened in a specific scenario. 12 | 13 | We already have a way to see each event and the resulting response of the app. The next step is to look into the computations happening for a single event and see which parts of the program code contributed to what parts of the app's response. 14 | 15 | To use terms of the programming language: To illustrate the data flow, we could use a tree view that follows the data flow backward via the applications. 16 | 17 | Let's take this function as an example: https://github.com/Viir/bots/blob/5f711e9043bd20810578b1185a81ef5764d45e7c/implement/applications/eve-online/eve-online-combat-anomaly-bot/BotEngineApp.elm#L175-L197 18 | This function expresses an application of `branchDependingOnDockedOrInSpace`. This application has a return value. 19 | I notice I am going too far when looking for a useful visualization of this case. At first, I was thinking of a complete variant that supports the inspection of everything everywhere. But I notice that I find it easier to think about a variant where we would only see inspection branches for applications of named functions. Even this limited version seems a vast improvement over today's state. I will continue with this simplified version for now. I think we can more fine-grained inspection support later. 20 | 21 | So `branchDependingOnDockedOrInSpace` is applied, or instantiated, which means we have arguments and a return value. Besides that, we want a way to see the program code that is responsible for this part. How do we make the connection between the value and the next instantiations? 22 | We can add an option to expand at the `branchDependingOnDockedOrInSpace` text in `anomalyBotDecisionRoot`. One of the branches to view here is the arguments given to `branchDependingOnDockedOrInSpace`. The arguments look different from the expression we see in `anomalyBotDecisionRoot`, because this expression contains applications that lead to more concrete values. 23 | 24 | We could use an approach more focusing on the return value: For every component, like a record field or an element in a tuple, we can add a branch to show the originating expression. More generally, for every value, offer to show the originating expression. 25 | 26 | To help with reading the parts that are program code, we could highlight the expressions used/forced at least once from those not evaluated/forced in the current scenario. Or we could collapse the ones which are not used by default. 27 | 28 | How could the visual tree look like starting at an application of `anomalyBotDecisionRoot` and expanding a few branches? 29 | 30 | + `anomalyBotDecisionRoot` 31 | + Arguments values 32 | + Return value 33 | + [Function code](https://github.com/Viir/bots/blob/5f711e9043bd20810578b1185a81ef5764d45e7c/implement/applications/eve-online/eve-online-combat-anomaly-bot/BotEngineApp.elm#L175-L197) 34 | + Evaluation 35 | + `branchDependingOnDockedOrInSpace` 36 | + Arguments values 37 | + Return value 38 | + [Function code](https://github.com/Viir/bots/blob/5f711e9043bd20810578b1185a81ef5764d45e7c/implement/applications/eve-online/eve-online-combat-anomaly-bot/EveOnline/AppFramework.elm#L1287-L1313) 39 | + Evaluation 40 | + `case readingFromGameClient.shipUI of` 41 | + Matching case `CanSee shipUI` 42 | + Arguments values 43 | + Return value 44 | + [Expression code](https://github.com/Viir/bots/blob/5f711e9043bd20810578b1185a81ef5764d45e7c/implement/applications/eve-online/eve-online-combat-anomaly-bot/EveOnline/AppFramework.elm#L1300-L1313) 45 | + Evaluation 46 | + `Maybe.withDefault` 47 | + Unused cases 48 | 49 | Can we simplify this further for a MVP? What else can we remove? 50 | --------------------------------------------------------------------------------