diff --git a/GUIDELINES.md b/GUIDELINES.md new file mode 100644 index 0000000..f6f77f4 --- /dev/null +++ b/GUIDELINES.md @@ -0,0 +1,125 @@ +# Project guidelines + +How this project relates to the code, data and trademarks it depends on. Read +this before adding a dependency, shipping anything, or writing anything +user-facing. + +## The one-line summary + +This is a **non-commercial fan project**. Three separate obligations already +force that — MegaMek's asset licence, Microsoft's fan-content rules, and the +BattleTech trademarks — and a fourth (AGPL) requires us to publish our changes. +Nothing here is negotiable by choosing a different architecture. + +## Webswing Lite — read this carefully + +We use **[Webswing Lite](https://github.com/manticore-projects/webswing)**, the +AGPL-3.0 community fork maintained by manticore-projects, continuing from +Webswing v20.2.5 — the last release made under an open-source licence. + +We do **not** use, and have **no affiliation with**, the commercial Webswing +product at [webswing.org](https://www.webswing.org) or the company behind it. +The two are easy to confuse: the fork keeps the repository name `webswing`, its +artifacts are named `webswing-server-*.war`, and its config keys are all +`webswing.*`. None of that implies any relationship. + +- Always write **"Webswing Lite"**, never bare "Webswing", in docs, commits and + anything user-facing. +- The Lite fork's README asks for attribution and a link to webswing.org for the + original architecture. We honour that. +- The distribution zip ships **no LICENSE file**. If we ever redistribute the + bundle, add the AGPL text ourselves. + +### What AGPL-3.0 means for us + +AGPL is GPL plus a network clause (§13): modify it and let people use it over a +network, and you must offer them your modified source. Ordinary GPL has no such +requirement, which is why this distinction matters far more than usual for a +hosted service. + +It is also not cleanly separable. Webswing Lite does not merely proxy a separate +process — it injects into the application JVM: + + -Xbootclasspath/a:...webswing-app-toolkit.jar:...modpatch-java-desktop.jar + --patch-module java.desktop=...modpatch-java-desktop.jar + -Dawt.toolkit=org.webswing.toolkit.WebToolkit11 + -Djava.awt.graphicsenv=org.webswing.toolkit.ge.WebGraphicsEnvironment11 + +MegaMek runs inside a JVM whose `java.desktop` has been patched with Webswing +Lite code. Whether the running combination is one work is a real question, not an +obvious no. + +**How we act on that:** + +1. **Keep the control plane / AppView at arm's length.** Separate process, + network protocol only. Never link Webswing Lite jars into it, and never run + our own code inside the patched app JVM. That boundary is what keeps the + control plane outside AGPL's reach. +2. **Publish this repository** — patches, configs, harness. It costs us nothing + we care about and makes the §13 question moot. +3. We currently **configure** Webswing Lite but do not modify it. If that ever + changes, the modified source must be offered to users over the network. + +## MegaMek + +Two licences, split by content type: + +| | licence | consequence | +|---|---|---| +| code | **GPL-3.0** | modifications must be GPL-3.0 and source provided when distributed | +| data & assets | **CC BY-NC-SA 4.0** | **non-commercial**, attribution, share-alike | + +GPL-3.0 and AGPL-3.0 are compatible — GPLv3 §13 explicitly allows the +combination — so there is no licence conflict, but the AGPL portion keeps its +network clause. + +Note GPL-3.0 alone would *not* reach a hosted service. Running modified MegaMek +on our own servers triggers no disclosure by itself. It is the AGPL dependency, +not MegaMek, that changes this. + +### Our patches + +- Stored as unified diffs in `patches/patchset/`, never as copied source files. +- Every one so far is a **latent MegaMek bug**, not an adaptation to our + environment. They should be offered upstream; an accepted PR costs nothing to + maintain, a carried patch costs something every release. +- `patches/build-patched-jar.sh` never modifies the MegaMek source or release + trees. + +## BattleTech IP + +MegaMek itself operates under **Microsoft's Game Content Usage Rules**, and its +own notices state: + +> MechWarrior, BattleMech, `Mech and AeroTech are registered trademarks of The +> Topps Company, Inc. Catalyst Game Labs and the Catalyst Game Labs logo are +> trademarks of InMediaRes Productions, LLC. MechWarrior Copyright Microsoft +> Corporation. + +Practical rules: + +- **Non-commercial only.** The Game Content Usage Rules and CC BY-NC-SA both + require it, independently. +- **Avoid the marks in our own naming**: BattleTech, BattleMech, 'Mech, + MechWarrior, AeroTech, Alpha Strike, Clan names, Catalyst product names. This + is why the domain is `lance.blue` — generic military vocabulary, no mark. +- Lore vocabulary inside internal identifiers (a `batchall` record type) is lower + risk than in a brand or domain, but keep it out of anything public-facing. +- We ship no BattleTech artwork or unit data of our own; we run MegaMek's, under + MegaMek's terms. + +## Java runtime + +Eclipse Temurin (OpenJDK) — **GPLv2 with the Classpath Exception**. The exception +is what allows normal application use without the GPL propagating to our code. +A `jlink` runtime we build and ship carries the same terms. + +## Checklist for adding a dependency + +1. What is the licence, verified from the artifact or repo — not from a search + result or memory? (This project has already been bitten by exactly that.) +2. Is it AGPL or otherwise network-triggering? +3. Does it require non-commercial use, and does that change anything? +4. Does it run in-process with MegaMek, or at arm's length? +5. Is it easily confused with a commercial product of a similar name — and if so, + is the distinction stated everywhere? diff --git a/README.md b/README.md index 48f2d23..9872fe6 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,17 @@ Feasibility spikes for running MegaMek as the tactical engine behind a browser-based, ATProto-backed campaign game. A 2v2 against Princess plays end-to-end in a browser via Webswing Lite rendering -the stock MegaMek Swing client. See [TODO.md](TODO.md). +the stock MegaMek Swing client. See [TODO.md](TODO.md) for what's next and +[GUIDELINES.md](GUIDELINES.md) for licensing, trademarks and IP. + +> **Webswing Lite, not Webswing.** We use +> [Webswing Lite](https://github.com/manticore-projects/webswing), the AGPL-3.0 +> community fork by manticore-projects continuing from the last open-source +> Webswing release (v20.2.5). We have **no affiliation** with the commercial +> Webswing product at [webswing.org](https://www.webswing.org). The fork keeps the +> upstream repository name, artifact names and `webswing.*` config keys, so the +> two are easy to confuse — credit for the original architecture goes to the +> Webswing team. ## Constraint @@ -38,10 +48,10 @@ Still shared between instances: MegaMek's `mmconf/` (both seed the same `clientsettings.xml`, so identical content) and `logs/`. **One browser per instance; restart the instance between runs, not just the -browser.** Webswing keeps the client JVM alive after the page closes. If a second +browser.** Webswing Lite keeps the client JVM alive after the page closes. If a second client connects while the first holds `TraineeA`, the server renames it `TraineeA.2` — that player owns no units and has no team, so controls are greyed -out and Player Settings throws an NPE. Webswing session settings do not help: +out and Player Settings throws an NPE. Webswing Lite session settings do not help: `maxClients: 1` refuses the second browser, and `CONTINUE_FOR_USER` + `allowStealSession` lets it evict the first and locks out both. @@ -59,10 +69,10 @@ classpath shadowing because the jar is sealed.) Applied, and verified to be the only differences from the stock jar: - **`0001-sound-guard-optional-master-gain-control`** — `Sound.setVolume()` - assumed the optional `MASTER_GAIN` control exists. Webswing's mixer doesn't + assumed the optional `MASTER_GAIN` control exists. Webswing Lite's mixer doesn't provide it, so the client died at startup with an uncaught NPE. - **`0002-extrapanel-use-lightweight-jlabel`** — `ExtraPanel` used a heavyweight - `java.awt.Label`. Webswing supports only lightweight Swing components, so + `java.awt.Label`. Webswing Lite supports only lightweight Swing components, so `createLabel()` threw and aborted the client's `PHASE_CHANGE` handler, leaving it stuck on "Waiting for the server..." forever. - **`0003-clientgui-honour-minimap-enabled-preference`** — `ClientGUI` called @@ -90,7 +100,7 @@ Applied, and verified to be the only differences from the stock jar: - **`units.cache` isn't shipped**: 2.9s to load a prebuilt one vs 20.2s to build it from 10,989 files. Bake it into the image. - **jlink runtime is 59MB** vs 346MB, and runs a 4v4 fine. -- **Headless works** under Webswing — no Xvfb needed. +- **Headless works** under Webswing Lite — no Xvfb needed. ## Layout @@ -99,9 +109,9 @@ Applied, and verified to be the only differences from the stock jar: - `harness/src/spike/` — `HostForHuman` (server + bot, one slot open for a human), `WatchGame` + `TextRenderer` (observer client dumping full text state; the adapter-pattern prototype) -- `spike-webswing/` — Webswing + MegaMek settings templates, `start.sh` +- `spike-webswing/` — Webswing Lite + MegaMek settings templates, `start.sh` - `patches/` — patchset, archive, patched-jar builder -- `scripts/` — `fetch-deps.sh`, `gen-fontconfig.sh` (legacy fontconfig Webswing's +- `scripts/` — `fetch-deps.sh`, `gen-fontconfig.sh` (legacy fontconfig Webswing Lite's toolkit needs), `cdp-screenshot.py`, `summarize.py` - `results/` — bench CSVs and jstacks kept as evidence for Findings diff --git a/TODO.md b/TODO.md index 43bdee9..b036b0e 100644 --- a/TODO.md +++ b/TODO.md @@ -26,7 +26,7 @@ which removed all font-load rejections but fixed nothing. is seeded into `mmconf/` on every launch (MegaMek rewrites it on exit, so once is not enough). Fullscreen works without hardcoding a resolution: a huge stored window size is clamped by `UIUtil.updateWindowBounds()` to the screen union, -which under Webswing is the browser viewport. The unit display is docked +which under Webswing Lite is the browser viewport. The unit display is docked (`UnitDisplayLocation=1`), the keybinds overlay is off to reclaim map area, and the minimap is nudged clear of the left panel. @@ -54,8 +54,8 @@ deployment always blocks. Confirm during a real match. everything, so the page dies with no summary. Decouple "game over" from "process exit" in `HostForHuman`: stay up until the player dismisses the report. -**Webswing chrome is unstyled** — spinner, window decorations and error dialogs -clash with MegaMek. Webswing supports a per-app `webFolder` and decorator +**Webswing Lite chrome is unstyled** — spinner, window decorations and error dialogs +clash with MegaMek. Webswing Lite supports a per-app `webFolder` and decorator theming. **MegaMek defaults look bad** — scale, fonts and skin. `GUIPreferences` plus @@ -76,6 +76,12 @@ allowing only the proxy — avoid NAT (~$33/mo) and interface endpoints (~$15-29/mo). Bake `units.cache` (saves 17.3s cold start) and use a jlink runtime (59MB vs 346MB). +**Licensing follow-through** — Webswing Lite is AGPL-3.0, which unlike plain GPL +reaches a networked service, and it injects into the app JVM +(`-Xbootclasspath`, `--patch-module java.desktop`) rather than staying at +arm's length. Keep the control plane a separate process that never links its +jars, and plan to publish this repo. See [GUIDELINES.md](GUIDELINES.md). + **Security analysis** — not started. The proxy is the auth boundary (MegaMek has no per-player auth); ATProto token custody; user-uploaded camo is decoded by other players' browsers, so sanitise on upload; observers see everything, which @@ -94,7 +100,7 @@ input the model is most sensitive to. Measure a few human 4v4s. - **Upstream both patches** — each is a latent MegaMek bug, not an adaptation. - **Regression-test against a local MegaMek build** *(future, not now)* — today everything is pinned to release 0.51.0. There is no signal for when an upstream - change breaks us: patches failing to apply, the Webswing incompatibilities + change breaks us: patches failing to apply, the Webswing Lite incompatibilities returning, or new heavyweight AWT components appearing. Build MegaMek from source and run the harness plus a scripted browser session against it, so upstream breakage surfaces before a release pins it in.