ultimatedarktower 3.0.0 → 4.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +48 -0
- package/README.md +28 -15
- package/dist/esm/index.mjs +1043 -45
- package/dist/src/UltimateDarkTower.d.ts +42 -0
- package/dist/src/UltimateDarkTower.js +102 -2
- package/dist/src/UltimateDarkTower.js.map +1 -1
- package/dist/src/adapters/NodeBluetoothAdapter.js +9 -5
- package/dist/src/adapters/NodeBluetoothAdapter.js.map +1 -1
- package/dist/src/adapters/WebBluetoothAdapter.js +11 -8
- package/dist/src/adapters/WebBluetoothAdapter.js.map +1 -1
- package/dist/src/index.d.ts +8 -0
- package/dist/src/index.js +34 -1
- package/dist/src/index.js.map +1 -1
- package/dist/src/sinks/IndexedDBSink.d.ts +26 -0
- package/dist/src/sinks/IndexedDBSink.js +165 -0
- package/dist/src/sinks/IndexedDBSink.js.map +1 -0
- package/dist/src/udtBleConnection.d.ts +24 -1
- package/dist/src/udtBleConnection.js +68 -2
- package/dist/src/udtBleConnection.js.map +1 -1
- package/dist/src/udtBluetoothAdapter.d.ts +6 -6
- package/dist/src/udtBluetoothAdapter.js.map +1 -1
- package/dist/src/udtCommandQueue.d.ts +4 -1
- package/dist/src/udtCommandQueue.js +26 -2
- package/dist/src/udtCommandQueue.js.map +1 -1
- package/dist/src/udtConstants.d.ts +2 -0
- package/dist/src/udtConstants.js +2 -0
- package/dist/src/udtConstants.js.map +1 -1
- package/dist/src/udtDiagnostics.d.ts +122 -0
- package/dist/src/udtDiagnostics.js +228 -0
- package/dist/src/udtDiagnostics.js.map +1 -0
- package/dist/src/udtGameBoard.d.ts +38 -0
- package/dist/src/udtGameBoard.js +86 -0
- package/dist/src/udtGameBoard.js.map +1 -0
- package/dist/src/udtLogger.d.ts +15 -0
- package/dist/src/udtLogger.js +17 -0
- package/dist/src/udtLogger.js.map +1 -1
- package/dist/src/udtSeedParser.d.ts +124 -0
- package/dist/src/udtSeedParser.js +369 -0
- package/dist/src/udtSeedParser.js.map +1 -0
- package/dist/src/udtSystemRandom.d.ts +58 -0
- package/dist/src/udtSystemRandom.js +154 -0
- package/dist/src/udtSystemRandom.js.map +1 -0
- package/dist/src/udtTowerCommands.d.ts +2 -0
- package/dist/src/udtTowerCommands.js +15 -29
- package/dist/src/udtTowerCommands.js.map +1 -1
- package/package.json +5 -1
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,54 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/), and this
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [4.0.1] - 2026-05-28
|
|
10
|
+
|
|
11
|
+
### Fixed
|
|
12
|
+
|
|
13
|
+
- **`rotateWithState()` no longer bounces already-rotated drums back to their old positions** — `rotateDrumStateful()` was reading the live tower state to build its 20-byte stateful packet but never updating that state after sending. Inside `rotateWithState()` the three sequential calls therefore all read the same pre-rotation state, so call 2's packet re-sent the original top-drum position (rotating it back) and call 3's packet re-sent the original middle position. Local state is now updated immediately after the command is built, so subsequent calls in the loop encode the correct cumulative positions. Same pattern as the prior `setLEDStateful` fix.
|
|
14
|
+
|
|
15
|
+
## [4.0.0] - 2026-05-28
|
|
16
|
+
|
|
17
|
+
- **Tower Emulator has been added** — Utilising the UltimateDarkTowerDisplay the example app can now connect to a software rendered version of the tower. The controller and the software tower share actual packets, so this can be a useful feature for testing certain features of both the UDT library and the UDT Display Library.
|
|
18
|
+
|
|
19
|
+
### Fixed
|
|
20
|
+
|
|
21
|
+
- **Eliminated all 85 `@typescript-eslint/no-explicit-any` lint warnings** — All `any` types across source and test files replaced with proper TypeScript types (`unknown`, type-narrowed catch blocks, typed mock helpers, typed cast chains). Also added a `no-undef` disable comment for the `globalThis` usage in `udtDiagnostics.ts`. Local interface declarations for the Web Bluetooth API (`BluetoothDevice`, `BluetoothRemoteGATTCharacteristic`, etc.) were added to `WebBluetoothAdapter.ts` since these types are not included in TypeScript's standard DOM lib. The codebase now reports `0 problems (0 errors, 0 warnings)` from ESLint.
|
|
22
|
+
|
|
23
|
+
### Added
|
|
24
|
+
|
|
25
|
+
- **Tower Controller gains a "Seals" tab for 3D emulator seal visibility** — When connected in Tower Emulator mode, a new "Seals" tab appears in the left column of the Tower Controller. It shows a labeled 3×4 grid (Top/Mid/Btm × N/E/S/W) of toggle buttons: clicking a button removes the corresponding seal from the 3D emulator view (button turns dark red); clicking again restores it. "Remove All" and "Replace All" action buttons operate on all 12 seals at once. Seal state is kept in sync with the existing Library tab seal grid on all mutation paths (`breakSeal`, Library grid clicks, "Clear All Lights"). The seal state is communicated to the emulator popup via a new `applySeals` postMessage type, which calls `TowerRenderView.applySeals()` on the display. When not in emulator+connected mode the tab shows an explanatory notice.
|
|
26
|
+
|
|
27
|
+
- **BLE disconnect diagnostics ("flight recorder")** — Opt-in structured capture of BLE disconnect incidents. Each of the five disconnect detection paths is tagged with a typed `DisconnectCause` (`adapter_event`, `gatt_health_check`, `heartbeat_timeout`, `response_timeout`, `bt_unavailable`) plus `user_initiated` and browser-only `page_unload`. Captures a snapshot of `ConnectionStatus`, command queue (including in-flight command + age), tower state, broken seals, the last ~500 structured BLE events (commands sent/received, timeouts, near-miss heartbeats, log lines), and the last 60 battery readings. Pluggable `DiagnosticsSink` interface mirrors `LogOutput`; ships with `InMemorySink` and `IndexedDBSink` (browser-only, durable across page refresh). Off by default — when disabled, hot paths add a single boolean check. Configure via `new UltimateDarkTower({ diagnostics: { enabled: true, ... } })` or toggle at runtime via `tower.setDiagnosticsEnabled(true)`. Public API: `getDiagnosticsRecorder()`, `getLastIncident()`, `exportDiagnosticsJSON()`. Tower Controller example gains a "BLE Debug" tab with capture toggle, live event stream, persistent incident log, breakdown-by-cause metrics, and JSON export. See [`docs/BLE_DIAGNOSTICS.md`](docs/BLE_DIAGNOSTICS.md). Schema version 1.
|
|
28
|
+
|
|
29
|
+
- **Seed parser** — New `src/udtSeedParser.ts` provides complete base-34 seed encoding and decoding, matching the game's C# `SeedParser` class. Exports `decodeSeed()`, `createSeed()`, `encodeSeed()`, `validateSeed()`, `compareSeedsRaw()`, `dumpSeedChars()`, and all related types (`DecodedSeed`, `SeedConfig`, `SeedBank`, `SeedComparison`, `CharDiff`, `CharDump`, foe/adversary/ally union types, and lookup arrays).
|
|
30
|
+
|
|
31
|
+
- **C# System.Random replica** — New `src/udtSystemRandom.ts` implements a byte-exact TypeScript replica of .NET Framework's `System.Random` (modified Knuth subtractive generator). Exports the `SystemRandom` class with `next()`, `nextMax()`, `nextRange()`, and `nextDouble()` methods. Verified against C#-generated test vectors for multiple seeds including edge cases. This is the foundation for future game state prediction from seeds.
|
|
32
|
+
|
|
33
|
+
- **Game board data** — New `src/udtGameBoard.ts` exports types and constants for all 60 Return to Dark Tower board locations: `TerrainType`, `BuildingType`, `BoardKingdom`, `BoardGrouping`, `BoardLocation`, `BOARD_LOCATIONS` (array), `BOARD_LOCATION_BY_NAME` (name-keyed lookup), and `BOARD_GROUPINGS` (Long Water, The Great Woods, Regal Run).
|
|
34
|
+
|
|
35
|
+
- **Tower Emulator shows audio playback notifications** — When an audio command is sent while connected to the Tower Emulator, the emulator popup now briefly displays the sound name, loop state, and volume level. The notification auto-dismisses after 4 seconds. Detection is done at the adapter level by reading the audio bytes from the outgoing command packet, so all audio commands are captured regardless of which API method triggered them.
|
|
36
|
+
|
|
37
|
+
### Changed
|
|
38
|
+
|
|
39
|
+
- **Tower Emulator now renders a 3D tower model** — The emulator popup now uses `TowerRenderView` from `ultimatedarktowerdisplay` with the `'3d-view'` renderer, replacing the previous `TowerDisplay` default of readout text + 2D SVG side view. The existing connection-status banner and audio-event banner remain above the render, and the render view shows a "Tower Emulator" title bar.
|
|
40
|
+
|
|
41
|
+
- **Tower Emulator plays LED light sequences with bound audio** — `Tower.lightOverrides(N)` (the controller's Light Override dropdown) now drives a transient LED animation on the emulator's 3D tower **and** plays the firmware-bound audio sample alongside it (mirroring real-tower behavior). Same architectural fix as the audio cut-off: the framework strips `state.led_sequence` on every response (parallel to audio), so the popup was previously seeing `SequenceAnimator.apply(0)` immediately after each light-override command and killing the sequence before any frames played. `TowerEmulatorAdapter` now exposes an `onLightSequenceCommand` callback (parallel to `onAudioCommand`); the controller posts a `playSequence` message to the popup, which calls the display package's new `playSequence(id)` transient API (UltimateDarkTowerDisplay ≥ 0.7.0). The popup enables `audio.bindSequenceToSample: true` in its `TowerRenderView` config so the bound sample fires automatically via `playSampleOneShot` inside `playSequence` — same firmware behavior the display's own example app emulates. Detection reads `data[19]` (the `led_sequence` byte) from outgoing stateful commands.
|
|
42
|
+
|
|
43
|
+
- **Tower Emulator plays tower audio (full samples, no cut-off)** — The emulator popup now plays the same audio samples the real tower would, end-to-end. A "Click to enable audio" button appears on first load (required by browser autoplay policy); after clicking, all subsequent audio commands play through the popup. The popup's existing green audio-event banner continues to show sample name / loop / volume in parallel. Audio is driven via the display package's new `playSample(id, opts?)` one-shot API (requires `ultimatedarktowerdisplay` ≥ 0.6.0) — the previous synthetic-state workaround caused samples to cut off after ~100ms because the framework's audio-reset state updates triggered the display's `sync(0)` → `stop()` pipeline. The one-shot path is independent of state-driven `sync()`, so it plays to completion. Polyphony works (overlapping samples). The emulator's esbuild target was bumped from `es2017` to `es2020` and the output format from `iife` to `esm` (with a `<script type="module">` tag) so that the display package's per-file `new URL('./assets/<file>.ogg', import.meta.url)` references resolve at runtime against the bundle URL. Audio samples are copied from `UltimateDarkTowerDisplay/src/audio/assets/` to `dist/examples/controller/assets/` by `build-examples.js`.
|
|
44
|
+
|
|
45
|
+
- **`breakSeal()` now uses the firmware `sealReveal` LED override** — Previously composed ledge and doorway light states manually and sent them as a `lights()` command alongside the audio command. Now sends a single `lightOverrides(TOWER_LIGHT_SEQUENCES.sealReveal, ...)` packet that triggers the firmware's built-in seal reveal animation. The tower blocks until the animation completes before acknowledging the command, so callers no longer need an explicit delay between `breakSeal()` calls.
|
|
46
|
+
|
|
47
|
+
### Removed
|
|
48
|
+
|
|
49
|
+
- **Old seed decoder** — Deleted `src/udtSeedDecoder.ts` and its exports (`extractBits`, `seedGroupToNumber`, `BitDiff`, `BitDump`, `DecodedField`). The old implementation used an incorrect base-36/62-bit model. All functionality is replaced by `udtSeedParser.ts` with the confirmed base-34 encoding.
|
|
50
|
+
|
|
51
|
+
### Fixed
|
|
52
|
+
|
|
53
|
+
- **`connect()` swallowed errors instead of propagating to callers** — `udtBleConnection.connect()` caught all errors from the Bluetooth adapter (including `BluetoothUserCancelledError`) and called `onTowerDisconnect()` instead of re-throwing. This prevented callers from detecting user cancellation or connection failures. The catch block also incorrectly fired a disconnect event for a tower that was never connected. Errors are now re-thrown after logging, and the spurious disconnect callback has been removed.
|
|
54
|
+
|
|
55
|
+
- **Tower Emulator popup blocked on GitHub Pages (HTTPS)** — Moved `window.open` for the emulator display window to before the first `await` in `connectToTowerEmulator()`, ensuring it runs within the original user-gesture call stack and is not blocked by browser popup blockers on HTTPS origins.
|
|
56
|
+
|
|
9
57
|
## [3.0.0] - 2026-03-24
|
|
10
58
|
|
|
11
59
|
### Changed
|
package/README.md
CHANGED
|
@@ -10,12 +10,20 @@ A JavaScript/TypeScript library for controlling the Bluetooth-enabled tower from
|
|
|
10
10
|
|
|
11
11
|
I have spent many hours reverse engineering the Tower's protocol in order to create this library, I look forward to what others will create using this! - Chris
|
|
12
12
|
|
|
13
|
+
## Live Examples
|
|
14
|
+
|
|
15
|
+
Try the library in action! Just power on your Tower and visit:
|
|
16
|
+
|
|
17
|
+
- **[Tower Controller](https://chessmess.github.io/UltimateDarkTower/dist/examples/controller/TowerController.html)** - Replicates official app functionality and gives examples of library functionality.
|
|
18
|
+
|
|
19
|
+
_Requires Web Bluetooth support (Chrome, Edge, Samsung Internet). For iOS, use the [Bluefy app](https://apps.apple.com/us/app/bluefy-web-ble-browser/id1492822055)._
|
|
20
|
+
|
|
13
21
|
## Table of Contents
|
|
14
22
|
|
|
15
23
|
- [UltimateDarkTower](#ultimatedarktower)
|
|
24
|
+
- [Live Examples](#live-examples)
|
|
16
25
|
- [Table of Contents](#table-of-contents)
|
|
17
26
|
- [Features](#features)
|
|
18
|
-
- [Live Examples](#live-examples)
|
|
19
27
|
- [Installation](#installation)
|
|
20
28
|
- [Browser / Web Applications](#browser--web-applications)
|
|
21
29
|
- [Node.js Applications](#nodejs-applications)
|
|
@@ -27,6 +35,8 @@ I have spent many hours reverse engineering the Tower's protocol in order to cre
|
|
|
27
35
|
- [Documentation](#documentation)
|
|
28
36
|
- [📖 Complete API Reference](#-complete-api-reference)
|
|
29
37
|
- [Key Topics Covered:](#key-topics-covered)
|
|
38
|
+
- [Integration Testing](#integration-testing)
|
|
39
|
+
- [Lights Integration Test](#lights-integration-test)
|
|
30
40
|
- [Development](#development)
|
|
31
41
|
- [Building and Testing](#building-and-testing)
|
|
32
42
|
- [Project Structure](#project-structure)
|
|
@@ -50,16 +60,6 @@ I have spent many hours reverse engineering the Tower's protocol in order to cre
|
|
|
50
60
|
- **Battery Monitoring** - Real-time battery level tracking and low battery warnings
|
|
51
61
|
- **Extensible Adapter Pattern** - Implement `IBluetoothAdapter` for custom platforms
|
|
52
62
|
|
|
53
|
-
## Live Examples
|
|
54
|
-
|
|
55
|
-
Try the library in action! Just power on your Tower and visit:
|
|
56
|
-
|
|
57
|
-
- **[Tower Controller](https://chessmess.github.io/UltimateDarkTower/dist/examples/controller/TowerController.html)** - Replicates official app functionality and gives examples of library functionality.
|
|
58
|
-
|
|
59
|
-
- **[Tower Game](https://chessmess.github.io/UltimateDarkTower/dist/examples/game/TowerGame.html)** - "The Tower's Challenge" - a complete game using just the tower
|
|
60
|
-
|
|
61
|
-
_Requires Web Bluetooth support (Chrome, Edge, Samsung Internet). For iOS, use the [Bluefy app](https://apps.apple.com/us/app/bluefy-web-ble-browser/id1492822055)._
|
|
62
|
-
|
|
63
63
|
## Installation
|
|
64
64
|
|
|
65
65
|
### Browser / Web Applications
|
|
@@ -119,7 +119,7 @@ import UltimateDarkTower, { IBluetoothAdapter } from 'ultimatedarktower';
|
|
|
119
119
|
|
|
120
120
|
class MyCustomAdapter implements IBluetoothAdapter {
|
|
121
121
|
// Implement all IBluetoothAdapter methods
|
|
122
|
-
// See API_REFERENCE.md for the full interface
|
|
122
|
+
// See docs/API_REFERENCE.md for the full interface
|
|
123
123
|
}
|
|
124
124
|
|
|
125
125
|
const tower = new UltimateDarkTower({ adapter: new MyCustomAdapter() });
|
|
@@ -127,10 +127,18 @@ const tower = new UltimateDarkTower({ adapter: new MyCustomAdapter() });
|
|
|
127
127
|
|
|
128
128
|
## Documentation
|
|
129
129
|
|
|
130
|
-
### 📖 [Complete API Reference](API_REFERENCE.md)
|
|
130
|
+
### 📖 [Complete API Reference](docs/API_REFERENCE.md)
|
|
131
131
|
|
|
132
132
|
Comprehensive documentation with TypeScript examples, best practices, and troubleshooting guides.
|
|
133
133
|
|
|
134
|
+
### 📄 [Seed Format Specification](docs/SEED_FORMAT.md)
|
|
135
|
+
|
|
136
|
+
Complete documentation of the Return to Dark Tower game seed encoding — base-34 alphabet, setup section bitwise layout, RNG seed polynomial, and what each seed field controls.
|
|
137
|
+
|
|
138
|
+
### 🛠 [BLE Diagnostics (Flight Recorder)](docs/BLE_DIAGNOSTICS.md)
|
|
139
|
+
|
|
140
|
+
Opt-in diagnostic system for capturing BLE disconnect incidents. Tags each detection path, snapshots connection / queue / tower state at the moment of the drop, and includes a ring buffer of recent events so you can see the lead-up. Off by default; the controller example has a "BLE Debug" tab that exposes the full UI (toggle, live event stream, persistent incident log, JSON export).
|
|
141
|
+
|
|
134
142
|
### Key Topics Covered:
|
|
135
143
|
|
|
136
144
|
- **Multi-Platform Setup** - Configuration for Web, Node.js, Electron, and React Native
|
|
@@ -139,6 +147,8 @@ Comprehensive documentation with TypeScript examples, best practices, and troubl
|
|
|
139
147
|
- **Tower Control** - Detailed coverage of all tower commands (lights, sounds, rotation)
|
|
140
148
|
- **Glyph System** - Automatic tracking of glyph positions as towers rotate
|
|
141
149
|
- **Seal Management** - Breaking seals and tracking game state
|
|
150
|
+
- **Seed Parser** - Decode, encode, validate, and compare game seeds
|
|
151
|
+
- **SystemRandom** - C# System.Random PRNG replica for game state prediction
|
|
142
152
|
- **Event Handling** - Callback system for tower events
|
|
143
153
|
- **Logging System** - Multi-output logging for debugging and monitoring
|
|
144
154
|
- **Best Practices** - Performance tips, error handling, and common patterns
|
|
@@ -185,7 +195,7 @@ npm run test:integration:lights
|
|
|
185
195
|
- All lights breathe effect for 3 seconds
|
|
186
196
|
- All lights off
|
|
187
197
|
|
|
188
|
-
See [API_REFERENCE.md](API_REFERENCE.md) for API details on `allLightsOn` and `allLightsOff`.
|
|
198
|
+
See [API_REFERENCE.md](docs/API_REFERENCE.md) for API details on `allLightsOn` and `allLightsOff`.
|
|
189
199
|
|
|
190
200
|
**Prerequisites:**
|
|
191
201
|
|
|
@@ -230,6 +240,9 @@ src/
|
|
|
230
240
|
├── udtCommandQueue.ts # Command queue management
|
|
231
241
|
├── udtTowerResponse.ts # Response handling
|
|
232
242
|
├── udtTowerState.ts # Tower state management
|
|
243
|
+
├── udtGameBoard.ts # Board locations, kingdoms, and terrain data
|
|
244
|
+
├── udtSeedParser.ts # Game seed encoding/decoding (base-34)
|
|
245
|
+
├── udtSystemRandom.ts # C# System.Random PRNG replica
|
|
233
246
|
├── udtHelpers.ts # Utility helper functions
|
|
234
247
|
├── udtLogger.ts # Logging system
|
|
235
248
|
├── udtConstants.ts # Constants and type definitions
|
|
@@ -274,7 +287,7 @@ examples/
|
|
|
274
287
|
- **Sounds** - Sounds show as command complete which is true even though the sound itself has not completed. This is just the way the tower works. I'll have to add time lengths to each at some point, just don't use the command complete response as a way of thinking the associated sound has finished playing and you can play another sound.
|
|
275
288
|
- **Light Sequences** - Same as sound for lights that play for a duration.
|
|
276
289
|
|
|
277
|
-
> See [API_REFERENCE.md](API_REFERENCE.md) for performance best practices and workarounds.
|
|
290
|
+
> See [API_REFERENCE.md](docs/API_REFERENCE.md) for performance best practices and workarounds.
|
|
278
291
|
|
|
279
292
|
## Community
|
|
280
293
|
|