Skip to content

Add character tokens to the map and Group Manager - #562

Open
Sunnyl75 wants to merge 3 commits into
MUME:masterfrom
Sunnyl75:feature/map-tokens-only
Open

Sunnyl75 wants to merge 3 commits into
MUME:masterfrom
Sunnyl75:feature/map-tokens-only

Conversation

@Sunnyl75

@Sunnyl75 Sunnyl75 commented Oct 7, 2026 •

Copy link
Copy Markdown

This PR adds configurable character token images to the map and Group Manager.

Token on Map and in GM

It includes token image lookup and fallback, per-character image overrides, adjustment of icon and row size in Group Manager, immediate updates when tokens or their size change, and rendering that keeps the map’s coloured character square from tinting the token.

It need not be set to default to be active in either Group manager or on the map.

Token images are square .png files and respect alpha channels. A "tokens" folder sits with the "areas" and "pixmaps" folders and is scanned on startup for files. It has a fallback from a modding folder to an internal tokens folder (this has not been added and need not be within Mmapper) to the regular char-select image.

Selected tokens will be remembered for characters and npcs matched against names.

Preferences GM  menu

I do have a set of tokens that covers most character types and npcs you may group with, though this isn't included. It could be if you want. Am working on an updated set that is cleaner and uses alphas.

Summary by Sourcery

Add configurable character token support to map and Group Manager views.

New Features:

  • Add configurable character token images to the map and Group Manager, including per-character overrides and fallback images.
  • Add token asset discovery from configurable and packaged resource directories with live refresh support.

Enhancements:

  • Add preferences for enabling map and Group Manager tokens and controlling token icon size.
  • Refresh token rendering and layout immediately when token assets, overrides, or related settings change.
  • Preserve character color indicators while rendering token images with transparency.

@sourcery-ai

sourcery-ai Bot commented Oct 7, 2026 •

Copy link
Copy Markdown

Reviewer's Guide

This PR introduces a TokenManager-backed token asset pipeline with normalized lookup, layered fallbacks, per-character overrides, filesystem-driven refresh, and GL texture caching; it then integrates tokens into both map rendering and Group Manager with independent visibility controls, configurable sizing, context-menu selection, persistence, and immediate UI/map updates.

Sequence diagram for token rendering on the map

sequenceDiagram
    participant MapCanvas
    participant CharacterBatch
    participant TokenManager
    participant OpenGL

    MapCanvas->>CharacterBatch: drawCharacter(coordinate, color, fill, dispName)
    CharacterBatch->>TokenManager: overrideFor(dispName)
    CharacterBatch->>CharacterBatch: canonicalTokenKey(dispName)
    MapCanvas->>CharacterBatch: reallyDrawCharacters(OpenGL, textures)
    CharacterBatch->>TokenManager: processPendingTextureChanges(OpenGL)
    CharacterBatch->>TokenManager: textureIdFor(key)
    alt texture is not cached
        CharacterBatch->>TokenManager: getToken(key)
        CharacterBatch->>TokenManager: uploadNow(key, pixmap)
    end
    CharacterBatch->>TokenManager: textureById(id)
    CharacterBatch->>OpenGL: renderColoredTexturedQuads(token quad, texture)
Loading

Sequence diagram for token selection and immediate refresh

sequenceDiagram
    actor User
    participant GroupWidget
    participant Configuration
    participant GroupModel
    participant MapCanvas

    User->>GroupWidget: Set Icon action
    GroupWidget->>Configuration: update tokenOverrides
    GroupWidget->>GroupModel: resetModel()
    GroupWidget-->>MapCanvas: sig_characterUpdated
    MapCanvas->>MapCanvas: slot_requestUpdate()
    User->>GroupWidget: Use default icon action
    GroupWidget->>Configuration: set kForceFallback override
    GroupWidget->>GroupModel: resetModel()
    GroupWidget-->>MapCanvas: sig_characterUpdated
    MapCanvas->>MapCanvas: slot_requestUpdate()
Loading

