Set up DOTS + Netcode for Entities foundation

One-time stack setup per Docs/dots-setup-task.md (Unity 6.4.7 / 6000.4.7f1).
Packages: entities 6.4.0, entities.graphics 6.4.0, netcode 1.13.2, physics 1.4.6.

- Assets/_Project asmdef split: ProjectM.Simulation/Client/Server/Authoring (root ns ProjectM)
- GameBootstrap : ClientServerBootstrap; verified separate client + server worlds in Play Mode
- Gameplay subscene wired into SampleScene as a baking target
- Heartbeat component + Burst ISystem; EditMode smoke test green (1/1)
- In-repo Obsidian vault (Docs/Vault) incl. DR-001 (plain-Entities test over internal NetCodeTestWorld)
- Portable .mcp.json (basic-memory + serena via ${CLAUDE_PROJECT_DIR}); CLAUDE.md conventions
- .gitignore for DOTS baking cache + machine-local config

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Luis Gonzalez
2026-05-29 22:06:44 -07:00
parent 25e3493e75
commit 99d8d2d2a9
74 changed files with 1609 additions and 36 deletions
+1
View File
@@ -0,0 +1 @@
{}
+1
View File
@@ -0,0 +1 @@
{}
+33
View File
@@ -0,0 +1,33 @@
{
"file-explorer": true,
"global-search": true,
"switcher": true,
"graph": true,
"backlink": true,
"canvas": true,
"outgoing-link": true,
"tag-pane": true,
"footnotes": false,
"properties": true,
"page-preview": true,
"daily-notes": true,
"templates": true,
"note-composer": true,
"command-palette": true,
"slash-command": false,
"editor-status": true,
"bookmarks": true,
"markdown-importer": false,
"zk-prefixer": false,
"random-note": false,
"outline": true,
"word-count": true,
"slides": false,
"audio-recorder": false,
"workspaces": false,
"file-recovery": true,
"publish": false,
"sync": true,
"bases": true,
"webviewer": false
}
+25
View File
@@ -0,0 +1,25 @@
---
tags:
- moc
- home
updated: 2026-05-29
permalink: gamevault/00-home/home
---
# Project M — Home (Map of Content)
Multiplayer game on **Unity DOTS** (Entities) + **Netcode for Entities** (server-authoritative, client prediction). This vault is the canonical, cross-machine, human-facing record. Code lives in `Assets/_Project/`; engine/API truth comes from **context7**, not this vault.
## Map of Content
- **Vision** → [[Pillars]] — design pillars & locked decisions
- **Game Design** → [[Systems_Index]] — per-system design docs
- **Roadmap** → [[Milestones]] · [[Backlog]]
- **Sessions** → `07_Sessions/2026/` — dated work logs (latest: [[2026-05-29_Project_Setup]])
- **Decisions** → `07_Sessions/_Decisions/` — decision records (DR-###) · [[DR-001_Netcode_Test_Harness]]
- **Meta** → [[Documentation_Protocol]] · [[Tags]]
- **Templates** → [[Session_Log_Template]] · [[Decision_Record_Template]]
## How knowledge is organized
See [[Documentation_Protocol]]. In short: design / decisions / sessions live here (committed to git); **basic-memory** recalls over these notes; **serena** navigates C# symbols; native Claude memory holds machine-local facts; **context7** is the source of truth for DOTS / Netcode APIs.
+24
View File
@@ -0,0 +1,24 @@
---
tags:
- vision
- pillars
status: draft
updated: 2026-05-29
permalink: gamevault/01-vision/pillars
---
# Design Pillars & Locked Decisions
> The few non-negotiables every system must serve. Keep this short; promote only decisions that are truly locked.
## Pillars
- _TBD — define the 35 experiential pillars of Project M._
## Locked decisions
- **Tech stack:** Unity DOTS (Entities) + Netcode for Entities — server-authoritative, input-only clients, client prediction. Established [[2026-05-29_Project_Setup]].
## Related
- Decision records: `07_Sessions/_Decisions/`
@@ -0,0 +1,19 @@
---
tags:
- design
- index
updated: 2026-05-29
permalink: gamevault/02-game-design/systems-index
---
# Systems Design — Index
One design doc per gameplay system, linked here. Each should state: purpose, components (`IComponentData`), systems (`ISystem`), netcode shape (ghost? predicted vs interpolated? inputs / RPCs), and open questions.
## Systems
- _None yet._
## Conventions
DOTS/ECS conventions live in repo `CLAUDE.md` and the `dots-dev` skill's `dots-conventions.md`. Don't duplicate volatile API details here — link to context7-derived notes instead.
+16
View File
@@ -0,0 +1,16 @@
---
tags:
- roadmap
- backlog
updated: 2026-05-29
permalink: gamevault/06-roadmap/backlog
---
# Backlog
Unordered pool of candidate work. Promote to a [[Milestones|milestone]] when committed.
- [ ] Decide whether to upgrade Unity 6.4 → 6.6 for newer Entities (6.6.x). Stack is forward-compatible; `NetCodeTestWorld` stays internal regardless — see [[DR-001_Netcode_Test_Harness]].
- [ ] Define the core gameplay loop and the first predicted player ghost.
- [ ] Replace template `SampleScene` with a dedicated bootstrap scene + gameplay subscene.
- [ ] Optional template cleanup: remove `com.unity.visualscripting`, `Assets/TutorialInfo/`, `Assets/Readme.asset` (delete each asset **with** its `.meta`).
+16
View File
@@ -0,0 +1,16 @@
---
tags:
- roadmap
- milestones
updated: 2026-05-29
permalink: gamevault/06-roadmap/milestones
---
# Milestones
| Milestone | Goal | Status |
|---|---|---|
| **M0 — Foundation** | DOTS + Netcode stack, asmdef split, bootstrap, smoke test green | ✅ Done 2026-05-29 — [[2026-05-29_Project_Setup]] |
| **M1 — _TBD_** | Define the first playable slice (core loop + first predicted ghost) | ⬜ |
Promote items from [[Backlog]] here when committed.
@@ -0,0 +1,36 @@
---
date: 2026-05-29
type: session
tags:
- session
- setup
- dots
- netcode
permalink: gamevault/07-sessions/2026/2026-05-29-project-setup
---
# Session 2026-05-29 — DOTS + Netcode + Memory Stack Setup
One-time project setup per `Docs/dots-setup-task.md`.
## Done
- **DOTS stack** (Unity 6.4.7 / 6000.4.7f1): `com.unity.entities` 6.4.0, `com.unity.netcode` 1.13.2, `com.unity.physics` 1.4.6, `com.unity.entities.graphics` 6.4.0. Console clean. (Entities / Collections / Graphics now track the Editor version → 6.4.0; Netcode / Physics still independent 1.x.)
- **Asmdef split** under `Assets/_Project/Scripts/`: `ProjectM.Simulation` (shared), `ProjectM.Client`, `ProjectM.Server`, `ProjectM.Authoring`. Root namespace `ProjectM`.
- **Bootstrap**: `GameBootstrap : ClientServerBootstrap` (Simulation) → `CreateDefaultClientServerWorlds()`, auto-connect off. Play Mode verified: separate `ServerWorld` (GameServer) + `ClientWorld` (GameClient).
- **Subscene**: `Assets/_Project/Subscenes/Gameplay.unity` wired into `SampleScene` as a baking target.
- **Smoke test**: `Heartbeat` IComponentData + `[BurstCompile] HeartbeatSystem : ISystem`; EditMode test ticks `SimulationSystemGroup` 8× and asserts advance → green (1/1).
- **Vault + memory MCPs + `CLAUDE.md`**: scaffolded.
## Decisions
- [[DR-001_Netcode_Test_Harness]] — smoke test uses a plain-Entities tick test, not the internal `NetCodeTestWorld`.
## Open / deferred
- Unity 6.6 upgrade considered, deferred. Stack is forward-compatible; `NetCodeTestWorld` stays internal regardless of version.
- Optional template cleanup (visualscripting / TutorialInfo / Readme) deferred → [[Backlog]].
## Next
- Define pillars ([[Pillars]]) and the first playable slice ([[Milestones]]).
@@ -0,0 +1,26 @@
---
id: DR-001
title: Netcode smoke/test harness approach
status: accepted
date: 2026-05-29
tags:
- decision
- netcode
- testing
permalink: gamevault/07-sessions/decisions/dr-001-netcode-test-harness
---
# DR-001 — Test harness: plain-Entities over internal NetCodeTestWorld
## Context
Setup (`Docs/dots-setup-task.md` §4) called for a `NetCodeTestWorld` EditMode test. In **Netcode for Entities 1.13.2**, `Unity.NetCode.Tests.NetCodeTestWorld` (assembly `Unity.NetCode.TestsUtils.Runtime.Tests`) is **`internal`**, reachable only via a fixed `[InternalsVisibleTo]` allow-list of Unity's own assemblies. A consumer test can use it only by naming its test assembly to match an entry (e.g. `Unity.NetcodeSamples.EditModeTests`) — effectively impersonating a Unity sample assembly. Research (Unity ECS status, Dec 2025) shows no public consumer test harness on the roadmap, and that this is **unchanged by a Unity 6.6 upgrade** (Netcode stays independent 1.x; only Entities/Collections/Graphics renumber to the Editor version).
## Decision
Use a **plain-Entities EditMode test** as the default test pattern: create a `World`, register the system under test in `SimulationSystemGroup`, tick, assert. Public API only, no assembly-name impersonation, version-independent. Netcode **world boot** is verified separately by the §3 Play Mode check (`GameBootstrap` creates `ServerWorld` + `ClientWorld`).
## Consequences
- Clean, always-green tests with no fragile naming hacks.
- Full client+server **connect+tick** coverage is not provided by this pattern. When needed (ghost/prediction work), revisit per-system: either name a dedicated test asmdef `Unity.NetcodeSamples.EditModeTests` to borrow the IVT grant, or vendor a copy of the netcode test utilities.
@@ -0,0 +1,37 @@
---
tags:
- meta
- protocol
updated: 2026-05-29
permalink: gamevault/meta/documentation-protocol
---
# Documentation Protocol
How knowledge is read and written for Project M. Four layers, each with a distinct job; the **in-repo vault is the single source of human-facing, cross-machine truth**.
## Layers
| Layer | Holds | Crosses machines? |
|---|---|---|
| **This vault** (`Docs/Vault/`) | Design docs, decision records, session logs, roadmap | **Yes** (git) |
| **basic-memory** MCP | Semantic + wikilink recall over these same vault files | Yes (indexes the vault) |
| **serena** MCP | C# symbol navigation of `Assets/_Project/` | N/A (from code) |
| **Native Claude memory** | Machine-local facts / preferences (`memory/`, `MEMORY.md`) | **No** |
**Cross-machine rule:** durable truth → vault or repo `CLAUDE.md` (both committed). Native memory is local-only, never the sole home of a decision or design fact.
## Which tool when
- Where is X defined / who calls it → **serena** (fallback `Grep` / `Glob`).
- What did we decide / how does system Z work → **basic-memory** recall → read the note here.
- Literal string / asset GUID → **Grep / Glob**.
- Current DOTS / Netcode API → **context7** (never memory).
- Conventions / preferences → repo `CLAUDE.md` + native memory.
## Session bookends
- **Start (read-only):** `CLAUDE.md` → [[Home]] + latest session log → open decision records + [[Backlog]] → basic-memory recall on the goal's nouns.
- **End:** write a session log (`07_Sessions/<year>/`) → firm decisions to DR records → edit touched design docs in place (wikilink, don't duplicate) → durable knowledge to basic-memory, machine-local facts to native `MEMORY.md`.
Driven by the `/dots-dev` skill; this scaffold was created by the one-time setup task.
+20
View File
@@ -0,0 +1,20 @@
---
tags:
- meta
- taxonomy
updated: 2026-05-29
permalink: gamevault/meta/tags
---
# Tag Taxonomy
Keep tags few and meaningful.
- `#moc` — map of content / index notes
- `#vision`, `#pillars` — north-star docs
- `#design` — system design docs
- `#roadmap`, `#milestones`, `#backlog`
- `#session` — dated work logs
- `#decision` — decision records (DR-###)
- `#meta` — protocol / taxonomy
- Domain: `#dots`, `#netcode`, `#physics`, `#rendering`, `#testing`
@@ -0,0 +1,25 @@
---
permalink: gamevault/templates/decision-record-template
---
---
id: DR-###
title: <short title>
status: proposed # proposed | accepted | superseded
date: {{date:YYYY-MM-DD}}
tags: [decision]
---
# DR-### — <title>
## Context
_What forced a choice? Constraints, versions, evidence._
## Decision
_What we chose, stated plainly._
## Consequences
_Trade-offs accepted; what to revisit later and when._
@@ -0,0 +1,23 @@
---
permalink: gamevault/templates/session-log-template
---
---
date: {{date:YYYY-MM-DD}}
type: session
tags: [session]
---
# Session {{date:YYYY-MM-DD}} — <title>
## Goal
## Done
## Decisions
- <link any DR-### created this session>
## Open / deferred
## Next
+138
View File
@@ -0,0 +1,138 @@
# One-Time Project Setup Task — DOTS + Netcode + Memory Stack
**This is the separate setup task referenced by the `/dots-dev` skill.** Run it ONCE per project (some steps once per machine — see §0). It installs the DOTS stack, scaffolds the project + vault, wires the memory MCPs, and writes `CLAUDE.md`. After this completes, `/dots-dev` drives feature work; this file is no longer needed (keep it for reference / the second machine).
> **How to run:** open a normal Claude Code session in this project (NOT a worktree — the open Unity Editor + UnityMCP target the live working copy) and say *"Run the DOTS setup task in Docs/dots-setup-task.md."* Work top to bottom; each step has a verification.
> **Conventions reference:** the ECS rules and context7 library IDs live in the skill at
> `~/.claude/skills/dots-dev/references/dots-conventions.md` and `…/context7-libraries.md`
> (Windows: `%USERPROFILE%\.claude\skills\dots-dev\references\`). Use context7 for any current API shape — do not trust memory for DOTS APIs.
> **Cross-platform rule:** never write a machine-specific absolute path (`/Users/...`, `C:\...`) into any committed file. Use `${CLAUDE_PROJECT_DIR}` and repo-relative paths. The vault lives in-repo so it travels via git.
---
## §0 — Per-machine prerequisites (do on EACH machine, once)
- [ ] Install **uv / uvx** (for the `basic-memory` and `serena` MCP servers). macOS: `brew install uv` or the official installer; Windows: the official installer / `winget install astral-sh.uv`.
- [ ] Install the **Obsidian** app and the **obsidian-cli** (the `obsidian-cli` skill drives it). Point Obsidian at `<repo>/Docs/Vault` once it exists (§5).
- [ ] Copy/sync the **`dots-dev` skill** to this machine's user skills dir (`~/.claude/skills/dots-dev/` on macOS, `%USERPROFILE%\.claude\skills\dots-dev\` on Windows). It is path-agnostic — same files on both.
- [ ] Confirm Unity 6.4 opens the project and the **CoplayDev Unity-MCP** bridge connects (`mcpforunity://editor/state``ready_for_tools`).
The repo-committed parts (§1–§6) are done once total; §0 is the only per-machine work.
---
## §1 — Install the DOTS stack
Add these to `Packages/manifest.json` (it is NOT a `.csproj`/`.sln` — editing it is correct) or via UnityMCP `manage_packages(action="add", ...)`. Let UPM resolve the version compatible with Unity 6.4; then pin from `Packages/packages-lock.json`.
- [ ] `com.unity.entities`
- [ ] `com.unity.netcode`**Netcode for Entities** (ECS). NOT `com.unity.netcode.gameobjects`.
- [ ] `com.unity.physics` ← Unity Physics (DOTS), if the game needs collision/triggers
- [ ] `com.unity.entities.graphics` ← renders entities under URP (already on URP 17.4)
(`com.unity.burst`, `com.unity.collections`, `com.unity.mathematics`, `com.unity.transport` come transitively.)
- [ ] `read_console` until clean after the domain reload. **Verify:** `manage_packages(action="list")` shows all four; `packages-lock.json` records the resolved versions.
- [ ] Optional cleanup: the template's `com.unity.visualscripting` and `TutorialInfo`/`Readme.asset` are unused for a DOTS game — remove if you don't want them (delete the asset **and** its `.meta` together).
## §2 — Project structure & asmdefs
Pick a root namespace (e.g. `ProjectM`) and record it in `CLAUDE.md`. Create a Netcode-aware assembly split under `Assets/_Project/`:
```
Assets/_Project/
Scripts/
Simulation/ <Root>.Simulation.asmdef → Entities, Collections, Mathematics, Burst, Unity.Physics, Unity.NetCode
Client/ <Root>.Client.asmdef → Simulation, Entities, Unity.NetCode, Unity.Entities.Graphics
Server/ <Root>.Server.asmdef → Simulation, Entities, Unity.NetCode
Authoring/ <Root>.Authoring.asmdef → Simulation, Entities, Unity.NetCode
Subscenes/
Prefabs/
```
- Shared **Simulation** = components + systems that run in BOTH client and server worlds. Client/Server hold world-specific systems; Authoring holds `…Authoring` MonoBehaviours + `Baker<T>`.
- [ ] **Verify** against the official ECS Samples / Netcode sample layout (context7 ID `/unity-technologies/entitycomponentsystemsamples`) — adjust the split if the current sample differs. Confirm each asmdef compiles (`read_console`).
- Never create/edit `.csproj`/`.sln`; only `.asmdef`.
## §3 — Bootstrap & worlds
- [ ] Add a `ClientServerBootstrap` subclass (confirm exact method names — `CreateClientWorld`/`CreateServerWorld`/`WorldSystemFilter` — via context7 `…com_unity_netcode_…`).
- [ ] Create a minimal subscene so baking has a target.
- [ ] **Verify:** entering Play Mode creates separate client and server `World`s (check the Entities Hierarchy / world dropdown).
## §4 — Smoke test (prove it compiles AND ticks)
- [ ] One trivial unmanaged component (`struct Heartbeat : IComponentData { public int Tick; }`) + one `ISystem`+`[BurstCompile]` that increments it in `SimulationSystemGroup`.
- [ ] One **`NetCodeTestWorld`** EditMode test that boots in-process client+server, connects, ticks N times, and asserts the component advanced. (Get the current `NetCodeTestWorld` API from context7.)
- [ ] **Verify:** `run_tests(mode="EditMode")` → green; console clean of Burst/source-gen errors.
## §5 — In-repo vault
Create `<repo>/Docs/Vault/` via the `obsidian-cli` skill (plain markdown is fine if obsidian-cli isn't set up yet):
```
Docs/Vault/
00_Home/Home.md (Map of Content)
01_Vision/ (pillars, locked decisions)
02_Game_Design/ (systems design docs)
06_Roadmap/{Milestones,Backlog}.md
07_Sessions/<year>/ (session logs)
07_Sessions/_Decisions/ (decision records, DR-001…)
_Templates/{Session_Log,Decision_Record}_Template.md
_Meta/{Documentation_Protocol,Tags}.md
```
- [ ] Point the Obsidian app at this folder as a vault.
- [ ] **Verify:** obsidian-cli can list/read a note here.
## §6 — Memory MCPs (`.mcp.json`, committed, portable)
Create `<repo>/.mcp.json` (or merge into existing) using `${CLAUDE_PROJECT_DIR}` so it loads unchanged on both machines:
```json
{
"mcpServers": {
"basic-memory": {
"command": "uvx",
"args": ["basic-memory", "mcp"]
},
"serena": {
"command": "uvx",
"args": ["--from", "git+https://github.com/oraios/serena",
"serena", "start-mcp-server",
"--context", "ide-assistant",
"--project", "${CLAUDE_PROJECT_DIR}"]
}
}
}
```
- [ ] Configure **basic-memory**'s project to point at the vault: `basic-memory project add gamevault "<repo>/Docs/Vault"` (and set it default), per basic-memory's current docs. **Verify:** a semantic recall returns a hit on a vault note.
- [ ] Run **serena** onboarding; test `find_symbol` on the §4 smoke-test system.
- ⚠️ **Serena C# caveat:** its language server is flaky on Unity (auto-installs the wrong .NET, `.sln` load timeouts). If `find_symbol` errors/stalls, record it in `CLAUDE.md` and **fall back** to `Glob`/`Grep` — or add **`claude-context`** (local LanceDB vector index over `Assets/` + the vault) as the documented code-search fallback. Prefer local embeddings (FastEmbed/Ollama) to keep game code off third-party APIs.
- [ ] **Verify:** `.mcp.json` contains no machine-specific absolute paths (only `${CLAUDE_PROJECT_DIR}`), so it loads on the other machine as-is.
## §7 — `CLAUDE.md` (repo root, committed)
Write `<repo>/CLAUDE.md` covering:
- [ ] Project root namespace + the asmdef split from §2.
- [ ] The **DOTS/ECS conventions** (summarize / link the skill's `dots-conventions.md`): `ISystem`+Burst default, unmanaged `IComponentData`, `IEnableableComponent`, baking, jobs+allocators, ECB for structural changes, determinism (no wall-clock in predicted sim), server-authoritative + input-only clients, `[GhostField]`/ghost authoring. **Aspects deprecated (1.4).**
- [ ] Guardrails (still valid from classic Unity): never edit `.meta` independently of its asset; never read/write `Library/`, `Temp/`, `obj/`, `Logs/`, `UserSettings/`; never edit/commit `.csproj`/`.sln`; no edits during Play Mode.
- [ ] **"Which memory tool when"**: serena = C# symbols, basic-memory = design knowledge over the vault, grep = literals, context7 = current DOTS APIs, native memory = machine-local facts.
- [ ] **Cross-machine rule:** durable/cross-machine truth goes in the in-repo vault or `CLAUDE.md` (both committed); native `memory/` is machine-local and does NOT sync.
## §8 — Native memory seed (machine-local)
- [ ] Append to `MEMORY.md` (this machine): project uses Unity DOTS + Netcode for Entities; the chosen memory stack (vault + basic-memory + serena, claude-context fallback); that `/dots-dev` is the dev driver and this setup is one-time. (Repeat on the other machine, or re-derive from `CLAUDE.md`.)
---
## Done-when
- All four DOTS packages installed, console clean, smoke-test `NetCodeTestWorld` green.
- `Assets/_Project` asmdef split compiles; client+server worlds spin up.
- Vault scaffolded; obsidian-cli reads it; basic-memory recalls a note; serena resolves a symbol (or fallback recorded).
- `CLAUDE.md` + committed `.mcp.json` (portable) exist.
- Second machine reproduces from §0 alone (everything else is in git).