https://github.com/mikemequis/asher
Dust: An Elysian Tail launcher-based modding platform
https://github.com/mikemequis/asher
csharp dust-an-elysian-tail harmony launcher modding-tools patch
Last synced: 8 days ago
JSON representation
Dust: An Elysian Tail launcher-based modding platform
- Host: GitHub
- URL: https://github.com/mikemequis/asher
- Owner: MikeMequis
- Created: 2025-12-19T18:13:29.000Z (7 months ago)
- Default Branch: develop
- Last Pushed: 2026-07-02T20:16:06.000Z (8 days ago)
- Last Synced: 2026-07-02T20:19:14.384Z (8 days ago)
- Topics: csharp, dust-an-elysian-tail, harmony, launcher, modding-tools, patch
- Language: C#
- Homepage:
- Size: 26 MB
- Stars: 1
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# 🧱 Asher Modding Platform
**Asher** is a launcher-based modding platform for *Dust: An Elysian Tail*, designed to support **runtime code patching** and **content replacement** in a safe, modular, and reversible way.
Inspired by mature mod loaders such as **SMAPI**, Asher prioritizes **explicit initialization order**, **runtime lifecycle control**, and **clean debugging**, deliberately avoiding fragile early-injection patterns.
---
## 🎯 Project Goals
- Runtime code patching using **Harmony**
- Asset replacement without modifying `.xnb` files
- Modular and reversible mod loading
- UI-based patch selection and configuration
- Full compatibility with **Steam**, **XNA**, and **.NET Framework**
---
## 🧠 Core Architecture (Launcher-First)
Asher is built around a **custom launcher**, which guarantees a deterministic initialization order and reliable runtime behavior.
**Key principle:**
Injection and patching are **controlled and delayed**, never performed blindly at process startup.
This design mirrors proven approaches used by SMAPI and other stable modding platforms.
A companion **WPF manager app** (`Asher.App`) handles installation, mod management, and user settings without touching the game process directly.
---
## 🗂️ Solution Structure
```
/Asher.sln
│
├── Asher.App/ → WPF installer & mod manager (.NET 8, x86)
├── Asher.UserInterface/ → WPF views, view models, theming
├── Asher.Services/ → Installation, launch, patch manager, shortcuts
├── Asher.Core/ → Paths, settings, shared models
├── Asher.Localization/ → UI strings (en-US, pt-BR)
│
├── Asher.Launcher/ → Custom game launcher (.NET Framework 4.8)
│ └── Program.cs → Entry point and bootstrap orchestration
│
├── Asher.Runtime/ → Runtime mod loader foundation (.NET Framework 4.8)
│ ├── Bootstrap/
│ │ ├── AssemblyLoader.cs → Dynamic mod assembly loading
│ │ ├── GameLifecycleHooks.cs → Game lifecycle event hooks
│ │ ├── GameTitleBootstrap.cs → Sets game window title
│ │ ├── HarmonyLifecycleBootstrap.cs → Optional lifecycle hook injection
│ │ ├── PreInitBootstrap.cs → PreInit module discovery & execution
│ │ ├── PatchModuleLoader.cs → Harmony patch application
│ │ └── LifecycleModuleLoader.cs → Lifecycle event registration
│ ├── Core/
│ │ ├── GameContext.cs → Game instance access
│ │ ├── RuntimeContext.cs → Configuration and paths
│ │ ├── RuntimeController.cs → Initialization and shutdown
│ │ └── RuntimeResult.cs → Operation result wrapper
│ ├── Lifecycle/
│ │ ├── LifecycleEvent.cs → Lifecycle state enum
│ │ └── GameLifecycleEventBus.cs → Lifecycle state management
│ ├── RuntimeEntry.cs → Public runtime API
│ ├── RuntimeLogger.cs → File-based logging system
│ └── RuntimeLoggerAdapter.cs → SDK logger bridge
│
├── Asher.SDK/ → API for mod developers (.NET Framework 4.8)
│ ├── Logging/
│ │ ├── AsherLog.cs → Static logger facade
│ │ └── IAsherLogger.cs → Logger interface
│ └── Patching/
│ ├── AsherLifecycleModuleBase.cs → Base class for lifecycle monitoring
│ ├── IAsherLifecycleModule.cs → Lifecycle event interface
│ ├── IAsherPatchModule.cs → Harmony patch module interface
│ └── IAsherPreInitModule.cs → PreInit module interface
│
├── Asher.Patching.*/ → Built-in patch mods (DebugEnabler, IntroSkipper, etc.)
│
├── PrepareDistribution.ps1 → Bundles Distribution/ folder for install & deploy
└── Distribution/ → Output folder (generated, not committed)
```
---
## 🖥️ Asher Manager App
`Asher.App` is a WPF application built with **Prism**, **Material Design**, and a modular service layer.
### Installation mode
When Asher is not yet installed in a game folder, the app opens in **installation mode** and starts on the **Start** page:
1. **Start** — welcome and begin installation
2. **Detect Game** — auto-detect or browse for the Dust folder
3. **Installing** — deploy runtime, launcher wrapper, and default mods
4. **Complete** — summary with optional **desktop shortcut** creation
On finish, the app switches to mod manager mode and navigates to **Home**. If the installer was run from `Distribution\`, the distribution app closes and the installed copy at `[Game]\Asher\Asher.App\Asher.App.exe` is launched automatically.
### Mod manager mode
When Asher is already installed (detected from settings or from running inside `[Game]\Asher\Asher.App\`), the app opens in **manager mode** and starts on **Home**:
| Page | Description |
|------|-------------|
| **Home** | Quick actions — launch game, open Patch Manager, Settings |
| **Content Patcher** | Asset replacement UI (planned functionality) |
| **Patch Manager** | Enable/disable mods by moving DLLs between `Mods/` and `Mods/disabled/` |
| **Settings** | Game path, language, theme, backups, auto-launch |
### App features
- **Localization** — English and Portuguese (Brazil); language changes refresh labels without resetting the current page
- **Light / Dark theme** — full-window Material Design theming via Settings
- **Settings persistence** — `settings.json` in AppData, game manager folder, and local app directory
- **Game launch** — launches `DustAET.exe` (Asher launcher wrapper) from the detected game folder
- **Desktop shortcut** — optional shortcut to `Asher.App.exe` after installation
- **Legacy layout migration** — automatically moves old root-level `Asher.App`, `Asher.Backup`, and `patches` into `Asher/`
---
## 🚀 Runtime Flow Overview
### Initialization Sequence
```
1. User launches DustAET.exe via Steam or Asher Manager (Asher.Launcher wrapper)
↓
2. Launcher validates game installation
↓
3. RuntimeEntry.Init(context)
├─> RuntimeLogger initialized
├─> Directories prepared (Asher/Mods/, Asher/AsherLogs/)
└─> Configuration loaded
↓
4. Assembly.LoadFrom(DustAET.real.exe)
↓
5. AssemblyLoader.LoadAssembliesFrom("Asher/Mods/")
└─> All *.dll files in Mods/ loaded dynamically
↓
6. PreInitBootstrap.ExecutePreInitModules()
└─> Scans all loaded assemblies for IAsherPreInitModule
└─> Executes each module's Execute() method
↓
7. GameTitleBootstrap.Apply(gameAssembly)
└─> Sets window title to "Dust - An Elysian Tail (Asher)"
↓
8. PatchModuleLoader.Load()
├─> Creates Harmony instance ("com.asher.runtime.mods")
├─> Scans for IAsherPatchModule implementations
├─> Applies each module's patches via Harmony
├─> LifecycleModuleLoader.Load()
└─> HarmonyLifecycleBootstrap.InitializeIfNeeded()
↓
9. Dust.Program.Main(args) invoked via Reflection
↓
10. Game executes normally with patches applied
```
> **Important:** Launch the game through **Steam** or the manager's **Launch Game** button. Do not run `Asher.Launcher.exe` directly from the distribution folder — it must sit in the game root as `DustAET.exe` with `DustAET.exe.config` probing `Asher` and `Asher\Mods`.
---
## 📁 Installed Game Folder Layout
After installation, the game directory looks like this:
```
/GameFolder/
├── DustAET.exe (Asher.Launcher copy — Steam entry point)
├── DustAET.exe.config (assembly probing: Asher; Asher\Mods)
├── DustAET.real.exe (original game executable, renamed)
│
└── Asher/
├── Asher.Runtime.dll
├── Asher.SDK.dll
├── 0Harmony.dll (net472 build — required)
│
├── Mods/ (active runtime mods)
│ ├── Asher.Patching.DebugEnabler.dll
│ ├── Asher.Patching.IntroSkipper.dll
│ ├── Asher.Patching.GraphicsDeprofiler.dll
│ └── disabled/ (mods disabled via Patch Manager)
│
├── AsherLogs/
│ └── runtime_YYYYMMDD_HHMMSS.log
│
├── patches/ (content patcher assets, future)
├── Asher.Backup/ (original exe backup)
│
└── Asher.App/ (manager app + install payload)
├── Asher.App.exe
├── settings.json
├── Asher.Launcher.exe
└── DefaultMods/
```
Folders are created automatically during installation.
---
## 🔧 Build & Distribution
### Requirements
- Visual Studio 2022 (or `dotnet` CLI)
- **Platform: x86**
- **Configuration: Release** (for distribution)
### Steps
1. Build the solution as **x86 Release** in Visual Studio
2. Run the distribution script from the repo root:
```powershell
.\PrepareDistribution.ps1
```
3. Run `Distribution\Asher.App.exe` to install Asher into a game folder
4. After install, use `[GameFolder]\Asher\Asher.App\Asher.App.exe` for day-to-day management
5. Launch the game via **Steam** or the manager's **Launch Game** button
### Distribution notes
- `PrepareDistribution.ps1` explicitly bundles the **net472** `0Harmony.dll` — using the wrong Harmony build will cause `System.Runtime` version errors at launch
- The script copies launcher, runtime, SDK, default mods, and the manager app into `Distribution/`
- `Distribution/` is generated output and should not be committed
---
## 📊 Project Status Overview
| Area | Status | Notes |
| ------------------------- | ----------- | ---------------------------------------------- |
| Solution structure | ✅ Done | Multi-project architecture stabilized |
| Launcher-based runtime | ✅ Done | Wrapper EXE approach validated |
| Steam compatibility | ✅ Done | Game launches normally via Steam |
| Runtime initialization | ✅ Done | Logs, lifecycle and folders working |
| Injection strategy | ✅ Done | No blind injection, controlled bootstrap |
| Harmony bootstrap | ✅ Done | Runtime patching confirmed and working |
| PreInit system | ✅ Done | Flag configuration before patches |
| Lifecycle hooks | ✅ Done | Optional event system for game lifecycle |
| Mod SDK | ✅ Done | Clean interfaces for mod developers |
| First gameplay patch | ✅ Done | Debug Menu Enabler working |
| External mod loader | ✅ Done | Dynamic .dll loading from Asher/Mods/ |
| **Installer / Manager UI**| ✅ Done | WPF app with install wizard & mod manager |
| **Patch Manager UI** | ✅ Done | Enable/disable mods via folder move |
| **Localization** | ✅ Done | English and Portuguese (Brazil) |
| **Light / Dark theme** | ✅ Done | Full-window Material Design theming |
| **Game window title** | ✅ Done | Shows "Dust - An Elysian Tail (Asher)" |
| Content patcher | 🔜 Planned | XNA ContentManager interception |
| Mod metadata (json) | 🔜 Planned | mod.json for description, dependencies, etc. |
| Public Mod API docs | 🔜 Planned | Developer documentation and examples |
---
## 🧩 Learning & Implementation Kanban
### 🟢 DONE — Consolidated Phases
#### 🟢 Task 0 — Core Architecture & Bootstrap
**Status:** ✔ Completed
**Deliverables achieved:**
- Stable multi-project solution architecture
- Clear separation between Launcher, Runtime, SDK, and Manager App
- Wrapper EXE approach validated:
- `DustAET.exe` → Asher Launcher
- `DustAET.real.exe` → original game executable
- Full Steam compatibility preserved
- Explicit runtime initialization order guaranteed
#### 🟢 Task 1 — Runtime Modding Foundations
**Status:** ✔ Completed
**Concepts mastered:**
- Generics (used for Asher infrastructure)
- Reflection (runtime inspection, private member access)
- Harmony (Prefix / Postfix / Transpiler patterns)
**Key decisions locked in:**
- Harmony is the official runtime patch engine
- No permanent modification of game binaries or `.xnb` files
#### 🟢 Task 2 — Launcher-Based Runtime Control
**Status:** ✔ Completed
- Custom launcher fully controls game startup
- Runtime initialization occurs before game execution
- Logging, folders, and context prepared deterministically
- Runtime survives Steam launches transparently
#### 🟢 Task 3 — Module System Architecture
**Status:** ✔ Completed
1. **PreInit System** — configuration before patches
2. **Patch System** — Harmony patch application via `IAsherPatchModule`
3. **Lifecycle System** — optional game event hooks
#### 🟢 Task 4 — First Runtime Patch (Debug Enabler)
**Status:** ✔ Completed ✨
- First working gameplay patch: **Debug Menu Enabler**
- PreInit → Patch → Lifecycle flow validated
#### 🟢 Task 5 — Installer & Manager App
**Status:** ✔ Completed
**What was implemented:**
- `Asher.App` WPF installer with guided setup flow
- Game folder auto-detection (Steam, manual browse)
- Deploys runtime, launcher wrapper, and default mods into `Asher/`
- Mod manager with Home, Patch Manager, Settings, and Content Patcher shell
- Patch enable/disable by moving DLLs between `Mods/` and `Mods/disabled/`
- Launch game from manager
- Settings: language, Light/Dark theme, game path, backups
- Desktop shortcut option after installation
- `AsherPaths` helpers and legacy layout migration
- `PrepareDistribution.ps1` for repeatable builds
---
### 🟨 DOING — Current Phase
#### 🟨 Task 6 — Patch Porting & Reverse Engineering
**Status:** 🔄 In Progress
Port and modernize existing gameplay patches from **DustAetPatchingPlatform** into the Asher runtime architecture.
**Current workflow:**
1. Analyze original patch behavior
2. Inspect game internals using **dnSpy** when required
3. Reimplement using `IAsherPreInitModule`, `IAsherPatchModule`, and optional lifecycle hooks
4. Validate with runtime logs
---
### 🟥 BACKLOG — Short Term
#### 🔴 Task 7 — Mod Metadata System
- Design `mod.json` schema
- Parse metadata on mod load
- Load priority and dependency support
#### 🔴 Task 8 — Content Patcher (Core)
- Intercept `ContentManager.Load()`
- Resolve replacements via `content.json`
- Support external assets (textures, fonts, data files)
#### 🔴 Task 9 — Mod Configuration System
- `IAsherConfigModule` interface
- Per-mod configuration files
- UI integration for settings
#### 🔴 Task 10 — Mod Dependency System
- Declare dependencies in `mod.json`
- Validate dependency graph on load
- Automatic load order resolution
---
## 🧠 Project Principles (Non-Negotiable)
- 🚫 No `.xnb` editing
- 🚫 No permanent binary modification
- ✅ 100% runtime patching
- ✅ Fully reversible (remove mod = original behavior)
- ✅ Modular and extensible
- ✅ Inspired by SMAPI, adapted to Dust
- ✅ Clean separation: Launcher → Runtime → SDK → Mods
- ✅ Comprehensive logging for debugging
---
## 🎮 Confirmed Working Features
### Runtime & Modding
- ✅ Dynamic mod loading from `Asher/Mods/`
- ✅ Three-stage mod lifecycle: PreInit → Patch → Lifecycle
- ✅ Clean SDK for mod developers
- ✅ Comprehensive logging in `Asher/AsherLogs/`
- ✅ Game window title: **Dust - An Elysian Tail (Asher)**
### Manager App
- ✅ Guided installation into any valid Dust game folder
- ✅ Patch Manager — toggle mods on/off without deleting files
- ✅ Launch game from manager
- ✅ English and Portuguese (Brazil) UI
- ✅ Light and Dark theme (full window)
- ✅ Desktop shortcut creation after install
- ✅ Settings persisted across sessions
### Working Mods
* ✅ **Debug Menu Enabler** — Tab in pause menu opens debug menu
* ✅ **Intro Skipper** — Skips ESRB rating, splash screens, and startup videos
* ✅ **Graphics Deprofiler** — Bypasses HiDef GPU profile restrictions
All implemented as external, runtime-loaded mods in `Asher/Mods/`.
---
## 📘 References
- **Harmony** — https://github.com/pardeike/Harmony
- **SMAPI** — https://github.com/Pathoschild/SMAPI
- **SMAPI Content Patcher** — https://stardewvalleywiki.com/Modding:Content_Patcher
- **DustAetPatchingPlatform** — https://github.com/GMMan/DustAetPatchingPlatform
- Steam Forum Discussion — https://steamcommunity.com/app/236090/discussions/0/540744936409038540/
*Last Updated: July 2, 2026*