Skip to content

lextpf/salma

Repository files navigation

salma

Wizardless FOMOD installer with automatic selection inference

🎀 Features | 💃 Quick Start | 📘 Documentation | 🤝 Contributing

ReactJS Crow Mo2 Tailwind Vite CMake License
Quality Gate Status Maintainability Rating Reliability Rating
build tests

Sponsor

A mod installer for Skyrim built with C++23 and powered by Crow and React. It pairs a C DLL that handles archive extraction and FOMOD processing with a Crow HTTP server and React web interface for interactive installations. salma integrates with Mod Organizer 2 via a Python plugin, automatically inferring FOMOD selections by comparing archives against installed files - no wizard clicks required.


Preview

Important

Windows 10/11 Only - salma targets Mod Organizer 2 on Windows and will not build on other platforms.

  • Requires vcpkg with the toolchain file at a known path.
  • Requires a Mod Organizer 2 instance for plugin integration and FOMOD testing.
/* ============================================================================================== *
 *
 *       ::::::::      :::     :::        ::::    ::::      :::         ⢠⣤⣤⣀ ⠀⠀⠀⠀⠀⠀ ⣀⣤⣤⡄
 *      :+:    :+:   :+: :+:   :+:        +:+:+: :+:+:+   :+: :+:      ⢸⣿⣿⣿⣿⣦⣄⣀⣠⣴⣿⣿⣿⣿⡇⠀⊹
 *      +:+         +:+   +:+  +:+        +:+ +:+:+ +:+  +:+   +:+     ⣸⣿⣿⣿⣿⣿⡽⣿⣯⣿⣿⣿⣿⣿⣇
 *      +#++:++#++ +#++:++#++: +#+        +#+  +:+  +#+ +#++:++#++:    ⢻⣿⣿⣿⠿⣻⣵⡟⣮⣟⠿⣿⣿⣿⡟
 *             +#+ +#+     +#+ +#+        +#+       +#+ +#+     +#+    ⠀⠀⠀⠀⣼⣿⡿ ⠀⢿⣿⣷⡀
 *      #+#    #+# #+#     #+# #+#        #+#       #+# #+#     #+#    ⊹⠀⣠⣾⣿⣿⠃ ⠀⠈⢿⣿⣿⣦⡀
 *       ########  ###     ### ########## ###       ### ###     ###    ⠀⠈⠉⠹⡿⠁⠀⠀⠀⠀⠈⢻⡇⠉⠉
 *
 *                                 << M O D   I N S T A L L E R >>
 *
 * ============================================================================================== */

🎀 Features

🖥️ Interface

salma ships with a C DLL for direct integration, a REST API for programmatic access, and a React web UI for interactive installations.

---
config:
  look: handDrawn
  theme: mc
  themeVariables:
    fontSize: 18px
  layout: elk
---
graph LR
    classDef dll fill:#134e3a,stroke:#10b981,color:#e2e8f0
    classDef api fill:#1e3a5f,stroke:#3b82f6,color:#e2e8f0
    classDef web fill:#2e1f5e,stroke:#8b5cf6,color:#e2e8f0

    subgraph DLL["C DLL (mo2-salma.dll)"]
        Install["install()"]:::dll
        Infer["inferFomodSelections()"]:::dll
        Config["installWithConfig()"]:::dll
    end

    subgraph API["Crow REST API"]
        Upload["Upload & Install"]:::api
        Scan["FOMOD Scan"]:::api
        Status["Job Status"]:::api
    end

    subgraph Web["React Frontend"]
        UI["Interactive Installer"]:::web
        FomodView["FOMOD Browser"]:::web
        Logs["Log Viewer"]:::web
    end

    Web --> API
    API --> DLL
Loading

📦 FOMOD Processing

---
config:
  look: handDrawn
  theme: mc
  themeVariables:
    fontSize: 18px
  layout: elk
---
graph LR
    classDef parse fill:#7c2d12,stroke:#f97316,color:#fef3c7
    classDef eval fill:#4c1d95,stroke:#e879f9,color:#e2e8f0
    classDef ops fill:#064e3b,stroke:#34d399,color:#e2e8f0
    classDef detect fill:#713f12,stroke:#facc15,color:#fef9c3

    P["XML Parser"]:::parse
    D["Dependency Evaluator"]:::eval
    F["File Operations"]:::ops
    S["Structure Detector"]:::detect

    P --- D --- F --- S
