├── .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 | 
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 | 
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 | 
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 | 
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 | 
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 | 
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 | 
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 | 
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 | 
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 | 
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 | 
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 | 
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 | 
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 |
--------------------------------------------------------------------------------