Skip to content

Add native PNG object import and optional tagged asset packs - #17

Closed
arhidavid wants to merge 1 commit into
thekannen:mainfrom
arhidavid:feat/native-image-import
Closed

arhidavid wants to merge 1 commit into
thekannen:mainfrom
arhidavid:feat/native-image-import

Conversation

@arhidavid

Copy link
Copy Markdown
Contributor

Problem and behavior

Dungeondraft can turn a loose PNG dropped onto a map into a normal embedded object, but the MCP does not expose that workflow. import_image now uses the native ObjectTool.EmbedObject mechanism, with explicit centre and dimensions in woxels, rotation, sorting, layer, snapping and optional light blocking. Transparency is preserved, and saved maps contain the image bytes. These are exportable objects, not traces; an asset pack is not required.

For optional reuse, create_image_pack writes native packs with searchable names and tags, and refresh_asset_packs rescans newly written archives through the native Assets window. Existing prepare_map_with_packs includes the chosen pack in a map copy. No separate mod is introduced: this extends the existing bridge.

Implementation

  • Content-addressed staging prevents the native filename cache from returning stale pixels after a source PNG is revised. Import participates in the bridge's create undo/checkpoint handling.
  • PNG validation bounds file size and dimensions, verifies chunks and decodes pixels. The bridge independently checks dimensions before decoding and checks staging-write completion before native import.
  • Pack output is published atomically without overwriting an existing or competing file. The archive includes both the native root registration manifest and the inner pack.json, plus native tags and sets. Tags are normalized before checking the reserved Colorable tag.
  • Adds regression coverage, an explicitly guarded scratch-map live runner, packaging inclusion, and workflow documentation.

Validation

On Windows with Python 3.12, battlemap-mcp 1.4.1, Dungeondraft 1.2.0.1 and Godot 3.4.2:

  • Full server/tools/gate.py passed: formatting, lint, bridge/contract/lifecycle/engine checks, types and tests.
  • tools/release.py check, release-tool lint/format checks and git diff --check passed.
  • Live tests on an explicitly authorized disposable scratch map passed: import with explicit/aspect-preserving sizes, movement, rotation, layer, duplication, undo/redo, checkpoint rollback, save/reopen and DD2VTT export. Rendered output was visually inspected.
  • Confirmed that revised bytes at the same filename create a new embedded texture and identical bytes reuse it; a controlled staging-open failure created no object.
  • A transparent piano was embedded and separately packaged with native descriptive tags. Verified name/tag search, library placement, persistence after reopening, and export. Test objects were rolled back; artwork and maps are not included in this PR.
  • The final bridge was restarted and its authenticated identity matched the reviewed source.

Limits and operational notes

  • Live acceptance is Windows-only; macOS/Linux editor behavior is not claimed. An actual disk-full mid-write failure was not induced.
  • Staged images and native embedded texture entries may remain after undo; staging is not automatically pruned.
  • The pack builder creates complete packs rather than appending to existing third-party archives. New IDs can be rescanned and included without an application restart; already-loaded IDs remain subject to Dungeondraft's native texture cache.
  • Do not move/remove mounted packs until Dungeondraft closes. During test cleanup, moving an invalid early test archive produced a native read error and the editor exited after successful map/export saves. This restriction is now documented. The early missing root-manifest issue is fixed and regression-tested.

Documentation

Adds docs/image-import.md. The public tool reference and asset-pack workflow pages at https://knownframe.com/battlemap-mcp/docs/ need matching updates for these three tools and the optional pack workflow.

@thekannen

Copy link
Copy Markdown
Owner

Thank you, this is a feature people have asked about, and the live testing you did (undo, checkpoints, save and reopen, VTT export, revised bytes) is exactly what this needs.

It's really two features, and I'd like to take them separately:

import_image: yes. It uses Dungeondraft's own drag-and-drop path, stays self-contained in the saved map, and works with the bridge's undo. I'll port it as your commit and test it on macOS, since only Windows has been tried so far. Small things I'll handle in the port unless you'd rather:

  • The bridge builds HashingContext with ClassDB.instance("HashingContext") elsewhere, on purpose, so the script doesn't depend on that class at parse time. I'll match that.
  • Staged images in imported_images are never pruned. I'd like a simple cap, like the capture retention. If you have a view on the right limit, say so.

create_image_pack and refresh_asset_packs: as a follow-up PR, please. A few things I'd want settled first:

  • No-clobber via os.link fails on exFAT, FAT32 and many network shares, which is where large asset libraries often live. Opening the destination with O_CREAT | O_EXCL and writing into it, or a temp file plus a checked rename, would work everywhere.
  • Where it writes. The path comes from the model, so the companion can write a pack anywhere the user can. I'd like it limited to Dungeondraft's configured asset folder, which the companion can already find.
  • refresh_asset_packs. Assets.UpdateTree is new to the bridge. Your notes mention Dungeondraft quitting after a mounted pack was moved during cleanup. I'd want to understand that before exposing a refresh, even if the cause was the move and not the refresh.
  • Three new tools at once makes the server's tool list longer for every session. If the pack builder lands, it may fit better as an option of an existing tool, or behind a clearer workflow. Happy to talk that through.

Same note as on #16: I'll port import_image as a commit authored by you, so you're credited as a contributor, and it ships in the next release. Thanks again.

@thekannen

Copy link
Copy Markdown
Owner

import_image from this PR shipped in 1.4.2, credited to you: a local PNG is embedded in the map, so it survives the original being moved or deleted. Two fixes went in while porting it: a name clash after switching maps that could save the object without its image, and an array sort that could crash Dungeondraft.

I'm leaving this PR open for the pack-builder half (create_image_pack / refresh_asset_packs), whenever you get to it. No rush.

cursor Bot referenced this pull request in arhidavid/battlemap-mcp Nov 13, 2026
Carry forward the pack-builder half of upstream #17 on top of 1.4.2.
Publish with O_CREAT|O_EXCL into Dungeondraft's configured asset folder
only, add one companion tool (no Assets.UpdateTree refresh), and cover
no-clobber and path limits in offline tests.

Co-authored-by: arhidavid <arhidavid@users.noreply.github.com>
@arhidavid arhidavid closed this Nov 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants