Skip to content

Commit ef221a8

Browse files
committed
v4.0.0
1 parent caef591 commit ef221a8

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

51 files changed

+658
-1984
lines changed

.cursor/settings.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{}

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,3 +98,5 @@ Motely.API/wwwroot/jammy-seed-finder/main.js
9898
/Motely.API/wwwroot/jammy-seed-finder
9999
/motely-node
100100
/JamlFilters
101+
/Motely.HomeControlAPI/wwwroot
102+
Motely.HomeControlAPI/Properties/launchSettings.json

AGENTS.md

Lines changed: 57 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -4,20 +4,34 @@
44

55
A .NET library + WASM/Node packages for Balatro seed analysis. It predicts what items, jokers, tags, vouchers, etc. a given seed will produce using Balatro's PRNG system.
66

7-
## Architecture: Two Paths
7+
## Architecture: Two Thin Hosts, One Brain
88

99
```
10-
motely-wasm/ ← Browser WASM output (published to npm)
10+
JS (browser) → Bootsharp → IMotelyWasmBackend → MotelyWasmBackend → MotelySearchOrchestrator
11+
JS (node) → Node-API → MotelyNodeExports → MotelySearchOrchestrator
12+
```
13+
14+
```
15+
motely-wasm/ ← Browser WASM output (published to npm, Bootsharp bundle)
1116
motely-node/ ← Node.js native addon output (published to npm)
1217
```
1318

14-
Both are **OUTPUT DIRECTORIES**. They are populated by the build/pack/publish pipeline.
19+
Both are **OUTPUT DIRECTORIES**. They are populated by `build-and-pack.ps1`.
20+
21+
### The Layering Rule
22+
23+
```
24+
Platform hosts (WASM/Node) → MotelySearchOrchestrator → Motely (core library)
25+
thin interop only all search logic don't touch
26+
```
27+
28+
- `MotelyWasmBackend` builds `MotelySearchRequest`, manages `MotelySearchSession`, wires Bootsharp events, calls `MotelySearchOrchestrator` directly.
29+
- `MotelyNodeExports` builds `MotelySearchRequest`, calls `MotelySearchOrchestrator` directly.
30+
- There is NO intermediate static class. If you feel the urge to create a "shared interop API" between the two hosts, stop. They both call the orchestrator.
1531

1632
### DO NOT EDIT these directories:
1733
- `motely-wasm/` — generated output
1834
- `motely-node/` — generated output
19-
- `motely-wasm/index.js` — generated
20-
- `motely-node/index.cjs` — generated
2135

2236
### DO NOT EDIT core Motely library files:
2337
- `Motely/MotelySingleSearchContext*.cs` — core PRNG engine, not ours
@@ -27,29 +41,47 @@ Both are **OUTPUT DIRECTORIES**. They are populated by the build/pack/publish pi
2741

2842
### Files YOU should edit:
2943
- `Motely/MotelyGameplayState.cs` — our game state wrapper
30-
- `Motely.Orchestration/MotelyExports.cs` — shared export logic (handle management, API)
31-
- `Motely.BrowserWasm/MotelyWasmExports.cs` — thin `[JSExport]` wrappers calling MotelyExports
32-
- `Motely.NodeAddon/MotelyNodeExports.cs` — thin Node-API wrappers calling MotelyExports
44+
- `Motely.Orchestration/MotelySearchOrchestrator.cs` — all search logic lives here
45+
- `Motely.Orchestration/MotelySearchSession.cs` — browser instance handles / cancellation
46+
- `Motely.BrowserWasm/Interop/` — Bootsharp interfaces + implementation (calls orchestrator)
47+
- `Motely.NodeAddon/MotelyNodeExports.cs``[JSExport]` boundary (calls orchestrator)
3348
- `Motely/Analysis/` — analyzer and DTOs
3449

35-
## The Layering Rule
50+
## Browser WASM: Bootsharp
3651

