ESPACE PUBLICITAIRE DISPONIBLE · PARLONS-EN

Architecture du modding sous Unity : BepInEx sous Mono contre IL2CPP, crochets Harmony et injection d'assemblys

365Finds Editorial
11 430 articles Wiki répertoriés

Utilisez 365 Wiki avec votre IA

Copiez le prompt ci-dessous, collez-le dans l’IA que vous utilisez déjà, puis posez directement votre question.

Télécharger le Skill complet

Commencez par essayer le prompt. Si vous utilisez souvent 365 Wiki, installez le Skill 365Wiki complet pour ne plus avoir à le coller. Sans IA habituelle, les versions web de Gemini ou Microsoft Copilot conviennent aussi.

Introduction : Le fonctionnement du modding sous le moteur Unity

Le moteur de jeu Unity alimente une immense part de la production vidéoludique contemporaine sur PC, depuis les jeux de survie coopératifs comme Valheim et Lethal Company jusqu'aux simulations complexes telles que Cities: Skylines II et Dyson Sphere Program. Contrairement aux moteurs propriétaires s'appuyant sur des archives binaires monolithiques ou au système de plugins déclaratifs de Bethesda, les jeux développés sous Unity reposent sur l'écosystème logiciel .NET et C#.

La modification d'un jeu Unity n'implique généralement pas le remplacement destructif des archives de données stockées sur le disque. Le modding moderne sous Unity s'opère par injection dynamique d'assemblys en mémoire vive et interception de méthodes lors de l'exécution. Au cœur de cette infrastructure se trouvent BepInEx (Bepis Injector Extensible), un injecteur et chargeur de plugins open source, associé à la bibliothèque Harmony, développée par Andreas Pardeike.

Cependant, les créateurs de mods et les joueurs se heurtent fréquemment à des incompatibilités bloquantes en installant des mods sur différents jeux. L'origine de cette complexité réside dans le modèle de compilation du moteur : la profonde divergence architecturale entre le compilateur historique Mono et le compilateur anticipé IL2CPP (Intermediate Language to C++). Comprendre comment BepInEx et Harmony gèrent ces deux environnements est indispensable pour résoudre les plantages, les crochets inopérants et les conflits d'ordre de chargement.

La scission des moteurs de script : architecture Mono contre IL2CPP

Lors de la compilation et du déploiement d'un jeu Unity, les développeurs sélectionnent obligatoirement l'une des deux cibles d'exécution suivantes :