File-Level Changes

Change Details Files
Added token discovery, fallback resolution, per-character overrides, and OpenGL texture lifecycle management.
  • Scans user, packaged, and Qt-resource token directories with filesystem watching and priority-based lookup.
  • Normalizes character names for matching and supports explicit icon selection or forced fallback.
  • Caches pixmaps and uploaded textures, invalidating them when token files change and cleaning them up with the GL context.
src/group/tokenmanager.cpp
src/group/tokenmanager.h
src/configuration/configuration.cpp
src/configuration/configuration.h
src/mainwindow/mainwindow.cpp
src/display/mapcanvas_gl.cpp
src/CMakeLists.txt
Integrated token rendering into map character batches without tinting the token image.
  • Carries display names through map character rendering and draws token quads separately from colored room squares.
  • Shows tokens for group members while suppressing the token on the player’s current room marker.
  • Requests map redraws when token assets or character overrides change.
src/display/Characters.cpp
src/display/Characters.h
src/mainwindow/mainwindow.cpp
Added a configurable token column and token sizing behavior to Group Manager.
  • Introduces a token column delegate that paints transparent-token imagery over the character color background.
  • Adjusts row, icon, and state-column sizing from the configured token size.
  • Adds context-menu actions for selecting a token image or restoring default lookup, with model refreshes.
src/group/GroupModel.cpp
src/group/GroupModel.h
src/group/groupwidget.cpp
src/group/groupwidget.h
src/group/CGroupChar.h
Exposed token visibility and sizing preferences and persisted token overrides.
  • Adds separate Group Manager and map token visibility settings plus selectable icon sizes.
  • Loads and writes token settings and name-to-token override mappings through QSettings.
  • Connects preference changes to immediate Group Manager layout and visibility updates.
src/preferences/grouppage.cpp
src/preferences/grouppage.ui
src/configuration/configuration.cpp
src/configuration/configuration.h
src/mainwindow/mainwindow.cpp

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 5 issues

Prompt for AI Agents
Please address the comments from this code review:

## Individual Comments

### Comment 1
<location path="src/group/CGroupChar.h" line_range="158" />
<code_context>
         m_server.maxmp = _maxmoves;
     }
+
+    QString getDisplayName() const;
 };
</code_context>
<issue_to_address>
**Application cannot build**

Calls to `CGroupChar::getDisplayName()` from the map and Group Manager have no definition, so linking fails and the application cannot be built.

Provide a definition for `CGroupChar::getDisplayName()`.

Also at `src/display/Characters.cpp:588-589`, `src/group/groupwidget.cpp:159`.
</issue_to_address>