37-
```
38-
Platform-specific (WASM/Node) → MotelyExports (orchestration) → Motely (core library)
39-
thin wrappers all shared logic don't touch
52+
The browser build uses [Bootsharp](https://bootsharp.com) with `Microsoft.NET.Sdk` (not `Sdk.WebAssembly`).
53+
54+
- `IMotelyWasmBackend``[JSExport]` interface, auto-generates JS bindings + TypeScript types
55+
- `IMotelyJsUi``[JSImport]` interface, events pushed from .NET to JS (`NotifySearchProgress`, `NotifySearchResult`)
56+
- `Program.cs` — DI wiring: `AddBootsharp()` + `AddSingleton<IMotelyWasmBackend, MotelyWasmBackend>()` + `RunBootsharp()`
57+
- `Motely.BrowserWasm.csproj` has a `BootsharpLLVM` flag (currently `false`) for future NativeAOT-LLVM
58+
59+
Bootsharp output lands in `Motely.BrowserWasm/bin/bootsharp/`. The stage script copies it to `motely-wasm/bootsharp/` (and `bootsharp_st/` for single-thread).
60+
61+
## Build Pipeline
62+
63+
```powershell
64+
./build-and-pack.ps1 # auto-bumps patch version, builds ST+MT WASM, stages, packs both npm packages
4065
```
4166

42-
WASM and Node exports must be **one-liner pass-throughs** to `MotelyExports`. All logic lives in orchestration. Never duplicate logic across WASM and Node.
67+
The script:
68+
1. Bumps patch version in `Directory.Packages.props` + both `package.json` files
69+
2. Publishes single-thread WASM → stages to `motely-wasm/bootsharp_st/`
70+
3. Publishes multi-thread WASM → stages to `motely-wasm/bootsharp/` (falls back to ST copy if MT fails)
71+
4. Runs `npm pack` for motely-wasm
72+
5. Builds linux-x64 Node addon via Docker
73+
6. Runs `npm pack` for motely-node
74+
7. Prints 3 copy-paste blocks: `npm login`, publish wasm, publish node
4375

4476
## Key Concepts
4577

4678
### Streams Are Doubles
4779

48-
Every PRNG stream's state is ultimately a `double`. `MotelySinglePrngStream(double state)` wraps it. Higher-level streams (ShopItemStream, TarotStream, etc.) compose multiple PrngStreams. Each call to get the next item advances the double. That's it.
80+
Every PRNG stream's state is ultimately a `double`. `MotelySinglePrngStream(double state)` wraps it. Higher-level streams compose multiple PrngStreams. Each call to get the next item advances the double.
4981

5082
### ref struct vs struct
5183

52-
Some stream types are `ref struct` (stack-only, cannot be stored on the heap). Others are plain `struct`. When you need to store a `ref struct` as a class field, decompose its fields into a storage struct (they're just doubles and strings), then reconstruct on demand. See `StreamCache` in `MotelyGameplayState.cs`.
84+
Some stream types are `ref struct` (stack-only, cannot be stored on the heap). When you need to store a `ref struct` as a class field, decompose its fields into a storage struct (they're just doubles and strings), then reconstruct on demand. See `StreamCache` in `MotelyGameplayState.cs`.
5385

5486
Do NOT change `ref struct` to `struct` in core Motely files. Work around it.
5587

@@ -63,7 +95,7 @@ Do NOT change `ref struct` to `struct` in core Motely files. Work around it.
6395

6496
### One Ante At A Time
6597

66-
The game state represents sequential gameplay. One ante at a time. When the ante changes, reset streams. Do NOT use `Dictionary<int, StreamType>` to cache per-ante. Think fibonacci: hold (a, b), advance. Don't cache every step.
98+
The game state represents sequential gameplay. One ante at a time. When the ante changes, reset streams. Do NOT use `Dictionary<int, StreamType>` to cache per-ante.
6799

68100
### MotelyGameplayState IS the Single Seed Context
69101

@@ -72,13 +104,14 @@ It's a stateful object that wraps `MotelySingleSearchContext` for one seed. You
72104
## Common Pitfalls
73105

74106
1. **"Let me redesign the architecture"** — No. Make the minimal fix. Use what exists.
75-
2. **"Let me wrap the analyzer output"** — No. The analyzer pre-computes a fixed set. GameState is infinite scroll.
76-
3. **"Let me add a Dictionary for caching"** — No. One ante at a time. Direct fields, reset on ante change.
77-
4. **"Let me create a new search/filter"** — No. The parked filter IS the mechanism. Use it.
78-
5. **"Let me edit MotelySingleSearchContext"** — No. Use Motely. Don't edit it.
79-
6. **"Let me edit the output JS/CJS files"** — No. They're build output.
80-
7. **"These stream types should be struct not ref struct"** — Don't change core Motely types. Write storage wrappers if needed.
81-
8. **"Let me hand-roll PRNG logic"** — No. Motely already provides high-level stream interfaces. Use them.
107+
2. **"Let me add a shared interop API class"** — No. Both hosts call orchestrator directly.
108+
3. **"Let me wrap the analyzer output"** — No. The analyzer pre-computes a fixed set. GameState is infinite scroll.
109+
4. **"Let me add a Dictionary for caching"** — No. One ante at a time. Direct fields, reset on ante change.
110+
5. **"Let me create a new search/filter"** — No. The parked filter IS the mechanism. Use it.
111+
6. **"Let me edit MotelySingleSearchContext"** — No. Use Motely. Don't edit it.
112+
7. **"Let me edit the output JS/CJS files"** — No. They're build output.
113+
8. **"These stream types should be struct not ref struct"** — Don't change core Motely types.
114+
9. **"Let me hand-roll PRNG logic"** — No. Motely provides high-level stream interfaces. Use them.
82115

83116
## Build
84117

@@ -87,7 +120,7 @@ dotnet build Motely.BrowserWasm/Motely.BrowserWasm.csproj
87120
dotnet build Motely.NodeAddon/Motely.NodeAddon.csproj
88121
```
89122

