Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
8 changes: 4 additions & 4 deletions .github/workflows/ci-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -80,9 +80,9 @@ jobs:
path: ${{ env.VCPKG_DEFAULT_BINARY_CACHE }}
# run_id (+ job) keeps every save key unique so a fresh build always
# saves; the prefix restore-keys then pick up the most recent cache.
key: vcpkg-${{ runner.os }}-${{ env.VCPKG_REF }}-${{ hashFiles('vcpkg.json', 'tests/frontends/runtime/vcpkg.json') }}-${{ github.run_id }}-${{ github.job }}
key: vcpkg-${{ runner.os }}-${{ env.VCPKG_REF }}-${{ hashFiles('vcpkg.json', 'tests/runtime/vcpkg.json') }}-${{ github.run_id }}-${{ github.job }}
restore-keys: |
vcpkg-${{ runner.os }}-${{ env.VCPKG_REF }}-${{ hashFiles('vcpkg.json', 'tests/frontends/runtime/vcpkg.json') }}-
vcpkg-${{ runner.os }}-${{ env.VCPKG_REF }}-${{ hashFiles('vcpkg.json', 'tests/runtime/vcpkg.json') }}-
vcpkg-${{ runner.os }}-${{ env.VCPKG_REF }}-
- name: Set up pinned vcpkg (binary cache + MSBuild manifest restore)
shell: pwsh
Expand Down Expand Up @@ -170,9 +170,9 @@ jobs:
uses: actions/cache/restore@v4
with:
path: ${{ env.VCPKG_DEFAULT_BINARY_CACHE }}
key: vcpkg-${{ runner.os }}-${{ env.VCPKG_REF }}-${{ hashFiles('vcpkg.json', 'tests/frontends/runtime/vcpkg.json') }}-${{ github.run_id }}-${{ github.job }}
key: vcpkg-${{ runner.os }}-${{ env.VCPKG_REF }}-${{ hashFiles('vcpkg.json', 'tests/runtime/vcpkg.json') }}-${{ github.run_id }}-${{ github.job }}
restore-keys: |
vcpkg-${{ runner.os }}-${{ env.VCPKG_REF }}-${{ hashFiles('vcpkg.json', 'tests/frontends/runtime/vcpkg.json') }}-
vcpkg-${{ runner.os }}-${{ env.VCPKG_REF }}-${{ hashFiles('vcpkg.json', 'tests/runtime/vcpkg.json') }}-
vcpkg-${{ runner.os }}-${{ env.VCPKG_REF }}-
- name: Set up pinned vcpkg (binary cache + MSBuild manifest restore)
shell: pwsh
Expand Down
8 changes: 4 additions & 4 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -81,9 +81,9 @@ jobs:
path: ${{ env.VCPKG_DEFAULT_BINARY_CACHE }}
# run_id (+ job) keeps every save key unique so a fresh build always
# saves; the prefix restore-keys then pick up the most recent cache.
key: vcpkg-${{ runner.os }}-${{ env.VCPKG_REF }}-${{ hashFiles('vcpkg.json', 'tests/frontends/runtime/vcpkg.json') }}-${{ github.run_id }}-${{ github.job }}
key: vcpkg-${{ runner.os }}-${{ env.VCPKG_REF }}-${{ hashFiles('vcpkg.json', 'tests/runtime/vcpkg.json') }}-${{ github.run_id }}-${{ github.job }}
restore-keys: |
vcpkg-${{ runner.os }}-${{ env.VCPKG_REF }}-${{ hashFiles('vcpkg.json', 'tests/frontends/runtime/vcpkg.json') }}-
vcpkg-${{ runner.os }}-${{ env.VCPKG_REF }}-${{ hashFiles('vcpkg.json', 'tests/runtime/vcpkg.json') }}-
vcpkg-${{ runner.os }}-${{ env.VCPKG_REF }}-
- name: Set up pinned vcpkg (binary cache + MSBuild manifest restore)
shell: pwsh
Expand Down Expand Up @@ -182,9 +182,9 @@ jobs:
uses: actions/cache/restore@v4
with:
path: ${{ env.VCPKG_DEFAULT_BINARY_CACHE }}
key: vcpkg-${{ runner.os }}-${{ env.VCPKG_REF }}-${{ hashFiles('vcpkg.json', 'tests/frontends/runtime/vcpkg.json') }}-${{ github.run_id }}-${{ github.job }}
key: vcpkg-${{ runner.os }}-${{ env.VCPKG_REF }}-${{ hashFiles('vcpkg.json', 'tests/runtime/vcpkg.json') }}-${{ github.run_id }}-${{ github.job }}
restore-keys: |
vcpkg-${{ runner.os }}-${{ env.VCPKG_REF }}-${{ hashFiles('vcpkg.json', 'tests/frontends/runtime/vcpkg.json') }}-
vcpkg-${{ runner.os }}-${{ env.VCPKG_REF }}-${{ hashFiles('vcpkg.json', 'tests/runtime/vcpkg.json') }}-
vcpkg-${{ runner.os }}-${{ env.VCPKG_REF }}-
- name: Set up pinned vcpkg
shell: pwsh
Expand Down
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
/TODO.md