Loading
  • 📄 XML Parser — Parses fomod/ModuleConfig.xml for installation steps and options
  • 🧩 Dependency Evaluator — Resolves flag-based and file-based FOMOD dependencies
  • 📂 File Operations — Priority-sorted file copy, folder creation, and patching
  • 🔎 Structure Detector — Identifies mod folder layout (meshes/, textures/, SKSE/, etc.)

🔍 Inference Engine

salma's inference service compares an archive's FOMOD options against an already-installed mod to determine which selections were originally chosen:

  • 🌳 Walks every permutation of FOMOD steps and flags
  • 🎯 Matches expected file output against the installed file tree
  • 📋 Returns a JSON configuration that reproduces the original install
  • 🧪 Powers the round-trip test suite for validation

🔌 MO2 Integration

  • 🐍 Python Pluginmo2-salma.py loads the DLL via ctypes and exposes tools inside MO2
  • 🔬 Scan FOMOD Choices — Batch-scans all installed mods for FOMOD selections
  • 📁 Centralized Output — Reinstalled mods go to a dedicated "Salma FOMODs Output" folder
  • Deploy & Purgedeploy.bat and purge.bat scripts for plugin lifecycle management

🗜️ Archive Support

Format Backend
7z bit7z (native 7-Zip SDK wrapper)
ZIP libarchive
RAR libarchive
TAR.* libarchive (bzip2, lz4, lzma, zstd)

✨ Additional Capabilities

  • 🌐 REST API — Full programmatic access for custom installers and automation
  • 🎨 Web UI — React SPA with dark/light theme, served directly by the Crow backend
  • 📝 Logging — Unified thread-safe logger with subsystem tags ([archive] [install] [fomod] [infer] [server])
  • 🧪 Round-Trip Testing — Infer selections, reinstall, and diff against the original mod

🛠️ Technology Stack

Component Technology
Language C++23
HTTP Framework Crow (with CORS handler)
Frontend React 18 + TypeScript + Vite
Styling Tailwind CSS 4
XML Parsing pugixml
JSON nlohmann-json
Archive libarchive + bit7z
Formatting clang-format (Google-based)
Build System CMake 3.20+
Package Manager vcpkg
Documentation Doxide + MkDocs
Plugin Python 3 (MO2 ctypes bridge)
CI/CD GitHub Actions
Platform Windows 10/11 (64-bit)

💃 Quick Start

📋 Prerequisites

  • Windows 10/11 (64-bit)
  • Visual Studio 2022 (MSVC v143, C++23)
  • CMake 3.20+
  • vcpkg with the toolchain at a known path
  • Node.js (for building the React frontend)
  • Python 3 (for MO2 plugin and documentation post-processing)
  • clang-format (optional, for code formatting — CI enforces it)
  • doxide + mkdocs (optional, for API docs generation)

🔨 Building

# 1. Clone the repository
git clone https://github.com/lextpf/salma.git
cd salma

# 2. Build (format + configure + compile + docs)
.\build.bat

# 3. Run the server
.\build\bin\Release\mo2-server.exe

Output:

  • DLL: build/bin/Release/mo2-salma.dll
  • Server: build/bin/Release/mo2-server.exe

🚀 Deploying to MO2

# Copy DLL + Python plugin to your MO2 instance
.\deploy.bat

🏗️ Architecture

---
config:
  look: handDrawn
  theme: mc
  themeVariables:
    fontSize: 18px
  layout: elk
---
graph TB
    classDef server fill:#1e3a5f,stroke:#3b82f6,color:#e2e8f0
    classDef core fill:#134e3a,stroke:#10b981,color:#e2e8f0
    classDef fomod fill:#4a3520,stroke:#f59e0b,color:#e2e8f0
    classDef ext fill:#2e1f5e,stroke:#8b5cf6,color:#e2e8f0

    Main["main.cpp (Crow)"]:::server

    subgraph Server["REST API Layer"]
        InstCtrl["InstallationController"]:::server
        Mo2Ctrl["Mo2Controller"]:::server
        Static["StaticFileHandler"]:::server
    end

    subgraph Core["Core Services"]
        InstSvc["InstallationService"]:::core
        Archive["ArchiveService"]:::core
        FileOps["FileOperations"]:::core
        Detect["ModStructureDetector"]:::core
    end

    subgraph FOMOD["FOMOD Engine"]
        FomodSvc["FomodService"]:::fomod
        DepEval["FomodDependencyEvaluator"]:::fomod
        Infer["FomodInferenceService"]:::fomod
    end

    subgraph External["External Integration"]
        CApi["C API (DLL Export)"]:::ext
        Plugin["Python Plugin (MO2)"]:::ext
        WebUI["React Frontend"]:::ext
    end

    Main --> Server
    Server --> Core
    Core --> FOMOD
    CApi --> Core
    Plugin --> CApi
    Static --> WebUI