### Comment 2
<location path="src/group/tokenmanager.cpp" line_range="76" />
<code_context>
+    : QObject(parent)
+{
+    g_tokenManager = this;
+    scanDirectories();
+
+    m_rescanTimer.setSingleShot(true);
</code_context>
<issue_to_address>
**New folder tokens stay missing**

When the user changes the resource directory while the application is running, `TokenManager::scanDirectories()` runs only at startup or for watched old paths, so `m_availableFiles` and the watchers stay pointed at the previous folder; tokens from the newly selected folder remain unavailable until a rescan or restart.

Rescan the token directory and retarget its watchers when the resource directory changes.

Also at `src/group/tokenmanager.cpp:119-121`, `src/group/tokenmanager.cpp:168-170`.
</issue_to_address>

### Comment 3
<location path="src/display/Characters.cpp" line_range="333-337" />
<code_context>
+            pushVert(sc, {1.f, 1.f});
+            pushVert(sd, {0.f, 1.f});
+
+            QString key = TokenManager::overrideFor(dispName);
+            if (key.isEmpty())
+                key = canonicalTokenKey(dispName);
+            else
+                key = canonicalTokenKey(key);
+
+            m_charTokenKeys.emplace_back(key);
</code_context>
<issue_to_address>
**Map shows the wrong character’s token**

When a canonical map key matches another character’s display name, and that character has an override, `drawBox` canonicalizes the display name or selected override, then `getToken` applies `overrideFor` again; the map shows the other character’s override, while the Group Manager resolves the original character once and shows a different icon.

Ensure canonical map keys are not treated as display names and have overrides applied a second time.

Also at `src/group/tokenmanager.cpp:189`.
</issue_to_address>

### Comment 4
<location path="src/display/Characters.cpp" line_range="301" />
<code_context>
         addTransformed(c);
         addTransformed(d);

+        if (!dispName.isEmpty() && getConfig().groupManager.showMapTokens && numAlreadyInRoom == 0) {
+            const Color tokenColor{1.f, 1.f, 1.f, 1.f};
+            const auto &mtx = m_stack.top().modelView;
</code_context>
<issue_to_address>
**Later room members lack tokens**

When multiple group characters occupy the same mapped room, `drawBox` skips token quads when `numAlreadyInRoom` is nonzero, even though it draws those characters’ offset squares; the map shows a token for at most one member.

Generate token quads for every group character, not only the first character drawn in a room.
</issue_to_address>

### Comment 5
<location path="src/display/Characters.cpp" line_range="301" />
<code_context>
         addTransformed(c);
         addTransformed(d);

+        if (!dispName.isEmpty() && getConfig().groupManager.showMapTokens && numAlreadyInRoom == 0) {
+            const Color tokenColor{1.f, 1.f, 1.f, 1.f};
+            const auto &mtx = m_stack.top().modelView;
</code_context>
<issue_to_address>
**Map tokens disappear when zoomed out**

When the map is zoomed out far enough for `isFar` to be true, `isFar` selects the other rendering branch before this token-generation block, so characters drawn at the far/beacon scale never get token quads. The configured map tokens therefore disappear at those zoom levels.

Generate and render token quads for the far-scale character path as well, or document and enforce a token visibility scale limit.
</issue_to_address>

Sourcery assessment

Approval pending. 5 findings to address first.

Blocking findings: src/group/CGroupChar.h:158, src/group/tokenmanager.cpp:76, src/display/Characters.cpp:337, src/display/Characters.cpp:301, src/display/Characters.cpp:301


Sourcery is free for open source - if you like our reviews please consider sharing them ✨

Comment thread src/group/CGroupChar.h
Comment thread src/group/tokenmanager.cpp
Comment thread src/display/Characters.cpp Outdated
Comment thread src/display/Characters.cpp Outdated
Comment thread src/display/Characters.cpp Outdated
@codecov

codecov Bot commented Oct 7, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 3.23450% with 359 lines in your changes missing coverage. Please review.
✅ Project coverage is 27.72%. Comparing base (cca5ea3) to head (42597f7).
⚠️ Report is 1 commits behind head on master.

Files with missing lines Patch % Lines
src/group/tokenmanager.cpp 0.00% 164 Missing ⚠️
src/group/groupwidget.cpp 0.00% 78 Missing ⚠️
src/display/Characters.cpp 0.00% 66 Missing ⚠️
src/preferences/grouppage.cpp 0.00% 23 Missing ⚠️
src/mainwindow/mainwindow.cpp 0.00% 12 Missing ⚠️
src/preferences/generalpage.cpp 0.00% 6 Missing ⚠️
src/group/GroupModel.cpp 0.00% 3 Missing ⚠️
src/configuration/configuration.cpp 85.71% 2 Missing ⚠️
src/group/CGroupChar.cpp 0.00% 2 Missing ⚠️
src/display/mapcanvas_gl.cpp 0.00% 1 Missing ⚠️
... and 2 more
Additional details and impacted files
@@            Coverage Diff             @@
##           master     #562      +/-   ##
==========================================
- Coverage   27.91%   27.72%   -0.19%     
==========================================
  Files         563      564       +1     
  Lines       46169    46527     +358     
  Branches     4884     4949      +65     
==========================================
+ Hits        12889    12901      +12     
- Misses      33280    33626     +346     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

This branch has not been deployed

No deployments
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.

1 participant