# Local-only MSBuild overrides (e.g. a personal post-build install step)
src/glue/*/*.local.targets
src/dlls/*/*.local.targets

# Local-only build settings (e.g. a personal Aptabase app key)
/d2bs.local.props
Expand Down
114 changes: 57 additions & 57 deletions CLAUDE.md

Large diffs are not rendered by default.

12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -139,17 +139,17 @@ command-line scrollback with separate, ImGui-rendered panels:

## Architecture

The codebase builds seven targets plus a test executable. A frontend (JS) and a backend (1.14d) both compile against a shared `contract`; a thin glue project links one of each into the injectable DLL:
The codebase builds seven targets plus a test executable. A frontend (JS) and a backend (1.14d) both compile against a shared `contract`; a thin DLL project under `src/dlls/` links one of each into the injectable DLL:

| Target | Source | Output | Role |
| --- | --- | --- | --- |
| `utils` | `src/utils/` | `utils.lib` | Standalone utilities (crypto, threading, stack walking) |
| `contract` | `src/contract/` | `contract.lib` | The version-agnostic game-abstraction *interface* (`game/` handle types) plus shared DTOs. The boundary both frontends and backends compile against. |
| `core` | `src/core/` | `core.lib` | Shared infrastructure: config, speedhack, proxy. Depends on `contract`. |
| `runtime` | `src/frontends/runtime/` | `runtime.lib` | JavaScript scripting frontend: engine + V8 JavaScript API, plus the game-agnostic navigation algorithms (A* pathfinder, level-exit finder) and the bot's background services (analytics, character-state IPC, DDE, profile switching, update checks). Depends on `contract` + `core`. |
| `runtime` | `src/runtime/` | `runtime.lib` | JavaScript scripting frontend: engine + V8 JavaScript API, plus the game-agnostic navigation algorithms (A* pathfinder, level-exit finder) and the bot's background services (analytics, character-state IPC, DDE, profile switching, update checks). Depends on `contract` + `core`. |
| `lod114d` | `src/backends/lod114d/` | `lod114d.lib` | The 1.14d game *backend* (directory named for the patch it targets) - game-memory reads, function calls, hooks, offsets. Implements `contract`; depends on `contract` + `core`. No frontend dependency. |
| `d2bs` | `src/glue/js-v8-lod114d/` | `d2bs.dll` | Glue: `DllMain` + wiring. Links runtime + lod114d + contract + core + utils. This is the injectable DLL. |
| `js_tests` | `tests/frontends/runtime/` | `js_tests.exe` | A [doctest](https://github.com/doctest/doctest) suite (pathfinding) compiled against a fake game layer |
| `d2bs` | `src/dlls/js-v8-lod114d/` | `d2bs.dll` | `DllMain` + wiring. Links runtime + lod114d + contract + core + utils. This is the injectable DLL. |
| `js_tests` | `tests/runtime/` | `js_tests.exe` | A [doctest](https://github.com/doctest/doctest) suite (pathfinding) compiled against a fake game layer |

The key structural decision is the split between a **version-agnostic game interface**
(`src/contract/game/` - thin handle types like `Unit`, `Room`, `Level`, `Party`, `Control`
Expand All @@ -158,7 +158,7 @@ provides the actual game-memory reads, function calls, hooks, and offsets. The f
JavaScript API never touch game memory directly or depend on any particular game build;
supporting another game version means adding a new backend lib (sibling of `src/backends/lod114d/`)
over the same `contract` + `core`, and a new frontend (e.g. a non-JS host) is a sibling of
`src/frontends/runtime/`. Frontend and backend never reference each other - only the `d2bs` glue does.
`src/runtime/`. Frontend and backend never reference each other - only the `d2bs` DLL project does.

The project is **32-bit (Win32) only** (required for 1.14d), compiled with C++23 using the
LLVM/Clang (ClangCL) toolchain with link-time optimization, so the thin wrapper types inline
Expand Down Expand Up @@ -295,7 +295,7 @@ The suite compiles the real pathfinder against fake game-layer implementations -
V8, and no running game required. It currently covers the pathfinding engine.

Real-game collision benchmarks run against the `.d2col` fixtures under
`tests/frontends/runtime/fixtures/maps/` (collision dumps included in the repo). The benchmarks
`tests/runtime/fixtures/maps/` (collision dumps included in the repo). The benchmarks
auto-discover whatever is present and skip gracefully if the folder is empty.

## Compatibility with legacy d2bs scripts
Expand Down
4 changes: 2 additions & 2 deletions build.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ param(
# (MSBuild -p:D2bsProfiling=false; see Directory.Build.props).
[switch]$NoProfiling,
# Solution platform. Win32 builds the 1.14d backend into Release\ and the
# glue DLL into Release\js-v8-lod114d\; x64 builds the platform-independent
# DLL into Release\js-v8-lod114d\; x64 builds the platform-independent
# libraries into x64\Release\.
# The .slnx maps each project to the platforms it supports, so the ones that
# are Win32-only are skipped rather than failing.
Expand Down Expand Up @@ -190,7 +190,7 @@ switch ($mode) {
'deps' {
# Runs only the FetchV8 target, on the project that needs the headers
# earliest. Nothing compiles, so this does not need vcpkg restored.
& $msbuild 'src\frontends\runtime\runtime.vcxproj' '-t:FetchV8' '-p:Configuration=Release' "-p:Platform=$Platform" '-v:m' '-nologo'
& $msbuild 'src\runtime\runtime.vcxproj' '-t:FetchV8' '-p:Configuration=Release' "-p:Platform=$Platform" '-v:m' '-nologo'
exit $LASTEXITCODE
}
'test' {
Expand Down
6 changes: 3 additions & 3 deletions d2bsng.slnx
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,14 @@
<Project Path="src/utils/utils.vcxproj" />
<Project Path="src/contract/contract.vcxproj" />
<Project Path="src/core/core.vcxproj" />
<Project Path="src/frontends/runtime/runtime.vcxproj" />
<Project Path="src/runtime/runtime.vcxproj" />
<Project Path="src/backends/lod114d/lod114d.vcxproj">
<Build Solution="*|x64" Project="false" />
</Project>
<Project Path="src/glue/js-v8-lod114d/d2bs.vcxproj">
<Project Path="src/dlls/js-v8-lod114d/d2bs.vcxproj">
<Build Solution="*|x64" Project="false" />
</Project>
<Project Path="tests/frontends/runtime/js_tests.vcxproj">
<Project Path="tests/runtime/js_tests.vcxproj">
<Build Solution="*|x64" Project="false" />
</Project>
<Folder Name="/Solution Items/">
Expand Down
2 changes: 1 addition & 1 deletion docs/analytics.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ and stays entirely anonymous - the only identity an event carries is a derived
profile it runs. There is no per-action tracking, no keystroke/screen capture,
and no game data of any kind.

- Component: `src/frontends/runtime/components/analytics/Analytics.h` / `.cpp`
- Component: `src/runtime/components/analytics/Analytics.h` / `.cpp`
- Launch switches: `src/backends/lod114d/game/LaunchOptions.cpp`
(`-noanalytics`)
- Contract surface: `game::GetAnalyticsLaunchOptions()`,
Expand Down
4 changes: 2 additions & 2 deletions docs/compatibility.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ can contribute its own flags to the same set.

## The registry

`d2bs::config::CompatibilityFlags` (`src/core/config/CompatibilityFlags.{h,cpp}`)
`d2bs::core::config::CompatibilityFlags` (`src/core/config/CompatibilityFlags.{h,cpp}`)
is the single, process-wide, thread-shared store. It holds an insertion-ordered
list of `{name, defaultEnabled, enabled}` entries behind a mutex (descriptions
are documentation-only - see below).
Expand Down Expand Up @@ -61,7 +61,7 @@ cover the framework catalog only.

## The `Compatibility` JS object

A non-constructable namespace object (`src/frontends/runtime/api/classes/scripting/JSCompatibility.h`),
A non-constructable namespace object (`src/runtime/api/classes/scripting/JSCompatibility.h`),
modeled on `TxtTables`. The set of available flag names is documented in the API
docs (the `CompatibilityFlag` option set), so there is no runtime enumeration
method:
Expand Down
6 changes: 3 additions & 3 deletions docs/coords.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ of truth, no `Pos()`/`Size()` pair.
| `runtime::navigation::ExitInfo::pos` | game-coords | derived from room/level offsets already scaled |

Consequences:
- `src/frontends/runtime/` contains zero `* 5` coordinate scaling.
- `src/runtime/` contains zero `* 5` coordinate scaling.
- `Room::Bounds()` and `Level::Bounds()` each produce a valid game-coord bounding
box in a single resolve.
- `LevelGrid` input/output is game-coords throughout.
Expand Down Expand Up @@ -81,8 +81,8 @@ Reference d2bs script contract (current behavior - Option A applied):
- `room.xsize`, `room.ysize` -> **game-coords** (already `* 5`)
- `level.x/y/xsize/ysize` -> **subtiles** for all four

At the JS-API boundary (`src/frontends/runtime/api/classes/game/JSRoom.h`,
`src/frontends/runtime/api/classes/game/JSArea.h`), the game-coord values from `Bounds()`
At the JS-API boundary (`src/runtime/api/classes/game/JSRoom.h`,
`src/runtime/api/classes/game/JSArea.h`), the game-coord values from `Bounds()`
are divided by `5U` where reference exposed raw-subtile. `JSRoom` divides `x/y` only;
`JSArea` divides all four. This preserves reference-d2bs script compatibility.

Expand Down
4 changes: 2 additions & 2 deletions docs/inspector.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ Every script isolate always registers a debuggable target; the port only governs
whether the server that exposes them is listening. Attaching costs nothing
measurable until a DevTools client actually connects.

All inspector code lives in `src/frontends/runtime/components/inspector/`. It is wired
into the script lifecycle from `src/frontends/runtime/components/script/Script.cpp` and
All inspector code lives in `src/runtime/components/inspector/`. It is wired
into the script lifecycle from `src/runtime/components/script/Script.cpp` and
started/stopped from `ScriptEngine`.

## Why WebSocket
Expand Down
2 changes: 1 addition & 1 deletion docs/window_message_handling.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

How d2bs intercepts and injects Windows messages. The game-window half is
backend-independent and lives in `src/core/input/InputHook.{h,cpp}` (namespace
`d2bs::input`); a backend's `hooks/HookManager.cpp` installs it and supplies the
`d2bs::core::input`); a backend's `hooks/HookManager.cpp` installs it and supplies the
callbacks it dispatches to. The console-window half is 1.14d-specific, because a
backend that renders its console as an in-game overlay needs no second window.
Two OS windows are involved:
Expand Down
10 changes: 5 additions & 5 deletions scripts/extract_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ def build_compile_flags():
"-w", # suppress diagnostics — we only want the AST
]
for d in (
REPO_ROOT / "src" / "frontends" / "runtime",
REPO_ROOT / "src" / "runtime",
REPO_ROOT / "src" / "contract",
REPO_ROOT / "src" / "core",
REPO_ROOT / "src",
Expand Down Expand Up @@ -1000,15 +1000,15 @@ def fresh(entry):


def find_api_sources():
api_dir = REPO_ROOT / "src" / "frontends" / "runtime" / "api"
api_dir = REPO_ROOT / "src" / "runtime" / "api"
files = []
for ext in ("*.h", "*.cpp"):
files.extend(sorted(api_dir.rglob(ext)))
return files


EVENTS_FILE = REPO_ROOT / "src" / "frontends" / "runtime" / "components" / "events" / "Events.h"
TXT_TABLES_FILE = REPO_ROOT / "src" / "frontends" / "runtime" / "api" / "globals" / "TxtTables.h"
EVENTS_FILE = REPO_ROOT / "src" / "runtime" / "components" / "events" / "Events.h"
TXT_TABLES_FILE = REPO_ROOT / "src" / "runtime" / "api" / "globals" / "TxtTables.h"


def extract_txt_tables(path=TXT_TABLES_FILE):
Expand Down Expand Up @@ -1408,7 +1408,7 @@ def extract_events(events_path=EVENTS_FILE):


_DRAWABLE_BASE_FILE = (
REPO_ROOT / "src" / "frontends" / "runtime" / "api" / "classes" / "drawing" / "JSDrawableBase.h"
REPO_ROOT / "src" / "runtime" / "api" / "classes" / "drawing" / "JSDrawableBase.h"
)
_DRAWABLE_REG_RE = re.compile(
r'Base::(Property|Method)\(\s*isolate\s*,\s*\w+\s*,\s*"([^"]+)"'
Expand Down
8 changes: 4 additions & 4 deletions scripts/gen_txt_tables.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

Usage:
python scripts/gen_txt_tables.py [--reference-dir reference/d2bs]
[--output src/frontends/runtime/api/globals/TxtTables.h]
[--output src/runtime/api/globals/TxtTables.h]
"""

from __future__ import annotations
Expand Down Expand Up @@ -85,7 +85,7 @@ def emit_header(tables: list[tuple[str, list[str]]], script_rel: str) -> str:
emit("#include <span>")
emit("#include <string_view>")
emit("")
emit("namespace d2bs::game {")
emit("namespace d2bs::runtime::api::globals {")
emit("")

# Widths for aligning trailing `// [idx] ...` comments.
Expand Down Expand Up @@ -145,7 +145,7 @@ def emit_header(tables: list[tuple[str, list[str]]], script_rel: str) -> str:
emit("};")
emit("")

emit("} // namespace d2bs::game")
emit("} // namespace d2bs::runtime::api::globals")
emit("")

return "\n".join(lines)
Expand All @@ -162,7 +162,7 @@ def main() -> int:
)
parser.add_argument(
"--output",
default=str(repo_root / "src" / "frontends" / "runtime" / "api" / "globals" / "TxtTables.h"),
default=str(repo_root / "src" / "runtime" / "api" / "globals" / "TxtTables.h"),
help="Output header path",
)
args = parser.parse_args()
Expand Down
4 changes: 2 additions & 2 deletions src/backends/lod114d/asm_thunks/asm_thunks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
// d2bs DLL (see asm_thunks::* references in src/backends/lod114d/game/). Unreferenced
// entries are not maintained.

namespace d2bs::asm_thunks {
namespace d2bs::lod114d::asm_thunks {

namespace {

Expand Down Expand Up @@ -241,4 +241,4 @@ D2AutomapLayerStrc* InitAutomapLayerForLevel(uint32_t levelNo) {
return InitAutomapLayer(layerNo);
}

} // namespace d2bs::asm_thunks
} // namespace d2bs::lod114d::asm_thunks
4 changes: 2 additions & 2 deletions src/backends/lod114d/asm_thunks/asm_thunks.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ struct D2UnitStrc;
// hooks, not register-shuffle trampolines. A naked thunk is the smallest
// expression of "set ecx/edx/eax/edi to these values, then jmp".

namespace d2bs::asm_thunks {
namespace d2bs::lod114d::asm_thunks {

// Resolve every thunk's target address from the imports::d2client
// GameAsmFunc instances. Must be called after Bridge::Init() has run
Expand Down Expand Up @@ -76,4 +76,4 @@ D2AutomapLayerStrc* __fastcall InitAutomapLayer(uint32_t nLayerNo);
// with the resolved layer number. Reference: D2Helpers.cpp:347-350.
D2AutomapLayerStrc* InitAutomapLayerForLevel(uint32_t levelNo);

} // namespace d2bs::asm_thunks
} // namespace d2bs::lod114d::asm_thunks
Loading
Loading