Ignorer le rechargement du domaine : itération plus rapide grâce à la fonctionnalité MethodReload

Oct 22, 2026
Programming and DevOps
MéthodeReload

Cette page a été traduite automatiquement pour faciliter votre expérience. Nous ne pouvons pas garantir l'exactitude ou la fiabilité du contenu traduit. Si vous avez des doutes quant à la qualité de cette traduction, reportez-vous à la version anglaise de la page web.

Nous sommes tous passés par là : vous modifiez un peu le code de jeu, puis vous attendez que l'Éditeur termine un rechargement de domaine. Le processus peut ralentir votre temps d'itération et vraiment épuiser votre créativité. Sans parler du temps supplémentaire passé à itérer sur un appareil, où chaque cycle nécessite une construction complète.

Notre réponse à cela est MethodReload. Nous l'avons démontré sur scène à Unite Seoul et il est maintenant disponible en tant que paquet expérimental. Dans ce billet, nous aborderons comment utiliser MethodReload, quelles sont ses limites et comment il se compare aux outils de rechargement à chaud que vous pourriez déjà avoir dans votre projet.

Pourquoi nous sommes bloqués à recharger

Un peu d'histoire aide ici, car la raison pour laquelle le rechargement de domaine existe est aussi la raison pour laquelle il est difficile de s'en débarrasser.

Play Mode a été construit sur les AppDomains de Mono où les changements de code déclenchaient un processus familier : démanteler le domaine, charger les nouvelles assemblées, re-JITer, puis reprendre dans le même processus. Pendant des années, c'était un véritable superpouvoir, et c'est une grande partie de la raison pour laquelle itérer dans Unity semblait rapide par rapport à construire un joueur.

C'est aussi un instrument brutal, ce qui signifie que pendant le rechargement, tout disparaît et tout revient, que vous ayez changé une méthode ou cent. De plus, IL2CPP ne prend pas en charge les rechargements de domaine du tout, donc chaque changement nécessite de reconstruire l'intégralité du jeu.

Vous pourriez vous demander : « Est-ce que CoreCLR va régler ça ? » et la réponse est : Pas magiquement. Bien que CoreCLR se débarrasse des rechargements de domaine, il doit toujours recharger des assemblies, et MethodReload peut aider à cet égard également.

Comment utiliser MethodReload

Comme mentionné ci-dessus, MethodReload est disponible maintenant et il est inclus dans com.unity.pipeline, actuellement à 0.7.0-exp.1.

Le processus d'utilisation de MethodReload est assez simple. Taggez simplement une ou plusieurs méthodes avec l'attribut [MethodReload], démarrez le watcher, entrez en Mode Jeu ou attachez un joueur de développement, puis modifiez le corps de vos méthodes. L'instance en cours de fonctionnement récupère le nouveau corps lors de son prochain appel.

MethodReload ne remplace pas complètement les rechargements de domaine, cependant. Les changements plus importants passent toujours par la compilation habituelle. Mais pour les petites modifications qui constituent la majeure partie d'une boucle d'itération, cela transforme une longue attente en une affaire de secondes, dans l'Éditeur et sur l'appareil.

Essayez

Le moyen le plus rapide de comprendre MethodReload est de l'exécuter, donc si vous souhaitez l'essayer vous-même, voici quelques étapes pour commencer. Note : étant donné qu'il s'agit d'une fonctionnalité expérimentale, le processus pourrait changer à l'avenir et être différent de ce qui est décrit ici

1. Installer le package (Unity 6.0+ requis). Vous pouvez soit l'installer via l'interface de ligne de commande Unity (CLI), soit utiliser le Gestionnaire de paquets pour ajouter manuellement le paquet Pipeline en utilisant « Installer le paquet par nom technique » et cette chaîne : com.unity.pipeline@0.7.0-exp.1.

2. Taguez les méthodes sur lesquelles vous itérez. L'attribut doit être présent avant d'entrer en Mode Jeu ou de construire un joueur, car la vérification de répartition est tissée au moment de la compilation. Les méthodes marquées doivent être public (instance ou statique) et retourner void ou IEnumerator; tout autre chose est ignoré au moment de la compilation avec un avertissement.

using Unity.Pipeline.MethodReload;
using UnityEngine;

public class Spinner : MonoBehaviour
{
    public float rotationSpeed = 90f;

    [MethodReload]
    public void Update()
    {
        transform.Rotate(Vector3.up, rotationSpeed * Time.deltaTime);
    }
}

3. Démarrer le watcher. Afin que votre MethodReload voie vos changements en direct, vous devrez démarrer le Watcher de MethodReload. Faites cela en allant dans Paramètres du projet → Pipeline → Éditeur, puis dans la section « Méthode Recharger l'observateur de l'interpréteur », cliquez sur Démarrer l'observation.

Paramètres du projet

Alors que le watcher couvre tout l'arbre Assets, un .cs sauvegardé ne compile que s'il contient un attribut MethodReload, donc les sauvegardes sans rapport ne vous coûtent rien.

4. Si vous testez dans l'éditeur : entrez le Mode Jeu. Une fois en cours d'exécution, tout changement de code étiqueté sera compilé et injecté sur place. Une fois que vous quittez le mode jeu, vos modifications seront compilées et passeront par le rechargement de domaine habituel.

5. Si vous testez sur un appareil : branchez un appareil. Construisez un joueur de développement avec le pilote de pipeline d'exécution activé. Connectez l'appareil avec Autoconnect Profiler, ou attachez-le via la fenêtre Profiler ou Console. À partir de là, chaque sauvegarde compile dans l'Éditeur en utilisant les définitions du préprocesseur player's et est poussée à chaque joueur connecté. Aucun redémarrage n'est nécessaire dans aucun sens.

Deux détails de flux de travail à connaître dès le départ :

  • L'auto-actualisation est désactivée pendant l'exécution du watcher, donc une sauvegarde recharge au lieu de déclencher un rechargement du domaine ; les autres ressources ne seront pas importées tant que vous n'aurez pas appuyé sur Ctrl/Cmd+R, et Arrêter l'observation rétablira vos paramètres.
  • La montre survit aux rechargements de domaine : elle réapplique les modifications qu'un rechargement en mode jeu a effacées, et les repousse à un joueur qui se reconnecte, car un joueur redémarré démarre le code compilé original.

Et si on utilisait l'interface en ligne de commande?

Si vous préférez travailler dans un terminal, souhaitez travailler via un agent ou voulez pousser toutes les méthodes étiquetées plutôt que seulement ce qui a changé depuis le début de la surveillance, la même fonctionnalité est exposée en tant que commandes CLI Unity :

# Reload in the Editor through the interpreter
unity command reload_file_editor_interpreter "Assets/Scripts/Spinner.cs"

# Compile in the Editor, push to connected players (folders work too)
unity command reload_file_player_interpreter "Assets/Scripts" --player 2

Limitations

Il n'y a pas de moyen d'éviter le rechargement du domaine sans compromis, et les limites de MethodReload se situent à trois endroits : les types de changements qu'il peut appliquer, le C# qu'il peut exécuter et la rapidité avec laquelle il s'exécute.

Seuls les corps de méthodes étiquetées changent. Un rechargement ne touche jamais les sites d'appel, les champs ou la disposition des types. Pas de nouveaux champs, pas de nouvelles classes. Cette contrainte est ce qui rend sûr de l'appliquer à une instance en direct, et c'est sur laquelle vous planifiez : décidez quelles méthodes vous allez itérer et taguez-les. Un rechargement peut déclarer une nouvelle méthode et l'appeler depuis un corps rechargé, mais cette méthode ne peut pas être un point d'entrée de rechargement, car rien de compilé ne sait l'appeler avant votre prochaine compilation réelle.

Il exécute un sous-ensemble de C#. L'interpréteur est construit à la main et doit rester assez petit pour vivre à l'intérieur d'un joueur, il n'implémente donc pas tout le C#. Dans un corps [MethodReload] vous ne pouvez pas utiliser :

  • await et Task, try/catch/finally, lock, syntaxe de requête LINQ, checked
  • décimal, dynamique, types de réflexion, types de thread
  • ref, out, et in paramètres, ref retours et locaux, tableaux multidimensionnels (jagged est acceptable), méthodes génériques

Ce que fait couvre la plupart du code de jeu : primitives, appels de méthode, boucles, délégués, interpolation de chaînes, coroutine yield, Collections. Un analyseur Roslyn est livré avec le package et signale les violations dans votre IDE, uniquement sur les corps étiquetés, vous permettant de découvrir les problèmes pendant la frappe plutôt qu'après un push.

Sur l'appareil, le code interprété ne peut appeler que ce que le joueur expose. IL2CPP supprime le code sans références, donc un corps rechargé qui appelle un membre de UnityEngine ou de BCL que votre build n'a jamais utilisé n'a rien à appeler. Dans l'Éditeur, les membres manquants se lient à la demande. Sur un appareil, les vérifications de poussée sont faites en avant et listent les membres manquants comme avertissements ; si le code atteint l'un d'eux de toute façon, il lève une exception. Règle générale : changer ce qu'une méthode fait, pas l'ensemble des API sur lesquelles elle dépend.

Le code interprété est plus lent que le code compilé. C'est la nature d'un interpréteur, que la comparaison soit IL2CPP en amont ou Mono et CoreCLR juste à temps. Cela n'affecte que les méthodes étiquetées dans les builds de développement. Dans les versions de publication, il n'y a ni prologue ni interpréteur ; une méthode étiquetée exécute simplement son corps compilé. En fin de compte, c'est à vous de décider si le ralentissement pendant l'itération vaut la vitesse et la commodité d'itération améliorées.

Les coroutines captent les changements à la création. Une méthode [MethodReload] IEnumerator utilise le nouveau corps la prochaine fois que StartCoroutine s'exécute. Les coroutines déjà en cours conservent le corps avec lequel elles ont commencé. Associez-le à [OnMethodReloaded], une méthode d'instance sans paramètres qui se déclenche sur chaque instance vivante après un rechargement qui atterrit sur son type, et vous avez un OnEnable sans rechargement de domaine pour redémarrer des boucles de longue durée :

[OnMethodReloaded]
void OnMethodReloaded()
{
    StopAllCoroutines();
    StartCoroutine(MainLoop());
}

Comment ça fonctionne en coulisses

C'est la combinaison de deux idées : la première est que la compilation de C# produit du bytecode IL, et que l'IL qui reste dans un sous-ensemble modeste peut être exécuté par un interpréteur au lieu d'être compilé. Cet interpréteur est lui-même en C# ordinaire, donc IL2CPP le compile avec le reste de votre jeu, ce qui lui permet de fonctionner sur l'appareil.

La deuxième idée est de s'y mettre. Chaque méthode [MethodReload] a un chemin câblé vers l'interpréteur. Le branchement vers l'interpréteur est effectué en tissant un prologue dans les méthodes étiquetées au moment de la compilation. Décompilé, cela ressemble à ceci :

[MethodReload]
public void TakeDamage(int amount)
{
    // weaved during compilation
    if (MethodReloadRegistry.HasOverride("Player.TakeDamage") &&
        MethodReloadRegistry.TryInvokeMethodReload(
            "Player.TakeDamage", this, amount))
    {
        return;
    }

    // initial code
    hp -= amount;
}

Le contrôle tissé demande à l'enregistrement s'il existe une substitution pour cette méthode. Le watcher et le CLI remplissent ce registre avec du IL fraîchement compilé. S'il y a une entrée, l'interpréteur l'exécute et le corps original est ignoré. Sinon, le code compilé s'exécute comme d'habitude.

Comment cela se compare

De bons outils existent déjà pour itérer sur C# sans rechargement du domaine, et nous préférons être précis sur l'application de chacun plutôt que de prétendre le contraire.

Les méthodes de patch des paquets du Asset Store dans un runtime Mono en cours d'exécution. Cela leur donne une excellente expérience d'édition, du C# complet dans le corps rechargé, sans étape de balisage, et dans le cas de Hot Reload, un mode sur appareil pour les constructions de joueurs Mono. Tous les avantages réels. Cela signifie également qu'ils ne travaillent pas avec un joueur IL2CPP car il n'y a pas de runtime à patcher.

.NET Hot Reload, la fonctionnalité de Visual Studio et de Rider pour les applications .NET, applique les modifications via le chemin d'édition et de continuation du temps d'exécution. Il est conçu pour CoreCLR et ne cible pas les environnements d'exécution Mono ou IL2CPP d'Unity.

MethodReload se situe à un endroit différent avec sa couverture de langage d'interprète backend pour la portée : un sous-ensemble de C#, mais fonctionnant sur la même version de développement IL2CPP que vous redéployeriez autrement sur un téléphone ou un kit de développement de console, via le câble que vous avez déjà branché, sans serveur supplémentaire dans le jeu et sans port à ouvrir.

Version honnête : si votre douleur d'itération réside dans l'Éditeur, les outils existants sont matures et vous devriez continuer à utiliser ce qui fonctionne pour vous. Si votre douleur d'itération réside sur un appareil, et surtout sur IL2CPP, c'est la première option qui y va.

Conseils finaux

Si vous êtes en train de configurer un flux de travail pour un projet en ce moment :

  • Taguez vos points chauds. [MethodReload] ne coûte rien dans les builds de sortie, alors taguez les méthodes Update, de réglage et de sensation de jeu sur lesquelles vous savez que vous allez travailler sur l'appareil.
  • Laissez l'analyseur vous garder à l'intérieur de l'ensemble. Si une méthode a besoin de try/catch ou await, déplacez cette partie dans une fonction auxiliaire non balisée et rechargez la logique autour de celle-ci. L'analyseur vous fera savoir si vous faites quelque chose de mal.
  • Essayez-le d'abord dans l'Éditeur. Le surveillant, ou reload_file_editor_interpreter depuis la CLI, exécute votre édition à travers le même interpréteur qui s'exécute sur l'appareil. Si cela fonctionne là, cela fonctionnera sur le matériel, vous attrapez donc les problèmes de sous-ensemble et de API manquante sans attendre une compilation.

Quoi de neuf

La référence des commandes, la page de configuration d'exécution et la liste complète des contraintes se trouvent dans com.unity.pipeline docs.

Nous vous encourageons à essayer cela dans vos projets et faites-nous savoir comment cela se passe. Les commentaires sont grandement appréciés et les paquets expérimentaux s'améliorent le plus rapidement lorsque les gens y travaillent.

Le rechargement du domaine n'est pas en cours pour les changements qui l'exigent. Pour les changements qui ne, vous pouvez arrêter d'attendre.