Split the emulator into core, headless and desktop Maven modules - #34
Merged
Conversation
`NESPalette` is a table of ARGB integers and `Palettes` reads files; neither has ever imported Swing, and both were only under `ui` because the window was the first thing to want them. The headless mode has wanted them for as long as it has existed, which is why CLAUDE.md carried a carve-out saying so. They move to `mynes.palette`, which is where the next commit needs them: with the core in a module of its own, a front end reaching down for a palette is fine and the core reaching up for one is a cycle. `PaletteDialog` stays behind in `mynes.ui` next to `GameUIFrame`, its only caller, rather than leaving a one-class package where the tables used to be. The carve-out goes with them. Nothing outside `mynes.ui` imports it now. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The boundary was a convention: CLAUDE.md asked that nothing in the console or the command line reach into the window, and only a reader enforced it. It is three Maven modules now, so a chip that wants a JFrame does not compile. mynes-core the console and the picture it makes; nothing at compile scope mynes-headless the command line; core mynes-desktop the window and Main; core, headless, FlatLaf, MigLayout Desktop depends on headless rather than the reverse because Main is the one way into either mode, which is also why the fat jar and the release zip are built there. They move with it: `mynes-desktop/target/mynes.jar`, and the same for the zip, which every document and both workflows now name. Two paths had to move rather than merely be renamed. The Harte fixtures go to mynes-core/testdata, because HarteCaseLoader resolves them relative to wherever Surefire runs and that is the module now -- and getting it wrong is silent, a quiet fall back to the committed 500-case subset. And two cartridges are copied into the headless module, which needs a path on disk to hand to --rom rather than a resource on the class path. Nothing about the emulation changed. Against the jar built before the split, the same 400 frames of nestest give an identical save state, identical RAM, OAM, palette, nametable, PRG-RAM and CHR dumps, an identical PNG and an identical WAV, on the same CPU cycle. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…at the ROM The exec configuration lives in mynes-desktop now, and a goal invoked from the command line is invoked on every project in the reactor -- so the short command died on the parent before it reached the module that could serve it. Naming the module on the command line does not help: -am pulls the parent back in, and without -am a fresh clone has nothing to resolve mynes-core against. So the other three declare the plugin skipped instead, and both commands stay as short as they were. Skipped and given an executable, which looks redundant and is not: `executable` is a required parameter, so Maven refuses the goal while injecting it, before the mojo has run far enough to notice it was told to skip. The execution id has to be spelled out too -- `exec:exec@headless` on a project with no execution of that name runs with an empty configuration rather than with the plugin's. The forked process also gets an explicit working directory, the checkout rather than the module, so that a --rom path means what it looks like and the report still lands in target/headless beside the other target directories. .conductor/settings.toml keeps both commands unchanged and follows nestest to mynes-core/src/test/resources. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The emulator is three Maven modules now —
mynes-core(the console, with no compile-scope dependencies at all),mynes-headless(the command line) andmynes-desktop(the Swing window, FlatLaf and MigLayout) — so the rule that the console and the CLI must not reach into the window is enforced by the class path rather than by a sentence in CLAUDE.md. The palette tables moved frommynes.ui.palettedown intomynes.palettein the core, since both front ends draw with them and neither owns them, whilePaletteDialogstayed behind inmynes.ui. The jar and the release zip now build undermynes-desktop/target/, which the docs, both workflows, all four scripts and.conductor/settings.tomlfollow, and the Harte fixtures move tomynes-core/testdatabecause Surefire resolves that path relative to the module rather than the checkout. The parent declaresexec-maven-pluginskipped — with an executable named, since Maven refuses the goal while injecting that required parameter before the mojo can notice the skip — somvn -q compile exec:execandexec:exec@headlessstill work unqualified from the root.Nothing about the emulation changed: against a jar built before the split, 400 frames of nestest give a byte-identical save state, memory dumps, PNG and WAV on the same CPU cycle, all 1567 tests pass (1348/120/99 across the modules), and the distribution smoke test still finds 12 palettes in the zip.
🤖 Generated with Claude Code