This commit is contained in:
2026-07-04 18:03:35 +02:00
parent 605d0e73b4
commit e0fdf2ff16
8 changed files with 488 additions and 52 deletions
+81 -27
View File
@@ -15,10 +15,12 @@ Blender, so they're directly testable.
| File | Role | Needs Blender? |
|---|---|---|
| `tiles.py` | **Single source of truth**: 40-tile table, 12 materials, the 12×12 test map, and all pure derivations (paint / height / walkmesh quads / `.set` corner+crosser mapping). `PREFIX=twu01`. | no |
| `build.py` | Builds `westgate_urban_foundation_mvp.blend` — 40 tile collections (`VIS_`/`WOK_`/`BLOCK_` + edge custom props), `TILE_EDGE_METADATA` text block, `PREVIEW_tile_library_grid`, `PREVIEW_12x12_test_district`. | yes (4.0.2) |
| `export_mdl.py` | Real NWN export via **Neverblender** → 40 `.mdl` + 40 `.wok` (AuroraBase `tile`/`dummy`, `trimesh`, one `aabb` walkmesh; correct surfacemats). | yes + addon |
| `make_wok.py` | Pure-Python ASCII `.wok` emitter (verts+faces+surfacemat+AABB tree). Fallback when Neverblender absent — format **validated identical** to Neverblender's output. | no |
| `make_set.py` | First-pass `twu01.set` (INI, **CRLF**) from the tile grammar. | no |
| `build.py` | Builds `westgate_urban_foundation_mvp.blend` — 40 tile collections (`VIS_`/`WOK_`/`BLOCK_` + edge custom props), `TILE_EDGE_METADATA` text block, `PREVIEW_tile_library_grid`, `PREVIEW_12x12_test_district`. Editable preview only (quads OK — the exporters triangulate). | yes (4.0.2) |
| `make_mdl.py` | **Shipping model path.** Pure-Python `.mdl` + `.wok` + solid-colour `.tga`: faces triangulated, one `trimesh` node **per texture** (each with `bitmap`+`tverts`), embedded `aabb` walkmesh. | no |
| `make_itp.py` | `twu01palstd.itp` (GFF `ITP ` via `nwn_gff`) — the palette the toolset needs to register the set. | no (needs `nwn_gff`) |
| `make_wok.py` | Pure-Python ASCII `.wok` emitter (verts+faces+surfacemat+AABB tree); shared `aabb_node()` reused by `make_mdl`. | no |
| `make_set.py` | `twu01.set` (INI, **CRLF**) from the tile grammar; field order/values mirror stock. | no |
| `export_mdl.py` | _Alt path, not shipped._ Neverblender export — **flattens** multi-material tiles to one unloadable material, so superseded by `make_mdl.py`. | yes + addon |
`flake.nix` exposes these as apps + a dev shell (pinned **Blender 4.0.2**,
`neverwinter-nim`, `cleanmodels`).
@@ -27,26 +29,41 @@ Blender, so they're directly testable.
```sh
cd wgt01
nix run .#build -- out.blend # 1. Blender tile library
nix run .#export -- out.blend mdl/ # 2. real .mdl + .wok (Neverblender)
nix run .#set -- twu01.set # 3. first-pass .set (CRLF)
# nix run .#wok -- wok/ # ASCII .wok fallback only (export_mdl preferred)
nix run .#mdl -- mdl/ # .mdl + .wok + .tga (shipping models)
nix run .#set -- twu01.set # twu01.set (CRLF)
nix run .#itp -- twu01palstd.itp # palette (needs nwn_gff)
nix run .#build -- out.blend # optional: editable .blend preview
# nix run .#export -- out.blend mdl/ # alt Neverblender path (flattens materials)
```
## Verified (2026-07-04)
- **build**: 40 collections, 144/144 district cells placed, 0 skipped, 12 materials.
- **export**: 40 `.mdl` + 40 `.wok`. Surfacemats correct — CP1 all `wok_Stone`(4),
CN1 all `wok_Nonwalk`(7), BR_1/CE_S walkable+blocker mixed. `.mdl` has
`newmodel twu01_cp1`, `classification TILE`, AuroraBase name == resref.
- **Neverblender**: enabled + working **headless** via the flake's
`blender-4.0.2 --background`, reading `~/.config/blender/4.0` (same config as
the interactive session). Surfacemat = walkmesh face **material slot index**
after `nvb_utils.create_wok_materials(mesh)` — not the material name.
- **`.set`**: CRLF (1224/1224 lines), 40 tiles, 3 terrains (`cobble`/`raised`/
`canal`), 2 crossers (`ramp`/`canal_edge`). Corners/heights derive from each
tile's N/E/S/W edge grammar; ramp N-corners → height 1, canal edges →
`canal_edge` crosser, non-walkable tiles → `PathNode=N`.
- **models (`make_mdl`)**: 40 `.mdl` + 40 `.wok` + 12 `.tga`. Each `.mdl` has
`newmodel`, `classification TILE`, AuroraBase name == resref, one `trimesh`
**per texture** with `bitmap`+`tverts` (tris), and the embedded `aabb`
walkmesh. E.g. `st_s` → 3 trimesh nodes (swlk/curb/wcob); `cp1` → 1 with
`bitmap twu01_wcob`. Walkmesh surfacemats: 4 (`wok_Stone`, walkable) / 7
(`wok_Nonwalk`). Matches the stock `trs02` tile structure field-for-field.
- **`.itp`**: `twu01palstd.itp` round-trips through `nwn_gff``ITP ` type,
40 named entries. Names render, but the **structure is wrong** (flat folder of
raw tile resrefs → unplaceable, no Terrain/eraser folder). See Diagnosis below;
needs a rebuild to the 3-folder Terrain/Features/Groups shape.
- **`.set`**: CRLF, 40 tiles, 3 terrains (`cobble`/`raised`/`canal`), 2 crossers
(`ramp`/`canal_edge`). `Version=V1.0`, stock field order (`WalkMesh=msb01`,
lights=1, `VisibilityNode=A`, `ImageMap2D` last). Corners/heights from each
tile's N/E/S/W edge grammar; non-walkable tiles → `PathNode=N`.
- **install path**: `~/Documents/Neverwinter Nights/development` is a symlink to
`~/.local/share/Neverwinter Nights/development` (the toolset's real dir); one
`nix run .#dev-install` stages all 94 loose files there.
### Why the models were rebuilt (2026-07-04, pass 2)
The Neverblender export produced tiles the toolset couldn't load — **no `tverts`,
no `bitmap`, a dangling `materialname` (>16 chars, no `.mtr`)** — and it
**flattened** each multi-material tile to a single arbitrary material. NWN needs
UV'd, bitmapped, one-texture-per-node trimeshes. Fixed by generating the `.mdl`
in pure Python (`make_mdl.py`) with full control, plus the required
`twu01palstd.itp`. Symptom that surfaced it: blank tileset name + "could not
create area" in the New Area wizard.
## Testing in the toolset — no `.hak` needed
@@ -68,9 +85,9 @@ validated.)
- **PathNode** is a placeholder (`A` walkable / `N` non-walkable) — verify creature
routing per tile shape in the toolset; real pathnode letters matter.
- **No `.itp` palette** yet — tiles may not appear in the toolset palette tree
until one is authored (GFF; `neverwinter-nim`'s `nwn_gff`). The `.set` still
loads for area creation.
- **Textures are flat solid-colour `.tga`s** (one per material, KICKOFF "geometry
not art"). They double as an in-toolset grammar read-out; swap in real art
later without touching geometry.
- **No minimaps** — `ImageMap2D` refs exist in the `.set` but the `.tga`s don't
(skipped by decision; Westgate doesn't use them).
- **Substitutions**: `RA_C` = straight-ramp geometry; `STA` = smooth ramp WOK
@@ -85,9 +102,46 @@ wgt01-tileset-kit` to promote). Commits:
- `60af184` — build guide + 40-tile generator kit
- `1284f15` — real `.mdl`/`.wok` export via Neverblender
## Diagnosis 2026-07-04 — palette names show but nothing paints
Tiles now carry names, but they're **not selectable/paintable**, and the standard
**Terrain** section (paint terrains + eraser, Raise/Lower) is missing. Root cause,
confirmed against the working `wut01palstd.itp` + `wut01.set` (see ../AGENTS.md
§2.3 for the full model):
- The toolset has **two placement systems** and our `.itp` uses neither correctly.
Ground is laid by **Paint Terrain** (the toolset corner-matches and auto-picks
the model); the palette only **click-places `[GROUP#]`-backed prefabs**. It never
places raw tile models.
- Our `.itp` is **one flat folder of 40 raw tile resrefs**, no Terrain folder, no
`eraser`, and the `.set` has **`[GROUPS] Count=0`**. So: none of the 40 entries is
a feature/group → unplaceable; and with no Terrain folder there's no paint/eraser
UI. `wut01` (123 tiles) lists only its **21 groups** in the palette and paints the
rest as terrain; its `PRIMARY/SECONDARY RULES` are `Count=0`, so rules aren't the
blocker.
**The real palette (verified):** `MAIN` = 3 category structs `{ID, STRREF folder
label, LIST}`; leaves `{NAME, RESREF}`. Folder 8282 = **Terrain** (leaf RESREF =
terrain/crosser *name*, plus a magic `eraser` leaf STRREF 63291); 63261 =
**Features** (1×1, RESREF = first-tile resref); 63262 = **Groups** (N×M).
## Next passes
1. Author `twu01palstd.itp` palette so tiles show in the toolset palette tree.
2. Walk-test in the toolset (`nix run .#dev-install`) → tune PathNodes, crossers,
corner terrains.
3. Pack `.hak` (`nwn_erf`) once validated.
1. **Rebuild `make_itp.py` + `make_set.py` to the real structure** (../AGENTS.md
§2.3):
- `.itp`: a **Terrain** folder (each `tiles.TERRAINS`/`CROSSERS` by name + an
`eraser` leaf) so terrain-painting + eraser exist; a **Features** folder with a
1×1 entry per tile we want click-placeable.
- `.set`: add `[GROUP#]` (1×1 feature) entries backing those Features leaves
(`Name` == palette NAME, `Tile0` == that tile's index).
- Then in the toolset lay ground via **Paint Terrain** (cobble/raised/canal), not
by clicking tiles.
2. Walk-test → tune PathNodes, crossers, corner terrains; add a tileset TLK if
we later want localized palette names (local `NAME` strings suffice for now).
3. **Textures (art pass, separate note).** Source assets live in
`/home/vicky/Blender/` (e.g. `textures/`, `PBR_Procampur/`, `td_floor/`,
`new_floors/`, `pd textures main lib/`). Map each `MAT_*` in `tiles.TEXTURES`
to a chosen texture, replacing the flat solid-colour `.tga`s. **Downscale to
≤2k** — NWN handles 4k textures poorly (perf/artifacts). Geometry is
unaffected; only the `.tga`/material path changes.
4. Pack `.hak` (`nwn_erf`) once validated.