90-
Build/pack/publish is handled by the user's pipeline. Don't run publish commands.
123+
Build/pack/publish is handled by `build-and-pack.ps1`. Don't run publish commands.
91124

92125
## Testing Reference
93126

Directory.Packages.props

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,15 @@
11
<Project>
22
<PropertyGroup>
33
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
4-
<MotelyVersion>3.20.0</MotelyVersion>
4+
<MotelyVersion>4.0.1</MotelyVersion>
55
</PropertyGroup>
66
<ItemGroup>
7+
<PackageVersion Include="Bootsharp" Version="0.7.0" />
8+
<PackageVersion Include="Bootsharp.Inject" Version="0.7.0" />
9+
<PackageVersion Include="Microsoft.Extensions.DependencyInjection" Version="10.0.0" />
10+
<PackageVersion Include="Microsoft.DotNet.ILCompiler.LLVM" Version="7.0.0-preview.4.23073.1" />
11+
<PackageVersion Include="runtime.win-x64.Microsoft.DotNet.ILCompiler.LLVM" Version="7.0.0-preview.4.23073.1" />
12+
<PackageVersion Include="runtime.linux-x64.Microsoft.DotNet.ILCompiler.LLVM" Version="7.0.0-preview.4.23073.1" />
713
<PackageVersion Include="Microsoft.JavaScript.NodeApi" Version="0.9.19" />
814
<PackageVersion Include="Microsoft.JavaScript.NodeApi.Generator" Version="0.9.19" />
915
<PackageVersion Include="McMaster.Extensions.CommandLineUtils" Version="4.1.1" />

Motely.API/Properties/launchSettings.json

Lines changed: 0 additions & 15 deletions
This file was deleted.

Motely.API/package-lock.json

Lines changed: 0 additions & 19 deletions
This file was deleted.

0 commit comments

Comments
 (0)