Skip to content

Add An MTP Import, new mod statut cache, fixes masives bugs and mores - #64

Open
mokapi48 wants to merge 1 commit into
nadrino:mainfrom
mokapi48:main
Open

Add An MTP Import, new mod statut cache, fixes masives bugs and mores#64
mokapi48 wants to merge 1 commit into
nadrino:mainfrom
mokapi48:main

Conversation

@mokapi48

Copy link
Copy Markdown

Table of Contents


New Features

1. USB MTP Mod Import (PC ↔ Switch)

New files:

  • src/ModManagerGui/FrameGameBrowser/include/ModsMtpServer.h
  • src/ModManagerGui/FrameGameBrowser/src/ModsMtpServer.cpp
  • src/ModManagerGui/FrameGameBrowser/include/TabImportMod.h
  • src/ModManagerGui/FrameGameBrowser/src/TabImportMod.cpp
  • src/ThirdParty/mtp-server-nx/ (entire vendored library, ~30 files)

What it does:

A full MTP (Media Transfer Protocol) responder runs on the Switch, exposing the sdmc:/mods/ directory over USB. When the user connects the Switch to a PC via USB, the PC sees the Switch as an MTP storage device and can drag-and-drop mod folders (or .zip archives) directly into sdmc:/mods/<TitleName>/.

Key implementation details:

Aspect Detail
USB identity VID 0x057e (Nintendo), PID 0x4000
Thread model Dedicated worker thread with state machine: IdleStartingRunningStopping
Auto-extract After MTP session ends, any .zip files found in the mods root are automatically extracted using minizip
Auto-restart If the USB host doesn't connect within 4.5 seconds, MTP auto-restarts up to 3 times
Boot guard 3.5-second delay before MTP starts to avoid USB race conditions
Transition cooldown 2-second cooldown between state transitions
Self-healing Stale states (e.g. "running" when the thread has already exited) are detected and corrected
Auto-sleep Disabled during active MTP session via appletSetAutoSleepDisabled(true) and appletSetMediaPlaybackState(true)
Clean shutdown Timeout-based stop with thread detach as a last resort

TabImportMod UI:

A new Borealis tab ("Import Mod") is added between the "Game Browser" tab and the separator in FrameRoot. It contains:

  • Multi-line instructions explaining the USB MTP workflow
  • A live status label (auto-refreshes every ~15 frames) showing: Idle / Waiting for USB connection... / MTP connected — browse on your PC / Stopped
  • A toggle button to start/stop the MTP server
  • MTP is automatically stopped when the tab disappears (willDisappear)

Metadata file hiding:

The vendored SwitchMtpDatabase (custom implementation in mtp-server-nx) filters out SimpleModManager metadata files from the MTP view when showDebugMtpFiles is false:

  • .smm_title_id
  • mods_status_cache.txt
  • this_folder_config.txt
  • mod_presets.conf

This keeps the MTP view clean for end users.


2. Touchscreen Controls

Modified file: src/Applications/SimpleModManager/src/SimpleModManager.cpp (~300 lines of new touch handling code)

What it does:

Complete touch input support for all GUI interactions, enabling the app to be used without Joy-Cons attached.

Implementation:

Component Detail
API hidInitializeTouchScreen() + hidGetTouchScreenStates()
State machine Tracks TouchState: NonePressedHeldReleased
Tap detection Touch-down and touch-up within 24px slop radius and 500ms window triggers a tap
Swipe-to-scroll Vertical drag beyond 10px triggers scroll; step size is 56px (normal views) or 104px (settings views)
View hit-testing Recursive traversal through TabFrame → active tab → ScrollViewBoxLayoutListItem / Button, checking bounding boxes at each level
Dialog support Taps on dialog buttons are detected by checking brls::Application::getTopStackView()
Footer actions Taps on the bottom action bar (A/X/Y hints) are mapped to the corresponding registered actions

Processing loop:

processTouchInput() is called once per frame in the main runGui() loop, after brls::Application::frame().


3. Battery & Clock Status Overlay

New files:

  • src/ModManagerGui/CoreExtension/include/SystemStatusOverlay.h
  • src/ModManagerGui/CoreExtension/src/SystemStatusOverlay.cpp

What it does:

Draws the current battery percentage and clock time in the header bar of the application, using NanoVG directly.

Implementation details:

Aspect Detail
Battery API psmInitialize()psmGetBatteryChargePercentage()
Clock API timeGetCurrentTime(TimeType_LocalSystemClock, ...)timeToCalendarTimeWithMyRule()
Fallback If Switch time APIs fail, falls back to std::localtime()
Refresh rate Re-draws every 1 second
Placement Right-aligned in the header bar, after TabFrame::draw()
Where rendered FrameRoot::draw() and FrameModBrowser::draw() (both override draw())
Cleanup SystemStatusOverlay::shutdown() calls psmExit()

4. Delete Mods from SD Card (GUI)

Modified files:

  • src/ModManagerGui/CoreExtension/include/GuiModManager.h
  • src/ModManagerGui/CoreExtension/src/GuiModManager.cpp
  • src/ModManagerGui/FrameModBrowser/include/TabModBrowser.h
  • src/ModManagerGui/FrameModBrowser/src/TabModBrowser.cpp

What it does:

Users can now press Y on any mod in the mod browser to delete it entirely — both the mod source folder on the SD card and its installed files in the LayeredFS overlay.

Implementation:

  • New action registered on Key::Y for each mod ListItem with action hint "Delete mod"
  • Confirmation dialog warns the user: "Do you want to delete 'X' from the SD card and remove its installed files?"
  • Rate limiting: canStartDeleteModFolderThread() prevents launching multiple deletions concurrently (enforces a cooldown via _lastDeleteModFolderFinishedMs_)
  • Background thread: deleteModFolderFunction() runs in a separate thread
    • Removes the mod folder from sdmc:/mods/<game>/<modname>/
    • Calls removeModInstalledFiles() to delete files that are byte-identical to the mod source
    • Calls finalizeModfilesystemChanges() to re-check remaining mods and update their caches
    • Triggers a full UI rebuild of the mod browser
  • Focus preservation: After deletion, focus moves to the adjacent mod (previous, or next if deleting the first item)
  • UI rebuild: rebuildUiFromSd() fully clears and repopulates the mod list from the SD card, re-syncing Borealis focus indices

5. Orphan Installed-Mod Cleanup

Modified files:

  • src/ModManagerCore/include/ModManager.h
  • src/ModManagerCore/src/ModManager.cpp
  • src/ModManagerGui/FrameModBrowser/include/FrameModBrowser.h
  • src/ModManagerGui/FrameModBrowser/src/FrameModBrowser.cpp
  • src/ModManagerCore/include/ConfigHandler.h (new config toggle)
  • src/ModManagerCore/src/ConfigHandler.cpp

What it does:

When a mod is deleted from the SD card outside of SMM (or its folder name changes), its installed files in the LayeredFS overlay become "orphans" — they no longer correspond to any mod folder. This feature detects such orphan files and offers to clean them up.

Implementation:

  • ModManager::refreshOrphanInstalledModList(): Scans all installed files in the game's LayeredFS overlay and compares them against every mod folder. Files that don't match any current mod are collected into _orphanInstalledModList_ (vector of OrphanInstalledMod structs, each with a modName and applyCache).
  • claimOrphanInstalledFilesForMod(): When a mod reappears (e.g. re-copied to SD), its files are claimed back from the orphan list.
  • removeOrphanInstalledModCache(): Clears orphan entries from the status cache file.
  • GuiModManager::deleteOrphanInstalledModsFunction(): Background thread that iterates the orphan list and removes the files.
  • Auto-prompt: FrameModBrowser::promptOrphanInstalledModsCleanup() automatically detects orphans when entering a game's mod browser and shows a dialog: "X orphan installed mod(s) detected. Clean up?"
  • Config toggle: offer-orphan-installed-mod-cleanup (default true) in config.ini lets users disable the prompt.

6. Automatic Game Folder Discovery

Modified file: src/ModManagerCore/src/Toolbox.cpp (from ~21 lines to ~300+ lines)

What it does:

Instead of requiring users to manually create mod folders for each game, the fork automatically discovers all installed retail games on the system and creates their mod folder structure.

Implementation:

Toolbox::ensureInstalledGameModFolders() does the following on startup:

  1. Calls nsListApplicationRecord() to enumerate all installed titles
  2. Filters to retail game titles only by checking:
    • Application ID prefix (must be a retail title, not system/update/DLC)
    • hasApplicationContentMeta() — confirms the title has actual content
    • Icon availability — confirms the title has a loadable icon
    • isKnownHomebrewTitle() — excludes known homebrew (hbmenu, tinfoil, goldleaf, edizon, etc.)
  3. For each qualifying title:
    • Resolves the title name and author via nsApplicationControlData
    • Sanitizes the folder name: removes invalid path characters (/ \ : * ? " < > |), strips Windows reserved names (CON, PRN, AUX, NUL, COM1-COM9, LPT1-LPT9), trims whitespace
    • Creates sdmc:/mods/<GameName>/ if it doesn't exist
    • Writes a .smm_title_id metadata file containing the title ID (for fast re-lookup without API calls)

Helper functions added to Toolbox:

Function Purpose
ensureModsRootFolder() Creates sdmc:/mods/ if missing
getGameFolderTitleId() Reads .smm_title_id first, falls back to lookForTidInSubFolders()
getGameFolderIcon() Loads game icon with in-memory cache (g_gameIconCache)
hasGameFolderIcon() Quick check for icon availability without allocating image data
trimFolderName() Trims whitespace and dots
toUpperAscii() ASCII-only uppercase conversion
isWindowsReservedName() Checks against Windows reserved device names
isLikelyRetailGameTitleId() Heuristic check on title ID format
formatTitleId() Formats a u64 title ID as 16-digit hex string
sanitizeGameFolderName() Full sanitization pipeline
hasApplicationContentMeta() NCM API check for content meta presence
writeGameFolderTitleIdMetadata() Writes .smm_title_id file
copyCachedIcon() Copies from icon cache
getApplicationName() / getApplicationAuthor() NACP parsing helpers
isKnownHomebrewTitle() Blacklist of known non-game title IDs

7. Per-File Mod Status Cache

Modified files:

  • src/ModManagerCore/include/ModManager.h (new structs and methods)
  • src/ModManagerCore/src/ModManager.cpp

What it does:

Instead of comparing every mod file against the installed overlay every time (which is slow, especially over SD I/O), the fork maintains a persistent per-file status cache on disk (mods_status_cache.txt inside each game folder).

New data structures:

struct ModFileStatusCache {
  std::string status;        // "MISSING", "ACTIVE", "DIFFERENT", etc.
  std::string relativePath;
  size_t sourceSize{0};
  size_t destSize{0};
  time_t sourceMtime{0};
  time_t destMtime{0};
};

Extended ApplyCache:

Field Type Purpose
totalFiles int Total mod files found
matchingFiles int Files identical to installed version
differentFiles int Files that differ from installed version
missingFiles int Files not present in the overlay
fileStatusCache std::map<std::string, ModFileStatusCache> Per-file status keyed by relative path

New methods:

Method Purpose
updateModStatusInternal(forceRecheck_, showTerminalProgress_, dumpCache_) Core verification logic, now with cache-awareness
refreshModStatus() Non-terminal wrapper: uses cache first, only re-checks if mtimes/sizes changed
refreshAllModStatusCache() Batch refresh of all mod caches without terminal output
readGameStatusSummary() Static: reads cache file and counts mods by status without file I/O
formatGameStatusSummary() Static: produces "X mods | Y active / Z partial / W inactive" string

8. Smart Game List Refresh (Signature-Based)

Modified files:

  • src/ModManagerCore/include/GameBrowser.h
  • src/ModManagerCore/src/GameBrowser.cpp

What it does:

The game list is only rebuilt when something actually changed, avoiding expensive re-scans on every frame or tab switch.

Implementation:

buildGameListSignature() computes a hash from:

  • Current configuration settings (sort mode, direction, etc.)
  • All game folder mtimes (via stat())
  • Cache file size and mtime (mods_status_cache.txt)
  • All mod folder names and their mtimes

refreshGameList(bool force_) compares the current signature against the cached one (_gameListSignature_). If they match and force_ is false, the rebuild is skipped entirely.

refreshGameListTag(const std::string& gameFolder) allows updating a single game's status tag in the selector without rebuilding the entire list.


9. Advanced Game List Sorting

Modified files:

  • src/ModManagerCore/include/ConfigHandler.h
  • src/ModManagerCore/src/ConfigHandler.cpp
  • src/ModManagerCore/src/GameBrowser.cpp
  • src/ModManagerGui/FrameGameBrowser/src/TabGeneralSettings.cpp

New sort modes added to SortGameList enum:

Mode Sorts by
GameLaunched Last launch timestamp (from pdmqryQueryPlayStatisticsByApplicationId)
ModAdded Most recently added/modified mod folder mtime
PlayTime Total play time in seconds
LaunchCount Number of times the game has been launched

New SortGameListDirection enum:

Direction Effect
Ascending A→Z, oldest first, least play time first
Descending Z→A, newest first, most play time first

Backward compatibility: Old config values are automatically migrated:

  • LastPlayedGameLaunched (Descending)
  • FirstPlayedGameLaunched (Ascending)
  • LastModAddedModAdded (Descending)
  • FirstModAddedModAdded (Ascending)

UI: The sort dropdown now shows user-friendly display names (e.g. "Last Played" instead of raw enum values), and a new X button toggles between Ascending/Descending.


10. Game Status Summary Tags

What it does:

Each game in the game list now shows a subtitle tag summarizing its mod status (e.g. "12 mods | 3 active / 2 partial / 7 inactive"), computed from the cache without doing file comparisons.

Implementation:

  • ModManager::readGameStatusSummary() reads the cache file and counts mods by status
  • ModManager::formatGameStatusSummary() produces the display string
  • TabGames::rebuildLayout() calls this for each game and sets it as the ListItem subtitle
  • TabGames::refreshDisplayedGameStatus() can update a single game's tag

11. Caching of Game Icons in Memory

Modified file: src/ModManagerCore/src/Toolbox.cpp

What it does:

Game icons (loaded from NSP metadata via nsApplicationControlData) are cached in two static maps:

Cache Key Value
g_gameIconCache title ID string std::vector<unsigned char> (raw JPEG data)
g_gameIconAvailabilityCache title ID string bool (whether icon is available)

This avoids redundant ns API calls when the game list is rebuilt or refreshed.


Modified / Improved Components

TabModBrowser — Full Rewrite

File: src/ModManagerGui/FrameModBrowser/src/TabModBrowser.cpp (148 → 438 lines)

Changes:

Change Detail
Delete mod action (Y) New Key::Y action on each mod item to trigger deletion with confirmation dialog
Action hints Added updateActionHint(brls::Key::X, "Disable") and updateActionHint(brls::Key::Y, "Delete mod")
rebuildUiFromSd() Full UI rebuild from SD card state after mod deletion. Clears all items, re-scans mod list, re-creates ListItems, restores focus to _focusModNameAfterDelete_
removeDisplayedMod() Two overloads (by name and by pointer) that remove a single mod item from the UI without full rebuild. Falls back to "No mods" placeholder if list becomes empty
resyncListItemFocusIndices() Fixes Borealis BoxLayout focus navigation after removeView() by resetting parentUserData child indices on all remaining children
getFocusTargetBeforeDelete() Determines which mod should receive focus after deletion (prefers previous, then next)
draw() rewrite Now handles deferred UI rebuild (isTriggerRebuildModBrowser()) before calling ScrollView::draw(), with guard against rebuilding while a view is disappearing
updateDisplayedModsStatus() Now uses cached status from applyCache instead of live file comparison. Displays "UNCHECKED" for mods without cached data. Handles "PARTIAL" prefix for proper orange coloring
Improved empty message Changed from verbose path explanation to cleaner: "No mods for this game are on your SD card."
Bounds checking Added iMod < _modItemList_.size() guard and null checks on items

TabGames — Lazy Rebuild & Focus Restoration

File: src/ModManagerGui/FrameGameBrowser/src/TabGames.cpp (127 → 245 lines)

Changes:

Change Detail
rebuildLayout(bool force_) Lazy rebuild: only rebuilds if GameBrowser::buildGameListSignature() changed. Filters out games without icons. Uses Toolbox::getGameFolderIcon() (cached). Sets game status summary as subtitle
willAppear() On subsequent appearances (after the first), triggers: game list refresh → status update → focus restoration
draw() Handles deferred refresh, status update, and focus restoration. Detects view transitions to avoid unnecessary work
resyncListItemFocusIndices() Same Borealis focus fix as TabModBrowser
findGameItem() Locates a ListItem by game folder name
refreshDisplayedGameStatus() Updates a single game's status tag without full rebuild
restoreFocusAfterRebuild() After list rebuild, restores keyboard focus to the previously selected game
Icon filtering Games without available icons are skipped entirely (hidden from the list)

FrameModBrowser — Orphan Detection & Status Overlay

File: src/ModManagerGui/FrameModBrowser/src/FrameModBrowser.cpp

Changes:

Change Detail
draw() override Calls SystemStatusOverlay::draw() to show battery/clock in mod browser
promptOrphanInstalledModsCleanup() On game entry, scans for orphan installed files and offers a cleanup dialog (if offerOrphan-installed-mod-cleanup config is enabled)
Auto-recheck disabled Commented out the automatic updateModStatus() call on mod browser open to prevent UI freezes
Better empty message Changed "No mod found" to a more helpful message for games with no mods
resetOrphanCleanupPrompt() New method to reset the orphan prompt state after mod browser rebuild

GameBrowser — Rewrite with Stats & Smart Refresh

File: src/ModManagerCore/src/GameBrowser.cpp (180 → 542 lines)

Changes:

Change Detail
init() rewrite Now populates GameSortEntry structs with: last launch time, mod folder timestamps, play statistics (total play time, launch count via pdmqryQueryPlayStatisticsByApplicationId), mod status summaries. Filters games without icons
sortGameEntries() New function supporting all sort modes (Alphabetical, GameLaunched, ModAdded, PlayTime, LaunchCount) with ascending/descending direction
buildGameListSignature() New: hashes config + folder mtimes + cache stats + mod folder names for cache invalidation
refreshGameList(bool force_) Only rebuilds if signature changed
refreshGameListTag() Updates a single game's status tag in-place
getFolderIcon() Now uses Toolbox::getGameFolderIcon() (cached) instead of direct ns API calls each time
Play statistics fillPlayStats() queries pdmqryQueryPlayStatisticsByApplicationId for play time and launch count
Preset resolution resolvePresetForGame() determines active preset for a game
Sort tag display buildSortTag() generates human-readable sort info for each game entry

New helper functions: fillModTimestamps, fillPlayStats, sortNeedsPlayStats, parseTitleId, formatTimestamp, formatPlaytime, resolvePresetForGame, buildSortTag, toLowerAscii, hasSortValue, getSortValue.

ModManager — Per-File Cache, Orphan Tracking, Status Summaries

File: src/ModManagerCore/src/ModManager.cpp

Changes:

Change Detail
updateModStatusInternal() Extracted from updateModStatus(). Now tracks per-file status in ModFileStatusCache, supports forceRecheck_ (bypass cache), showTerminalProgress_ (console output), and dumpCache_ (write cache to disk)
refreshModStatus() New: cache-first approach, only re-checks files whose mtime/size changed
refreshAllModStatusCache() New: batch refreshes all mod caches silently
refreshOrphanInstalledModList() New: scans installed files, identifies orphans
claimOrphanInstalledFilesForMod() New: reassigns orphan files when a mod reappears
removeOrphanInstalledModCache() New: removes orphan entries from cache
readGameStatusSummary() New static: reads cache, counts by status
formatGameStatusSummary() New static: produces display string
applyMod() / applyModList() Updated to populate ModFileStatusCache and handle orphan cleanup during apply
New structs ModFileStatusCache, ModStatusSummary (totalMods, activeMods, partialMods, inactiveMods, noFileMods, uncheckedMods), OrphanInstalledMod

Toolbox — Title ID Resolution, Icon Cache, Folder Sanitization

File: src/ModManagerCore/src/Toolbox.cpp (21 → ~300+ lines)

Changes:

Change Detail
ensureModsRootFolder() New: creates sdmc:/mods/
ensureInstalledGameModFolders() New: auto-discovers all retail games, creates mod folders with .smm_title_id metadata
getGameFolderTitleId() New: reads .smm_title_id file first, then falls back to subfolder search
getGameFolderIcon() New: loads icon with in-memory cache
hasGameFolderIcon() New: quick availability check
~15 helper functions Trim, sanitize, format, filter (see §6 table above)

ConfigHandler — New Sort Modes, Direction, MTP/Cleanup Toggles

Files: src/ModManagerCore/include/ConfigHandler.h, src/ModManagerCore/src/ConfigHandler.cpp

New enum values:

// Added to SortGameList:
GameLaunched, ModAdded, PlayTime, LaunchCount

// New enum:
enum class SortGameListDirection { Ascending, Descending };

New config fields:

Config Key Type Default Purpose
show-debug-mtp-files bool false Show/hide SMM metadata files in MTP view
offer-orphan-installed-mod-cleanup bool true Auto-prompt orphan cleanup
sort-game-list-direction SortGameListDirection Descending Default sort direction

New display name helpers: getSortGameListDisplayName(), getSortGameListDirectionDisplayName(), getSortGameListSettingDisplayName() — return human-readable names for config UI.

Backward compatibility: Old LastPlayed/FirstPlayed/LastModAdded/FirstModAdded values are migrated to the new GameLaunched/ModAdded + direction system.

GuiModManager — Background Deletion, Cache Finalization

Files: src/ModManagerGui/CoreExtension/include/GuiModManager.h, src/ModManagerGui/CoreExtension/src/GuiModManager.cpp

New methods:

Method Purpose
deleteModFolderFromSd() Public entry point, starts background thread
deleteOrphanInstalledMods() Public entry point for orphan cleanup
isBackgroundTaskRunning() Checks if any background operation is in progress
canStartDeleteModFolderThread() Rate-limits deletion (cooldown between operations)
startDeleteModFolderThread() Now returns bool (success/fail)
startDeleteOrphanInstalledModsThread() Now returns bool
removeModInstalledFiles() Removes files byte-identical to mod source from overlay
cleanupInstalledFilesByRelativePaths() Generic file cleanup by path list
deleteOrphanInstalledModsPass() Iterates orphan list and deletes
finalizeModfilesystemChanges() After deletion, rechecks remaining mods and updates caches
finishDeleteModFolderTask() Finalizes: cache refresh + triggers UI rebuild

New members: _triggerRebuildModBrowser_, _deleteModFolderRunning_, _lastDeleteModFolderFinishedMs_

New monitors: ModDeleteFolderMonitor, ModFinalizeMonitor (for background thread completion)

SimpleModManager (Main App) — Touch, MTP, Proper Shutdown

Files: src/Applications/SimpleModManager/include/SimpleModManager.h, src/Applications/SimpleModManager/src/SimpleModManager.cpp

Changes:

Change Detail
runGui() signature Now takes const std::string& modsRootFolder_ parameter
Startup sequence Calls Toolbox::ensureModsRootFolder() and Toolbox::ensureInstalledGameModFolders() before launching GUI
Touch init hidInitializeTouchScreen() called on startup
Main loop processTouchInput() called every frame
Shutdown SystemStatusOverlay::shutdown() + ModsMtpServer::shutdownForAppExit() + nsExit()
Console mode Now calls nsInitialize() + ensureInstalledGameModFolders() before ConsoleHandler::run(), and nsExit() after

SimpleModManagerConsole — ns Initialization

File: src/Applications/SimpleModManagerConsole/src/SimpleModManagerConsole.cpp

Changes:

  • Added nsInitialize() before console handler initialization
  • Added Toolbox::ensureInstalledGameModFolders() call for console mode
  • Added proper nsExit() after console handler exits

TabGeneralSettings — New UI Controls

File: src/ModManagerGui/FrameGameBrowser/src/TabGeneralSettings.cpp

Changes:

Change Detail
Sort dropdown Now shows user-friendly display names instead of raw enum values
Sort direction toggle New X button to toggle between Ascending/Descending
Debug MTP files New toggle switch (bound to show-debug-mtp-files config)
Orphan cleanup New toggle switch (bound to offer-orphan-installed-mod-cleanup config)

README.md — New Sections

File: README.md

Added sections:

  • "Import mods from a PC (USB MTP)" — Documents the MTP workflow: connect USB, toggle MTP server, drag mods from PC, auto-extract ZIPs
  • "Touchscreen controls" — Documents touch interactions: tap to select/activate, swipe to scroll

Build Changes

CMakeLists.txt modifications

File Change
src/Applications/SimpleModManager/CMakeLists.txt Added -lminizip -lz -lbz2 to linker flags (ZIP extraction for MTP auto-extract)
src/ModManagerGui/CoreExtension/CMakeLists.txt Added SystemStatusOverlay.cpp to sources
src/ModManagerGui/FrameGameBrowser/CMakeLists.txt Added ModsMtpServer.cpp and TabImportMod.cpp to sources

Vendored Dependencies

src/ThirdParty/mtp-server-nx/

Entire MTP server library vendored (~30 files). Not present in the upstream repository.

Key components:

Component Purpose
MtpServer Core MTP protocol state machine (OK/Cancel/DeviceInfo/StorageInfo/Object operations)
MtpStorage Virtual storage abstraction backed by a filesystem directory
SwitchMtpDatabase Custom database that maps MTP object handles to filesystem paths; hides SMM metadata files when showDebugMtpFiles is false
USBMtpInterface libusb-based USB communication layer using Nintendo's USB VID/PID
MtpObjectInfo MTP object metadata (name, size, format, parent, etc.)

Hidden files (when showDebugMtpFiles = false): .smm_title_id, mods_status_cache.txt, this_folder_config.txt, mod_presets.conf.


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