Loading
File Purpose
main.cpp Crow HTTP server entry point
InstallationService Main orchestrator for mod installation
ArchiveService Archive extraction (libarchive + bit7z)
FomodService FOMOD XML parsing and installation logic
FomodInferenceService Infers FOMOD selections from installed files
FomodDependencyEvaluator Evaluates FOMOD flag and file dependencies
FileOperations Priority-sorted file copy and patching
ModStructureDetector Detects mod folder layout
CApi C-linkage DLL exports for ctypes
Logger Thread-safe logging with callback support
ConfigService Configuration management

📁 Project Structure

salma/
|-- .github/
|   +-- workflows/
|       |-- build.yml                  # CI: format check + build
|       +-- test.yml                   # CI: round-trip integration tests
|-- src/                               # C++ source code
|   |-- main.cpp                       # Crow HTTP server entry point
|   |-- CApi.h/cpp                     # C-linkage DLL API (ctypes)
|   |-- Export.h                       # MO2_API export macro
|   |-- Types.h                        # Shared type definitions
|   |-- Logger.h/cpp                   # Thread-safe logging
|   |-- ArchiveService.h/cpp           # Archive extraction
|   |-- FileOperations.h/cpp           # Queued file operations
|   |-- ModStructureDetector.h/cpp     # Mod folder structure detection
|   |-- FomodService.h/cpp             # FOMOD installation logic
|   |-- FomodDependencyEvaluator.h/cpp # FOMOD dependency evaluation
|   |-- FomodInferenceService.h/cpp    # Selection inference engine
|   |-- InstallationService.h/cpp      # Main orchestrator
|   |-- InstallationController.h/cpp   # REST endpoint handlers
|   |-- Mo2Controller.h/cpp            # MO2 status endpoints
|   |-- ConfigService.h/cpp            # Configuration management
|   |-- MultipartHandler.h/cpp         # Form data parsing
|   +-- StaticFileHandler.h/cpp        # SPA serving
|-- web/                               # React frontend
|   |-- src/                           # TypeScript source
|   |-- dist/                          # Built SPA (served by Crow)
|   |-- package.json                   # Dependencies
|   +-- vite.config.ts                 # Dev proxy to :5000
|-- scripts/                           # MO2 plugin & utilities
|   |-- mo2-salma.py                   # MO2 Python plugin
|   |-- common.py                      # Shared utilities
|   +-- _clean_docs.py                 # Doc post-processing
|-- logs/                              # Runtime logs
|   |-- salma.log                      # Application log
|   +-- test.log                       # Test suite output
|-- .clang-format                      # Code formatting rules
|-- CMakeLists.txt                     # Build configuration
|-- CMakePresets.json                  # Build presets (vcpkg)
|-- vcpkg.json                         # Dependency manifest
|-- build.bat                          # Build pipeline
|-- deploy.bat                         # Deploy to MO2
|-- purge.bat                          # Remove plugin & clean output
|-- test.bat                           # Run test suite
|-- test.py                            # Test runner
|-- doxide.yml                         # API doc config
+-- mkdocs.yml                         # Documentation site config

📘 Documentation

API documentation is generated via a three-stage pipeline:

# 1. Generate markdown from C++ headers
doxide build

# 2. Post-process (strip noise, fix formatting)
python scripts/_clean_docs.py

# 3. Build the documentation site
mkdocs build

The site is output to site/ and can be served locally with mkdocs serve.

🔧 Troubleshooting

Problem Solution
vcpkg toolchain not found Set VCPKG_ROOT or update the path in CMakePresets.json
Crow port already in use Another process is on port 5000, kill it or change the port
DLL not found by plugin Run deploy.bat or manually copy mo2-salma.dll to MO2 plugins
FOMOD inference mismatch Mod may have been manually edited post-install, check .mohidden files
Vite proxy errors Ensure the Crow server is running on port 5000 before starting Vite

🤝 Contributing

Contributions are welcome! Please read the Contributing Guidelines before submitting pull requests.

💻 Development Workflow

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Make your changes
  4. Run tests and ensure the build passes
  5. Commit with descriptive messages
  6. Push to your fork and open a Pull Request

📄 License

This project is licensed under the MIT License - see the LICENSE file for details.

💖 Acknowledgments

About

Wizardless FOMOD-aware mod installation and FOMOD inference, backed by libarchive, bit7z, pugixml and Crow HTTP hosting the React frontend

Resources

License

Contributing

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors