Aperçu
Nouveautés
- Shift-F9 à Shift-F12 ont désormais leurs propres entrées de raccourcis, et les accès rapides 1 à 4 sont de nouveau libres.
- Les annonces de vol en taxi peuvent être désactivées, et elles ne nomment plus jamais le point de départ ni celui d'arrivée comme atterrissage possible.
- Nouvelle condition d'aura « Buff debuff vos sorts uniquement » qui filtre les listes de buffs et de debuffs de cette aura sur les effets que vous avez lancés.
- Nouvelle commande /skucheck qui vérifie des règles fixes sur l'état réel du jeu ; elle reprend aussi les outils de base de données comme sous-commandes (wp, db, mem).
- L'installateur collecte tous les journaux pour un rapport de bogue en un seul bouton.
- L'écran de connexion est désormais utilisable avec l'outil de connexion.
- Les listes de points de passage annoncent l'avancement du chargement.
Changements
- Les avertissements d'expiration d'aura arrivent à l'heure au lieu du prochain événement de combat.
- L'évaluation des auras par événement de combat est nettement moins coûteuse.
- Annuler la navigation ne passe plus que par une seule touche.
- Le moniteur de ressource peut suivre la barre que le jeu affiche : un druide obtient ainsi mana, rage ou énergie selon sa forme.
- Le journal de l'outil de connexion survit à un redémarrage de l'outil.
- Les données de points de passage sont utilisables bien plus tôt après la connexion, votre propre continent d'abord, et occupent environ 22 Mo de mémoire en moins ; la partie des données d'itinéraires que votre version de jeu ne lit pas n'est plus construite du tout.
- Les auras sont désormais interchangeables entre langues : une aura fonctionne sur tous les clients.
- Les ensembles d'auras partagés arrivent utilisables chez un équipier d'une autre langue.
- Tous les rangs d'un sort comptent pour une seule entrée d'aura.
- Les noms de sorts attribués plusieurs fois par le jeu se distinguent maintenant dans les listes de sélection.
- Les ensembles d'auras fournis ne sont plus réservés aux clients allemands.
- Le menu dans lequel on construit une aura a été refait : liste d'attributs triée par nom, conditions à deux valeurs en bascules, sorts saisissables autant que sélectionnables, et toutes les listes de valeurs s'ouvrent plus vite.
- Chaque entrée de menu de tout l'addon coûte environ 13 fois moins à créer, ce qui ouvre les grandes listes de sorts environ trois fois plus vite.
- Une liste dont la construction a été interrompue par le serveur est poursuivie à la frame suivante au lieu de rester incomplète sans le dire.
- Les réglages à deux valeurs annoncent leur valeur avec le nom et se basculent avec Entrée ; la flèche droite et le sous-menu disparaissent.
- Les curseurs de volume du menu Sku règlent directement le réglage du jeu ; Sku n'en garde plus de copie.
Corrections
- Clients français : tous les sons d'auras et les clips vocaux enregistrés étaient muets (correctif de Naxedim).
- Clients français : la vérification de distance n'annonçait rien et son menu levait une erreur (correctif de Naxedim).
- Clients français : deux suites du même rapport corrigées.
- Neuf libellés traduits signifiaient autre chose selon la langue (correctif de ZenqFR).
- Auras : certaines places de groupe étaient annoncées par un bip au lieu d'un mot.
- Auras : une aura réglée sur « une fois » pouvait se déclencher plusieurs fois de suite en combat dense.
- Menu : sur les grandes cartes, la liste de points de passage de Shift-F9 ne s'ouvrait qu'au deuxième essai.
- Les clés du porte-clés étaient annoncées comme « Vide ».
- Sur les royaumes hardcore, Sku termine désormais le chargement de ses points de passage au lieu de s'arrêter en silence.
- Navigation : la liste des itinéraires pouvait rester vide et muette lorsque les points de passage étaient reconstruits pendant qu'un menu était ouvert.
- Des données d'itinéraires manquantes sont désormais signalées au lieu d'apparaître comme une liste vide.
- Une fenêtre surgissante ouverte en combat (invitation de groupe, invocation, libération) pouvait être lue mais pas répondue.
- Un itinéraire ne démarrait pas si sa liste finissait de charger pendant que vous y étiez.
- L'outil de connexion prenait l'écran de connexion pour la sélection de personnage.
- L'outil de connexion : sur les royaumes comptant dix personnages ou plus, la liste des personnages était incomplète, mal numérotée ou refusait de revenir en arrière.
- Moniteur de ressource : le réglage « rien » provoquait une série d'erreurs Lua.
- Moniteur de ressource : un moniteur désactivé dans le menu des fonctions annonçait quand même les changements de ressource.
- Clients français : la liste des enchantements d'arme pour les auras était vide.
- La vérification de préparation n'arrivait pas directement sur « Prêt » comme le fait toute autre fenêtre surgissante.
- Un volume de jeu réglé dans le menu Sku pouvait revenir à une ancienne valeur sur un autre personnage.
- Les quatre profils standard sont créés sans changer de profil entre-temps - sur les royaumes hardcore, cela pouvait vous laisser dans un profil qui n'est pas le vôtre.
Avec nos remerciements à Naxedim et ZenqFR
Les quatre correctifs suivants sont les premières contributions de code directes au dépôt Sku désormais public. Naxedim a trouvé, analysé et corrigé les deux bogues qui rendaient muette une grande partie de la sortie audio de Sku sur les clients français ; ZenqFR a audité les fichiers de traduction, résolu tous les doublons contradictoires côté anglais et français et amélioré l'outil qui protège contre de nouveaux doublons. Tout le mérite de ces correctifs leur revient.
Clients français : tous les sons d'auras et les clips vocaux enregistrés étaient muets (correctif de Naxedim)
Simple : Sur un client français, depuis la v42.11, chaque aura dont la sortie est un son ne jouait plus rien du tout - pas d'erreur, pas de ligne de journal, juste le silence - et chaque clip vocal enregistré retombait sans bruit sur la synthèse vocale (TTS). La cause : depuis que Sku parle français, il cherche aussi un pack vocal FRANÇAIS, et un tel pack n'existe pas ; la recherche ne trouvait donc rien et tout ce que le pack vocal fournit devenait muet. La parole ne faisait que se dégrader en TTS, mais un effet sonore n'a rien vers quoi se dégrader - c'est pourquoi cela ressemblait à « mes auras ne fonctionnent plus » plutôt qu'à « l'audio a changé ». La recherche de pack utilise maintenant le même repli vers l'anglais que le reste du système audio depuis la v42.09. Les clients allemands et anglais ne sont absolument pas affectés.
Technique : Le résolveur de pack vocal dans Core.lua comparait les locales des packs à Sku.Loc ; depuis que la v42.11 livre locales/frFR.lua, Sku.Loc vaut « frFR » sur un client français, aucun pack ne pouvait la déclarer, Sku.AudiodataPath restait "" et VoicePackAudioDir() renvoyait nil - réduisant au silence les 64 entrées de SkuCore.outputSoundFiles (sons d'auras, son de combat de SkuMob, son de nouvelle ligne de SkuChat) plus chaque clip vocal du pack. La comparaison se fait maintenant sur Sku.LocAudio ou Sku.Loc, exactement la règle « vers quelle langue enregistrée est-ce que je me replie » qu'IntegratedAudioDir() utilise déjà ; Sku.LocAudio vaut « enUS » sur tout client non allemand, le comportement deDE/enUS est donc identique à l'octet près. Trouvé sur un vrai client français, corrigé et vérifié en jeu par Naxedim (PR #5).
Clients français : la vérification de distance n'annonçait plus rien et son menu levait une erreur (correctif de Naxedim)
Simple : Sur un client français, la vérification de distance n'annonçait plus aucune distance, quelle que soit la cible, et l'ouverture du menu de configuration des distances produisait une erreur au lieu du menu. Deux causes, toutes deux propres au français : premièrement, le réglage « prononcer la distance » est enregistré dans la configuration sous la forme du MOT traduit pour « Parlé » - une configuration écrite quand Sku tournait encore en anglais (avant la v42.11) contient le mot anglais, que le client désormais français ne reconnaît plus. Deuxièmement, les clips de nombres n'existent enregistrés qu'en allemand et en anglais, et le code énumérait exactement ces deux langues - un client français restait donc silencieux même avec une configuration française toute fraîche. Le marqueur enregistré est maintenant accepté dans les trois langues, une valeur inconnue ne peut plus casser le menu, et les clips se replient sur les enregistrements anglais comme le reste du système audio. Les clients allemands et anglais sont inchangés : même marqueur, mêmes clips, même audio.
Technique : Un nouveau RangeCheck:IsSpokenSound() accepte « Gesprochen »/« Spoken »/ « Parlé » (plus le L["vocalized"] traduit à chaud), utilisé par DoRangeCheck et par le constructeur de menu dans Options.lua - ce dernier tombait jusqu'ici dans la branche else pour une valeur inconnue et concaténait nil depuis SkuCore.RangeCheckSounds, ce qui levait l'erreur. Le dossier de clips vient maintenant de Sku.LocAudio (hans_de-de pour deDE, hans_en-us sinon) au lieu d'une chaîne de Sku.Loc qui ne correspondait à aucune branche en frFR. Les nouvelles entrées écrivent toujours L["vocalized"] ; pas de migration de données. Trouvé et vérifié sur un vrai client français par Naxedim (PR #6).
Traductions : neuf libellés signifiaient autre chose selon la langue (correctif de ZenqFR)
Simple : Neuf textes figuraient en double dans les fichiers de traduction avec deux significations DIFFÉRENTES, et chaque langue pouvait finir par retenir une version différente. C'était le plus audible sur les clients anglais, où le mauvais jumeau l'emportait plusieurs fois : la barre d'action de posture était annoncée « Special Action bar » (une toute autre barre), la touche de débogage « debug mode » au lieu de « debug output », une catégorie de menu « Features » au lieu de « Values ». Pour chaque paire, la signification réellement correcte a été déterminée d'après l'endroit où le texte est utilisé dans le code, et le mauvais jumeau a été supprimé dans les trois langues - l'anglais, l'allemand et le français sont maintenant d'accord sur les neuf. Six doublons purement allemands restent volontairement ouverts jusqu'à ce qu'un germanophone tranche.
Technique : AceLocale résout les clés en double par « le premier gagne » pour la langue par défaut (enUS) et par « le dernier gagne » partout ailleurs - un doublon à deux valeurs signifie donc silencieusement autre chose selon la langue. ZenqFR a retracé les points d'appel réels de chaque clé pour déterminer la valeur survivante (PR #3) et a appris à dev/rework-docs/_locale_dupes.py à ne comparer que le littéral de chaîne Lua analysé au lieu de la ligne brute, pour que les commentaires « -- » en fin de ligne ne comptent plus comme conflits (PR #4) - sur 64 conflits signalés, seuls 30 étaient réels ; enUS et frFR passent maintenant le lint à zéro, deDE avec les six paires de formulations allemandes laissées à un locuteur natif.
Clients français : deux suites du rapport de Naxedim sur le pack vocal
Simple : Le son nommé « bring » - une cloche, nommée d'après le bruit qu'elle fait - apparaissait dans les menus français comme « apporter » : la traduction l'avait lu comme le verbe anglais « to bring ». C'est un nom, pas un mot, et il reste désormais « bring » comme ses voisins non traduits « brang », « dang » et « drmm ». Par ailleurs, le diagnostic interne qui note quel pack vocal a été trouvé nomme maintenant la langue réellement cherchée au lieu de la langue du client - avant, un client français sans le pack anglais installé aurait affirmé « no voice pack found for frFR », désignant un pack qui ne peut pas exister.
Technique : locales/frFR.lua remet L["bring"] sur l'onomatopée. Core.lua renseigne maintenant Sku.AudiodataPathInfo dans une branche else du résolveur à partir de tWantedLoc (la clé de recherche basée sur Sku.LocAudio) plus la locale du client ; lisible via /wdeval Sku.AudiodataPathInfo. Le troisième point du rapport de la PR #5 - frFR traduit le préfixe des libellés de sortie en « aura;son » - a été examiné et volontairement CONSERVÉ : chaque site de comparaison reconstruit le préfixe depuis la table de locale active, et les réglages/auras enregistrés conservent des clés d'identifiants (« sound-brass1 »), jamais le libellé - la traduction est donc sûre ; une synthèse vocale française pour un libellé français vaut mieux qu'un clip anglais.
Sacs : les clés du porte-clés étaient annoncées comme « Vide »
Simple : Depuis la v42.13, chaque emplacement du porte-clés disait « Vide » alors que les clés étaient bien là et restaient utilisables - cela ne s'est vu que lorsque quelqu'un a vraiment eu besoin du porte-clés. Le déclencheur était le correctif de la banque de la v42.13 : dans le client du jeu, le porte-clés présente la même particularité que le conteneur principal de la banque et demandait le même traitement spécial, que seule la banque avait reçu à l'époque. Les clés sont de nouveau annoncées par leur nom. Le porte-clés n'affiche en outre plus que les emplacements qu'il utilise réellement au lieu de 32 fixes - auparavant, des dizaines d'emplacements vides suivaient les clés.
Technique : GameTooltip:SetBagItem(-2, slot) ne remplit rien sur ce client, exactement comme le conteneur de banque -1. Les noms de clés ne fonctionnaient que grâce au repli générique SetHyperlink de 67f2132 ; quand la v42.13 a volontairement supprimé ce repli et n'a basculé que la banque (-1) vers SetInventoryItem, le porte-clés est retombé en silence sur le SetBagItem vide. tSetTooltipContainerItem lit désormais -2 via SetInventoryItem("player", KeyRingButtonIDToInvSlotID(slot)) - exactement ce que fait ContainerFrameItemButton_OnEnter de Blizzard pour le porte-clés. Build_BagsFrame limite en plus le nombre d'emplacements de -2 avec GetKeyRingSize() (emplacements occupés arrondis à des rangées complètes de quatre), comme la fenêtre de porte-clés de Blizzard, au lieu de reprendre les 32 bruts de GetContainerNumSlots.
Diagnostic : nouvelle commande /skucheck qui vérifie des règles fixes sur l'état réel du jeu
Simple : /skucheck parcourt toutes les données des sacs et vérifie que chaque emplacement occupé fournit un nom prononçable ; le résultat tient en une ligne parlée, par exemple « Vérification des sacs : 64 vérifiés, aucun problème », avec un renvoi vers le journal en cas de problème. La commande vérifie les données elles-mêmes, pas les menus - elle aurait donc signalé le bogue du porte-clés même sans jamais l'ouvrir. La liste des règles ne grandit qu'avec les bogues corrigés : chaque correctif apportera désormais sa propre règle de garde, afin qu'une modification ultérieure ne puisse pas réintroduire le même bogue sans bruit. Depuis cette version, /skucheck est en outre la seule commande de vérification : les trois outils de base de données sont devenus des sous-commandes - /skucheck wp vérifie les données de points de passage et s'exécute avec un /skucheck sans argument, tandis que /skucheck db et /skucheck mem sont des mesures qui ne s'exécutent que sur demande. Les anciens noms /skudbwpcheck, /skudbcheck et /skudbmem fonctionnent toujours.
Technique : En fin de LocalMenu.lua ; parcourt tBagSlotListSorted avec la même API de conteneurs et la même résolution de noms que le menu des sacs. Règle 1 : emplacement avec un identifiant d'objet mais un texte d'infobulle vide = violation ; chaque violation est écrite dans l'anneau SkuDebugLog en ligne « skucheck » avec sac, emplacement, identifiant et lien. La banque fermée est sautée avec une ligne de journal (pas en silence), le porte-clés est volontairement balayé sur ses 32 emplacements bruts, et les objets pas encore envoyés par le serveur comptent comme « en attente » et non comme des échecs. Les domaines wp/db/mem appellent SkuDBTools.RunWpCheck/RunDbCheck/RunMem (SkuDBTools.lua) ; ils s'exécutent en tâche de fond et annoncent eux-mêmes leur résultat, mais l'écrivent aussi dans l'anneau en lignes « skucheck » - les violations de points de passage une par une, alors qu'elles n'étaient lisibles que dans les SavedVariables. /skucheck db indique en plus combien de jeux de données ont changé depuis la capture précédente. Raison de ce regroupement : avec trois commandes séparées, on pouvait lancer « la vérification » et manquer entièrement les règles des points de passage.
Auras : les avertissements d'expiration arrivent à l'heure, pas au prochain événement de combat
Simple : Deux plaintes anciennes avaient la même cause : une aura comme « affaiblissement sur la cible sous 3 secondes » ou « mon affaiblissement a disparu de la cible » n'était revérifiée que lorsqu'un AUTRE événement de combat arrivait. Dans un combat purement au corps à corps, l'avertissement pouvait donc arriver avec un coup d'arme entier de retard, hors combat avec des minutes - ou ne jamais partir avant l'expiration elle-même. Sku note désormais, en vérifiant l'effet, QUAND le seuil sera atteint et réveille la vérification exactement à ce moment ; l'apparition ou la disparition d'un effet déclenche aussi la vérification directement. De plus, les mots parlés d'une aura peuvent maintenant dépasser les annonces en attente, comme le font déjà les sons d'alerte - ils n'interrompent rien et ne chevauchent rien, ils ne se mettent simplement plus en queue. Les avertissements d'enchantement d'arme en profitent aussi : au lieu d'un retard pouvant atteindre une seconde, ils partent désormais à l'image près.
Technique : Trois mécanismes : (1) un planificateur d'échéances dans SkuAuras/Core.lua - chaque passe d'évaluation note dans tNextDurationDeadline le moment de seuil le plus proche (expirationTime moins seuil) de toutes les conditions de durée actives (opérateur « plus petit ») ; le pilote de trame compare un nombre par trame puis déclenche UNE passe synthétique DURATION_DEADLINE. Remplace la revérification approchée à la seconde des enchantements d'arme. (2) UNIT_AURA déclenche une évaluation lors d'un vrai changement d'ensemble des effets (ajout/retrait, pas les mises à jour de piles ou de durée) - différence de noms contre un instantané, filtrée contre les passes du journal de combat dans la même trame et contre les changements de cible. (3) les sorties en mots utilisent le chemin aInstant d'OutputString, présent mais jamais branché (insertion en tête au lieu d'ajout en queue) ; un curseur de trame garde les sorties en plusieurs parties dans l'ordre parlé.
Auras : évaluation par événement de combat nettement moins coûteuse
Simple : En raid, Sku évalue les auras des centaines de fois par seconde. Plusieurs coûts cachés ont disparu : les conditions étaient vérifiées deux fois, les durées restantes redemandées au client à chaque événement, et le groupe entier parcouru requête par requête pour chaque événement. Deux bogues silencieux corrigés au passage : une aura sans condition « sort en temps de recharge » pouvait annoncer le nom de recharge d'une AUTRE aura, et les temps de recharge d'objets étaient réhorodatés à chaque changement de sac. /skucheck gagne pour cela un domaine « auras » qui vérifie que l'évaluation n'écrit plus de globales.
Technique : Évaluer une fois au lieu de deux (la branche à valeur unique de la boucle d'attributs tournait deux fois par accident ; plus deux globales fuitées, tSpellNameOnCdValue injectait des valeurs périmées d'une aura à l'autre). Les durées restantes viennent d'une extension expirationTime du cache de listes de niveau 2 au lieu de rebalayages UnitAura (/skuauracache verify vérifie maintenant aussi les valeurs exp, /skuauracache off désactive les deux). Les GUID de groupe se résolvent via une carte invalidée aux événements de roster au lieu de boucles raid1..40 par événement (l'ordre du résultat et l'horizon historique raid1..25 du RoleChecker sont préservés exactement). targetUnitDistance et targetTargetUnitId sont paresseux, LogRecorder fait un accès aux réglages au lieu de quatre, et la garde UNIT_INVENTORY_CHANGED teste le vrai itemID au lieu d'une globale nil.
Installateur : un bouton collecte tous les journaux pour un rapport de bogue
Simple : L'écran d'accueil de l'installateur comporte un nouveau bouton, « Collecter tous les journaux ». Il crée UN seul fichier zip dans votre dossier Téléchargements contenant tout ce qu'il faut pour diagnostiquer un problème - et ce pour TOUTES les versions du jeu détectées à la fois, pas seulement une : le journal de débogage et d'erreurs de Sku, les captures de BugGrabber/BugSack et de WVDebug, les journaux du jeu lui-même avec ses erreurs Lua, le fichier de CVar Config.wtf, la liste de tous les addons installés avec leur version, le journal de l'outil de connexion et celui de l'installateur. Jusqu'ici il fallait aller chercher ces fichiers un par un dans trois arborescences différentes, et en oublier un valait une question de plus au lieu d'une réponse. Le fichier s'appelle Sku-Logs-<date>.zip ; l'installateur en énonce le chemin complet et ouvre le dossier avec le fichier déjà sélectionné, prêt à être joint à un rapport de bogue. Une collecte typique pèse environ 7 Mo.
Technique : Nouveau fichier LogCollector.cs dans l'installateur, déclenché par un quatrième bouton dans UpdatePromptForm (libellé et texte vocalisé dans les trois langues). La collecte se fait dans un sous-dossier par client : les SavedVariables de la portée compte ET de la portée personnage (Sku écrit dans les deux), y compris les copies .bak
- celles-ci sont l'état de la session PRÉCÉDENTE et donc souvent la seule copie
subsistante de l'anneau de débogage sur lequel porte le rapport - ainsi que Logs, Errors, Config.wtf, Sku.toc, .build.info et une liste des addons avec versions de TOC et marquage des liens symboliques. S'y ajoutent system-info.txt (système, langue, un bloc par client et la liste de ce qui n'a PAS été inclus et pourquoi - une omission doit se lire comme une omission et non comme une absence) et le journal de l'installateur, forcé pour l'occasion du tampon mémoire de Logger vers le disque. Le dossier Errors est délibérément exempté de la limite d'âge de 30 jours - il ne contient quelque chose que lorsque quelque chose a réellement cassé, et le premier essai réel n'en livrait sinon aucun des 21 rapports de plantage présents - et il est plafonné aux 25 plus récents à la place. L'installateur passe ainsi en version 4.2.
Outil de connexion : son journal survit désormais à un redémarrage de l'outil
Simple : L'outil de connexion effaçait son journal à CHAQUE démarrage. Quiconque tombait sur un bogue, fermait l'outil puis le rouvrait avant de collecter les journaux détruisait donc la preuve même qu'il s'apprêtait à signaler - et c'est la séquence la plus courante d'un rapport de bogue. Les cinq dernières sessions restent maintenant à côté du log.txt courant sous les noms log-1.txt à log-5.txt, et le nouveau bouton de collecte de l'installateur les emporte automatiquement.
Technique : log.ahk écrit désormais vers un chemin ABSOLU dérivé de l'emplacement du script au lieu du nom relatif « log.txt », qui se résout par rapport au répertoire de travail du processus - START.ahk le règle correctement, mais c'est un état global au processus que n'importe quoi peut changer ensuite, et un journal qui atterrit là où personne ne regarde ne vaut pas mieux que pas de journal. ClearLogFile() effectue une rotation au lieu d'effacer. L'empaquetage et le .gitignore excluent log-*.txt exactement comme log.txt, et les journaux d'une installation existante ne sont jamais touchés par une mise à jour.
Outil de connexion : l'écran de connexion s'annonçait comme la sélection de personnage
Simple : Quand le jeu n'atteint pas le serveur au démarrage, on n'arrive pas sur la sélection de personnage mais sur l'écran de connexion, avec nom de compte, mot de passe et bouton Login. L'outil y menait au menu principal, dont la première entrée est « sélectionner un personnage » : l'écran qui prouve justement qu'il n'y a aucune liste de personnages s'annonçait donc comme la sélection de personnage. Qui ne le voit pas n'entendait rien qui le distingue du vrai. L'outil annonce désormais une fois à l'arrivée : pas connecté, soit il n'y a pas de connexion au serveur, soit le nom de compte et le mot de passe doivent encore être saisis dans le jeu. Il remarque aussi maintenant le changement d'écran : si l'on se connecte à la main, la liste des personnages est construite aussitôt, au lieu de laisser l'outil muet sur l'ancien menu.
Technique : « pas de connexion » n'est PAS un écran distinct - vérifié sur le client 2.5.6 en fonctionnement, il est identique au pixel et à l'OCR près à un écran de connexion normal (mêmes sondes de widgets, checks.login = true, aucune fenêtre). Il n'y a donc rien à marquer : l'outil n'annonce que ce qui y est toujours vrai, ce client n'est pas connecté. Le menu est désormais son propre arbre plutôt que le menu principal, et InitLogin ne s'exécutait qu'au changement de MODE, d'où un changement d'écran passé inaperçu ; le veilleur déclenche maintenant une réinitialisation complète dès que l'écran de connexion est atteint ou quitté.
Outil de connexion : l'écran de connexion est désormais utilisable
Simple : Le menu de l'écran de connexion commence maintenant par les commandes de l'écran lui-même : nom de compte, mot de passe, se connecter, enregistrer le nom de compte - puis, inchangés, la voix, la langue, le type de jeu, la région et la version, afin que les réglages restent accessibles même si la connexion échoue. L'outil n'enregistre RIEN et ne saisit rien : il place seulement le curseur du jeu dans le champ et passe le clavier au client, c'est vous qui tapez. Il n'y a pas de connexion automatique et il n'y en aura pas. Le nom de compte est lu à voix haute, « vide » s'il est vide ; le mot de passe n'est JAMAIS lu. Tant que le clavier appartient à un champ, les flèches vont au jeu, pour pouvoir atteindre une faute de frappe ; Entrée termine la saisie, Échap la quitte, et aucune des deux n'est transmise au jeu - se connecter est une entrée à part, pour que rien ne parte par accident. Fermer et rouvrir Battle.net reste généralement plus rapide ; la voie manuelle existe pour ceux qui la veulent.
Technique : quatre nouveaux widgets dans data.ini ([Classic] et [BurningCrusade]) : LoginAccountField 10000,403, LoginPasswordField 10000,478, LoginSubmitButton 10000,531 et LoginSaveAccountCheckbox 26,662 - mesurés sur le client en fonctionnement en 2880x1800 puis convertis dans l'espace d'interface de 768 de haut, donc indépendants de la résolution, et recoupés avec des entrées déjà présentes (« Account erstellen » mesuré à 549 contre les 550 enregistrés). Le contenu du champ est lu par OCR du CHAMP seul, pour qu'aucune étiquette venue d'ailleurs ne passe pour du contenu. « Se connecter » suit la tentative : les fenêtres de progression à un seul bouton sont lues mais PAS cliquées, car leur unique bouton est Annuler et il coupe la connexion en cours - le même piège que pour l'entrée en royaume ; les fenêtres à deux boutons sont lues et traitées. Là où les widgets manquent (Cata, Retail), les entrées le disent et ne font rien.
Outil de connexion : la liste des personnages sur les royaumes de dix personnages ou plus
Simple : Le panneau des personnages en affiche exactement neuf à la fois. À partir du dixième, la liste défile, et tout a déraillé en même temps : des personnages manquaient, la numérotation ne correspondait pas à la liste réelle, et le retour au début de la liste ne fonctionnait pas de façon fiable. Les trois ont la même cause. L'outil parcourt la liste avec les touches fléchées et observe le déplacement de la barre de sélection - or dès que la liste défile, la barre ne bouge plus, et « rien n'a changé » était lu comme « la liste s'arrête ici ». Une touche avalée par le jeu a exactement la même allure, et c'est elle qui tronquait les listes. Avec neuf personnages ou moins la liste ne défile jamais, ce qui explique que rien de tout cela n'ait jamais été visible. L'outil demande maintenant deux fois avant de croire à une fin de liste, et s'appuie sur le grand nom affiché sous le modèle du personnage pour trancher - ce nom est celui du personnage sélectionné, quel que soit le défilement. Il annonce également le compte en cours tous les dix personnages, car une longue liste représente sinon une demi-minute de silence, et le menu reste utilisable pendant sa reconstruction au lieu de devenir muet. NON TESTÉ en jeu : il n'existe ici aucun royaume de plus de neuf personnages. Si la liste reste fausse, le journal de l'outil nomme désormais précisément la décision erronée.
Technique : Vérifié sur le code d'interface du client lui-même. Blizzard_GlueXML_TBC.toc charge Vanilla\CharacterSelectConstants.lua avec CHARACTER_SELECT_MAX_CHARACTERS = 9, et CharacterSelect_OnShow l'affecte à MAX_CHARACTERS_DISPLAYED. Toute condition d'arrêt du parcours qui reposait sur UNE seule observation en exige désormais deux, avec une attente plus longue entre les deux, et ne represse qu'après qu'un coup d'œil a prouvé que rien n'avait bougé - une seconde pression sur une étape déjà enregistrée saute un personnage sans laisser de trace. La détection du bouclage exige maintenant l'emplacement 1 exactement, car CharacterSelectScrollDown_OnClick, passé le dernier personnage, fait CHARACTER_LIST_OFFSET = 0 puis SelectCharacter(1) ; le retour en haut est en outre attendu avant confirmation. Le repli qui ne lit que la portion visible remonte désormais d'abord en haut, car UpdateCharacterSelection fixe le décalage à selectedIndex - MAX_CHARACTERS_DISPLAYED dès que le dernier personnage joué se trouve sous la limite - les neuf lignes visibles étaient alors les personnages 6 à 14, annoncés 1 à 9. Les sondes de pixels de la barre de sélection ont été déplacées vers la gauche : à dix personnages, UpdateCharacterList élargit le panneau de 260 à 280 et affiche une barre de défilement dont le fond noir recouvre précisément la bande que la barre de sélection libère. Le menu est maintenant construit détaché et publié en une seule affectation, comme la liste des royaumes.
Royaumes hardcore : Sku termine désormais le chargement de ses points de passage au lieu de s'arrêter en silence
Simple : Sur les royaumes hardcore, le client de jeu accorde aux addons nettement moins de temps de calcul par image que sur les royaumes normaux. Sku construit ses données de points de passage et d'itinéraires juste après la connexion, et c'est précisément cette construction qui se heurtait à cette limite : le client interrompait purement et simplement le travail en cours, et Sku ne s'en apercevait pas. Résultat : toutes les listes de points de passage répondaient « points de passage en cours de chargement » pendant toute la session - sans erreur, sans annonce vocale, sans entrée de journal - et recharger l'interface n'y changeait rien. Sku détecte maintenant que le client le freine, réduit la taille de ses lots de travail et continue au lieu de s'arrêter ; si un lot est malgré tout interrompu, la construction repart d'elle-même. Le prix à payer : sur ces royaumes, il faut quelques secondes de plus après la connexion avant que les itinéraires et les points de passage soient complets. Tout le reste de Sku est utilisable immédiatement, et les listes indiquent maintenant l'avancement (entrée suivante). Les royaumes normaux ne changent pas.
Technique : Le client signale l'interruption par le LUA_WARNING « insecure scripts exceeded execution limit for addon Sku », ou par « script ran too long » levé à l'intérieur de la coroutine en cours. Sur le royaume hardcore, cela s'est produit à chaque connexion (52/25/25 avertissements par connexion) et pas une seule fois dans les huit sessions enregistrées sur des royaumes Era et Anniversary normaux - pour un travail identique (1936 ms sur Era contre 1955 ms en hardcore pour la même construction). Sku:BuildFrameBudgetMs est désormais adaptatif : chaque avertissement de ce type divise par deux le plafond par image (150 -> 75 -> 37,5 -> 20 ms), ce dont profite toute la séquence de construction d'après-connexion, pas seulement le cache des points de passage. La construction n'est plus rythmée par une chaîne C_Timer qui se réarmait elle-même - c'est justement ce réarmement que l'interruption avalait, laissant la coroutine suspendue pour toujours sans personne pour la reprendre - mais par un pilote OnUpdate que le client appelle lui-même à chaque image : un lot interrompu coûte une image au lieu de toute la construction. Si la coroutine meurt malgré tout, la construction est relancée jusqu'à trois fois, et l'étape de construction remet sa demande en place au lieu de la perdre dans un pcall.
Navigation : une liste d'itinéraires pouvait rester vide sans dire pourquoi
Simple : un testeur sur un royaume hardcore a signalé que la liste d'itinéraires de Shift-F10 annonçait seulement « liste vide » à un endroit où il y a des itinéraires. Derrière cela se cachaient deux chemins différents par lesquels une liste pouvait devenir vide sans que rien ne l'indique.
Premièrement : depuis que Sku redémarre sa construction de points de passage sur les royaumes hardcore lorsque le client l'interrompt (voir ci-dessus), les points de passage peuvent être remplacés pendant qu'un menu est ouvert. Une liste issue de la construction précédente pointait alors vers un point de passage qui n'existait plus.
Cela levait une erreur en plein milieu de la construction des sous-entrées, et comme cette erreur était capturée, le niveau restait simplement vide : aucune entrée, aucune indication, aucun message d'erreur, rien à entendre.
Deuxièmement : si les données d'itinéraires elles-mêmes manquaient, Sku annonçait malgré tout « chargé » et toutes les listes d'itinéraires étaient vides - là encore sans la moindre indication. Les deux cas sont désormais visibles : la liste répond correctement au lieu de rester muette, et des données d'itinéraires manquantes sont annoncées comme n'importe quelle autre erreur de base de données.
Technique : trois endroits, tous de la même forme - un échec ne doit pas rester invisible. 1. SkuNav:GetAllMetaTargetsFromWp5 accédait au point de passage de départ (.worldX) sans vérification. Après une reconstruction du cache de points de passage - nouveauté de la v43.0, puisque la construction se relance d'elle-même sur les royaumes hardcore et que CleanupWaypoints supprime les points de passage sans liaison - ce nom peut avoir disparu. La fonction renvoie désormais une réponse vide et écrit une ligne de journal avec la génération du cache.
2. SkuOptions:VocalizeCurrentMenuName et le parcours de chemin appellent BuildChildren dans un pcall afin qu'un constructeur de sous-menu défectueux n'avale jamais l'annonce du NOM de l'entrée. Cela reste ainsi - mais l'erreur est maintenant journalisée avec le nom du nœud, et le nœud est marqué (buildChildrenFailed). Sans cela, un niveau à zéro entrée était indiscernable d'un niveau réellement vide.
3. Sku:EnsureData ignorait sans un mot une globale de constructeur qui n'est pas une fonction, puis déclarait quand même le jeu de données prêt. C'est la pire forme possible : toutes les protections du reste du code demandent « est-ce prêt », pas « est-ce là ». Pour les itinéraires, cela finit en données de liaison vides, points de passage d'itinéraire supprimés et menus annonçant tranquillement « liste vide ».
Chaque constructeur manquant est désormais journalisé individuellement ; s'ils manquent TOUS, le jeu de données est considéré comme en échec et annoncé.
S'y ajoute une ligne de journal dans SkuNav:GetAllLinkedWPsInRangeToCoords : lorsque Sku ne parvient pas à rattacher la zone actuelle à un continent (grottes, le Tram des Profondeurs, sous-zones non cartographiées), cette requête abandonne à vide - et la liste disait alors « liste vide », ce qui sonne comme une affirmation sur les données alors que ce n'en est pas une. /skuzoneprobe expose le même cas en entier.
Connexion : les données de points de passage des itinéraires sont prêtes bien plus tôt
Simple : Après la connexion, Sku reconstruit tous les points de passage et toutes leurs liaisons ; jusque-là, les listes répondent « les points de passage sont encore en cours de chargement ». Plus de la moitié de cette attente partait dans les liaisons, et les mêmes données étaient parcourues quatre fois. C'est un seul parcours maintenant, et il commence par le continent sur lequel vous vous trouvez : celui-ci est terminé en premier, et à partir de cet instant vos listes sont utilisables pendant que le reste du monde se construit encore. Si vous êtes justement sur le message d'attente, la première entrée vous est lue automatiquement, sans appuyer sur une touche. Mesuré sur la même machine : la partie liaisons coûte environ la moitié, et les listes de votre propre continent arrivent environ 0,7 seconde plus tôt. Les itinéraires eux-mêmes ne changent pas : mêmes points, mêmes liaisons, simplement plus tôt. S'y ajoute environ 22 Mo de mémoire en moins pour la gestion des points de passage, car chaque liaison n'est plus stockée en double - sur les machines modestes, c'est la moitié la plus perceptible. Et une autre part de l'attente disparaît complètement : Sku livre deux gros fichiers d'itinéraires, et la version TBC n'a besoin que des liaisons du second. Ses points de passage étaient malgré tout construits à chaque connexion, puis jetés sans avoir été lus un instant plus tard ; ils ne sont désormais tout simplement plus construits. Cela économise environ un quart de seconde et environ 21 Mo de mémoire de pointe par connexion - sur les royaumes Era, où le fichier entier est inutilisé, environ 0,4 seconde. Les deux fichiers continuent d'être livrés en entier : lors du passage ultérieur à Wrath of the Lich King, ce sont précisément ces données qui deviendront les bonnes, et la sélection s'inversera.
Technique : La partie liaisons de la construction du cache de points de passage était QUATRE parcours complets sur ~197 000 arêtes orientées : élaguer et symétriser (CheckAndUpdateProfileLinkData), matérialiser byId/byName, recalculer toute la table à partir du cache (SaveLinkDataToProfile) et un parcours final sur les ~145 000 entrées du cache (CleanupWaypoints). C'est un seul parcours désormais : l'élagage se fait au passage, l'arête inverse est écrite directement dans l'entrée cible - d'où l'indifférence à l'ordre des continents - et le recalcul disparaît, puisqu'il réécrivait la table déjà en place. Le seul cas où il pourrait encore changer quelque chose (une extrémité dont le nom appartient à une autre entrée du cache) est compté et déclenche l'ancien chemin ; il n'existe pas dans les données d'itinéraires livrées. Le parcours final reçoit de la passe « custom » la liste des entrées réellement supprimables, triée par continent, et s'exécute par continent dès que celui-ci est terminé. Corrigé au passage : l'ancienne passe d'élagage insérait de nouvelles CLÉS dans la table même qu'elle parcourait avec pairs() - comportement indéfini en Lua ; les arêtes inverses sont maintenant collectées puis appliquées ensuite. De plus, la séparation « son propre continent d'abord » ajoutée en juillet n'était jamais active à la connexion : elle résout la zone via GetMinimapZoneText, encore vide au démarrage de la construction - le continent est désormais résolu à nouveau avant la partie liaisons. Vérifié par une réimplémentation des deux variantes sur les vraies données (dev/rework-docs/simulate_link_build.py : cache identique, table de liaisons identique, pour chaque continent) et en jeu par /skucheck wp, qui vérifie désormais aussi que chaque liaison possède son arête inverse.
Technique, deuxième partie : chaque liaison était conservée deux fois - sous l'indice de cache du point cible (byId) et sous son nom (byName). byName a disparu et les 14 points d'appel utilisent byId ; le nouveau WaypointCacheGetIdForIndex est le pendant de WaypointCacheGetIdForName. L'écriture dans la table de liaisons est même devenue moins coûteuse : elle retraduisait chaque nom de cible en identifiant, et elle dispose maintenant directement de l'entrée. Mesuré : environ 70 000 tables et 224 000 chaînes en moins, 22 Mo de moins dans le rapport mémoire (/skucheck mem), et encore ~40 ms de gagnées sur la partie liaisons de la construction. Pourquoi ce doublon : une migration jamais terminée - Sku 32.31 contient déjà, en commentaire, l'appel censé écrire la table byName directement dans la table de liaisons enregistrée ; byId est arrivé plus tard comme chemin rapide pour la recherche d'itinéraire, et les deux sont restés. Trois bogues latents sont partis avec : une boucle de suppression de point qui ne nettoyait que le point supprimé contre lui-même, des identifiants construits sur « .areaid » au lieu de « .areaId » (donc toujours avec la zone 1), et un accès à Links[nil] pour les points temporaires.
Technique, troisième partie : chacun des deux fichiers d'itinéraires était UN seul constructeur qui bâtissait tout le fichier. Mesuré en jeu : 375 ms pour le fichier WotLK et 355 ms pour le fichier de base, à chaque connexion. Sur TBC la navigation utilise les points de passage du fichier de base et, du fichier WotLK, uniquement les LIAISONS (l'union des deux graphes, depuis juillet) - LoadDefaultMapData remettait à nil les points de passage, niveaux et numéros de séquence WotLK juste après la fusion. Cela représente 71 % des octets de ce fichier, construits puis jetés sans lecture. Les fichiers sont maintenant emballés par SECTION (dev/rework-docs/_wrap_deferred.py, mode « sections ») : un constructeur par section de premier niveau de routedata.global, chacun contenant une tranche exacte, octet pour octet, des données d'origine - l'outil vérifie que les tranches se recomposent en le fichier source, rien n'est re-sérialisé. SkuDeferredData.lua choisit les constructeurs selon la version du jeu (TBC : toutes les sections du fichier de base plus les liaisons WotLK ; Era : le fichier de base seul) et met à nil les globales des constructeurs ignorés, sans quoi leurs constantes de texte source resteraient en mémoire. Nouveau : /skucheck routes. La vérification est conçue pour qu'une sélection erronée soit bruyante au lieu de coûter silencieusement la moitié du graphe : après EnsureData, plus aucune globale SkuDBBuildRoute* ne doit exister - une survivante signale une section que la sélection ne connaît pas -, les tables que lit la navigation doivent être présentes et non vides, et selon la version du jeu c'est exactement la bonne moitié qui doit manquer.
Les listes de points de passage indiquent désormais l'avancement du chargement
Simple : Le message « points de passage en cours de chargement » avait été écrit pour une attente d'une ou deux secondes. Quand le client freine Sku (voir l'entrée précédente), il peut rester affiché dix secondes ou plus, et il devient alors impossible à distinguer d'un blocage. Il indique maintenant un pourcentage, par exemple « points de passage en cours de chargement, 47 % ». Le nombre bouge dès le début : les premières étapes sont les parties de la base de données que la construction doit attendre (0, 20, 40 pour cent), puis la construction elle-même compte jusqu'à 99. Chaque appui de touche sur l'entrée annonce la valeur actuelle, et dès que tout est là, le premier vrai point de passage est annoncé automatiquement comme avant.
Technique : L'étalon est le temps de travail d'une construction COMPLÈTE, que chaque exécution réussie enregistre dans les réglages globaux de SkuNav (wpcTotalWorkMs). Ce qui est mesuré, c'est le travail, pas le temps réel : le travail est stable, le temps réel varie maintenant avec la réduction du budget. Le pourcentage reste donc honnête sur n'importe quelle machine ; seule la toute première construction après une nouvelle installation utilise la valeur par défaut. Coût par image : une comparaison d'entiers - seul un pourcentage MODIFIÉ reconstruit le texte, et uniquement pour une entrée sur laquelle se trouve le focus. L'entrée porte pour cela un marqueur, car son nom n'est plus un texte fixe : les deux endroits qui la reconnaissaient au nom - le verrou « non sélectionnable » et le rafraîchissement automatique à la fin de la construction - testent maintenant le marqueur.
Shift-F9 à Shift-F12 : des raccourcis nommés, et quatre accès rapides retrouvés
Simple : quatre actions de Sku - les deux listes rapides de navigation (Shift-F9 et Shift-F10), le menu des barres d'action (Shift-F11) et l'annulation de la navigation (Shift-F12) - étaient câblées directement sur les touches des accès rapides du menu audio 1 à 4. Cela avait deux conséquences. Ces quatre accès rapides étaient morts : leurs touches de définition (Ctrl-Shift-F9 à Ctrl-Shift-F12) enregistraient toujours un chemin de menu et le confirmaient même à voix haute, mais aucune touche ne pouvait plus le rappeler. Et les quatre actions ne pouvaient être déplacées que en réassignant une entrée nommée « accès rapide au menu audio 1 » à « 4 » - ce n'est pas là que l'on cherche « annuler la navigation ». Chaque action possède maintenant sa propre entrée dans le menu des raccourcis, sous son propre nom, toujours sur Shift-F9 à Shift-F12. Les accès rapides 1 à 4 sont de nouveau libres et non assignés, exactement comme les emplacements 5 à 10. Vos réglages existants sont repris à la première connexion : la touche qui se trouve aujourd'hui sur l'accès rapide 1 à 4 continue d'exécuter la même action - elle se déplace simplement vers la nouvelle entrée, rien ne change pour vos doigts. Un emplacement que vous aviez volontairement vidé reste vide.
Technique : le OnClick de SkuZOptions/Core.lua interceptait SKU_KEY_MENUQUICK1..4 et retournait avant la boucle générale de sélection rapide située plus bas dans le même gestionnaire. Les trois actions déplacées s'appellent désormais
SKU_KEY_NAVWAYPOINTSQUICK, SKU_KEY_NAVROUTEDESTINATIONSQUICK et SKU_KEY_ACTIONBARSOPEN, chacune distribuée par le module qui la possède ; les deux listes de navigation ont rejoint le groupe « Navigation et points de passage ». Une migration unique dans SkuKeyBindsUpdate déplace key et key2 de l'ancien emplacement vers la nouvelle constante ; elle se détecte à l'absence de la nouvelle constante dans le profil, elle s'exécute donc exactement une fois et avant le remplissage des valeurs par défaut. Les chemins de sélection rapide enregistrés sont conservés : assigner une touche à l'emplacement 1 à 4 restaure l'ancien raccourci. Nouveau garde-fou :
/skucheck keys signale toute touche détenue par deux assignations Sku à la fois (sauf les touches d'écrasement transitoires, qui la partagent par conception).
Annuler la navigation passait par deux touches différentes
Simple : il existait deux façons d'arrêter de suivre un itinéraire ou un point de passage, et elles ne se comportaient pas pareil. L'assignation correctement nommée « arrêter de suivre l'itinéraire ou le point de passage » était livrée sans aucune touche, et quand on lui en donnait une, elle annonçait « suivi arrêté » - les mêmes mots que l'arrivée automatique, impossible donc de distinguer les deux - et elle ne disait strictement rien lorsque ce que l'on annulait était un itinéraire et non un point de passage isolé. L'autre était le Shift-F12 câblé en dur, qui disait « Navigation annulée » mais n'existait que comme accès rapide 4. Les deux ne font plus qu'une touche : « arrêter de suivre l'itinéraire ou le point de passage », sur Shift-F12 par défaut et librement réassignable, avec le son de confirmation et le « Navigation annulée » distinct. Elle reste totalement silencieuse quand il n'y avait rien à annuler, et elle fonctionne toujours en mouvement et en combat.
Technique : la branche OnClick de SkuNav pour SKU_KEY_STOPROUTEORWAYPOINT appelle maintenant SkuNav:CancelNavigationSilent() et ne parle et ne joue le son 835 que sur un retour true. Cela supprime l'ancien chemin non protégé, qui déclenchait SKU_NAVIGATION_STOPPED et le son même lorsque rien ne tournait, et dont l'annonce venait de EndFollowingWpOrRt et dépendait d'un point de passage sélectionné. EndFollowingWpOrRt lui-même reste inchangé : ses quinze autres appels l'utilisent comme démontage avant de sélectionner une nouvelle cible, où effacer les points de passage temporaires serait faux.
Navigation : un itinéraire ne démarrait pas si sa liste finissait de charger pendant que vous y étiez
Simple : Si vous ouvriez la liste des itinéraires (Shift-F10) pendant que Sku construisait encore ses données de points de passage, la liste se rafraîchissait au moment où ces données étaient prêtes - et à partir de là, Entrée sur un point d'itinéraire ne lançait plus la navigation. Le menu remontait au contraire au niveau des points d'entrée, comme si la touche n'avait rien fait du tout. Fermer puis rouvrir le menu corrigeait le problème, ce qui donnait un aspect aléatoire à toute l'affaire. La liste rafraîchie se comporte désormais exactement comme une liste fraîchement ouverte : Entrée démarre la navigation. Cela vaut aussi pour la liste des points de passage à proximité (Shift-F9) et pour toute liste de points de passage qui se rafraîchit à l'arrivée des données.
Technique : le rafraîchissement à la fin de la construction asynchrone du cache des points de passage reconstruisait le niveau avec un simple children = {} suivi de BuildChildren. Cela saute ce que fait OnPostSelect pour un niveau de sélection : initialiser selectTarget sur le niveau et le copier sur chaque enfant fraîchement construit. Sans cela, tout le sous-niveau hérite de selectTarget = nil, donc l'Entrée de la feuille tombe dans la branche générique d'OnPostSelect - aucun OnAction ne s'exécute (RouteFollowOnAction n'a jamais été appelé) et le curseur est placé sur self.parent, exactement le saut observé. Cette reconstruction se trouve maintenant à un seul endroit, SkuOptions:RebuildNodeChildren, utilisé par OnPostSelect lui-même, par le rafraîchissement des points de passage et par celui des listes volatiles - ce dernier en mode conservation, afin qu'un rafraîchissement en cours ne jette pas une cible déjà sélectionnée. Deux fils-pièges accompagnent la correction : OnPostSelect journalise et compte chaque Entrée qui atterrit sur une feuille sans selectTarget sous un niveau de sélection, et /skucheck menu reconstruit un niveau de sélection jetable pour vérifier le contrat et rapporte ce décompte de session.
Auras : les places de groupe étaient annoncées par un bip au lieu d'un mot
Simple : Quand une aura annonce l'unité qui a déclenché l'événement, certaines places de groupe ne produisaient qu'un bref bip au lieu d'un mot - le son que Sku joue quand l'enregistrement d'un mot lui manque. La place 3 et toutes les places « cible de » étaient concernées. Ces indications sont désormais découpées en mots que le pack vocal fournit à coup sûr : « party 3 », « cible party 2 ». Toutes les autres unités continuent de dire leur nom traduit.
Technique : sourceUnitId et destUnitId passaient le jeton d'unité brut à la sortie audio comme UN seul mot. Les packs livrent party0/1/2/4, mais pas party3 ni le moindre fichier partyNtarget ; le reste retombait donc sur le bip missingAudio (party3 à lui seul en comptait 129). tUnitIdToSpokenName dans SkuAuras/data.lua découpe les jetons party ; les autres jetons retombent sur leur friendlyName traduit issu des listes de valeurs, puis seulement sur le jeton brut. Corrigé au passage : notifyChat affichait la référence de table au lieu de l'unité.
Auras : une aura réglée sur « une fois » pouvait se déclencher plusieurs fois de suite en combat dense
Simple : Une aura censée signaler UNE seule fois par application - typiquement « Mot de l'ombre : douleur expire dans une seconde » - pouvait produire quatre sons en une seconde lors d'un combat de boss. Cela arrivait quand plusieurs joueurs avaient le même effet sur la cible, ou quand la durée restante n'était pas lisible du tout lors d'un passage : Sku l'interprétait à tort comme « l'effet est de nouveau frais » et levait le verrou « une fois ». Sans lecture, le verrou reste désormais fermé. Un vrai rafraîchissement ou une nouvelle application le lève toujours immédiatement.
Technique : La formule de réinitialisation de la condition de comptage réarmait used à chaque passage où les autres conditions tenaient et où la condition de durée « plus petit » lisait false - et un passage SANS lecture (nom absent de la liste, pas d'entrée exp, ou la carte exp répondant avec l'aura de même nom d'un autre lanceur) remplit exactement cela. tSmallerDurationNoRead dans SkuAuras/Core.lua empêche la réinitialisation en l'absence de lecture ; la nouvelle ligne de journal « aura gate re-armed » consigne chaque levée. Observé : quatre déclenchements en 987 ms (DURATION_DEADLINE, puis deux fois UNIT_POWER et SPELL_PERIODIC_DAMAGE).
Menu : sur les grandes cartes, la liste de points de passage de Shift-F9 ne s'ouvrait qu'au deuxième essai
Simple : Sur les cartes comptant beaucoup de points de passage, Shift-F9 restait sur l'entrée du haut au lieu d'ouvrir la liste ; une pression de flèche supplémentaire l'ouvrait ensuite. La cause : un travail effectué trois fois au lieu d'une. Le saut construisait la même liste - environ 1900 entrées sur certaines cartes - trois fois dans une seule image, et le client du jeu interrompait tout via sa limite de temps de script. Cette interruption est silencieuse, d'où l'impression qu'il ne se passait rien. S'y ajoutait que chaque appui de touche sur une entrée reconstruisait sa sous-liste en doublant les entrées. Les deux sont réglés, la liste est construite une fois. Shift-F10 n'a jamais été concerné, cette liste étant limitée à dix destinations.
Technique : SlashFunc construisait les enfants trois fois : avant la comparaison de nom, dans le OnSelect de la boucle, puis encore dans la phase finale. La comparaison se décide maintenant AVANT la construction, et la phase finale saute sa resélection quand la boucle a déjà sélectionné ce même nœud (nœuds actionOnEnter exclus : là, les deux appels diffèrent réellement). VocalizeCurrentMenuName ne construit plus que s'il n'y a rien à compter - il n'a besoin des enfants que pour le marqueur « ;plus », et la plupart des constructeurs AJOUTENT via InjectMenuItems au lieu de remplacer (mesuré 1859 -> 3718 -> 5577 entrées en parcourant). Suite du test : les niveaux de fenêtre sous « Local » (Dialogue, Marchand, Quête, Maître de vol) construisent leurs enfants paresseusement et ne portent pas d'indicateur dynamic ; sans pré-construction ils ressemblaient à des feuilles sans enfants, et la branche feuille appelle CloseMenu - or fermer clique le bouton de fermeture de chaque fenêtre d'interactFramesList, si bien que le saut vers un maître de vol refermait aussitôt sa fenêtre. La construction a donc lieu quand la liste est vide, sauf si le nœud est dynamic. Deux fils déclencheurs dans /skucheck menu comptent les deux cas.
Vol en taxi : les annonces peuvent être désactivées - et elles ne nomment plus le point de vol de départ ni celui d'arrivée
Simple : Pendant un vol en taxi, Sku annonce « Prochain point de vol X » puis, environ 800 mètres avant, « Atterrissage anticipé possible à X », afin de pouvoir descendre plus tôt avec le raccourci. Pour qui vole beaucoup, c'est du bavardage : il existe désormais un réglage, Paramètres > Général > « Annoncer les points de vol où atterrir ». Il est activé par défaut et ne coupe QUE la parole - le vol reste suivi, et la touche d'atterrissage anticipé fonctionne exactement comme avant, avec sa confirmation vocale, car celle-ci répond à une touche que l'on vient d'appuyer. Ensuite, plusieurs retours signalaient que Sku nommait le point de vol où le vol avait COMMENCÉ, ou celui vers lequel il se dirigeait, comme un endroit où atterrir par anticipation. Ni l'un ni l'autre n'est un atterrissage anticipé : le premier est l'endroit d'où l'on vient, le second n'est que l'arrivée. Les deux sont désormais impossibles. Troisièmement, dès que l'atterrissage anticipé a réellement été demandé, Sku cesse de commenter l'itinéraire. Il nommait auparavant le point APRÈS celui où l'on était déposé - dix secondes avant de se poser à Ratchet, il annonçait encore « Prochain point de vol Astranaar », comme si le vol continuait.
Technique : L'annonce avait un angle mort, le repli sur le point de vol le plus proche. L'itinéraire est capturé au décollage depuis la carte des vols (le seul moment où l'interface des itinéraires répond), et toutes les annonces dépendent de lui. S'il manque, le code se rabat sur « le point de vol utilisable le plus proche » - qui ne sait rien du vol : peu après le décollage, c'est précisément le point de départ pendant un moment, et peu avant l'atterrissage, le point d'arrivée. La seule manière courante de perdre l'itinéraire est un /reload en plein vol : le crochet de capture s'est déclenché avant le rechargement et ne peut pas se déclencher une seconde fois. C'est exactement pour cela que le problème était reproductible chez les personnes concernées et invisible ici. Trois changements : (1) l'itinéraire capturé survit à un /reload - il est écrit dans les variables sauvegardées du personnage avec l'étape en cours, puis relu en vol, si bien qu'un rechargement ne fait plus du tout basculer dans le repli ; (2) le point de départ du vol est désormais lu lui aussi dans la capture de l'itinéraire (l'emplacement source de la première étape), donc départ et destination sont connus par leur nom et aucun des deux ne peut plus être annoncé, dans quelque mode que ce soit ; (3) en mode repli, un point de vol doit se RAPPROCHER avant d'être proposé comme possibilité d'atterrissage - un point dont on s'éloigne est derrière soi ; (4) une demande acceptée met fin à l'itinéraire pour le curseur aussi : le point demandé est la fin du vol, le franchir c'est arriver, pas faire une étape. La porte de sortie est géométrique et non minutée - encore en vol mille mètres au-delà signifie que le serveur a ignoré la demande, et l'itinéraire reprend aussitôt. Le nouveau contrôle
« /skucheck taxi » fixe la règle : un atterrissage anticipé n'est jamais le point de départ ni le point d'arrivée du vol lui-même. Le réglage est enregistré par profil sous taxiAnnounceLandingPoints.
Moniteur de ressource : « rien » devient « Ressource actuelle », et elle suit la barre que vous voyez
Simple : Le moniteur de vie & de ressource surveille exactement une ressource, et c'était un choix figé : mana, rage, énergie - ou « rien ». Mais « rien » n'était pas un interrupteur, c'était un trou : il provoquait une série d'erreurs Lua, et ce que le moniteur surveillait à la place n'avait été choisi par personne. L'entrée s'appelle désormais « Ressource actuelle » et figure en tête de liste. Elle suit la barre que le jeu vous affiche : un druide obtient le mana en forme normale, la rage en ours et l'énergie en félin, sans jamais retourner dans le menu. Toutes les autres classes n'ont qu'une seule barre - pour elles, c'est simplement leur ressource. Choisir une ressource fixe fonctionne exactement comme avant. Pour désactiver le moniteur, utilisez « Activé : Non » - c'est à cela que sert le réglage. Si vous aviez « rien » de sélectionné, vous trouverez le moniteur désactivé et la ressource réglée sur « Ressource actuelle » ; réactivez-le si vous voulez l'entendre.
Technique : « NOTHING » transmettait l'indice de ressource -1 (Enum.PowerType.None) directement à UnitPower et UnitPowerMax - une valeur que le moniteur n'a aucune raison de demander. À sa place vient GetMonitoredPowerType(), qui résout la valeur enregistrée au moment de la lecture : un choix fixe vers son indice, « Ressource actuelle » via UnitPowerType("player") vers la barre affichée. Les deux chemins de lecture passent par là, y compris la comparaison de jeton dans UNIT_POWER_UPDATE - avec le type automatique, le jeton auquel réagir n'est pas celui qui est enregistré. Les deux chemins vérifient aussi désormais nil et un maximum de 0 au lieu de diviser par lui ; c'était la véritable source des erreurs, et comme l'un des deux se trouve dans le pilote OnUpdate, il ne produisait pas une erreur mais une par tick. Comme la ressource surveillée peut maintenant changer sous le moniteur, le pourcentage précédent est réinitialisé à chaque changement de jeton - sinon la première annonce après un changement de forme serait avalée ou recevrait la mauvaise direction (hausse/baisse). En outre, le gestionnaire s'arrête si le module est désactivé : il dépend de deux enregistrements (son propre objet AceEvent et le répartiteur dans Core.lua) alors qu'OnDisable ne retirait que le premier, si bien qu'un moniteur désactivé dans le menu des fonctions continuait d'annoncer. Le nouveau contrôle « /skucheck power » fixe la règle : la ressource configurée doit toujours se résoudre vers quelque chose que le client peut lire ; une ressource choisie volontairement mais absente de la classe compte comme « en attente », pas comme une infraction. La valeur enregistrée « NOTHING » est migrée une seule fois vers « ACTIVE » à la connexion, moniteur désactivé.
Les auras reconnaissent les sorts à leur identité, plus à leur nom traduit
Simple : Une aura que vous aviez créée était jusqu'ici liée à la langue de votre jeu. La valeur enregistrée était le nom traduit du sort - « Frostblitz » - et un client anglais ne connaît que « Frostbolt » : la même aura ne s'y déclenchait donc jamais. Pour la même raison, un ensemble d'auras partagé en groupe arrivait mort chez un équipier d'une autre langue, et les ensembles d'auras fournis n'existaient que sur les clients allemands. Sku retient désormais l'identité du sort, indépendante de la langue. Ce que vous voyez et entendez reste exactement le nom qu'emploie votre jeu - dans le menu, dans le nom de l'aura et dans l'annonce quand elle se déclenche. Vos auras existantes sont converties une seule fois à la première connexion, sans rien faire de votre côté ; leurs noms ne changent pas.
Un second gain vient avec : tous les rangs d'un sort, ainsi que les variantes lancées par les ennemis, appartiennent à une seule entrée. « Préviens-moi quand ma cible lance Éclair de givre » couvre donc les 103 variantes au lieu de la seule qui se trouvait dans la liste. Savoir si c'est VOUS ou un ennemi qui l'a lancé reste décidé par la condition « Source de l'événement », pas par le sort.
Là où un nom traduit recouvre plusieurs noms anglais différents - l'allemand « Verblassen » est à la fois « Fade » et « Fade Out » - la liste ajoute le nom anglais entre parenthèses pour que les entrées restent distinguables. La liste seulement ;
l'annonce au déclenchement reste courte. Si vous choisissez une telle entrée, c'est la variante la plus ancienne qui l'emporte : pour « Verblassen », le sort de prêtre et non « Fade Out ». Les auras déjà enregistrées sous un tel nom restent intactes et continuent de réagir à toutes les variantes, comme avant.
Technique : L'identité est le nom anglais du sort tiré de SkuDB.SpellDataTBC, déjà livré et déjà maintenu - aucun nouveau fichier, aucune table d'ID générée (il faudrait la garder synchronisée avec spells.lua, et une régénération orphelinerait silencieusement les auras enregistrées). Les valeurs enregistrées portent la marque « spellgroup: » ; l'affichage vient toujours de SkuAuras.values[key].friendlyName. La liste vivante issue de UnitAura est ramenée au nom de groupe via la valeur de retour 10 (spellId) ; sur un client non anglais, le nom localisé reste à côté comme alias de compatibilité pour qu'une ancienne valeur non convertie continue de correspondre. Sur un client anglais, nom de groupe et nom vivant sont la même chaîne, l'alias n'est jamais écrit et le coût est exactement nul. Un ID que SpellDataTBC ne connaît pas - la population la plus susceptible de dériver au fil du cycle Anniversary - retombe sur le nom localisé, c'est-à-dire sur le comportement précédent. 838 des 26 603 noms allemands (3,15 %) recouvrent plus d'un nom anglais. À l'exécution, c'est le groupe dont l'ID de sort est la plus basse qui l'emporte : les variantes en conflit sont sans exception des ajouts ultérieurs ; vérifié sur les cas dont la réponse est connue (Verblassen 586 contre 5543, Geschwächte Seele 6788 contre 36788, Schattenwort: Schmerz 589 contre 37603, Erneuerung 139 contre 37563, Gedankenkontrolle 605 contre 7645). Les valeurs DÉJÀ ENREGISTRÉES sous un tel nom ne sont malgré tout PAS converties, car elles correspondent aujourd'hui à toutes les variantes et une conversion supprimerait silencieusement les autres ; leurs entrées de menu reçoivent le nom anglais en suffixe. Le nom
affiché d'un groupe provient toujours de l'ID la plus basse qu'il contient, afin qu'il ne change pas d'une session à l'autre. Nouvelles vérifications sous « /skucheck auras »
: il existe bien des entrées de groupe, tous les ID d'un sort se résolvent vers UN seul groupe, et la conversion unique n'a laissé aucune valeur derrière elle.
Partage d'ensembles d'auras : nouveau format sans indicateur de langue
Simple : Un ensemble d'auras partagé ne porte plus d'indicateur de langue, et l'avertissement « l'ensemble est pour une autre langue » disparaît - les conditions sont désormais indépendantes de la langue. À l'acceptation, chaque aura reçoit en plus son nom dans VOTRE langue au lieu de garder la phrase de l'expéditeur. Les auras que vous avez nommées vous-même gardent leur nom.
Technique : C'est SkuAuraSetV2 (charge « AURASET2 », sans champ loc) qui est envoyé ; V1 reste reçu, avertissement compris, car de tels paquets portent encore des valeurs localisées. Seul V2 est envoyé, volontairement : un paquet V1 supplémentaire déposerait chez les anciens clients des auras avec des valeurs de groupe qu'ils ne savent pas résoudre. Le nom est redérivé via BuildAuraName à l'import
(SkuAuras:RelocalizedAuraName) ; les auras customName en sont exclues, et ce sont justement celles auxquelles d'autres auras peuvent renvoyer : les renvois restent donc intacts.
Créer une aura : le menu dans lequel on construit une aura a été refait
En clair : Une aura est toujours faite de conditions, et tout ce que vous avez déjà construit continue de s'évaluer sans changement - mais le chemin vers une condition est plus court à beaucoup d'endroits, et les listes que l'on parcourt en route sont triées, courtes et rapides. Dans l'ordre où on les rencontre :
La liste des attributs est triée par nom de bout en bout - y compris les entrées de groupe, qui se plaçaient auparavant toujours en tête quel que soit leur nom. Une entrée se trouve donc là où son nom la place, et les premières lettres suffisent pour l'atteindre. Les 35 événements tiennent derrière deux entrées, « Événements généraux »
et « Événements de sort » ; santé, ressource, mana, rage, énergie, puissance runique et points de combo sont ensemble dans « Votre santé ou ressource » ; et toutes les auras que vous avez nommées vous-même sont des conditions sous « Auras créées par vous » au lieu d'être éparpillées parmi les vrais attributs - la liste du haut grandissait d'une entrée à chaque aura nommée, et ces entrées se rangeaient dans toutes les lettres de l'alphabet. Chaque entrée de groupe annonce elle-même ce qui est sélectionné à l'intérieur : inutile d'y entrer pour le savoir.
Une condition à deux valeurs seulement - « vrai » et « faux », ou « buff » et « debuff » - est désormais une bascule au lieu de trois niveaux. La valeur figure sur l'entrée et Entrée la change : « En combat ; vrai », Entrée, « En combat ; faux ».
Pendant la CRÉATION, Entrée va un cran plus loin sur « non défini » puis revient, pour qu'une bascule posée par erreur puisse être retirée. À comprendre : « non défini »
n'est pas une troisième valeur, cela veut dire que la condition n'existe pas du tout - c'est l'état neutre, pas « faux ». « faux » est une comparaison comme une autre : « en combat égal faux » ne se déclenche QU'EN dehors du combat.
Les sorts viennent toujours d'une liste, mais on peut aussi les saisir : « Saisir le sort » est la première entrée de chaque liste de valeurs de sorts - Entrée, nom ou numéro, Entrée, et Sku annonce le sort qu'il en a fait. En échange, les deux conditions « ID du sort » et « ID de l'objet » ont quitté la liste des attributs : elles désignaient un SEUL rang de sort et signifiaient donc, juste à côté de « nom du sort », l'inverse de ce que la même valeur saisie y produit. Nouvelle venue : « Buff debuff vos sorts uniquement » - réglée sur vrai, les listes de buffs et de debuffs de cette aura ne voient plus que les effets que VOUS avez lancés, si bien que « mon Mot de l'ombre :
douleur expire » ne signale plus celui d'un autre prêtre sur la même cible. Et comme « Source (L) » et « cible (L) » étaient régulièrement pris pour votre propre cible, elles s'appellent maintenant « Source de l'événement (L) » et « Cible de l'événement (L) » : elles filtrent l'ÉVÉNEMENT déclencheur.
Enfin le comportement des listes : toutes les listes de valeurs s'ouvrent nettement plus vite, « Sort utilisable (L) » ne fige plus le jeu à l'ouverture, changer le sort d'une condition de durée se fait sans à-coup et sans continuer d'annoncer l'ancien sort comme sélectionné, et « Supprimer » demande confirmation avant qu'une aura disparaisse
- c'était la seule entrée de cette liste à ne pas le faire, juste à côté de
« Dupliquer », qui a toujours demandé.
Techniquement : Un attribut devient une bascule quand son type est BINARY, qu'il a exactement deux valeurs et que son type n'autorise qu'un seul opérateur (tBinaryValuesForAttribute dans SkuAuras/Options.lua) ; ce qui est écrit est exactement ce qu'écrivait l'ancienne liste de valeurs, une aura construite par la bascule est donc indiscernable d'une aura construite à l'ancienne, et une liste values vide sort du brouillon - c'est cela, « non défini ». La ligne de condition associe actionInPlace et actionOnEnter, ce qui distingue Entrée de la flèche droite sur le même nœud. La liste des attributs collecte groupes et attributs avec leur nom affiché et insère les deux dans l'ordre des noms. Les deux familles d'événements sont UN attribut et UNE condition stockée : chaque liste de famille propose l'autre comme une seule entrée, et les deux pointent vers la condition que le brouillon détient déjà - sans quoi passer par les deux laisserait deux conditions sur `event`, que l'enregistrement fusionne en un groupe OU toujours vrai. listsOwnOnly est un modificateur binaire : getAuraList récupère le lanceur (7e valeur de retour d'UnitAura) dans le même balayage et remplit des ensembles own parallèles qu'EvaluateAllAuras échange par aura marquée. Les listes de valeurs trient avec une clé de tri par entrée au lieu de deux par comparaison (27 057 au lieu d'environ 800 000 nouvelles chaînes par liste de sorts), « Sort utilisable (L) » interroge les 132 emplacements d'action au lieu des 49 000 sorts de la base, et la condition de durée laisse chaque entrée annoncer son propre état à la lecture (tValueToggleRefreshLiveName, UNE fonction partagée par référence) au lieu de réinitialiser 27 000 entrées à chaque Entrée. « ID du sort » et « ID de l'objet » sont toujours évaluées et seulement masquées du constructeur par un drapeau retired, pour qu'une aura importée ou ancienne ne tombe pas sur un nil ; avec elles disparaissent leurs listes de valeurs, environ 49 000 ID de sorts et 25 000 ID d'objets reconstruites à chaque chargement. Les CLÉS de localisation des conditions renommées sont inchangées, aucune aura stockée ne bouge donc. La suppression a également imposé de retirer la branche aName du menu de gestion : selectTarget n'est repointé qu'une fois le niveau entré, jusque-là la confirmation aurait été cosmétique. Supprimer rafraîchit désormais aussi les pseudo-attributs d'auras - une aura supprimée restait auparavant proposée comme condition.
Clients français : la liste des enchantements d'arme pour les auras était vide
Simple : Sur un client français, la condition d'aura portant sur les enchantements d'arme ne proposait pas une seule entrée, si bien qu'une telle condition ne pouvait pas être créée.
Technique : SkuAuras:ResolveWeaponEnchantName lisait la colonne 1 de la base d'enchantements pour enUS et la colonne 2 pour deDE, et laissait le nom à nil sinon - pour toute autre langue la fonction renvoyait donc nil pour CHAQUE enchantement et la liste de valeurs sortait vide. Elle prend maintenant la colonne de votre langue, sinon l'anglaise, comme le reste du système de noms depuis la v42.09. Trouvé lors du portage vers l'identité de groupe, pas via un rapport.
Menu : chaque entrée coûte désormais environ 13 fois moins à créer
Simple : Les longues listes se construisent nettement plus vite. Cela se voit surtout sur les listes de sorts d'une condition d'aura : elles comptent 27 057 entrées, et sur un royaume hardcore elles ne s'ouvraient plus du tout - ce serveur interrompt les scripts d'addon trop longs, et la construction n'allait qu'à peu près à la moitié. Cela ne concerne pas que les auras : tous les menus de Sku sont faits des mêmes entrées.
Technique : Une entrée de menu était une copie profonde du modèle SkuGenericMenuItem - par entrée une table auxiliaire, un parcours pairs() des 28 champs avec un appel type() et trois comparaisons de clé chacun, 28 écritures, et une copie récursive de la table children. Une entrée est maintenant une table presque vide dont la métatable pointe vers le modèle via __index : deux tables et une écriture. Mesuré sur 27 057 entrées : la création des nœuds passe de 78 à 6 ms (13x), et la construction complète de la liste de 100 à 31 ms (3,2x, et 2,7x plus rapide qu'avant la refonte des auras). Écrire un champ sur une entrée masque toujours le modèle comme avant ; children reste une table propre à chaque entrée, sinon tous les éléments de menu de l'addon partageraient UNE seule liste d'enfants. Le seul endroit qui copie une entrée (l'entrée de filtre dans SkuOptions:ApplyFilter) rattache la métatable. /skucheck menu vérifie les deux sur des entrées jetables.
Mesuré pour comparaison : la refonte des auras elle-même n'a presque pas ralenti ces listes. Le passage aux groupes a fait croître la liste de sorts de 460 entrées sur 26 597 (+1,7 %), et les bascules au lieu d'entrées simples coûtent environ 19 % de temps de construction en plus. La construction était coûteuse bien avant ; sur un royaume hardcore, cependant, une limite de script est une falaise et non une pente, et ces 19 % ont suffi à la franchir.
Menu : une liste interrompue restait incomplète sans le dire
Simple : Sur un royaume hardcore, le serveur interrompt un script d'addon trop long. Quand cela touchait la construction d'une longue liste, celle-ci s'ouvrait bien à la DEUXIÈME flèche droite - mais ce n'était pas une nouvelle tentative, c'était le reste à moitié construit de la première. Sur les listes de sorts, cela représentait environ 6 900 sorts sur 27 000, sans le moindre avertissement : qui ne trouvait pas son sort devait en conclure qu'il n'existait pas. La construction reprend désormais à la frame suivante là où elle s'est arrêtée, et la liste se complète en quelques frames sans que vous ayez à appuyer sur quoi que ce soit.
Technique : Le budget de script vaut par exécution, la frame suivante en a donc un neuf - c'est précisément pour cela que la construction des données d'itinéraires est découpée. SkuOptions:ContinueInterruptedBuild rappelle BuildChildren sur un minuteur à délai nul tant que le niveau est incomplet. Seul un constructeur qui se déclare via `resumableBuild` et tient son propre curseur est réinvoqué : un BuildChildren ordinaire AJOUTE, un second appel créerait donc chaque entrée en double - c'est exactement la raison d'être de l'ancien verrou. Le curseur est posé APRÈS une entrée, jamais avant, sinon une entrée empêchée par l'interruption compterait comme construite. Une passe sans progrès abandonne au lieu de se répéter indéfiniment. /skucheck menu vérifie sur un niveau jetable qu'une construction interrompue se poursuit au lieu de recommencer.
Les réglages à deux valeurs sont désormais des bascules, plus des sous-menus
Simple : Un réglage qui ne connaît que deux états - « Activé » et « Désactivé », « Oui » et « Non » - annonce maintenant sa valeur en même temps que son nom : vous entendez par exemple « Menu Sku en combat ; activé ». Entrée bascule, le focus ne bouge pas, et vous entendez aussitôt l'entrée dans son nouvel état. La flèche droite n'est plus nécessaire, car le sous-menu contenant les deux valeurs a disparu. Il fallait auparavant trois touches - droite, flèche, Entrée - et il fallait y entrer rien que pour savoir où en était le réglage. Cela concerne tous les réglages, le moniteur de santé et de combat, les filtres du chat et du journal de combat, le menu des fonctions, le menu de la caméra et les réglages des autres extensions : environ 150 entrées. Les réglages à PLUS de deux valeurs gardent leur liste, puisqu'il y a réellement quelque chose à y choisir.
Technique : Nouvel élément de menu partagé, SkuOptions:MakeToggleNode dans SkuZOptions/templates.lua ; SkuOptions:MakeInPlaceToggle convertit un emplacement isSelect existant en UNE ligne et continue d'utiliser ses propres GetCurrentValue et OnAction, afin que chaque particularité d'un réglage reste telle quelle. Peu importe laquelle des deux valeurs est passée comme « activé », et c'est précisément ce qui a rendu mécanique la conversion des quelque 50 emplacements Oui/Non existants. Une bascule est une feuille (actionInPlace, pas de dynamic, pas d'enfants) - d'où l'inaction de la flèche droite - et un RefreshLiveName relit l'état juste avant chaque annonce ; l'ancien sous-menu l'obtenait gratuitement en appelant GetCurrentValue à chaque descente. Trois pièges : le parcours de chemin de SkuOptions:SlashFunc et la recherche dans les réglages sélectionnent avec aEnterFlag = true et auraient BASCULÉ une bascule nommée dans un chemin au lieu d'y amener le curseur - les deux se contentent désormais de placer le focus, et la recherche compare avec toggleLabel puisque le nom porte l'état. RefreshLiveName ne s'applique pas à l'entrée de filtre d'une liste : SkuOptions:ApplyFilter la construit en copiant le premier enfant, et la copie écraserait sinon le texte que vous saisissez. Enfin, une bascule dont le lecteur lève une erreur est comptée par /skucheck menu - elle sonnerait sinon comme un réglage sans valeur plutôt que comme un défaut.
Vérification de préparation : la fenêtre n'arrivait pas sur la réponse comme toutes les autres
En clair : Quand quelqu'un du groupe lance une vérification de préparation, Sku ouvre le menu et y saute, exactement comme pour n'importe quelle fenêtre surgissante. Pour celle-ci, le curseur n'arrivait pas sur « Prêt » mais un niveau au-dessus, ce qui laissait deux appuis de touche de plus avant la réponse. Vous arrivez maintenant directement sur « Prêt », « Pas prêt » est juste en dessous, et la flèche gauche ramène sur « vérification de préparation ». Qui a lancé la vérification figure sur les deux entrées en texte complet.
Techniquement : ReadyCheckFrame n'est qu'une enveloppe autour de ReadyCheckListenerFrame, qui porte le message et les deux boutons ; parcourue génériquement, cette enveloppe devenait un niveau de menu à part entière et la descente automatique de SkuCore:CheckFrames y atterrissait. Il existe désormais un constructeur dédié (SkuCore:Build_ReadyCheckFrame dans SkuCore/LocalMenu.lua, inscrit dans interactFramesListManual) qui construit les deux réponses à plat en entrées directAction - le même schéma que Build_RolePollPopup pour le sondage de rôle. Les libellés viennent des boutons eux-mêmes, que Blizzard traduit dans ReadyCheckFrame_OnLoad : aucune nouvelle entrée de localisation n'est nécessaire. Seuls les boutons visibles sont listés : si vous avez lancé la vérification vous-même, Blizzard masque le côté réponse et il n'y a rien à répondre.
Volumes du jeu : une valeur réglée revenait forte sur un autre personnage
Simple : Si vous baissiez le volume général dans le menu Sku, vous le retrouviez à l'ancienne valeur sur un autre personnage. Sku conservait en effet sa propre copie des cinq volumes et des cinq interrupteurs de son, en plus de celle du jeu, et réécrivait cette copie dans le jeu à chaque connexion. Cette copie dépend du profil Sku, alors que le réglage du jeu dépend du compte : deux personnages dans des profils différents entendaient donc deux volumes différents, et une modification faite dans les options de son de Blizzard disparaissait sans bruit à la connexion suivante. Sku ne fait plus que régler les valeurs ; c'est au jeu de les retenir, comme pour tout autre joueur. Les curseurs du menu affichent désormais la valeur réelle du jeu, y compris si vous l'avez changée ailleurs. Ce que l'on perd : les volumes ne suivent plus un profil Sku.
Technique : SkuOptions:OnEnable réécrivait soundChannels et soundSettings du profil vers les CVars à chaque connexion, précédé d'une règle spéciale qui prenait une valeur stockée de 0 ou -1 pour un profil corrompu et réadoptait alors les cinq canaux depuis les CVars. Tout ce bloc a disparu. Les nœuds de menu dans SkuZOptions/Options.lua lisent et écrivent les CVars directement (tGetSoundCVarPercent, tSetSoundCVarPercent, tGetSoundCVarBool) ; les dix clés sont retirées de SkuOptions.defaults et du schéma, et un passage unique dans OnInitialize les nettoie de chaque profil enregistré - pas seulement de l'actif, car sans entrée dans les défauts AceDB ne les retirerait plus jamais. soundChannels reste : SkuChannel, le canal sur lequel Sku diffuse sa propre sortie, est un vrai réglage Sku. La lecture arrondit désormais au lieu de tronquer - tonumber("0.35") * 100 vaut 34,999... et serait revenu à 34. Les nouveaux profils n'apportent plus aucune valeur de volume par défaut ; ce sont les défauts du jeu qui s'appliquent.
Les quatre profils standard sont créés sans changer de profil entre-temps
Simple : À la première connexion, Sku crée les quatre profils standard s'ils manquent. Il le faisait jusqu'ici en basculant tour à tour dans chaque profil manquant puis en revenant dans le vôtre. Sur un royaume hardcore, le serveur interrompt les scripts d'addon trop longs, et si cela tombait sur cette séquence le personnage restait dans le profil d'un autre - avec tous les réglages de ce profil au lieu des vôtres. Or un profil existe dès qu'il porte un nom ; il n'y a rien à basculer pour cela. Dix étapes lourdes sont devenues quatre étapes courtes qui ne peuvent pas échouer à mi-chemin.
Technique : Les quatre appels à SetProfile plus le retour dans SkuCore/Core.lua sont remplacés par quatre affectations dans SkuOptions.db.sv.profiles. Le GetProfiles d'AceDB énumère exactement cette table, et un profil n'est de toute façon rempli par copyDefaults qu'au premier basculement - l'état enregistré final est le même qu'auparavant, quatre tables vides. Chaque appel à SetProfile déclenchait au contraire OnProfileShutdown et parcourait avec removeDefaults et copyDefaults l'arbre complet des défauts des huit modules, soit une dizaine de parcours dans une seule frame. Supprimer les basculements supprime aussi le drapeau SkuCore.AutoChange, qui rendait OnProfileChanged muet pendant ce temps et restait à true en cas d'interruption - après quoi plus aucun changement de profil ne passait pour le reste de la session. Le répartiteur enveloppe ce gestionnaire dans un pcall, l'interruption était donc invisible.