[Code source C# : Scripts de logique de jeu]
               │
               ▼
[Compilateur C# Roslyn / Unity] ---> Common Intermediate Language (Bytecode CIL)
               │
               ├─────────────────────────────────────────┐
               ▼                                         ▼
      [Filière Backend Mono]                    [Filière Backend IL2CPP]
- Empaquette le CIL en assemblys managés      - Transpilateur IL2CPP convertit CIL en C++
- Fichier principal : Assembly-CSharp.dll    - Compilateur C++ génère GameAssembly.dll
- Exécuté par la machine virtuelle JIT Mono  - Métadonnées extraites dans global-metadata.dat
- Réflexion complète, décompilation aisée    - Code machine pur, absence de CLR/JIT natif

Le moteur d'exécution Mono

Dans un jeu compilé avec Mono, l'ensemble des règles de jeu, de l'intelligence artificielle et des contrôleurs d'entités est regroupé dans des assemblys managés .NET, notamment Managed/Assembly-CSharp.dll.

Le moteur d'exécution IL2CPP

Dans un jeu exploitant IL2CPP, la chaîne d'outils applique une transformation radicalement différente :

L'architecture d'amorçage de BepInEx

Pour injecter du code externe dans un exécutable Unity sans modifier son binaire, BepInEx recourt à la technique du détournement de proxy DLL (DLL proxy hijacking).

La chaîne d'injection Doorstop

Sous Windows, le chargeur de l'OS inspecte en priorité le dossier local de l'exécutable pour trouver les bibliothèques dynamiques requises avant de consulter les répertoires système (C:\Windows\System32). BepInEx exploite cet ordonnancement :

  1. La DLL proxy : BepInEx place une bibliothèque factice dans le dossier racine du jeu, sous le nom d'un composant Windows standard tel que winhttp.dll, version.dll ou doorstop.dll.
  2. Interception du chargement : Dès le lancement du jeu, Windows charge la fausse winhttp.dll locale à la place de la véritable bibliothèque système.
  3. Amorçage du moteur : La DLL proxy active Unity Doorstop, qui charge immédiatement en mémoire vive les fichiers BepInEx.Preloader.dll et BepInEx.Core.dll avant même que les routines d'initialisation du moteur Unity ne prennent la main.
  4. Détection des extensions : Une fois l'environnement opérationnel, BepInEx ouvre une console de débogage (si configurée), démarre la journalisation et analyse le dossier BepInEx/plugins/ pour charger les mods compatibles.

BepInEx 5 contre BepInEx 6 : Le pont d'interopérabilité IL2CPP

Harmony : Interception dynamique et modification des méthodes en mémoire

Après l'initialisation assurée par BepInEx, les mods s'appuient sur Harmony pour altérer la logique du jeu sans modifier un seul fichier sur le stockage. Harmony opère en réécrivant à chaud les prologues des méthodes compilées dans la mémoire JIT.

Les quatre catégories fondamentales de crochets Harmony

[Appel de la méthode d'origine : ex. PlayerController.TakeDamage(float amount)]
           │
           ▼
[Crochet Prefix Harmony] ---> Renvoie true (poursuivre) OU Renvoie false (ignorer l'original)
           │
           ▼
[Exécution de la méthode d'origine : Calcul et déduction des points de vie]
           │
           ▼
[Crochet Postfix Harmony] ---> Lit/Modifie la valeur de retour (__result) ou l'état
           │
           ▼
[Crochet Finalizer Harmony] ---> Intercepte les exceptions non gérées et évite le crash
  1. Prefix ([HarmonyPrefix]) :
    • S'exécute immédiatement avant le déclenchement de la méthode d'origine du jeu.
    • Peut inspecter et altérer les arguments d'entrée (par exemple, ajuster la valeur float amount avant le calcul des dégâts).
    • Offre la possibilité de court-circuiter l'exécution : si le Prefix renvoie false, la méthode originale du jeu est purement ignorée.
  2. Postfix ([HarmonyPostfix]) :
    • S'exécute dès la fin de l'exécution de la méthode d'origine.
    • Permet de lire et de réécrire la valeur de retour via le paramètre spécial ref __result.
    • Constitue la méthode idéale pour déclencher des événements secondaires (comme débloquer un succès après la fabrication d'un objet).
  3. Transpiler ([HarmonyTranspiler]) :
    • La méthode d'interception la plus fine et technique. Elle capture le bytecode CIL d'une méthode sous forme de séquence d'instructions (IEnumerable de CodeInstruction) avant la compilation JIT.
    • Permet d'insérer, supprimer ou remplacer des instructions opérationnelles spécifiques (comme convertir une constante de ldc.i4.0 en ldc.i4.1).
  4. Finalizer ([HarmonyFinalizer]) :
    • Agit comme un bloc de protection dynamique try/finally autour de la méthode interceptée. Il intercepte les exceptions non gérées, empêchant ainsi une erreur de mod de fermer brusquement le jeu vers le bureau.

Matrice de dépannage : Résolution des pannes courantes de modding Unity

Lorsque des mods refusent de se charger ou provoquent des fermetures inattendues du jeu, appliquez la grille d'analyse suivante pour diagnostiquer les défaillances architecturales :

Symptôme de panneCause architecturale sous-jacenteIndicateur de diagnosticMesure corrective
Console absente / Mods ignorésLa DLL proxy est bloquée ou ignorée par le chargeur OSAucun fichier BepInEx/LogOutput.log crééVérifier la présence de winhttp.dll à la racine ; contrôler les droits du dossier
Fermeture immédiate au lancement (IL2CPP)Utilisation de BepInEx 5 sur un jeu compilé en IL2CPPGameAssembly.dll présent à la racine mais BepInEx 5 installéSupprimer BepInEx et déployer BepInEx 6 x64 spécialisé pour IL2CPP
Cache d'interopérabilité périméMise à jour du jeu sans régénération des wrappersErreur TypeLoadException ou MissingMethodException dans les logsSupprimer le dossier BepInEx/interop/ pour forcer une régénération propre
Collision de crochets PrefixPlusieurs mods interceptent la même fonction avec retour falseUn mod fonctionne correctement, l'autre perd ses fonctionnalitésRéorganiser l'ordre de chargement ; éviter les annulations agressives en Prefix
Blocage par système anti-tricheEAC ou BattlEye bloquent l'injection de la DLL proxyLe jeu se ferme avec un avertissement de fichier non approuvéExécuter le jeu hors ligne ou appliquer les paramètres de lancement moddé officiels

Lors de la mise en place d'ordres de chargement de mods, du débogage de conflits d'assemblys ou du développement d'extensions C# personnalisées pour différents moteurs de jeu, consulter les analyses techniques de 365Finds garantit une parfaite adéquation avec les contraintes d'exécution réelles. Envisager le modding Unity sous l'angle de la gestion de mémoire, de l'injection de proxys et du patchage non destructif de bytecode permet de pérenniser vos installations face aux mises à jour régulières des jeux.

Références