Une ville en pixel art vivante sans personne en ligne : PNJ et fantômes
Une ville en pixel art paraît habitée surtout grâce à des gens qui restent immobiles. Dans les 16 villes de Pokémon Version Émeraude, les 100 habitants qui ne portent aucun drapeau de masquage, et qui sont donc là à chaque visite, se répartissent ainsi : 59 se tiennent à un poste, tournés dans une direction ou regardant autour d’eux, 39 errent dans un cadre d’une ou deux cellules autour de leur point de placement, et 2 marchent sur place ; si l’on ajoute les 58 qu’un drapeau de scénario peut retirer, surtout des membres d’équipe, des rivaux et des personnages nommés, dont 54 se tiennent debout, la répartition devient 113 sur 158 (71,5 %), 43 (27,2 %) et 2. Un errant fait un pas en 16 images puis attend 32, 64, 96 ou 128 images, si bien qu’il est en mouvement au plus 11 à 33 % du temps.1 La journée est réglée au retour du joueur, par une fonction exécutée une fois avec le nombre de jours écoulés, et non par une horloge qui tourne pendant que personne ne joue.23 Quand personne d’autre n’est là, le canon remplit la ville des traces d’autres personnes dans de petits emplacements fixes (le mélange de données d’Émeraude copie 20 Bases Secrètes, 5 expressions à la mode et le vieil homme d’un autre joueur dans votre partie) et laisse des inconnus partager une présence sans partager de mots.45 J’ai mesuré tout cela parce que ma propre ville, Kiradex World, doit répondre à la même question lors de son premier matin calme, et le code de son propre serveur, piloté sur une horloge simulée, y répond mal sur trois points : ses quatre collectionneurs s’arrêtent quand la salle est vide ; ils font un pas par seconde au lieu des 0,7 seconde configurées et restent immobiles 75 % de chaque trajet ; et, dans un modèle du code de dessin de l’app elle-même, un autre collectionneur est dessiné en train de sauter en arrière quand un déplacement arrive au milieu d’un pas : sur 45 des 64 déplacements d’une course, et sur 7 et 16 images d’une marche de 40 tuiles avec 30 et 80 ms de gigue réseau, mais jamais sur une marche régulière sans gigue.67 Voici le canon mesuré, les références modernes, la présence en direct avec ses chiffres, les règles d’un monde où des enfants peuvent se trouver, et le cahier des charges.
En bref
- L’essentiel d’une ville reste debout. Six sur dix des 100 personnes des villes d’Émeraude sans drapeau de masquage ont un type de mouvement par défaut immobile, et sept sur dix des 158 une fois comptées les 58 que le scénario peut retirer (un script de scénario peut tout de même en faire marcher une, comme le garçon de l’arène de Petalburg conduit le joueur jusqu’à l’arène) ; presque tous les autres errent dans des cadres d’une ou deux cellules, au rythme même du joueur, 16 images (268 ms) par cellule, et attendent 0,54 à 2,14 secondes entre deux pas. Littleroot compte 6 personnes, Petalburg 7, Mauville 10, dont 2, 3 et 6 sans drapeau de masquage.18
- Une routine, ce sont quelques points horodatés et une clé ; un souvenir, c’est un drapeau par jour. Stardew Valley écrit la journée d’un villageois comme une chaîne de points horodatés (la journée ordinaire de Pierre en compte 7) et choisit la journée applicable parmi 22 formats de clé répartis en trois groupes, le premier qui correspond l’emporte : une clé spéciale vérifiée pour tout le monde, puis 5 formats de mariage pour un villageois marié, qui n’en utilise aucun autre, ou 16 formats ordinaires pour tous les autres ; parler une fois par jour à un villageois rapporte +20 d’amitié. Animal Crossing: New Horizons donne +1 sur 255 pour la première conversation du jour et enseigne une Réaction par jour.29101112
- Les traces des autres remplissent une ville vide, dans des emplacements fixes, et elles s’effacent. Le mélange de données d’Émeraude transporte 5 188 octets du monde d’un autre joueur ; dans l’avenue des rencontres (Join Avenue), des fans comblent les emplacements de boutique que de vrais visiteurs laissent vides, à 75 % de la valeur d’un visiteur (selon Serebii) ; les structures de Death Stranding sont « destroyed by Timefall after some time » (détruites par la chronopluie au bout d’un certain temps) ; Journey montre un seul inconnu à la fois, sans nom avant le générique et avec un unique carillon.413145
- La présence en direct est un tampon, pas une fréquence d’envoi. L’émulateur de serveur de Habbo construit par des fans fait avancer chaque salle sur un cycle de 500 ms ; Gaffer on Games met en tampon « 3X the packet send rate » (trois fois l’intervalle d’envoi des paquets) ; dans un modèle de la marche de Kiradex aux 3,75 et 7,5 tuiles par seconde de la série, dessiner les autres collectionneurs sur une horloge en retard de 350 ms sur l’heure estimée du serveur donne 0 image en arrière et 0 image affamée jusqu’à 80 ms de gigue, alors que 100 ms en affament 125 à 456 sur les 600 dessinées pendant que l’émetteur émet.15167
- Les règles pour les enfants sont datées. Game Center limite les enfants « to sending and receiving preset messages » (à l’envoi et à la réception de messages prédéfinis) ; la documentation d’Apple indique qu’un jeu doté d’une fonctionnalité multijoueur personnalisée « should disable it » (devrait la désactiver) quand Screen Time restreint le multijoueur ; la règle COPPA modifiée, applicable depuis le 22 avril 2026, impose une politique écrite de conservation des données assortie d’un délai de suppression.171819
- Kiradex diffère aujourd’hui de son propre plan sur quatre points. Les collectionneurs de la place s’arrêtent quand personne n’est dans la salle, alors que
server/app/npcs.pydit « A town is never empty » (une ville n’est jamais vide) ; ils font un pas toutes les 1,0 s au lieu des 0,7 s configurées ; l’app envoie un déplacement par tuile (4 par seconde en marchant, 6,0 à 6,4 en courant) là où le raisonnement du plan parlait de 8 à 10 Hz ; et rien ne lit les drapeaux de restriction de Game Center, bien que le plan fonde l’identité et le contrôle parental sur Game Center.62021222324 - Ce que cela apporte à Kiradex. Un cahier des charges pour huit habitants dont les routines sont indexées sur les moments de la journée de l’app elle-même, sur une horloge par salle, avec des positions calculées à partir de cette horloge ; les trajets des huit derniers visiteurs rejoués sous forme d’échos sans nom, dans une silhouette sobre choisie par le serveur, conservés sept jours et envoyés sans aucun identifiant ; un bonjour quotidien qui ne s’efface jamais ; un tampon de rendu de 350 ms ; un carnet de répliques de six branches de 8 à 12 phrases complètes chacune ; et sept réglages de sécurité, chacun avec une vérification qu’un script, un test ou une capture peut valider ou invalider.7119
1. Les habitants, mesurés : Émeraude, Stardew Valley et Animal Crossing
Tout petit monde social se heurte à la même question dès sa première nuit : que voit un joueur qui entre sur la place quand personne d’autre n’y est ? Le canon donne trois réponses, et cet article les examine l’une après l’autre. La première, ce sont des habitants qui mènent leur propre vie, de sorte que la ville s’anime que quelqu’un soit en ligne ou non. La deuxième, ce sont les traces d’autres personnes, laissées par des joueurs qui ne sont pas là en ce moment. La troisième, c’est une présence en direct bien faite quand des gens sont là, encadrée par les règles d’un monde où des enfants peuvent se trouver. La première réponse est la plus ancienne et la mieux mesurée, parce que le code source de l’un de ses chefs-d’œuvre est public.
Ce que font les habitants d’Émeraude
Pokémon Version Émeraude a été lu dans la décompilation de pret, un clone superficiel de pokeemerald au commit 731ad5b, et compté par un script, measure_npcs.py, qui lit les constantes des types de mouvement et les événements d’objet de chaque carte de ville.1 Émeraude définit 81 types de mouvement, de 0x00 à 0x50. Regroupés selon ce que fait le personnage à l’écran, 24 parcourent une boucle fixe en quatre segments, 17 se tiennent debout et regardent (de façon fixe, alternée ou en regardant autour d’eux), 16 marchent, trottinent ou courent sur place, 8 imitent le joueur, 5 errent au hasard dans une zone, 4 font des allers-retours, 4 sont cachés ou déguisés, et les trois derniers sont NONE, le joueur et l’arbre à baies, qui est un objet et non une personne.125
Les villes n’en utilisent que peu. Sur les 16 cartes de villes, on compte 172 événements d’objet, et tous ne sont pas des personnes : 6 sont des Poké Balls d’objet, 2 sont des camions de déménagement, 1 est un bateau et 5 sont des Pokémon. Le script les trie par graphics_id et compte à part les 158 personnes.18 Seuls 11 des 81 types de mouvement apparaissent parmi ces personnes. 113 des 158 (71,5 %) se tiennent debout et regardent, 43 (27,2 %) errent dans une zone et 2 (1,3 %) marchent sur place. Les types les plus fréquents sont FACE_DOWN avec 32, FACE_RIGHT avec 23, LOOK_AROUND avec 20, FACE_UP avec 19 et WANDER_AROUND avec 17.18
Ces 158 ne sont pas tous des résidents. 58 d’entre eux portent un drapeau de masquage, un drapeau de scénario qui les retire de la carte, et 41 de ces 58 utilisent le sprite d’une équipe de méchants, celui du rival ou celui d’un personnage nommé ; ces 58 sont donc surtout des acteurs des scènes du scénario, et 54 d’entre eux se tiennent debout. Les 100 personnes sans drapeau de masquage, présentes sur la carte à chaque visite, se répartissent autrement : 59 se tiennent debout et regardent, 39 errent dans une zone et 2 marchent sur place. Les résidents qu’un joueur voit la plupart du temps sont donc debout à six sur dix et errants à près de quatre sur dix ; les sept sur dix du total viennent de l’ajout des acteurs, presque tous debout. Il s’agit de types de mouvement par défaut, ce que fait une personne quand aucun script ne la déplace ; un script de scénario peut tout de même faire marcher une personne debout, comme le garçon de l’arène de Petalburg, qui regarde autour de lui par défaut et ne porte aucun drapeau de masquage, et qui conduit le joueur jusqu’à l’arène. Le décompte décrit la ville au repos, pas chacune de ses scènes.18
Six sur dix des habitants toujours présents sur les cartes d’Émeraude ont un type de mouvement par défaut immobile, sept sur dix si l’on compte les acteurs amovibles du scénario ; les errants restent dans des cadres d’une ou deux cellules. Les scènes scriptées, qui peuvent faire marcher n’importe qui, ne sont pas comptées.26
Trois villes de tailles différentes présentent la même forme. Le tableau ne compte que les personnes ; les événements d’objet écartés sont les deux camions de Littleroot et trois Poké Balls d’objet, deux à Petalburg et une à Mauville. La dernière colonne compte les personnes sans drapeau de masquage selon ce qu’elles font.1
| Ville | Personnes | Debout et tournées | Errent dans un cadre | Zones d’errance (x, y) | Avec drapeau de masquage | Sans drapeau de masquage (debout, errant) |
|---|---|---|---|---|---|---|
| Littleroot | 6 | 3 (vers le haut) | 3 (WANDER_AROUND) |
(1, 2), (2, 1), (2, 1) | 4 | 2 (0, 2) |
| Petalburg | 7 | 5 (2 regardent autour, 2 vers le haut, 1 vers le bas) | 2 (1 tout autour, 1 haut et bas) | (1, 1), (0, 1) | 4 | 3 (2, 1) |
| Mauville | 10 | 8 (2 regardent autour, 2 vers le haut, 2 vers la gauche, 1 vers la droite, 1 vers le bas) | 2 (gauche et droite) | (1, 1), (1, 0) | 4 | 6 (4, 2) |
Le cadre d’un errant est imposé une cellule à la fois : avant chaque pas, IsCoordOutsideObjectEventMovementRange refuse toute cible située hors de la zone de l’objet autour de son point de placement, si bien qu’un errant tourne autour de sa cellule d’origine au lieu de voyager.27 Les drapeaux de masquage forment l’autre moitié de la population. Quatre des 6 personnes de Littleroot, quatre des 7 de Petalburg et quatre des 10 de Mauville portent un drapeau qui les retire quand le scénario avance ; la population d’une ville est donc une fonction de la progression du joueur : des gens partent et arrivent parce que quelque chose s’est passé.1
À quelle fréquence ils bougent
Le minutage se trouve dans le même fichier. Un habitant qui erre ou qui regarde autour de lui attend 32, 64, 96 ou 128 images, tirées au hasard dans sMovementDelaysMedium, avant son prochain pas ou sa prochaine rotation : 0,54, 1,07, 1,61 ou 2,14 seconde aux 59,7275 Hz de la Game Boy Advance, soit 1,34 en moyenne. Il en va de même pour les deux types d’orientation qui alternent entre des directions opposées, FACE_DOWN_AND_UP et FACE_LEFT_AND_RIGHT. Les types qui alternent entre deux directions voisines ou entre trois puisent dans sMovementDelaysShort, 32, 48, 64 ou 80 images, soit 0,94 seconde en moyenne, et les deux types rotatifs attendent 48 images fixes. Une troisième table, sMovementDelaysLong, est marquée // Unused dans le source, et aucun type de mouvement ne la lit.127
Le pas lui-même est celui du joueur. PlayerWalkNormal appelle GetWalkNormalMovementAction, l’action même qu’utilise le pas d’un errant ; MOVE_SPEED_NORMAL correspond à sStep1Funcs, qui déplace de 1 pixel par image pendant 16 images, une cellule de 16 pixels en 268 ms, 3,73 cellules par seconde. La course est MOVE_SPEED_FAST_1, sStep2Funcs, 8 images par cellule, 134 ms, 7,47 cellules par seconde.127 En combinant les deux lignes, un errant est en mouvement pendant 268 ms sur chaque cycle d’un pas plus une attente, soit 0,81 à 2,41 secondes : entre 11 et 33 % du temps, par pas effectué. C’est une borne supérieure. Quand la direction qu’un errant choisit est bloquée, par un mur ou le bord de son cadre, MovementType_WanderAround_Step4 le renvoie regarder et attendre de nouveau sans bouger ; sa part réelle de temps en mouvement est donc plus faible. Le reste du temps, il se tient debout, ou se tourne.127
Un errant d’Émeraude bouge par pas isolés entre de longues attentes ; les collectionneurs de Kiradex, mesurés à la section 6, bougent par à-coups d’une tuile alors qu’ils sont censés marcher.26
Selon ma lecture, trois détails portent l’effet. Rien dans la ville ne marche plus vite ou plus lentement que vous, donc rien ne paraît d’une autre nature. Les pauses sont plus longues que les pas, si bien que la ville est une suite d’images fixes ponctuées de mouvement, ce qui explique qu’elle ne paraisse jamais encombrée avec 6 à 10 personnes. Et la population est inscrite dans le scénario par les drapeaux de masquage, de sorte que la ville change parce que le joueur a fait quelque chose, et non parce qu’un minuteur s’est déclenché.
La journée d’Émeraude se règle à l’arrivée
Émeraude tient une journée, mais pas avec une horloge qui tourne pendant que personne ne joue. Il réserve 64 emplacements de drapeaux quotidiens après DAILY_FLAGS_START et en utilise 12 : neuf dons de baies (celui d’un hall de concours, ceux du Maître des Baies et de sa femme, ceux de cinq donateurs de routes ou de villes, celui du fleuriste), le drapeau quotidien de la Base Secrète, le billet de loterie et FLAG_DAILY_APPRENTICE_LEAVES.228 Quand le joueur revient, UpdatePerDay s’exécute une fois avec le nombre de jours écoulés, et il s’exécute aussi depuis DoTimeBasedEvents en cours de partie ; il appelle, dans l’ordre, ClearDailyFlags, UpdateDewfordTrendPerDay, UpdateTVShowsPerDay, UpdateWeatherPerDay, UpdatePartyPokerusTime, UpdateMirageRnd, UpdateBirchState, UpdateFrontierManiac, UpdateFrontierGambler, SetShoalItemFlag et SetRandomLotteryNumber.23 L’expression à la mode, la télévision et la météo évoluent toutes selon les jours écoulés, calculés au moment du retour.3 Rien ne s’est passé pendant que la cartouche était éteinte ; la ville se comporte comme si c’était le cas.
Stardew Valley : un emploi du temps est une chaîne de caractères
Stardew Valley est la référence moderne des habitants qui ont une vie. La page « Villagers » de son wiki recense 6 célibataires masculins, 6 célibataires féminines, 22 villageois que l’on ne peut pas épouser et 12 à qui l’on ne peut pas offrir de cadeaux, soit 34 villageois à qui l’on peut offrir des cadeaux, et indique : « Each villager has a daily routine, so they can be located in different sections of town depending on the in-game time of the day and weather. » (Chaque villageois a une routine quotidienne, si bien qu’on peut le trouver dans différents quartiers de la ville selon l’heure du jour dans le jeu et la météo.)229
La routine est une donnée. Chaque villageois a un fichier sous Content/Characters/schedules/, et chaque entrée est une chaîne de points séparés par des barres obliques, chaque point étant <time> [location] <tileX> <tileY> [facing] [animation] [dialogue], avec l’heure au format 24 heures sans deux-points et l’orientation 0 pour le haut, 1 pour la droite, 2 pour le bas et 3 pour la gauche.9 Le mercredi d’Abigail, tel que la page le donne, est 1000 ArchaeologyHouse 11 9 0/1800 Town 47 87 0/2200 SeedShop 1 9 3 abigail_sleep : trois points, une marche entre chacun et une animation au dernier.9 Pierre, qui tient le magasin général, a 7 points horodatés lors d’une journée ordinaire (6 h 00 à son comptoir, 7 h 00 dans les rayons, 8 h 30 de retour au comptoir, puis 17 h 00, 19 h 00, 21 h 00 et 23 h 00 à travers les rayons, la cuisine, une bibliothèque et le lit), et sa page recense 6 variantes de son emploi du temps : la pluie verte, le bus réparé le 15 du printemps, le festival du désert, la pluie, le vendredi et la journée ordinaire.230
L’intelligence réside dans les clés. L’emploi du temps qui s’applique un jour donné est décidé par 22 formats de clé répartis en trois groupes, chacun essayé dans un ordre fixe, le premier qui correspond l’emporte. Une clé spéciale, GreenRain, est « checked first, regardless of marriage status » (vérifiée en premier, quel que soit l’état civil). Un villageois marié essaie ensuite uniquement les 5 formats de mariage, de marriage_<festivalID> à une date, marriageJob et le jour de la semaine : « Married NPCs don’t use any other schedule keys. If the marriage keys don’t match, they won’t have a schedule for that day. » (Les PNJ mariés n’utilisent aucune autre clé d’emploi du temps ; si aucune clé de mariage ne correspond, ils n’ont pas d’emploi du temps ce jour-là.) Tous les autres villageois essaient les 16 formats ordinaires, de <festivalID>, <season>_<dayofmonth>, <dayofmonth>_<hearts>, <dayofmonth>, bus, rain2 (une « 50% chance of applying on rainy days », 50 % de chances de s’appliquer les jours de pluie) et rain, puis les clés jour de la semaine et cœurs et le jour de la semaine, jusqu’à <season>, spring et enfin default.29 Selon ma lecture, un villageois a donc de nombreuses journées possibles, les mêmes quelques points se recombinent en une vie, et les clés de cœurs signifient qu’un villageois qui vous apprécie passe une autre journée. La note de la page sur les limites révèle comment la journée est calculée : quand un PNJ est ajouté à une sauvegarde existante, « they generally don’t follow their schedule correctly until you’ve slept once in-game (which triggers their first day update). » (ils ne suivent généralement pas correctement leur emploi du temps tant que vous n’avez pas dormi une fois dans le jeu, ce qui déclenche leur première mise à jour quotidienne.)9 Comme dans Émeraude, la journée de Stardew est calculée à la frontière du jour, et non avancée en continu.
L’amitié est la mémoire quotidienne, et elle a un coût. Un cœur vaut 250 points ; « talking to them once per day (+20) » (leur parler une fois par jour, +20) est le premier élément de la liste du wiki des façons de l’augmenter ; un villageois accepte un cadeau par jour et deux par semaine, un cadeau d’anniversaire comptant huit fois ; et ne pas parler coûte des points chaque jour, 2 pour la plupart des villageois et 10 après un bouquet, jusqu’à ce que la jauge soit pleine ou atteigne son plafond, et 20 pour un conjoint, dont la baisse ne s’arrête jamais.10 Les événements de cœur, les scènes scriptées, s’ouvrent à des seuils de cœurs, et « most events can be viewed anytime (with some time restrictions) or out of order. » (la plupart des événements peuvent être vus à tout moment, avec quelques restrictions horaires, ou dans le désordre.)10 Le villageois agit aussi sur vous pendant votre absence : à 3 cœurs, Pierre « will send you a recipe in the mail » (vous enverra une recette par courrier), et à tout niveau supérieur à zéro, il peut vous envoyer 250g ou plus.30
Animal Crossing : le villageois qui sait que vous êtes passé
New Horizons réduit le villageois qui sait que vous lui avez parlé aujourd’hui à un seul point. L’amitié va de 0 à 255 et commence à 25 ; le premier élément de la liste de Nookipedia de ce qui l’augmente est « +1 point » pour « speaking to the villager for the first time each day » (parler au villageois pour la première fois de la journée) ; un villageois accepte un cadeau par jour ; et à 150 points, un villageois a 6 % de chances de vous donner sa photo en échange d’un cadeau, chance qui augmente de 0,04 % par point jusqu’à 10,2 % à 255.11 Selon ma lecture, c’est un drapeau plutôt qu’une jauge, car le joueur ne la voit jamais bouger.
La vie visible des villageois est modeste et leur appartient. Chacun a l’un de six loisirs (Éducation, Mode, Forme, Musique, Nature, Jeu), et dans New Horizons « a villager always has one hobby that doesn’t change » (un villageois a toujours un loisir qui ne change pas) ; les villageois poursuivent les insectes et les poissons mais « still will not catch either of them » (n’en attrapent toujours aucun), font de l’exercice, lisent et chantent avec un lecteur de musique proche, et depuis la mise à jour 2.0 ils « invite the player to their house, ask the player for an invitation » (invitent le joueur chez eux, demandent au joueur une invitation) ou passent pour « a random visit » (une visite au hasard).3132 Huit personnalités façonnent ce qu’ils disent, quatre pour les villageois (paresseux, sportif, grincheux et suffisant) et quatre pour les villageoises (normale, vive, snob et grande sœur), dont « Smug and big sister were introduced in New Leaf, with the other six being present since Doubutsu no Mori. » (suffisant et grande sœur ont été introduits dans New Leaf, les six autres existant depuis Doubutsu no Mori.)33
Les villes sont restées petites tout au long de la série.32
| Jeu | Villageois au départ | Villageois au maximum |
|---|---|---|
| Animal Crossing | 6 | 15 |
| Wild World | 3 | 8 |
| Let’s Go to the City (City Folk) | 6 | 10 |
| New Leaf | 5 | 10 |
| New Horizons | 2 (un sportif et une grande sœur, parmi 83 possibles) | 10 |
Wild World a aussi changé le rythme : là, « the villagers walk at a much slower pace than the player » (les villageois marchent beaucoup plus lentement que le joueur), ce que Let’s Go to the City a conservé.32 C’est l’inverse de la règle d’Émeraude, et selon ma lecture les deux fonctionnent pour la même raison : un villageois qui flâne paraît être un résident, et un habitant qui fait un pas à votre rythme puis attend le paraît aussi. Ce qui brise l’effet, c’est une personne qui ne bouge à aucun de ces deux rythmes, et c’est le problème de Kiradex à la section 6.
L’expression prédéfinie de la série est la Réaction, et elle est elle-même un cadeau des habitants, distribué à la ration quotidienne. New Horizons comptait 44 Réactions en 1.0.0 et 44 de plus en 2.0, 88 au total, et « The player can learn one Reaction per day, » (le joueur peut apprendre une Réaction par jour), certaines seulement auprès de certaines personnalités ou avec une amitié élevée.212
2. Les traces des autres : ce qui remplit une ville quand personne n’est en ligne
Les habitants animent une ville, mais ce sont les mêmes personnes chaque jour. La deuxième réponse est celle vers laquelle s’est tourné chaque jeu étudié lorsqu’il craignait un monde vide : le remplir de traces de vraies personnes, laissées par des joueurs qui n’ont pas besoin d’être en ligne maintenant. Émeraude l’a fait avec un câble Link.
Le mélange de données : le monde d’un autre joueur, dans des emplacements fixes
Quand deux joueurs d’Émeraude mélangent leurs données (record mixing), chaque partie envoie à l’autre une structure fixe, PlayerRecordEmerald, de 11 types d’enregistrements en 0x1444 octets, 5 188 au total.434 Ce qui compte pour donner l’impression que d’autres sont passés, ce sont les emplacements : 20 Bases Secrètes, 25 emplacements de télévision (5 ordinaires et 20 de plus), 16 nouvelles, 5 expressions à la mode et 2 apprentis sur les 4 qu’une partie conserve.4 Selon ma lecture, c’est tout l’intérêt de ces emplacements : votre ville a changé parce que quelqu’un d’autre a joué, avec les bases, les émissions et l’expression d’un ami transportées dans votre partie.
Le cas le plus net est celui d’une seule personne. Le Centre Pokémon de Mauville abrite un vieil homme, l’un de cinq (le Barde, le Hipster, le Marchand, le Conteur et l’Exalté, en anglais the Bard, the Hipster, the Trader, the Storyteller et the Giddy). Celui qu’obtient une nouvelle partie est choisi par (trainerId % 10) / 2, avec ce commentaire du source lui-même : « Determine man based on the last digit of the player’s trainer ID, » (déterminer l’homme d’après le dernier chiffre de l’ID de dresseur du joueur), et lors d’un mélange de données, ReceiveOldManData copie le vieil homme du partenaire par-dessus le vôtre.435 Le résident de votre ville est littéralement l’habitant d’un autre joueur.
Le Hipster rationne le vocabulaire selon les contacts. Son script active FLAG_UNLOCKED_TRENDY_SAYINGS et enseigne un mot si son taughtWord vaut false, puis le passe à true ; le seul appel qui le remet à false, ResetHipsterFlag par l’intermédiaire de ResetMauvilleOldManFlag, est fait depuis un seul endroit, la fin de ReceiveOldManData dans record_mixing.c.35 Une expression à la mode se débloque donc une fois chaque fois que le mélange de données amène le Hipster, plus une fois pour un joueur qui commence avec lui, c’est-à-dire, selon la règle de sélection, un joueur dont l’ID de dresseur se termine par 2 ou 3. Le premier article de cette série énonce la règle de la même façon.3635 Le vocabulaire s’enrichit en rencontrant des gens, pas en attendant.
L’expression à la mode, en arithmétique
L’expression à la mode, deux mots Easy Chat que la ville de Dewford traite comme le dicton du moment, est la seule trace qu’Émeraude note. Son commentaire source dit qu’une expression « boring » (ennuyeuse) va « lose trendiness over time until it reaches 0, at which point it will stop being boring and gain trendiness until it reaches maxTrendiness (then it becomes boring again and the cycle repeats). » (perdre de sa popularité avec le temps jusqu’à atteindre 0, moment où elle cesse d’être ennuyeuse et gagne en popularité jusqu’à maxTrendiness, puis redevient ennuyeuse et le cycle recommence.)37 Le pic d’une expression est tiré entre 30 et 127 par jusqu’à trois tirages Random() % 98 imbriqués. En prenant chaque tirage comme indépendant et uniforme sur ses 98 valeurs, le pic moyen est de 62,9 et 81,3 % des pics sont inférieurs ou égaux à 80 ; le score de départ est uniforme entre 30 et le pic, 46,5 en moyenne ; et le score bouge de 5 par jour écoulé, réglé dans UpdatePerDay comme tout le reste.383 Ces chiffres sont une approximation du code, pas sa sortie exacte : Random() renvoie 16 bits, si bien qu’un reste compris entre 0 et 71 sort 669 fois sur 65 536, et un reste compris entre 72 et 97 sort 668 fois, et les tirages successifs viennent d’un même générateur, non de dés indépendants. Pondérer les restes de cette façon, en supposant toujours les tirages indépendants, ne change aucun des deux chiffres à la première décimale.3837 En taux continu, une expression de pic 30 monte de rien jusqu’à son pic et redescend en 12 jours, une expression de pic 64 en 25,6 et une de pic 127 en 50,8. Le jeu déplace le score par jours entiers, et un score qui dépasserait son pic ou zéro rebondit du reste, si bien que les scores quotidiens ne se répètent pas selon ces périodes fractionnaires : transposée jour par jour depuis un score nul en hausse, la séquence exacte se répète pour la première fois après 12, 128 et 254 jours.3837 Jusqu’à 5 expressions sont sauvegardées, et lors d’un mélange « their own trends are replaced with their mixing partner’s, unless the phrase is the same, in which case the version with a higher trendiness value is used. » (leurs propres expressions sont remplacées par celles du partenaire de mélange, sauf si l’expression est la même, auquel cas la version la plus populaire est conservée.)3837
Une expression à la mode est un lent zigzag échantillonné une fois par jour : 81,3 % des pics sont inférieurs ou égaux à 80, soit une montée et une descente d’environ 32 jours ou moins.2638
Selon ma lecture, c’est la bonne forme pour une trace qui doit empêcher une ville de s’encroûter : elle monte, elle descend, sa durée de vie est fixée à sa naissance, et le contact avec un autre joueur peut la remplacer par quelque chose de plus frais.
Easy Chat contre la Salle Union
Émeraude offrait aux joueurs deux façons de dire des choses, et ce sont les deux extrémités de l’argument de sécurité de cet article. La Salle Union (Union Room), son salon local sans fil, affiche 8 chefs de groupe, accueille 5 joueurs par groupe sans fil (RFU_CHILD_MAX, 4, plus un), dessine 40 sprites et définit 30 codes d’activité. Son chat est tapé au clavier : quatre pages de clavier (UPPER, LOWER, EMOJI, REGISTER), 15 caractères par message (MAX_MESSAGE_LENGTH) et 10 phrases enregistrées conservées dans la sauvegarde (UNION_ROOM_KB_ROW_COUNT).439 Ma lecture est que le chat tapé y était tolérable parce que tous ceux qui se trouvaient dans la salle étaient à portée sans fil de vous.
Tout ce que les joueurs se disaient d’autre passait par Easy Chat. Il compte 22 groupes et 1 815 entrées au total. Sont ouverts dès le début Dresseur (27, dont 6 désactivées), Statut (109), Combat (63), Salutations (42), Gens (75), Voix (63), Discours (60), Fins de phrase (69), Sentiments (69), Conditions (69), Actions (78), Mode de vie (45), Loisirs (54), Temps (45), Divers (42) et Adjectifs (36), plus une liste de 202 noms, chacun ne s’ouvrant qu’une fois l’espèce vue par le joueur ; sont verrouillés Événements (29) et deux listes de capacités (154 et 200) jusqu’à la fin du jeu, l’expression à la mode (33) jusqu’au drapeau du Hipster, et une liste nationale de 251 noms.3840 En laissant de côté les 6 entrées Dresseur désactivées, qu’aucun joueur ne peut choisir, cela fait 940 mots, noms non compris, ouverts dès la première heure. Un switch dans easy_chat.c décide quels groupes se débloquent, et un second décide de chaque entrée : un nom selon que son espèce a été vue, tout autre mot selon son champ enabled.3840 Les phrases sont des grilles fixes : un profil fait 2 sur 2, 4 emplacements ; une ouverture de combat 2 sur 3, 6 ; un courrier 2 sur 5, 10 emplacements contenant jusqu’à 9 mots ; l’expression à la mode et le bon dicton 2 sur 1 ; le questionnaire 2 sur 2, 4 mots.3840
Un vocabulaire combinable de 940 mots est expressif, et selon ma lecture c’est aussi un vocabulaire avec lequel un enfant déterminé peut épeler toutes sortes de choses. C’est l’échange que le cahier des charges de Kiradex refuse à la section 7 : des phrases entières, jamais des mots.
Les traces d’inconnus dans d’autres jeux
Tous les autres jeux étudiés qui craignaient un monde vide se sont tournés vers les autres joueurs, la plupart vers les traces que les joueurs laissent derrière eux. Les sources sont de solidité inégale, et chaque paragraphe nomme la sienne.
Dark Souls (FromSoftware, 2011). Wikipedia, citant sa propre source : « The player can see ghostly images of other players, activate bloodstains that show how other players died, and leave messages using preset phrases. » (Le joueur peut voir des images fantomatiques d’autres joueurs, activer des taches de sang qui montrent comment d’autres joueurs sont morts, et laisser des messages à l’aide de phrases prédéfinies.)41 Le Daily Telegraph lui a décerné le prix « Best Integration of Online Features » (meilleure intégration des fonctionnalités en ligne).41 La page de Bandai Namco Europe consacrée au remaster cite « The Way of the Multiplayer (up to 6 players with dedicated servers) » (la voie du multijoueur, jusqu’à 6 joueurs avec serveurs dédiés) parmi ses atouts et ne dit rien de plus sur la couche des fantômes et des messages ; la description de FromSoftware elle-même n’a pas pu être consultée.42 La page ne dit pas si les images fantomatiques rejouent des joueurs partis ou montrent des joueurs connectés à cet instant ; elle les range, avec les taches de sang et les messages, parmi les « online features » (fonctionnalités en ligne) que le jeu « integrates » (intègre) dans « the single-player world » (le monde solo), et place le « Direct multiplayer » (multijoueur direct), les invocations et les invasions, dans la phrase suivante.41
Journey (thatgamecompany, 2012). Wikipedia encore : « In each level, the player may come across one other player temporarily connected to their game » (à chaque niveau, le joueur peut croiser un autre joueur temporairement connecté à sa partie) ; les deux « cannot communicate via speech or text and cannot see each other’s names until after the game’s credits » (ne peuvent communiquer ni par la voix ni par le texte et ne voient pas le nom de l’autre avant le générique de fin) ; « The only form of communication between the two is a musical chime. » (La seule forme de communication entre eux est un carillon musical.) Les développeurs « felt having text or voice communication or showing usernames would allow players’ biases and preconceptions to come between them and the other player. » (estimaient qu’une communication écrite ou vocale, ou l’affichage des noms d’utilisateur, laisserait les préjugés et les idées préconçues des joueurs s’interposer entre eux et l’autre joueur.)5 C’est l’argument de sécurité sous forme de design, conçu pour des adultes.
Death Stranding (Kojima Productions, 2019). La page de Sony : « Donate valuable resources to rebuild structures in your world and others’, and offer likes in support of player structures that appear in yours. » (Donnez de précieuses ressources pour reconstruire des structures dans votre monde et dans celui des autres, et attribuez des likes aux structures de joueurs qui apparaissent dans le vôtre.)43 Wikipedia ajoute que les joueurs « can leave supplies, structures, and messages that can be viewed and used by other players, although structures will eventually be destroyed by Timefall after some time » (peuvent laisser des fournitures, des structures et des messages que d’autres joueurs peuvent voir et utiliser, même si les structures finissent par être détruites par la chronopluie au bout d’un certain temps), et que « The player does not directly encounter other players in the world. » (le joueur ne rencontre pas directement d’autres joueurs dans le monde.)14 Les traces s’effacent, si bien que le monde ne s’envase pas.
Splatoon (Nintendo, 2015). Les publications Miiverse des joueurs « appear in-game as graffiti on various buildings » (apparaissent dans le jeu sous forme de graffitis sur divers bâtiments), selon Wikipedia, citant sa source. Les graffitis provenaient de publications dans la communauté Miiverse du jeu ; selon ma lecture, la trace dépendait donc du service Miiverse de Nintendo plutôt que du jeu en ligne lui-même.44
Les trois fonctionnalités Pokémon plus récentes reposent sur une seule source, Serebii, un site de fans de longue date ; les pages de pokemon.com pour Noire 2 et Blanche 2 et pour Soleil et Lune ne mentionnent ni l’avenue des rencontres ni la Festi’Place, et aucune page d’éditeur sur les arènes de GO n’a été sauvegardée ; lisez donc chacun des trois paragraphes suivants comme la version de Serebii plutôt que celle de l’éditeur.45
L’avenue des rencontres (Join Avenue, Pokémon Version Noire 2 et Version Blanche 2, 2012). Selon Serebii, l’avenue « starts off as an empty pathway » (commence comme un chemin vide), et des gens arrivent pour ouvrir des boutiques, ce qui « is done automatically whenever you connect with someone » (se fait automatiquement chaque fois que vous vous connectez avec quelqu’un), par PassBy, infrarouge, la Salle Union, le Wi-Fi, le GTS et d’autres moyens. Il y a huit boutiques ; « every 10th person shown to the shop, the shop will rank up » (chaque dixième personne amenée à la boutique la fait monter d’un rang), jusqu’au rang 10, avec des « discounts of 1% for every rank up » (remises de 1 % par rang gagné) jusqu’à « a 40% discount » (une remise de 40 %) ; les visiteurs ordinaires valent « from 100 to 200 points » (de 100 à 200 points) ; et après le Conseil 4, « various fans will come and visit » (divers fans viendront en visite), et « If you help a fan rather than another player, they will give 75% of the normal popularity points. » (si vous aidez un fan plutôt qu’un autre joueur, il donnera 75 % des points de popularité habituels.)13 Selon ma lecture, c’est l’énoncé le plus net du canon d’une règle de repli : des remplaçants comblent les emplacements que de vraies personnes laissent vides, et valent un peu moins.
La Festi’Place (Festival Plaza, Pokémon Soleil et Lune, 2016). Selon Serebii, la place « will propogate itself with players you will find online and locally » (sic ; se peuplera de joueurs que vous trouverez en ligne et en local), et « This is not limited to people on your friend list » (cela ne se limite pas aux personnes de votre liste d’amis) ; les invités qui veulent quelque chose le disent, paient des Festi’Pièces quand vous les aidez, et un invité aidé peut devenir VIP, ce qui le rend « more likely to appear in your plaza in the future » (plus susceptible d’apparaître sur votre place à l’avenir) ; le rang de la place coûte 6 pièces au niveau 1 et monte à 300 à partir du niveau 101.46 Une présence par avatars : vous interagissez avec l’avatar d’un autre joueur, et Serebii décrit les personnes derrière ces avatars comme « all players that are also playing online » (tous des joueurs qui jouent eux aussi en ligne), qui, « when they see you » (quand ils vous voient), peuvent « challenge you to battles or request trades » (vous défier en combat ou demander des échanges). Selon ce récit, les personnages de la place représentent des joueurs eux-mêmes en ligne ; avec Journey, c’est l’une des deux fonctionnalités de cette liste que les sources décrivent comme une présence en direct plutôt que comme une trace.46
Les arènes de Pokémon GO (la refonte de 2017). Selon Serebii, une arène accueille jusqu’à six défenseurs ; chaque combat perdu fait baisser la motivation d’un défenseur, et « Once their Motivation has dropped to 0, then they are removed from the Gym » (une fois leur motivation tombée à 0, ils sont retirés de l’arène) ; les baies la restaurent ; et un défenseur gagne 1 pièce toutes les 10 minutes, « capped at 50 Coins earned a day. » (dans la limite de 50 pièces gagnées par jour.)47 Le lieu garde exposé le compagnon d’un autre joueur pendant son absence, et ce compagnon décline si la communauté ne le nourrit pas.
Le motif commun, selon ma lecture des huit : un petit nombre fixe d’emplacements (8 boutiques, 6 défenseurs, 1 compagnon, 20 bases), des traces qui s’effacent ou tournent (la chronopluie, la motivation, le cycle de l’expression à la mode), des remplaçants qui valent moins que des personnes, et, hormis les combats et les demandes d’échange de la Festi’Place, aucun canal direct entre inconnus au-delà d’une phrase prédéfinie ou d’un carillon.
3. La présence en direct : fréquences, tampons et le passage d’un marcheur
La troisième réponse est celle à laquelle on pense d’abord : quand d’autres joueurs sont en ligne, les montrer, en mouvement, sur la même place. Deux petits mondes sociaux en 2D, Habbo et Club Penguin, illustrent les deux extrémités de la présence sur grille. Aucune des deux entreprises n’a publié ses fréquences. Ce dont je dispose, ce sont deux serveurs de fans open source et un client de fans, écrits pour être compatibles avec les clients d’origine ; les chiffres ci-dessous témoignent donc de ce qu’attendaient ces clients, et non de chiffres publiés par Sulake ou par Disney.154849
Habbo : un pas par cycle serveur
Arcturus Morningstar, une réimplémentation open source du serveur de Habbo, fait tourner chaque salle sur un cycle fixe de 500 ms (scheduleAtFixedRate(this, 500, 500, TimeUnit.MILLISECONDS)) et appelle le cycle de chaque unité en marche une fois par cycle de salle ; il marque un avatar comme inactif à IDLE_CYCLES = 240, soit 120 secondes, et expulse un non-propriétaire à IDLE_CYCLES_KICK = 480, soit 240 secondes.15 Nitro, un client Habbo open source, déplace un objet de salle selon un DEFAULT_UPDATE_INTERVAL fixe de 500 ms : à chaque mise à jour du serveur, il prend l’écart jusqu’à la nouvelle position et l’interpole linéairement selon le temps écoulé divisé par 500, borné à la fin, puis remet l’écart à zéro.49 Qu’un cycle corresponde exactement à une tuile est ma lecture des deux ensemble (une période serveur de 500 ms dessinée comme une interpolation de 500 ms) ; je n’ai pas lu le RoomUnit du serveur pour le confirmer. Si cette lecture tient, le rendu a par construction une période serveur de retard, si bien qu’il ne manque jamais de données tant que le serveur suit.
Club Penguin : une destination, pas un flux
Houdini, un serveur Club Penguin open source du projet Solero, montre une autre conception. Un déplacement est un message sp portant une destination, x et y, relayé tel quel à la salle, et le client s’y rend de lui-même. Une ligne de chat sécurisé est un message ss portant un nombre, et les autres formes de parole prédéfinie voyagent de la même façon : sj pour une blague, sma pour le message d’une mascotte, sl pour une réplique de scène, sg pour une réplique de guide, se pour un emote, chacun relayé sous forme d’identifiant.48 Le serveur limite les emotes et les actions à une par seconde et les changements de dessin à un par demi-seconde, et une tâche de heartbeat contrôle les clients connectés toutes les 61 secondes et ferme ceux qui n’ont envoyé aucun heartbeat pendant ce délai.48 Le déplacement se fait par clic sur une destination, pas tuile par tuile, et la parole est un nombre que l’autre côté va chercher dans une table, ce qui, selon ma lecture, explique qu’un filtre de mots n’ait jamais eu à voir l’essentiel de ce qui se disait.
Aucun de ces deux mondes n’envoie les 10 à 60 mises à jour par seconde des démonstrations physiques ci-dessous.16 Pour un monde où les gens marchent de tuile en tuile, le pas ou la destination constitue la mise à jour.
Gaffer on Games : rendre en retard, entre deux points connus
La méthode qui régit le côté client est exposée dans « Snapshot Interpolation » de Glenn Fiedler (Gaffer on Games, 30 novembre 2014). Mettre en tampon ce qui arrive et rendre entre deux mises à jour retardées : « In effect, we’ve traded a small amount of added latency for smoothness. » (En fait, nous avons échangé un peu de latence supplémentaire contre de la fluidité.)16 Sa règle empirique pour le délai est « enough delay so that I can lose two packets in a row and still have something to interpolate towards » (assez de délai pour pouvoir perdre deux paquets de suite et avoir encore une cible vers laquelle interpoler) ; avec 2 à 5 % de perte de paquets, ce qui fonctionne le mieux « is 3X the packet send rate. At 10 packets per-second this is 300ms, » (c’est trois fois l’intervalle d’envoi des paquets, soit 300 ms à 10 paquets par seconde), plus une image ou deux pour la gigue, si bien que ses démonstrations tournaient à 350 ms. À « 30 snapshots per-second » (30 instantanés par seconde), la même protection coûte 150 ms, et « 60 packets per-second needs only 85ms. » (60 paquets par seconde ne demandent que 85 ms.)16 L’extrapolation, c’est-à-dire deviner en avance, « doesn’t work very well for rigid bodies because their motion is non-linear and unpredictable. » (ne fonctionne pas très bien pour les corps rigides, car leur mouvement est non linéaire et imprévisible.)16
La place de Kiradex fonctionne en WebSockets avec un serveur FastAPI,23 et les WebSockets reposent sur TCP, où rien n’est perdu mais où un paquet retransmis arrive en retard. Selon ma lecture, le budget d’un monde en WebSocket porte donc sur la gigue plutôt que sur la perte, et un marcheur sur grille devient le cas facile pour la méthode de Fiedler : il se déplace en ligne droite entre les centres de tuiles et s’arrête net, il n’y a donc rien à extrapoler et rien de non linéaire à masquer.
Un modèle du passage d’un marcheur
Pour dimensionner le tampon de Kiradex, j’ai simulé un autre collectionneur qui passe, avec la logique du rig de l’app tel que je l’ai lu le 5 octobre. Le script, measure_remote_walk.py, modélise deux choses. D’abord, le comportement actuel, dans l’arithmétique même du rig : le progress d’un pas est un Float 32 bits, augmenté à chaque image de Float(deltaTime) fois 4 tuiles par seconde ; chaque déplacement reçu replanifie à partir de la dernière tuile entière du marcheur et remet à zéro le pas en cours, même à mi-pas ; un chemin de plus de 6 tuiles est un saut ; et le marcheur est dessiné sur des pixels entiers. Le rig dessine tous les autres collectionneurs aux 4 tuiles par seconde de la marche, parce que seule la marche du joueur lui-même est jamais marquée comme une course. Ensuite, l’alternative : l’interpolation d’instantanés sur une horloge de rendu régulière, l’heure estimée du serveur moins un délai de 100 à 350 ms, en dessinant entre les deux mises à jour reçues dont les horodatages encadrent l’horloge de rendu.750 Pour le rig actuel, l’émetteur envoie un déplacement par tuile achevée aux fréquences mesurées aujourd’hui : toutes les 250 ms en marchant à 4 tuiles par seconde, et toutes les 156 ms en courant à 6,4, la fréquence nominale de la course (l’article sur le mouvement de cette série modélise la course de l’app à 6,0 tuiles par seconde à 60 Hz, parce que le dépassement de chaque tuile est abandonné). Pour le tampon, l’émetteur se déplace aussi selon le contrat de mouvement de la série, le cahier des charges de l’article sur le mouvement avec 16 ticks par tuile en marche et 8 en course à 60 Hz, soit 3,75 et 7,5 tuiles par seconde, ce vers quoi tend la section 7. Le réseau ajoute une gigue uniforme de 0, 30 ou 80 ms, et les images sont dessinées à 60 par seconde pendant 10 secondes de marche.72122
L’arithmétique compte. En 32 bits, 15 images de 1/60 de seconde à 4 tuiles par seconde font exactement 1,0, si bien qu’un pas prend 15 images, exactement les 250 ms de l’émetteur ; en arithmétique 64 bits, la même somme vaut 0,9999999999999999, le pas prend 16 images, et un modèle écrit ainsi trouve sur une marche régulière des retours en arrière que l’arithmétique propre du rig ne produit pas.7
C’est un modèle, et ses hypothèses sont la raison de traiter ses chiffres comme un guide de dimensionnement plutôt que comme un résultat. Il suppose une route droite et dégagée, si bien que la longueur d’un chemin est la distance de Manhattan ; un pas en diagonale, qui prend √2 fois plus de temps dans le rig, n’est pas modélisé ; la gigue est uniforme ; le deltaTime de chaque image vaut exactement 1/60 de seconde, alors que celui d’un téléphone varie ; les opérations 32 bits s’exécutent dans l’ordre du code, sans fused multiply-add ; rien n’y a été capturé sur deux appareils. Qu’une marche régulière sans gigue revienne jamais en arrière sur un téléphone est donc une question que le modèle ne peut pas trancher : une durée d’image légèrement différente de 1/60 peut laisser un pas à un arrondi de 1,0. La remise à zéro elle-même, qui se déclenche chaque fois qu’un déplacement arrive à mi-pas, est une lecture du code source, pas un résultat du modèle. La moitié tampon suppose en outre deux choses dont dépend son résultat : l’estimation de l’horloge du serveur par le moteur de rendu est exacte, et une mise à jour ne met aucun temps à arriver au-delà de sa gigue. Un vrai client doit estimer l’horloge du serveur, et toute erreur dans cette estimation, ou tout délai aller constant qu’elle ne prend pas en compte, se retranche directement du tampon.7
Dans le modèle, le rig actuel dessine un collectionneur qui passe en train de reculer quand un déplacement arrive à mi-pas, à chaque course et à chaque marche avec gigue ; aux vitesses du contrat de mouvement, un tampon de 350 ms ne le fait jamais et n’est jamais affamé.26
Le rig actuel, en marche sans gigue, dessine proprement le marcheur : chaque pas se termine sur l’image qui précède l’arrivée du déplacement suivant, il y a donc 0 retour en arrière, 0 saut et 0 image en arrière sur 40 tuiles. La gigue casse cela. À 30 ms, 13 déplacements arrivent à mi-pas et le remettent à zéro, dont 7 assez tard dans le pas pour dessiner le marcheur en arrière, et 1 chemin est assez long pour provoquer un saut ; à 80 ms, 25 remises à zéro, 16 images en arrière et 2 sauts. En course, l’émetteur va plus vite que les 4 tuiles par seconde auxquelles le rig le dessine, si bien qu’à chaque gigue testée 45 des 64 déplacements arrivent à mi-pas, chacun dessinant une image en arrière, avec 9 sauts. Chaque fois qu’il recule, le marcheur dessiné prend jusqu’à 5,9 à 6,7 tuiles de retard sur l’émetteur avant qu’un saut ne le ramène en avant ; sur la marche régulière, il n’a jamais une tuile entière de retard (0,94 au plus).7 Un retour en arrière ramène le marcheur d’autant qu’il avait déjà dessiné du pas, jusqu’à 14 pixels sur une tuile de 16 pixels dans ces exécutions.750
Avec un tampon, le marcheur ne recule jamais : 0 image en arrière dans les 60 exécutions avec tampon, quatre vitesses par trois gigues par cinq délais. La seule question est la fréquence à laquelle le moteur de rendu n’a rien vers quoi dessiner, comptée sur les 600 images dessinées pendant que l’émetteur émet encore. À la marche du contrat de mouvement, 3,75 tuiles par seconde, une horloge de rendu en retard de 300 ms affame 0, 0 et 27 images à 0, 30 et 80 ms de gigue ; 325 ms en affament 0, 0 et 6 ; 350 ms aucune. À 100 ms de retard, elle en affame 125 à 456 dans tous les cas à ces vitesses. En course à 7,5, 300 ms et plus n’affament aucune image à chaque gigue testée. Aux 4 et 6,4 tuiles par seconde actuelles, le même modèle en affame 0, 0 et 7 en marche à 300 ms, et aucune à 325 ou 350.7 Selon ma lecture, une horloge de rendu en retard de 350 ms sur l’heure estimée du serveur est le bon chiffre, et la raison en est une borne plutôt qu’un décompte. Avec un déplacement par tuile, la mise à jour dont une image a besoin est horodatée au plus un pas après l’horloge de rendu et arrive au plus la pire gigue après son horodatage. À 3,75 tuiles par seconde, un pas dure 1/3,75 de seconde, soit 266,7 ms, et un pas plus 80 ms de gigue font 346,7 ms ; avec une horloge exacte, un délai de 350 ms n’affame donc aucune image pour aucun tirage de gigue jusqu’à 80 ms, avec 3,3 ms de marge.7 Ces 3 ms constituent toute la tolérance laissée à l’estimation de l’horloge : une estimation en avance de plus d’environ 3 ms sur l’horloge du serveur perd la garantie et peut affamer des images. Les décomptes ci-dessus proviennent d’un seul tirage de gigue, la graine 1, et 325 ms ont franchi sur ce tirage le seuil fixé par la section 7.4, avec 4 images de marge, mais pas sur tous les tirages : relancé sur les graines 1 à 200, en marche à 3,75 tuiles par seconde avec 80 ms de gigue, 325 ms ont affamé des images sur les 200 et plus de 10 sur 8 d’entre elles, alors que 350 ms n’en ont affamé sur aucune.7 350 ms est aussi le délai auquel tournaient les propres démonstrations de Fiedler. Avec un déplacement par tuile, c’est un peu plus d’un pas de marche de retard, un pas durant 267 ms à 3,75 tuiles par seconde, soit le « 3X the packet send rate » de Fiedler retourné pour un monde où les paquets sont des pas et, via TCP, arrivent en retard plutôt que pas du tout.16
4. Le métier, en règles chiffrées
Chaque règle ci-dessous renvoie à une mesure ou à une source citée plus haut. Quand une règle est ma synthèse de plusieurs sources, la colonne des sources indique lesquelles.
| Élément | Règle | Source |
|---|---|---|
| Qui bouge | Parmi les habitants toujours présents, environ six sur dix ont un type de mouvement par défaut immobile, se tenant à un poste tournés vers une direction ou regardant autour d’eux, et près de quatre sur dix errent dans un cadre d’une ou deux cellules autour de leur poste. Les acteurs du scénario qui vont et viennent sont surtout debout, ce qui porte le total à sept sur dix et un sur quatre. | Les 100 personnes d’Émeraude sans drapeau de masquage : 59 debout, 39 errants, 2 marchant sur place ; les 158 : 113 et 43 ; zones de 1 ou 2 cellules1 |
| Rythme | Un habitant fait un pas au rythme du joueur puis attend plus longtemps que le pas n’a duré : un pas de 268 ms, puis 0,54, 1,07, 1,61 ou 2,14 s, tiré au hasard. Une flânerie plus lente fonctionne aussi (Wild World) ; un rythme qui n’est ni l’un ni l’autre, non. | L’action de marche partagée et la table des délais d’Émeraude1 ; Wild World32 |
| Part de mouvement | Un errant est en mouvement au plus 11 à 33 % du temps, par pas effectué ; un pas bloqué se contente de regarder et d’attendre. | Émeraude, arithmétique sur les deux lignes ci-dessus ; une borne supérieure127 |
| Population | Six à dix personnes font une ville ; les villages entiers d’Animal Crossing plafonnent à 8 à 15. | Littleroot 6 personnes, Petalburg 7, Mauville 10, dont 2, 3 et 6 sans drapeau de masquage1 ; les villages d’Animal Crossing, 8 à 15 au plus32 |
| Changement | Certains habitants partent et arrivent selon la progression du joueur, par drapeau. | 12 des 23 personnes des trois villes portent un drapeau de masquage1 |
| Routine | Une journée compte trois à sept points horodatés ; une clé choisit la journée applicable, dans un ordre fixe de spécificité, la première qui correspond l’emporte. | Le mercredi d’Abigail, 3 points, la journée ordinaire de Pierre, 7 ; 22 formats de clé92 |
| La journée | Régler la journée au retour du joueur, en une exécution qui prend le nombre de jours écoulés ; ne jamais faire tourner de minuteur quand personne ne joue. | UpdatePerDay3 ; la première mise à jour quotidienne de Stardew9 |
| Mémoire | Retenir la première conversation du jour par un drapeau par habitant ; garder la récompense modeste. | +1 sur 255 dans New Horizons11 ; +20 pour 250 par cœur dans Stardew10 |
| Nouveaux mots | Rationner l’expression nouvelle à une par jour, ou une par rencontre. | Une Réaction par jour12 ; une expression à la mode par arrivée du Hipster35 |
| Traces | Les traces des autres arrivent dans de petits emplacements fixes et s’effacent ou tournent. | 20 bases et 5 expressions4 ; 8 boutiques13 ; 6 défenseurs47 ; la chronopluie14 ; montée et descente d’une expression à la mode de 12 à environ 50,8 jours38 |
| Remplaçants | Des remplaçants comblent les emplacements que les gens laissent vides, et comptent moins. | Les fans de l’avenue des rencontres à 75 %, selon Serebii13 |
| Inconnus | Les inconnus partagent une présence, pas des mots : pas de noms, un carillon ou une phrase prédéfinie. | Journey5 ; Dark Souls41 ; Game Center pour les enfants17 |
| Parole | Les répliques prédéfinies voyagent sous forme d’identifiants et répondent, au lieu de seulement saluer ; une phrase entière ne peut rien épeler de ce qu’une liste de mots peut épeler. | Les identifiants ss de Club Penguin48 ; les 940 mots ouverts d’Easy Chat dans des grilles de 2 à 10 emplacements38 |
| Mises à jour | Une mise à jour par pas sur une grille ; rendre les marcheurs distants sur une horloge en retard d’un peu plus d’un pas de marche sur l’heure estimée du serveur, et ne jamais remettre à zéro un pas en cours. | Le cycle de 500 ms et l’interpolation linéaire de Habbo (émulateur et client de fans)1549 ; le modèle à 3,75 et 7,5 tuiles par seconde, en supposant une synchronisation d’horloge exacte et aucune latence de base : 350 ms de retard donnent 0 image en arrière et 0 image affamée jusqu’à 80 ms de gigue7 |
| Inactivité | Marquer un joueur comme inactif après deux minutes sans saisie, et fermer une connexion qui ne répond plus à son heartbeat. | Arcturus : inactif à 240 cycles (120 s), et un non-propriétaire inactif expulsé à 480 (240 s)15 ; Houdini ferme tout client qui n’a envoyé aucun heartbeat dans une fenêtre de 61 s48. Les 240 s sans ping du cahier des charges réunissent les deux, mon adaptation |
| Restrictions | Quand Game Center signale le multijoueur comme restreint, y compris en mode amis seulement, le multijoueur personnalisé disparaît, et selon ma lecture cela inclut les rediffusions des trajets de vrais joueurs : un tel joueur n’a que des habitants. | La documentation d’Apple pour isMultiplayerGamingRestricted18 ; considérer les échos comme du multijoueur est ma lecture (section 7.6) |
| Communication | Quand Game Center signale la communication personnalisée comme restreinte, ou le joueur comme mineur, la communication personnalisée disparaît. | La documentation d’Apple pour isPersonalizedCommunicationRestricted51 |
| Conservation | Ne conserver les données des enfants que le temps nécessaire à leur finalité écrite, avec le délai de suppression dans l’avis. | 16 CFR 312.10 tel que modifié ; applicable depuis le 22 avril 202619 |
5. La voie Apple : les drapeaux de Game Center, les tranches d’âge, les Guidelines et la COPPA
Une ville où des enfants peuvent entrer est encadrée par des règles d’Apple et de la Federal Trade Commission américaine, et la plupart sont datées. Cette section reprend les termes mêmes d’Apple et de la FTC, avec la disponibilité quand Apple la publie. Tout ce que je dis de ce qu’une règle signifie pour Kiradex est une lecture, signalée comme telle, et rien de tout cela ne constitue un conseil juridique.
Les trois drapeaux de restriction de Game Center
Le joueur local de Game Center porte trois booléens qu’un jeu peut lire avant d’ouvrir quoi que ce soit de social. Leur disponibilité provient de la documentation d’Apple telle que sauvegardée le 4 octobre 2026, et chaque explication est citée mot pour mot.185152
| Propriété | iOS | Ce que dit Apple |
|---|---|---|
GKLocalPlayer.isMultiplayerGamingRestricted |
13.0 | « If this property is true, the local player can’t join multiplayer games. If your game uses a custom multiplayer feature, you should disable it. » (Si cette propriété vaut true, le joueur local ne peut pas rejoindre de parties multijoueurs. Si votre jeu utilise une fonctionnalité multijoueur personnalisée, vous devriez la désactiver.) |
GKLocalPlayer.isPersonalizedCommunicationRestricted |
14.0 | « If this property or the underage property is true, the local player can’t include personalized messages on invitations or enable voice communication in multiplayer games. If your game includes any custom communication features, you should disable them. » (Si cette propriété ou la propriété underage vaut true, le joueur local ne peut pas joindre de messages personnalisés aux invitations ni activer la communication vocale dans les parties multijoueurs. Si votre jeu comporte des fonctionnalités de communication personnalisées, vous devriez les désactiver.) |
GKLocalPlayer.isUnderage |
4.1 | « If this property is true, Game Center disables some features for the local player. » (Si cette propriété vaut true, Game Center désactive certaines fonctionnalités pour le joueur local.) |
La page du premier drapeau ajoute le détail qui compte le plus : la valeur provient de Screen Time, qui permet à un parent d’autoriser les jeux multijoueurs avec tout le monde, avec les amis seulement ou avec personne, et « when you configure the setting to friends only, this property returns true for restricted. » (quand vous réglez le paramètre sur amis seulement, cette propriété renvoie true, c’est-à-dire restreint.)18 Un enfant autorisé à jouer uniquement avec ses amis est donc lu comme restreint, et un jeu doté de sa propre place est invité à la désactiver. La page du deuxième drapeau contient deux phrases de portée différente. La première nomme ce que Game Center bloque lui-même, les messages personnalisés dans les invitations et la voix ; la seconde demande au jeu de désactiver lui-même « any custom communication features » (toutes ses fonctionnalités de communication personnalisées), sans exception pour les fonctionnalités prédéfinies. Selon ma lecture, un menu de phrases prédéfinies entières est une fonctionnalité de communication personnalisée, et le cahier des charges le traite comme tel.51
Game Center pour les enfants, et Screen Time
La page de confidentialité de Game Center d’Apple fixe la règle que Kiradex a déjà adoptée pour tout le monde : « when communicating with other players in Game Center, children cannot send or receive user-inputted text. They are restricted to sending and receiving preset messages. In-game voice chat is disabled for children. » (lorsqu’ils communiquent avec d’autres joueurs dans Game Center, les enfants ne peuvent ni envoyer ni recevoir de texte saisi par un utilisateur ; ils sont limités à l’envoi et à la réception de messages prédéfinis ; le chat vocal en jeu est désactivé pour eux.)17 Elle indique aussi « Children’s accounts never make real names visible to friends, » (les comptes d’enfants ne rendent jamais les vrais noms visibles des amis), et qu’un parent peut utiliser Screen Time pour bloquer « multiplayer functionality, the ability to add friends, and the ability to connect with friends playing the same game. » (les fonctions multijoueurs, la possibilité d’ajouter des amis et celle de se connecter avec des amis qui jouent au même jeu.)17 La page d’assistance d’Apple sur Screen Time énumère nommément les restrictions de Game Center, parmi lesquelles « Connect with Friends » (se connecter avec des amis) et « Private Messaging » (messagerie privée), chacune « Allowed or Blocked. » (autorisée ou bloquée).53
Declared Age Range
Le 11 juin 2025, Apple a annoncé qu’un compte enfant « is required for children under 13 » (est obligatoire pour les enfants de moins de 13 ans), et que « App developers will be able to request this information through the new Declared Age Range API » (les développeurs d’apps pourront demander cette information via la nouvelle API Declared Age Range), les parents choisissant de partager la tranche d’âge d’un enfant « always, for each app request, or never » (toujours, à chaque demande d’une app, ou jamais), « in a way that does not reveal the child’s birth date. » (d’une manière qui ne révèle pas la date de naissance de l’enfant.)54 La même annonce indiquait que les classifications par âge seraient « expanded to five categories » (étendues à cinq catégories) d’ici la fin de cette année-là, avec 13+, 16+ et 18+ pour les adolescents.54 Le plan du monde de Kiradex désigne l’API comme l’interrupteur de ses règles junior et consigne la décision du 2 octobre : moins de 13 ans selon la tranche déclarée, pas de place du tout ; 13 à 15 ans, la place avec les règles junior ; 16 ans et plus, ou non déclaré, la place complète.23 Je n’ai pas consulté la page de référence de l’API elle-même pour cet article, sa version minimale d’iOS n’est donc pas indiquée ici.
Les App Review Guidelines
Trois directives encadrent une place sociale, citées d’après la version qu’Apple date « Last Updated: June 8, 2026 » (dernière mise à jour le 8 juin 2026).55
- 1.2, contenu généré par les utilisateurs. Les apps « with user-generated content or social networking services must include » (proposant du contenu généré par les utilisateurs ou des services de réseau social doivent inclure) une méthode de filtrage des contenus répréhensibles, « A mechanism to report offensive content and timely responses to concerns » (un mécanisme de signalement des contenus offensants et des réponses rapides aux préoccupations), « The ability to block abusive users from the service » (la possibilité de bloquer les utilisateurs abusifs) et « Published contact information so users can easily reach you. » (des coordonnées publiées pour que les utilisateurs puissent facilement vous joindre). Les apps qui finissent par être « used primarily for pornographic content, Chatroulette-style experiences, random or anonymous chat » (utilisées principalement pour du contenu pornographique, des expériences à la Chatroulette, du chat aléatoire ou anonyme) et le reste de cette liste « do not belong on the App Store and may be removed without notice. » (n’ont pas leur place sur l’App Store et peuvent être retirées sans préavis).55
- 1.3, la catégorie Enfants. Les apps de cette catégorie « must not include links out of the app, purchasing opportunities, or other distractions to kids unless reserved for a designated area behind a parental gate, » (ne doivent pas inclure de liens vers l’extérieur de l’app, d’occasions d’achat ou d’autres distractions pour les enfants, sauf dans une zone désignée derrière un contrôle parental) et « should not include third-party analytics or third-party advertising, » (ne devraient pas inclure d’outils d’analyse ou de publicité tiers), à quelques exceptions près.55
- 5.1.4, enfants. Les apps qui « collect, transmit, or have the capability to share personal information (e.g. name, address, email, location, photos, videos, drawings, the ability to chat, other personal data, or persistent identifiers used in combination with any of the above) from a minor must include a privacy policy and must comply with all applicable children’s privacy statutes, » (collectent, transmettent ou peuvent partager des informations personnelles d’un mineur, par exemple nom, adresse, e-mail, localisation, photos, vidéos, dessins, possibilité de discuter, autres données personnelles ou identifiants persistants combinés à l’un de ces éléments, doivent inclure une politique de confidentialité et respecter toutes les lois applicables sur la vie privée des enfants), et « the parental gate requirement for the Kid’s Category is generally not the same as securing parental consent » (l’exigence d’un contrôle parental pour la catégorie Enfants n’équivaut généralement pas à l’obtention du consentement parental) au sens de ces lois.55
Le plan de Kiradex emprunte la seconde des deux voies que son document de conception tire des Guidelines : hors de la catégorie Enfants, classé 9+ ou 12+ (la classification n’est pas encore choisie), sous 5.1.4.23 Selon ma lecture, « the ability to chat » (la possibilité de discuter) dans la liste de 5.1.4 signifie qu’une place à répliques prédéfinies a tout de même besoin de la politique de confidentialité, quoi qu’elle évite par ailleurs.
La COPPA telle que modifiée
La Children’s Online Privacy Protection Rule modifiée de la FTC a été publiée au Federal Register le 22 avril 2025 (document 2025-05904, 90 FR 16918). Elle « is effective June 23, 2025, » (entre en vigueur le 23 juin 2025), et « Except with respect to § 312.11(d)(1), (d)(4), and (g), regulated entities have until April 22, 2026 to comply. » (à l’exception du § 312.11(d)(1), (d)(4) et (g), les entités réglementées ont jusqu’au 22 avril 2026 pour se mettre en conformité.)19 Le communiqué de la FTC du 16 janvier 2025, à l’issue d’un vote à 5 voix contre 0, résumait le changement : un consentement parental vérifiable distinct pour communiquer les informations des enfants à des tiers « related to targeted advertising or other purposes » (à des fins de publicité ciblée ou à d’autres fins), et une conservation « for as long as reasonably necessary to fulfill a specific purpose, » (aussi longtemps que raisonnablement nécessaire pour remplir une finalité précise), de sorte que « operators cannot retain the information indefinitely. » (les opérateurs ne peuvent pas conserver ces informations indéfiniment.)56
Trois passages du texte de la règle concernent une place qui se souvient de quoi que ce soit.
- Conservation, § 312.10. « Personal information collected online from a child may not be retained indefinitely. At a minimum, the operator must establish, implement, and maintain a written data retention policy that sets forth the purposes for which children’s personal information is collected, the business need for retaining such information, and a timeframe for deletion of such information. » (Les informations personnelles collectées en ligne auprès d’un enfant ne peuvent être conservées indéfiniment. L’opérateur doit au minimum établir, mettre en œuvre et maintenir une politique écrite de conservation des données précisant les finalités de la collecte, le besoin commercial justifiant la conservation et un délai de suppression.) La politique figure dans l’avis en ligne.19
- Identifiants persistants, § 312.2. Les informations personnelles comprennent « A persistent identifier that can be used to recognize a user over time and across different websites or online services, » (un identifiant persistant permettant de reconnaître un utilisateur dans le temps et à travers différents sites ou services en ligne), tel que « a customer number held in a cookie, an Internet Protocol (IP) address, a processor or device serial number, or unique device identifier. » (un numéro client stocké dans un cookie, une adresse IP, un numéro de série de processeur ou d’appareil, ou un identifiant unique d’appareil.)19
- Fonctionnement interne, § 312.5(c)(7). Le consentement n’est pas requis « Where an operator collects a persistent identifier and no other personal information and such identifier is used for the sole purpose of providing support for the internal operations of the website or online service, » (lorsqu’un opérateur ne collecte qu’un identifiant persistant, sans autre information personnelle, et que cet identifiant sert uniquement au fonctionnement interne du site ou du service en ligne), avec un avis.19
Le § 312.8 modifié exige aussi un programme écrit de sécurité de l’information pour les données des enfants.19 Ma lecture de ce que cela implique pour une place qui rejoue les trajets des visiteurs figure dans le cahier des charges, signalée comme telle ; la section 3 de WORLD.md demande qu’un avocat examine la conception finale, et les décisions du 2 octobre reportent cet examen jusqu’à ce que l’app trouve son public, si bien que la lecture tient jusque-là.23
Ce que cela coûte
Rien dans cette section n’a été mesuré sur un appareil. La lecture de trois booléens sur GKLocalPlayer après l’authentification n’est pas chronométrée ici ; la mémoire et le CPU d’un tampon de rendu de 350 ms pour jusqu’à 39 autres collectionneurs dans une salle de 40 ne le sont pas non plus.21 Selon ma lecture, ni l’un ni l’autre ne peut peser à côté du dessin d’une image, mais c’est une lecture, et les vérifications du cahier des charges portent sur le comportement, pas sur les durées.
6. L’étude de cas : la place de Kiradex, mesurée sur son propre code
Kiradex World est la ville en pixel art de Kiradex, mon app de collection de cartes : une place de 40 tuiles sur 30, dessinée en tuiles de 16 pixels, servie par un petit serveur FastAPI et WebSocket qui garde la présence en mémoire et ne stocke rien, hormis ce que son serveur web journalise par défaut (section 7.6, réglage 6).212357 J’ai lu le serveur et le code du monde de l’app le 5 octobre depuis l’arbre de travail, sans rien modifier, et j’ai piloté les propres classes du serveur sur une horloge simulée avec deux scripts ; les chiffres de cette section sont donc le comportement du code et non ma lecture de celui-ci.21620 Le dépôt est privé, les fichiers sont donc désignés par leur chemin. Il s’agit d’écarts entre le plan de docs/WORLD.md, les docstrings du code lui-même et ce que fait le code ; aucun n’est un défaut que quelqu’un aurait caché, et le plan range déjà une partie du quatrième parmi ce qui n’est pas encore construit.
Ce qui existe
Le serveur contient 23 répliques prédéfinies, 14 pour les joueurs (indices 0 à 13) et 9 pour les collectionneurs propres à la ville (14 à 22) ; des salles de 40 ; une limite de 8 déplacements par seconde et d’une réplique toutes les 2,0 secondes par joueur ; une horloge de ville qui fait un tick toutes les 0,5 s (TICK_SECONDS dans server/app/main.py) ; un délai de 60 secondes avant de montrer de nouveau une carte au même collectionneur ; et une arrivée sur la tuile (19, 13) de la place de 40 sur 30.2120 Quatre collectionneurs scriptés vivent sur le serveur pour que tout le monde dans une salle voie les mêmes : Moss, Prism, Comet et Dawn, chacun avec 4 points de passage sur des boucles de 18, 22, 30 et 32 tuiles, un type de carte qu’il aimerait qu’on lui montre (vintage, holo, n’importe laquelle, japonaise) et 2 ou 3 répliques. server/app/npcs.py fixe STEP_SECONDS = 0.7, fait s’arrêter chaque collectionneur à un point de passage pendant une durée uniforme de 3 à 8 secondes, et lui fait dire une réplique toutes les 20 à 40 secondes (tirage uniforme), la première au bout de 8 à 20.2120
Selon ma lecture, c’est le bon instinct : des habitants sur le serveur plutôt que dans chaque téléphone, des répliques sur une horloge lente, et une envie pour chacun, pour qu’une collection ait un endroit où compter. Mesurées, trois choses le sapent, et une quatrième est un écart entre le plan et le code.
1. La marche est saccadée
measure_npc_cadence.py importe server/app/npcs.py et rooms.py, construit la place et les quatre collectionneurs, et les fait avancer sur le vrai tick de 0,5 s pendant une heure simulée.6 Chacun des 6 253 intervalles entre deux pas au sein d’un segment vaut exactement 1,0 seconde, et non 0,7 : un pas se déclenche au premier tick égal ou postérieur à son next_move, si bien que 0,7 seconde est arrondi à deux ticks. Cela fait 1,0 tuile par seconde contre les 1,43 qu’implique la constante. Les pauses avant un segment durent en moyenne 6,75 secondes (4,5 à 9,0, sur 1 202 pauses), et les répliques sont espacées en moyenne de 30,7 secondes, sur 465 intervalles entre répliques consécutives d’un même collectionneur (469 répliques dans l’heure).6
Le client dessine n’importe quel pas en 250 ms : PlazaRig.swift fixe tilesPerSecond à 4 à la ligne 101.50 Un collectionneur qui marche à une tuile par seconde est donc dessiné en mouvement pendant 25 % de chaque segment et immobile pendant les 75 % restants, entre chaque paire de tuiles.6 Les errants d’Émeraude font un pas au rythme du joueur puis attendent ; les collectionneurs de Kiradex bougent au rythme du joueur par à-coups d’une tuile alors qu’ils sont censés marcher, ce qui, selon ma lecture, ne ressemble ni à la flânerie d’un résident ni à une marche (la dernière ligne de la frise de la section 1).
2. Un autre collectionneur qui passe revient en arrière
Quand le serveur relaie le déplacement d’un autre collectionneur, PlazaRig.move(other:to:facing:) (lignes 526 à 542 de PlazaRig.swift) planifie un chemin depuis la dernière tuile entière du marcheur, lui attribue les pas de ce chemin et fixe progress = 0 à chaque message, même quand un pas est à moitié dessiné ; un chemin de plus de 6 tuiles est un saut.50 Le modèle de la section 3, dans l’arithmétique 32 bits du rig lui-même, chiffre le phénomène. Une marche régulière sans gigue ne recule jamais, parce que chaque pas se termine juste avant l’arrivée du déplacement suivant. Avec 30 ou 80 ms de gigue, une marche de 40 tuiles est remise à zéro à mi-pas 13 ou 25 fois, dont 7 ou 16 dessinées en arrière. En course, le rig dessine le marcheur aux 4 tuiles par seconde de la marche, si bien que 45 des 64 déplacements arrivent à mi-pas à chaque gigue testée, avec 9 sauts ; et chaque fois qu’il recule, le marcheur dessiné prend jusqu’à 5,9 à 6,7 tuiles de retard sur l’émetteur.7 Le mouvement en pixel art, un article précédent de cette série, lit le même retour en arrière dans le code pour le second appui du joueur à mi-pas ; la règle que fixe son cahier des charges, ne jamais remettre à zéro un pas en cours, est celle que ce cahier des charges applique aux autres collectionneurs.22
3. La ville s’arrête quand elle est vide
La docstring du module server/app/npcs.py dit des collectionneurs : « A town is never empty, and it has somewhere for a collection to matter. » (Une ville n’est jamais vide, et elle offre un endroit où une collection compte.)20 Room.tick dans server/app/rooms.py dit le contraire dans sa propre docstring, « A room with nobody in it stands still, » (une salle où il n’y a personne reste immobile), et le fait : quand la salle n’a pas de joueurs, la méthode retourne aussitôt, et les collectionneurs se figent là où ils étaient.206 Le script mesure ce que voit alors le premier arrivant : faire avancer des collectionneurs neufs jusqu’à 10 000 secondes simulées en un seul tick produit quatre répliques d’un coup, une par collectionneur, chacun là où il se trouvait ; rien ne s’est passé entre-temps.6 Et comme le serveur ne stocke rien, le premier collectionneur arrivé par un matin calme voit les quatre mêmes personnes et aucun signe que quelqu’un d’autre soit jamais passé. Une recherche dans Kiradex/ et server/app/ ne trouve rien qui enregistre une visite ou une conversation quotidienne.24
4. Les fréquences, et les drapeaux de Game Center
Deux écarts séparent docs/WORLD.md du code. La section 5 du plan conserve, comme raisonnement ayant mené au serveur, une conception dans laquelle les clients envoient position et orientation à 8 à 10 Hz.23 L’app envoie plutôt un move par tuile achevée : aujourd’hui 4 par seconde en marchant et 6,4 en courant à la fréquence nominale de la course (6,0 à 60 Hz dans le modèle du code de l’article sur le mouvement), sous la limite de 8 par seconde du serveur dans les deux cas ; le contrat de mouvement de la série, 16 ticks par tuile en marche et 8 en course à 60 Hz, les porterait à 3,75 et 7,5, toujours sous la limite (section 7.4).2122 Selon ma lecture, l’envoi par tuile est la meilleure conception pour une grille, et le cahier des charges la conserve ; c’est la ligne du plan qu’il faut mettre à jour.
La section 3 du plan fonde l’identité sur Game Center pour que « a child’s Game Center is controlled by the parent in Screen Time (multiplayer on/off, adding friends on/off, sharing the friend list with games on/off). » (le Game Center d’un enfant soit contrôlé par le parent dans Screen Time : multijoueur activé ou non, ajout d’amis activé ou non, partage de la liste d’amis avec les jeux activé ou non.)23 Rien dans Kiradex/ ou server/app/ ne lit GKLocalPlayer.isMultiplayerGamingRestricted, isUnderage ou isPersonalizedCommunicationRestricted, ni n’appelle l’API Declared Age Range.24 La section 5 du plan range déjà « junior mode by Declared Age Range » (le mode junior selon Declared Age Range) parmi ce qui n’est pas encore construit.23 Les drapeaux de Game Center sont la partie qu’elle ne mentionne pas : le réglage multijoueur de Screen Time régit le multijoueur propre à Game Center, et la documentation d’Apple demande à un jeu doté d’« a custom multiplayer feature » (une fonctionnalité multijoueur personnalisée) de la désactiver lui-même ; tant que l’app ne lit pas le drapeau, le réglage d’un parent n’atteint donc pas la place.18
Le client se reconnecte après la chute d’un socket avec un délai exponentiel de min(30, 2^attempts) secondes (PlazaClient.swift, ligne 165), et masquer un collectionneur se fait sur l’appareil, par identifiant.215023 Les deux restent en l’état dans le cahier des charges, qui ajoute un usage à la liste de masquage : elle accompagne chaque demande des échos de la place, pour que le serveur puisse écarter les trajets des collectionneurs que ce joueur a masqués (section 7.2).
7. Le cahier des charges : ce que Kiradex construit et les vérifications à passer
Le cahier des charges conserve ce que la place possède (les collectionneurs propres au serveur, uniquement des répliques prédéfinies, un déplacement par tuile, la présence en mémoire) et ajoute les trois réponses dans l’ordre où le canon les donne : des habitants dont la vie ne s’arrête pas, les traces de gens qui sont passés, et une présence dessinée sans retour en arrière. Chaque élément comporte une vérification qu’un script, un test ou une capture peut valider ou invalider. Les coordonnées de tuiles sont celles de la place, x vers la droite et y vers le bas.21
La limite de l’emprunt est celle que trace le premier article de cette série pour les brevets et pour l’expression : aucune créature, aucun nom de lieu Pokémon, aucun terme de la franchise comme nom de fonctionnalité, et rien qui vise et lance pour capturer, affiche une probabilité de capture, envoie un compagnon se battre ou monte sur quoi que ce soit pour le chevaucher.36 Chaque élément ci-dessous se compose d’habitants qui marchent, se tiennent debout et disent des phrases prédéfinies entières, et de rediffusions pâles des trajets d’autres collectionneurs. Les systèmes des jeux sont nommés plus haut en tant que faits relatifs à des œuvres publiées ; les fonctionnalités de Kiradex reçoivent ici des noms propres à Kiradex : les habitants, les échos, le bonjour du jour, le carnet de répliques et la place tranquille. La section 3 de docs/WORLD.md appelle déjà passant tout collectionneur en direct qui n’est pas un ami ; cette formulation reste, et les rediffusions s’appellent des échos pour que les deux ne soient jamais confondus.23 Les notes juridiques sont des lectures, pas des conseils.
7.1 Des habitants avec des routines
- Population. Faire passer les collectionneurs propres à la place de 4 à 8, chacun avec un poste.21 La répartition suit les personnes toujours présentes d’Émeraude, 59 sur 100 debout et 41 non (39 errants, 2 marchant sur place), ce qui, ramené à huit, donne cinq debout et trois en mouvement. Cinq se tiennent à des postes et se tournent : le comptoir de la boutique, la porte du hall, la fontaine et deux étals. Deux errent dans un cadre de 2 cellules autour d’un poste, comme les errants d’Émeraude. Le troisième qui bouge ne vient pas de la répartition d’Émeraude, dont les 158 habitants se tiennent tous debout, errent dans un cadre ou marchent sur place, sans aucun sur un itinéraire : c’est l’une des quatre boucles de points de passage actuelles, conservée, qui fait une ronde entre les postes, si bien que les quatre boucles actuelles deviennent une.121 Les quatre nouveaux collectionneurs sont dessinés par le système de silhouettes propre à l’app, avec des pseudonymes tirés des listes de mots de l’app, comme les quatre actuels.20
- Attentes. Un collectionneur à un poste se tourne, et un errant fait un pas, après une attente de 1, 2, 3 ou 4 ticks de l’horloge de 0,5 s du serveur, tirée au hasard : 0,5, 1,0, 1,5 ou 2,0 secondes, soit les 0,54, 1,07, 1,61 et 2,14 d’Émeraude arrondis au tick le plus proche. Une attente en ticks entiers n’est pas arrondie une seconde fois par le tick, ce qui est précisément le défaut que la section 6 a mesuré sur le pas.16
- L’horloge de la salle. Chaque salle fonctionne sur une seule horloge : l’heure du serveur en UTC, lue dans le fuseau horaire propre à la salle, un fuseau IANA par salle dans la configuration du serveur. Le serveur envoie les deux à l’arrivée, dans
welcomeet dans la réponse de la place tranquille ({"zone": "<IANA name>", "clock": <server ms>}), et tant que la place est ouverte, l’app en tire son moment de la journée plutôt que du téléphone, pour que tout le monde dans une salle voie les mêmes habitants sous la même lumière. Aujourd’hui,Daylight.nowprend l’heure deCalendar.current, le calendrier et le fuseau propres au téléphone, et le serveur ne garde qu’une horloge monotone et ne nomme aucun fuseau.50 Le fuseau qu’utilise une salle, et la salle vers laquelle un collectionneur est envoyé, relèvent d’une configuration que ce cahier des charges laisse ouverte ; un seul fuseau pour toutes les salles est le point de départ le plus simple. En dehors de la place, l’horloge du téléphone reste celle du collectionneur. - Routines. La journée de chaque habitant compte 3 à 7 points horodatés écrits sous forme d’une chaîne dans les données du serveur, choisie par une clé essayée dans l’ordre : une date, un jour de la semaine, un moment de la journée, puis la valeur par défaut, chacune lue sur l’horloge de la salle.9 Les moments de la journée sont ceux de l’app, issus de
Daylight.PhasedansKiradex/World/Daylight.swift: le matin de 6 h à 9 h, la journée de 9 h à 17 h, le soir de 17 h à 20 h, et la nuit le reste du temps.50 La nuit, sur l’horloge de la salle, les cinq aux postes et les deux errants rentrent par leur propre porte, comme se termine le vendredi de Pierre dans Stardew Valley, depuis le saloon (« Returns home to sleep. », rentre dormir chez lui), et le marcheur de la boucle conservée raccourcit sa ronde.30 - Le rythme. Corriger la marche saccadée par l’un de deux changements. De préférence : le serveur envoie un segment une seule fois,
{"t": "walk", "id": ..., "path": [...], "at": <server ms>}, et le client le parcourt à partir deatau pas de marche du joueur selon le contrat de mouvement de la série, 16 ticks par tuile à 60 Hz, 3,75 tuiles par seconde (4 dans le rig actuel).22 Au minimum : un intervalle de pas du serveur égal à un nombre entier de ticks,STEP_SECONDS = 0.5, le client dessinant le pas d’un habitant sur les mêmes 0,5 seconde, 2 tuiles par seconde, la flânerie d’un résident plutôt que la marche du joueur.632 - Le temps quand la salle est vide. La tuile d’un habitant est une fonction pure de l’horloge de la salle : l’itinéraire, le moment de la journée et une graine, calculés à la demande, et non avancés par
Room.tick. La graine est une valeur globale unique dans la configuration du serveur, pas une par salle ou par fuseau, si bien que deux salles de même fuseau montrent les mêmes habitants sur les mêmes tuiles. Le premier collectionneur qui entre à 07:40 selon l’horloge de la salle voit Moss là où Moss serait à 07:40, tout comme un collectionneur qui rejoint la même salle depuis un téléphone réglé sur un autre fuseau.63
Vérifications. (a) Le rythme, selon la conception. Pour le segment préféré, un test client fournit un walk scripté avec un chemin rectiligne de 5 tuiles et un horodatage at, journalise la position de l’habitant à chaque tick, comme le -motionLog du cahier des charges sur le mouvement journalise celle du joueur, et vérifie qu’il part au tick où tombe at selon l’estimation par le client de l’horloge de la salle, visite les tuiles du chemin dans l’ordre, se déplace d’exactement 1 pixel à chaque tick et jamais en arrière, met 16 ticks par tuile et se tient sur la dernière tuile 80 ticks après at ; un test serveur vérifie que chaque segment est envoyé une seule fois, en entier, avec son horodatage. Pour le repli minimal, un test serveur fait tourner les habitants pendant une heure simulée sur le tick de 0,5 s et vérifie que chaque intervalle de pas au sein d’un segment est égal à celui configuré ; aujourd’hui, measure_npc_cadence.py trouve 1,0 s contre 0,7 s configurées. Dans les deux cas, un test serveur vérifie que chaque attente est un nombre entier de ticks.622 (b) Un test ouvre deux salles de même fuseau à 600 secondes d’intervalle, toutes deux sur l’unique graine globale, et vérifie que les tuiles des habitants sont identiques à la même heure serveur ; un test client, avec le fuseau du téléphone réglé sur un autre que celui de la salle, vérifie que le moment de la journée de la place suit l’horloge de la salle. (c) Un test règle l’horloge du serveur sur un instant UTC qui correspond à 03:00 dans le fuseau de la salle et vérifie que les cinq aux postes et les deux errants ne sont pas sur la carte de la place, et que le marcheur de la boucle conservée y est. (d) Un test serveur compte les huit par type et trouve 5 à des postes, 2 errants et 1 sur la boucle conservée.
7.2 Les échos : les huit derniers trajets
- Mécanique. La place conserve les 8 dernières visites.413 Une visite est le chemin parcouru, sous forme de paires tuile et temps, de l’arrivée jusqu’à la première porte franchie ou 60 secondes, selon ce qui est le plus court ; la silhouette du marcheur n’est pas conservée. Quand une salle compte moins de 8 collectionneurs en direct, des échos comblent le vide : chacun rejoue son trajet à son propre rythme et s’efface à la porte qu’il a prise. Un écho n’a pas de plaque de nom, ne brandit aucune carte, n’a pas de zone tactile et ne dit rien. C’est un trajet, pas une personne.5
- Apparence. La silhouette d’un écho n’est jamais dérivée de celle du marcheur. Le serveur attribue à chacun l’une de quatre silhouettes sobres, les pièces par défaut du manifeste en quatre teintes sobres, réalisées par la forge pour les échos et dessinées pâles (l’une des rampes de teintes de la forge avec un alpha fixe). Laquelle des quatre est choisie par un hachage à clé du sel propre au trajet, sous le secret du serveur, que le serveur garde et n’envoie jamais, si bien que deux trajets d’un même collectionneur reçoivent des silhouettes sans rapport. Un collectionneur peut lui aussi porter des pièces par défaut, et un marcheur qui en porte par hasard l’une des quatre peut donc ressembler par hasard à son écho, sans que cette ressemblance ne révèle rien : la silhouette ne dit rien de qui a marché.58
- Effacement. Un écho est supprimé au bout de 7 jours ou à l’arrivée de 8 visites plus récentes, selon ce qui survient en premier.14
- Qui voit les échos. Les collectionneurs présents sur la place en direct, chaque fois qu’elle en compte moins de 8. Personne dont
isMultiplayerGamingRestrictedvaut true : sa place tranquille n’a que des habitants, parce que, selon ma lecture, un écho fait partie du multijoueur de la place (7.6, réglage 1).18 - Masquage. Masquer un collectionneur masque aussi ses échos, et c’est le serveur qui filtre. Chaque trajet stocké porte un sel aléatoire et une étiquette : un hachage à clé (un HMAC) de l’identifiant du marcheur et de ce sel, sous un secret que seul le serveur détient, si bien que deux trajets d’un même collectionneur portent des étiquettes sans rapport. Une demande d’échos porte les identifiants que le demandeur a masqués ; le serveur recalcule, pour chaque trajet stocké, l’étiquette de chaque identifiant masqué, écarte les trajets qui correspondent, et abandonne la liste une fois la demande traitée, ou, sur une connexion en direct, à la fermeture du socket. Ce qui parvient à un client, c’est une silhouette sobre, le chemin et l’heure : ni identifiant, ni étiquette, ni sel, ni rien qui provienne de la silhouette du marcheur. Cela supprime l’identifiant et l’apparence, qui voyagent aujourd’hui ensemble à chaque arrivée (
Player.public()dansserver/app/rooms.pyenvoie l’identifiant, le pseudonyme et la silhouette dans un seul objet, etserver/app/main.pyle diffuse à la salle). Cela ne supprime pas le trajet. Un chemin, son rythme et son heure peuvent désigner un collectionneur pour quelqu’un qui était sur la place à cette heure-là ou qui sait où va toujours un ami, et un client présent dans la salle pendant ce même trajet a reçu chaque tuile avec l’identifiant du marcheur dansmoved. Les échos sont sans nom, pas anonymes.2320 - Ce qui est stocké, et la lecture COPPA. Pas de pseudonyme, pas d’identifiant Game Center, pas d’identifiant d’appareil, pas de silhouette du marcheur, pas de région et pas de temps plus fin que l’heure : les tuiles, les temps des pas relatifs au début du trajet, l’heure, le sel, qui choisit aussi la silhouette sobre, et l’étiquette qui applique un masquage. Lecture, pas un conseil : l’étiquette est dérivée d’un identifiant persistant, je la traite donc comme tel. Elle reste sur le serveur, n’est jamais envoyée et sert uniquement à appliquer un masquage, ce que je lis comme l’usage de fonctionnement interne que décrit le § 312.5(c)(7), avec un avis. Le trajet tel qu’envoyé, sans identifiant et avec une silhouette choisie par le serveur, je le lis comme hors de la définition des informations personnelles de la règle. Le point faible de cette lecture est qu’un trajet est un comportement, et que quelqu’un qui a vu la place à cette heure-là peut le relier à un collectionneur ; le temps limité à l’heure, le plafond de 60 secondes et les sept jours réduisent ce risque, sans l’éliminer. Les identifiants masqués que porte une demande servent à cette demande et ne sont ni journalisés ni conservés. La politique écrite de conservation de l’avis de confidentialité indique 7 jours, comme le demande le § 312.10.19 Le serveur passe ainsi de ne rien stocker à stocker des trajets pendant une semaine, et cette lecture relève de l’avocat que le plan reporte jusqu’à ce que l’app trouve son public.23
- Qui est enregistré. Personne de moins de 13 ans : selon la décision du 2 octobre, ils n’ont pas de place du tout.23 Personne dont
isMultiplayerGamingRestrictedvaut true (ils n’ont pas de place en direct où marcher, réglage 1), personne dontisUnderagevaut true, ce que le réglage 2 traite déjà comme un signal d’enfant, et personne de 13 à 15 ans selon la tranche déclarée, ce qui est la première des règles junior que le plan laisse à écrire.185223 - Ne doit pas ressembler à. Une tache de sang, une mort rejouée, un signe d’invocation, un mur de messages de joueurs. Un écho n’est jamais une créature et ne combat jamais.4144
Vérifications. (a) Un test serveur enregistre 10 visites et vérifie que 8 sont conservées, la plus ancienne étant supprimée, et qu’aucune ne survit à une horloge avancée de 7 jours. (b) Un test de schéma vérifie qu’un trajet stocké a exactement les champs path, hour, salt et tag, sans pseudonyme, identifiant ni chaîne de silhouette, et que les échos reçus par un client ont exactement les champs figure, path et hour : aucun champ de hachage, d’étiquette, de sel ou d’identifiant. Il vérifie que la chaîne de silhouette de l’écho est celle des quatre que choisit le hachage à clé du sel du trajet, la même quoi que portait le marcheur, et, pour un marcheur portant une silhouette hors des quatre sobres, qu’elle n’est pas celle du marcheur. (c) Un test d’interface sans pair en direct affiche jusqu’à 8 échos, et aucun ne réagit au toucher. (d) Un test avec le drapeau de multijoueur restreint, un avec isUnderage et un avec la tranche 13 à 15 ans vérifient que le serveur n’enregistre aucune visite de ce client. (e) Un test serveur stocke les trajets de deux collectionneurs, demande les échos avec l’un d’eux masqué, constate que les trajets de ce collectionneur sont écartés, puis ne trouve l’identifiant masqué nulle part dans l’état du serveur.
7.3 Le bonjour du jour
- Mécanique. Chaque habitant se souvient si vous lui avez parlé aujourd’hui.1110 La première conversation de la journée locale choisit une réplique de salutation (« Back again! » et ses semblables, écrites pour Kiradex et ajoutées après l’indice 22 dans
server/app/lines.py) ; les conversations suivantes du même jour choisissent une réplique ordinaire.21 Chaque troisième jour où vous avez parlé au même habitant le fait monter d’un échelon sur une échelle cachée des habitués, comptée à partir de votre première conversation et jamais remise à zéro, et à chaque échelon il dit une nouvelle réplique. Aucune jauge n’est affichée. - Pas d’effacement. Rien n’est perdu si vous manquez un jour, ou un mois. L’amitié de Stardew baisse chaque jour où vous ne parlez pas ; celle-ci jamais, parce que PEGI classe les « daily quests, log-in streak or event-based rewards that expire after a while » (quêtes quotidiennes, séries de connexions ou récompenses événementielles qui expirent au bout d’un moment) en PEGI 7, et en PEGI 12 lorsque « players are punished by losing rewards or game status when they do not return in time. » (les joueurs sont punis par la perte de récompenses ou de statut s’ils ne reviennent pas à temps.)105958
- Où il réside. Sur l’appareil : un dictionnaire associant l’identifiant de chaque habitant à la dernière date locale de conversation et au nombre de jours de conversation, dans le profil du collectionneur, si bien que le serveur reste sans stockage par joueur.
Vérifications. (a) Un test unitaire parle deux fois à un habitant le 2026-10-05 et une fois le 2026-10-06, et obtient deux salutations de premier contact du jour et une réplique ordinaire. (b) Un test unitaire avance et recule la date de l’appareil et ne constate jamais la perte d’un échelon. (c) Une recherche dans server/app ne trouve aucun stockage par joueur ajouté pour cette fonctionnalité. (d) Un test unitaire avec des premières conversations sur trois jours espacés de plusieurs semaines constate que l’habitant est monté d’un échelon.
7.4 Une présence sans retour en arrière
- Envoi. Un
movepar tuile achevée, comme aujourd’hui. La référence actuelle est de 4 par seconde en marchant et de 6,0 à 6,4 en courant (la course telle que modélisée à 60 Hz et à sa fréquence nominale) ; selon le contrat de mouvement de la série, les 16 ticks par tuile en marche et 8 en course à 60 Hz du cahier des charges sur le mouvement, c’est 3,75 et 7,5, et c’est vers ce contrat que tend ce cahier des charges. Les deux restent sous la limite de 8 par seconde.2122 Le serveur ajoute son propre horodatage en millisecondes à chaquemovedqu’il relaie. - Rendu. Chaque client tient une estimation de l’horloge du serveur à partir des horodatages qu’il reçoit, et dessine chaque autre collectionneur sur une horloge de rendu en retard de 350 ms sur cette estimation : de façon linéaire entre les deux horodatages reçus qui encadrent l’horloge de rendu, le cycle de marche étant piloté par la distance parcourue. Ne jamais remettre à zéro un pas en cours. Quand le tampon est vide, rester sur la dernière tuile ; un marcheur sur grille s’arrête net, donc rien n’est extrapolé. Ne sauter que si un marcheur a plus de 6 tuiles ou 2 secondes de retard.716 Les 350 ms viennent d’une borne, vérifiée dans un modèle qui supposait une estimation d’horloge exacte et aucun délai aller au-delà de la gigue (section 3) : à la marche du contrat de mouvement, 3,75 tuiles par seconde, un pas dure 266,7 ms, un pas plus 80 ms de gigue font 346,7 ms, et un délai au moins aussi long n’affame aucune image pour aucun tirage de gigue. Cela laisse environ 3 ms pour l’erreur de l’estimation d’horloge ; une estimation davantage en avance sur l’horloge du serveur peut affamer des images. 325 ms ont passé la vérification (a) sur le premier tirage de gigue du modèle, avec 6 images affamées à 80 ms, mais l’ont échouée sur 8 tirages sur 200 ; 350 ms n’en ont affamé sur aucun.7 C’est une valeur de départ qu’une capture sur appareils doit confirmer, pas un résultat.
- Inactivité. Marquer un collectionneur comme inactif après 120 secondes sans saisie, montré par le cycle d’inactivité
dozequi existe déjà dans le rig, comme Arcturus marque un avatar inactif à 240 cycles de 500 ms.1550 Fermer le socket après 240 secondes sans ping. Cette règle est mon adaptation de deux sources : le contrôle du ping vient de Houdini, qui ferme tout client n’ayant envoyé aucun heartbeat pendant une fenêtre de 61 secondes, et les 240 secondes sont la durée après laquelle Arcturus expulse un non-propriétaire inactif, même si Arcturus compte des cycles sans action, et non des pings manquants.4815
Vérifications. (a) Transposer la nouvelle logique dans measure_remote_walk.py, avec l’horloge de rendu tirée de l’estimation par le client de l’horloge du serveur plutôt que de la propre horloge de l’émetteur, et, avec l’émetteur à 3,75 et 7,5 tuiles par seconde, exiger 0 image en arrière dans les six cas, 0 image affamée à 0 et 30 ms de gigue, et au plus 10 images affamées sur les 600 dessinées pendant que l’émetteur émet à 80 ms. Le modèle à horloge exacte donne 0 image affamée dans les six cas à 350 ms, sur chacun des 200 tirages de gigue.7 (b) Un test d’interface avec un pair scripté traversant la place vers la droite ne capture aucune image où le x du pair diminue. (c) Un test serveur vérifie que chaque moved relayé porte un horodatage. (d) Un test serveur avance l’horloge de 241 secondes sans ping et vérifie que le socket est fermé.
7.5 Le carnet de répliques
- Forme. Six branches de 8 à 12 répliques chacune au lancement, 48 à 72 au total, chaque réplique à deux touchers (la branche, puis la réplique) : Salutations, Réponses (une époque préférée, depuis combien de temps vous collectionnez, quelle extension), Collection, Échanges (organiser un échange, jamais en fixer le prix), Encouragements et Au revoir. Aujourd’hui, il y a 14 répliques de joueur dans une seule liste.21 Les emotes restent une rangée distincte. Un joueur pour qui Game Center signale la communication comme restreinte, ou qui est mineur, n’obtient pas du tout le carnet de répliques (7.6, réglage 2).
- Croissance. Jusqu’à 30 répliques supplémentaires débloquées par le jeu, au plus une par jour, issues de l’échelle des habitués de 7.3 et des niveaux.1235 Le serveur détient la liste et peut retirer une réplique dans l’heure, puisqu’il envoie déjà la liste à l’arrivée.20
- Face au canon. Easy Chat ouvre 940 mots et les compose en grilles de 2 à 10 emplacements ; New Horizons a 88 Réactions ; la Salle Union d’Émeraude acceptait 15 caractères tapés.38124 Les répliques de Kiradex sont des phrases entières, jamais composées de mots, si bien qu’aucune suite de choix ne peut épeler un nom, un nombre ou un lieu.
- Ne doit pas ressembler à. La structure de groupes d’Easy Chat ou sa grille de mots, la liste des expressions à la mode, ou un quelconque terme de la franchise.40
Le carnet de répliques proposé : la seule figure de cet article qui soit une proposition plutôt qu’une mesure.26
Vérifications. (a) Un test sur lines.py vérifie 6 branches de 8 à 12 répliques chacune au lancement, et que chaque réplique est à au plus 2 touchers de la racine. (b) Un test vérifie qu’aucune réplique ne contient de chiffre ni d’emplacement libre. (c) Un test lit les listes de mots Easy Chat de pret et ne trouve aucune réplique égale à une entrée, ni aucune entrée de deux mots ou plus à l’intérieur d’une réplique. (d) Un test unitaire débloque une réplique sur chacun de deux jours consécutifs et refuse un second déblocage le même jour.
7.6 Réglages de sécurité, chacun avec une vérification
- La restriction de Game Center désactive les autres collectionneurs, en direct et rejoués. Quand
GKLocalPlayer.local.isMultiplayerGamingRestrictedvaut true, mode amis seulement compris, la place s’ouvre en place tranquille : uniquement des habitants, sans échos et sans WebSocket. Les habitants et l’horloge de la salle arrivent en une seule requête qui ne porte ni identifiant de compte, ni identifiant d’appareil, ni identifiants masqués ; le serveur n’utilise l’adresse IP de la requête que pour y répondre, et le serveur de la place ne la journalise pas ; les journaux de requêtes en périphérie de l’hébergeur ne sont pas vérifiés ici (réglage 6).18 Lecture : la page dit « If your game uses a custom multiplayer feature, you should disable it, » (si votre jeu utilise une fonctionnalité multijoueur personnalisée, vous devriez la désactiver), et un écho est la rediffusion du trajet d’un vrai collectionneur, une trace d’un autre joueur du type qu’examine la section 2, et une trace qu’un spectateur peut reconnaître (7.2). Wikipedia décrit les images fantomatiques d’autres joueurs de Dark Souls sous l’intertitre Multiplayer du jeu, sans dire s’il s’agit d’enregistrements ou de joueurs connectés à ce moment. Cette source est ambiguë : le texte sous cet intertitre dit que le jeu « integrates online features into the single-player world » (intègre des fonctionnalités en ligne au monde solo) et présente le « Direct multiplayer » (multijoueur direct) comme les invocations coopératives et les invasions, séparément des fantômes. Le cahier des charges choisit tout de même la prudence : selon ma lecture, les échos font partie de la fonctionnalité multijoueur personnalisée de la place, et un joueur dont le parent a restreint le multijoueur n’en voit aucun.1841 Ce qui permettrait de rendre les échos à ce joueur, c’est qu’App Review, ou Apple par écrit, considère un trajet rejoué dans une silhouette sobre, sans aucun identifiant attaché, comme autre chose que du multijoueur ; ce cahier des charges ne le suppose pas. Vérification : un test d’interface avec le drapeau forcé à true vérifie qu’aucun WebSocket n’est ouvert, qu’aucun écho n’est dessiné et que la place indique qu’elle est tranquille ; un test serveur appelle la route de la place tranquille et ne trouve aucun écho dans la réponse ni aucune adresse IP dans le journal du serveur. - Communication personnalisée désactivée. Quand
isPersonalizedCommunicationRestrictedouisUnderagevaut true, le défaut est les emotes seuls : le carnet de répliques est masqué, aucunsayn’est envoyé, les répliques des autres collectionneurs ne sont pas dessinées pour ce joueur, et il n’y a jamais de voix, de message d’invitation ni de champ de saisie.5152 Lecture : la page dit « If your game includes any custom communication features, you should disable them, » (si votre jeu comporte des fonctionnalités de communication personnalisées, vous devriez les désactiver), et un carnet de phrases prédéfinies est une fonctionnalité de communication personnalisée. Que Game Center autorise les messages prédéfinis aux enfants dans ses propres fonctionnalités n’exempte pas celles d’un jeu.5117 Je garde les emotes parce qu’un signe de la main ou un hochement de tête ne porte rien dont un enfant pourrait se servir pour joindre quelqu’un, mais un emote est une forme de communication (le récit de Wikipedia sur Journey appelle son carillon « The only form of communication between the two », la seule forme de communication entre eux), et c’est le maillon le plus faible de la lecture : si App Review considère aussi les emotes comme une fonctionnalité de communication personnalisée, ils disparaissent et la place n’offre plus à ce joueur qu’une présence.5 Garder les répliques pour ce joueur serait une exception nécessitant l’accord écrit d’Apple ; ce cahier des charges ne la prend pas. Vérification : une recherche deTextField,TextEditoretUITextFielddansKiradex/Worldne renvoie rien, et un test d’interface avec chaque drapeau forcé à true affiche la rangée d’emotes, aucun carnet de répliques, n’envoie aucunsayet ne dessine aucune réplique d’un autre collectionneur. - Tranches d’âge selon Declared Age Range, comme décidé le 2 octobre. Moins de 13 ans : pas de place, seulement un pseudonyme généré. 13 à 15 ans : la place avec les règles junior, dont la première est que leurs trajets ne sont jamais enregistrés. 16 ans et plus, ou non déclaré : la place complète.2354 Vérification : un test unitaire de la table des modes sur les trois tranches et les trois drapeaux de Game Center.
- Le signalement et le masquage atteignent les échos. Masquer un collectionneur masque sa silhouette en direct et, filtrés sur le serveur pour chaque requête comme en 7.2, ses échos ; le signalement reste disponible sur le panneau de chaque collectionneur.55 Un écho porte une silhouette sobre et n’a pas de panneau, si bien qu’un joueur ne peut pas repérer l’écho d’un collectionneur masqué pour le masquer ; le filtre du serveur s’en charge. Un masquage atteint les trajets stockés avant et après lui ; il ne peut pas atteindre ce qu’un autre joueur a vu en direct ou reconnaît dans un trajet. Vérification : le test serveur de 7.2(e), et un test d’interface qui masque un pair scripté, rejoue son trajet enregistré et vérifie qu’il n’est pas dessiné.
- Pas d’appariement aléatoire, pas de chat anonyme. Les inconnus ne partagent jamais que la place ; rien n’apparie deux inconnus dans un espace privé.55 Vérification : un test sur les gestionnaires de
server/app/main.pyne trouve aucun message ouvrant un canal entre deux collectionneurs qui ne sont pas amis sur Game Center. - La conservation par écrit. L’avis de confidentialité intègre la politique écrite de conservation des données : la présence en mémoire uniquement ; les échos 7 jours, chacun avec un hachage à clé de l’identifiant du marcheur qui reste sur le serveur, ne sert qu’à appliquer les masquages et n’est jamais envoyé ; les identifiants masqués que porte une requête, non conservés ; l’adresse IP d’une connexion, utilisée uniquement pour y répondre et acheminer la réponse, ce que je lis comme un soutien au fonctionnement interne au sens du § 312.5(c)(7), et non journalisée par le serveur de la place ; les signalements journalisés par motif et par salle.19 Aujourd’hui, le serveur lance uvicorn 0.37.0 avec ses valeurs par défaut (
server/Procfile,--proxy-headers), et d’après ma lecture du code d’uvicorn lui-même, ces valeurs par défaut écrivent dans le journal l’adresse transmise du client pour chaque requête HTTP (le journal d’accès est actif sauf s’il est désactivé) et pour chaque WebSocket accepté (une ligne INFO suruvicorn.error) ; le cahier des charges le lance avec--no-access-log --log-level warning.57 Vérification : l’URL de l’avis est accessible depuis les Réglages, le test serveur de 7.2(a) tient les 7 jours, et un test qui ouvre un WebSocket et appelle la route de la place tranquille avec la commande de démarrage de production ne trouve aucune adresse IP dans le journal capturé. Les journaux de requêtes en périphérie de l’hébergeur sortent du périmètre de ce test et ne sont pas vérifiés ici : s’ils enregistrent l’adresse du client, et pour combien de temps, reste à confirmer auprès de l’hébergeur avant de rédiger l’avis. - Aucun outil d’analyse ni de publicité tiers dans le monde.55 Vérification : un audit des dépendances de la cible de l’app ne recense aucun SDK d’analyse ou de publicité.
Ce qu’il faut refuser
- Un minuteur de jeu maison. Screen Time limite déjà le temps passé dans une app, et le serveur de Club Penguin décomptait les minutes autorisées d’un enfant et le déconnectait à zéro ; la limite de la plateforme est celle qu’un parent connaît déjà.1748
- Les compteurs d’abonnés, et tout décompte de qui aime qui ; le plan les exclut déjà.23
- Une liste de visiteurs avec des noms, une page de qui est passé. Un écho est sans nom à dessein : il ne porte aucun identifiant ni rien qui provienne de la silhouette du marcheur. Il n’est pas anonyme : quelqu’un qui était sur la place à cette heure-là, ou qui connaît les habitudes d’un ami, peut tout de même reconnaître un trajet, et c’est pourquoi un écho porte l’heure et aucun temps plus fin, et pourquoi il n’existe aucune liste où lire les échos.
- Un écho que l’on peut toucher, à qui l’on peut parler ou que l’on peut suivre.
- Une jauge sur le bonjour du jour, ou quoi que ce soit de perdu pour ne pas être revenu.59
Hors de ce cahier des charges
- Les pièces que les gens décorent. Les meubles, les casquettes et les visites des pièces d’autres collectionneurs relèvent d’un prochain article de cette série.
- La formulation des nouvelles répliques. Le cahier des charges fixe la forme du carnet de répliques ; les phrases sont écrites pour Kiradex et localisées séparément.
- Le jeu en groupe. Les échanges, la présentation de cartes et l’écran d’échange que le plan range parmi ce qui n’est pas encore construit sortent du cadre de ce cahier des charges.23
- Quoi que ce soit des jeux mesurés. Aucune créature, aucun nom de lieu, aucune marque, aucune tuile ni aucun son de Pokémon, Stardew Valley, Animal Crossing, Dark Souls, Journey, Death Stranding, Splatoon, Habbo ou Club Penguin.
- Des durées sur un appareil. Les vérifications portent sur le comportement, des captures et un modèle ; rien ici ne promet une durée d’image.
Points clés à retenir
Si vous dessinez les graphismes
- Dessinez plus de gens debout que de gens qui marchent. Six sur dix des habitants toujours présents sur les cartes d’Émeraude se tiennent à un poste, la plupart tournés vers une direction et certains regardant autour d’eux (sept sur dix si l’on compte les acteurs du scénario) ; donnez à chaque personnage debout une orientation et un regard circulaire, et gardez les cycles de marche pour les près de quatre sur dix qui errent.1
- Faites en sorte que l’écho du trajet d’un autre joueur se lise comme une trace, pas comme une personne : pâle, sans nom, les mains vides, s’effaçant à une porte. Rien dans son dessin ne devrait inviter au toucher.5
Si vous construisez le moteur
- Réglez la journée de la ville à l’arrivée, en une exécution qui prend le nombre de jours écoulés, et calculez la tuile d’un habitant à partir d’une horloge que partagent tous les occupants de la salle, et non à partir de celle de chaque téléphone ; une boucle serveur qui s’interrompt quand la salle est vide fige la ville, comme celle de Kiradex mesurée ici.36
- Faites de l’intervalle de pas du serveur un nombre entier de ticks et dessinez chaque pas sur l’intervalle qui lui a été attribué ; un pas de 0,7 s sur un tick de 0,5 s tombe toutes les 1,0 s et se dessine en 0,25 s, une marche immobile 75 % du temps.6
- Envoyez une mise à jour par tuile, horodatez-la sur le serveur, et dessinez les autres marcheurs sur une horloge en retard de 350 ms sur l’heure estimée du serveur sans jamais remettre à zéro un pas en cours ; dans le modèle, aux 3,75 et 7,5 tuiles par seconde de la série et avec une estimation d’horloge exacte, cela donne 0 image en arrière et 0 image affamée jusqu’à 80 ms de gigue.7
- Lisez
isMultiplayerGamingRestricted,isPersonalizedCommunicationRestrictedetisUnderageavant d’ouvrir un socket ; le mode amis seulement est lu comme restreint, et selon ma lecture un joueur restreint ne devrait pas voir non plus les rediffusions d’autres joueurs.185152
Si vous concevez la boucle de jeu
- Gardez les traces des autres dans quelques emplacements fixes qui s’effacent : huit trajets pendant sept jours suffisent à dire que quelqu’un est passé. Appliquez les masquages sur le serveur, envoyez une trace sans identifiant et dans une silhouette sobre plutôt que celle du marcheur, et dites clairement qu’un trajet peut tout de même être reconnu par quelqu’un qui l’a vu.414
- Retenez le bonjour du jour par un drapeau et ne reprenez jamais rien pour un jour manqué ; PEGI classe les séries qui expirent.59
- Donnez aux inconnus des phrases, pas des mots : un carnet de phrases entières ne peut être détourné pour épeler quoi que ce soit, et Game Center limite déjà les enfants aux messages prédéfinis. Quand Game Center indique que la communication est restreinte, retirez aussi le carnet de répliques.381751
Questions fréquentes
Comment rendre une ville de jeu vivante quand aucun autre joueur n’est en ligne ?
Donnez-lui des habitants avec leurs propres routines et des traces de gens qui sont passés. Dans les 16 villes de Pokémon Version Émeraude, 59 des 100 habitants sans drapeau de masquage se tiennent à des postes, 39 errent dans des cadres d’une ou deux cellules et 2 marchent sur place (71,5 %, 27,2 % et 1,3 % de l’ensemble des 158, en comptant les acteurs du scénario qu’un drapeau peut retirer, surtout debout), en faisant leurs pas au rythme du joueur et en attendant 0,54 à 2,14 secondes entre deux pas ; les villageois de Stardew Valley ont des journées de quelques points horodatés choisies par 22 formats de clé ; et le mélange de données d’Émeraude copie les bases, les expressions à la mode et le résident d’un autre joueur dans votre ville.124
À quelle fréquence les PNJ doivent-ils bouger dans un jeu en pixel art vu de dessus ?
Dans Émeraude, un errant fait un pas de 16 images (268 ms, la même action que la marche du joueur) puis attend 32, 64, 96 ou 128 images, si bien qu’il est en mouvement au plus 11 à 33 % du temps, par pas effectué, et moins quand un pas qu’il choisit est bloqué ; la plupart des habitants ont un type de mouvement par défaut qui ne fait jamais de pas, même si un script de scénario peut tout de même en faire marcher un. Animal Crossing: Wild World a pris le chemin inverse en ralentissant ses villageois sous le rythme du joueur. Ce qui rend mal, c’est un rythme qui n’est ni l’un ni l’autre : les collectionneurs de Kiradex bougent à la vitesse du joueur par à-coups d’une tuile, avec des arrêts de 0,75 seconde entre les tuiles.1326
Qu’est-ce que le mélange de données dans Pokémon Émeraude ?
Un échange par câble Link dans lequel chaque partie envoie à l’autre une structure fixe de 11 types d’enregistrements en 5 188 octets, dont 20 Bases Secrètes, 25 emplacements de télévision, 16 nouvelles et 5 expressions à la mode. Le vieil homme de Mauville du partenaire remplace le vôtre, et l’arrivée du Hipster est la seule chose qui lui permette d’enseigner une nouvelle expression à la mode.435
Quel délai d’interpolation faut-il pour un jeu multijoueur en 2D ?
La règle de Glenn Fiedler est d’avoir de quoi survivre à deux paquets perdus, environ trois intervalles d’envoi, plus une image ou deux pour la gigue.16 Sur des WebSockets, qui reposent sur TCP, rien n’est perdu et un paquet en retard est retransmis ; selon ma lecture, le budget porte donc sur la gigue plutôt que sur les paquets perdus, et un tampon d’un peu plus d’un intervalle peut suffire. Pour un monde sur grille qui envoie une mise à jour par tuile, un modèle de la marche de Kiradex aux 3,75 tuiles par seconde en marche et 7,5 en course de la série a montré qu’une horloge de rendu en retard de 350 ms sur l’heure estimée du serveur donne 0 image en arrière et 0 image affamée jusqu’à 80 ms de gigue ; sur un tirage de gigue, 300 ms affament 27 images sur 600 en marche à 80 ms et 325 ms en affament 6, tandis que 100 ms en affament 125 à 456 dans tous les cas, et sur 200 tirages, 350 ms n’en affament sur aucun. Les 350 ms reposent sur une borne : un pas de 266,7 ms à 3,75 tuiles par seconde plus 80 ms de gigue font 346,7 ms. C’est un modèle avec une route droite, une gigue uniforme, une estimation d’horloge exacte et aucune latence de base, pas une capture sur appareil.7
Les enfants peuvent-ils utiliser le chat dans un jeu iOS ?
Game Center indique que les enfants « cannot send or receive user-inputted text » (ne peuvent ni envoyer ni recevoir de texte saisi par un utilisateur) et sont « restricted to sending and receiving preset messages » (limités à l’envoi et à la réception de messages prédéfinis), le chat vocal étant désactivé. La documentation d’Apple demande à un jeu doté d’« any custom communication features » (fonctionnalités de communication personnalisées) de les désactiver quand isPersonalizedCommunicationRestricted ou isUnderage vaut true, et la directive 1.2 exige pour le contenu généré par les utilisateurs un filtrage, un signalement, un blocage et des coordonnées publiées. Cette phrase n’exempte pas les messages prédéfinis ; selon ma lecture, les répliques prédéfinies propres à un jeu disparaissent donc dès que l’un des deux drapeaux vaut true, même si Game Center autorise les messages prédéfinis aux enfants dans ses propres fonctionnalités ; le cahier des charges de Kiradex ne garde que les emotes pour un tel joueur, et cette lecture est la mienne, pas le texte d’Apple.175155
La COPPA permet-elle de stocker les déplacements d’autres joueurs pour les rejouer comme des fantômes ?
Je ne suis pas avocat, et ceci est une lecture, pas un conseil. La règle modifiée range « A persistent identifier that can be used to recognize a user over time » (un identifiant persistant permettant de reconnaître un utilisateur dans le temps) parmi les informations personnelles, permet à un opérateur d’utiliser un identifiant persistant seul « for the sole purpose of providing support for the internal operations » (dans le seul but d’assurer le fonctionnement interne) moyennant un avis, et exige depuis le 22 avril 2026 une politique écrite de conservation assortie d’un délai de suppression. La conception de Kiradex stocke un trajet sans pseudonyme, sans identifiant de compte, sans identifiant d’appareil et sans la silhouette du marcheur, plus un hachage à clé de l’identifiant du marcheur qui reste sur le serveur, ne sert qu’à appliquer les masquages des autres joueurs et n’est jamais envoyé ; l’écho est dessiné dans l’une de quatre silhouettes sobres que choisit le serveur, et les deux sont conservés sept jours et mentionnés dans cette politique. Je traite le hachage comme un identifiant persistant utilisé pour le fonctionnement interne, et le trajet tel qu’envoyé comme hors de la définition, mais un trajet est un comportement que quelqu’un ayant vu la place à cette heure-là pourrait relier à un collectionneur ; les échos sont donc sans nom plutôt qu’anonymes, et un avocat devrait vérifier la conception finale.19
À lire aussi sur ce site : Des mondes en pixel art sur iPhone est le premier guide de cette série, avec les systèmes de tuiles et la place dans laquelle vit la ville de cet article, et sa FAQ juridique trace la limite des brevets que suit le cahier des charges ; Des personnages en pixel art a construit les collectionneurs et la forge dont les échos portent les silhouettes sobres, et cite la règle PEGI qui empêche le bonjour du jour de s’effacer ; Des structures en pixel art a construit les portes par lesquelles les habitants rentrent chez eux la nuit ; Le mouvement en pixel art mesure les marches des consoles portables, modélise celle de l’app et fixe la règle de ne jamais remettre un pas à zéro que le cahier des charges applique aux autres collectionneurs ; et L’iPhone Duo pour les développeurs présente l’appareil pour lequel la place est dessinée.
Sources
-
Mesure de l’auteur,
measure_npcs.pydans le dossier de preuves de l’auteur pour cet article, révisé et relancé le 5 octobre 2026, sortie enregistrée sousmeasure_npcs.out. Entrées : la décompilationpokeemeraldde pret, un clone superficiel au commit731ad5b(master, 1er octobre 2026) :include/constants/event_object_movement.h(les 81 types de mouvement), les 16 fichiersdata/maps/*/map.jsondes villes (événements d’objet, identifiants graphiques, types de mouvement, zones, drapeaux de masquage) etsrc/event_object_movement.c(les tables de pas, les trois tables de délais minutées à 59,7275 Hz, quel type de mouvement fixe quel délai, etMovementType_WanderAround_Step4). La révision trie les événements d’objet pargraphics_iden personnes, objets (6ITEM_BALL, 2TRUCK, 1MR_BRINEYS_BOAT) et créatures (5), et s’arrête si un identifiant graphique non classé apparaît ; les événementsVAR_0etVAR_3, dont le sprite provient d’une variable, sont comptés comme des personnes parce que chacun d’eux porte le drapeau de masquage d’un rival. La version précédente comptait les 172 événements d’objet comme des habitants ; elle et sa sortie sont conservées à côté avec un suffixe.r1, et la sortie de la révision reprend à l’identique les lignes précédentes. La première révision et sa sortie sont conservées avec un suffixe.r2; le script actuel, une seconde révision, répartit les 158 personnes selon le drapeau de masquage de leur événement d’objet : les 58 qui en ont un (54 debout, 4 errants ; 41 d’entre eux utilisent le sprite d’une équipe de méchants, du rival ou d’un personnage nommé, d’après une liste fixe d’identifiants graphiques dans le script) et les 100 qui n’en ont pas (59 debout, 39 errants, 2 marchant sur place), et recompte les personnes sans drapeau de masquage des trois villes (Littleroot 2, Petalburg 3, Mauville 6) ; sa sortie reprend à l’identique chaque ligne précédente. Une personne sans drapeau de masquage est sur la carte à chaque chargement ; appeler les 58 des acteurs du scénario est ma lecture de leurs sprites et des noms de leurs drapeaux, pas un champ des données. Les parts de mouvement (11 à 33 %) sont de l’arithmétique sur les lignes de pas et de délai, 16 images sur 16 plus 32 à 128, par pas effectué : une borne supérieure, puisqu’un errant dont la direction choisie est bloquée regarde et attend de nouveau sans bouger. ↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩ -
Mesure de l’auteur,
measure_daily.pydans le même dossier, relancé le 5 octobre 2026, sortie identique àmeasure_daily.out. Entrées : pretpokeemerald731ad5binclude/constants/flags.hetsrc/clock.c; les pages sauvegardées du Stardew Valley Wiki « Villagers » (oldid 191346, modifiée le 26 février 2026), « Pierre » et « Modding:Schedule data » (les 22 formats de clé comptés à partir des tableaux de la page) ; et la page « Reaction » de Nookipedia (les nombres de New Horizons par version). ↩↩↩↩↩↩↩↩↩↩↩ -
pret,
pokeemerald/src/clock.c(DoTimeBasedEvents, etUpdatePerDay, qui s’exécute une fois avecdaysSince, le nombre de jours depuis sa dernière exécution), commit731ad5b;DoTimeBasedEventsest aussi appelé au chargement des cartes danssrc/overworld.cet par une tâche de terrain périodique danssrc/field_tasks.c, consulté le 4 octobre 2026, https://github.com/pret/pokeemerald/blob/master/src/clock.c. ↩↩↩↩↩↩↩ -
Mesure de l’auteur,
measure_record_mixing.pydans le même dossier, relancé le 5 octobre 2026, sortie identique àmeasure_record_mixing.out. Entrées : pretpokeemerald731ad5bsrc/record_mixing.c(struct PlayerRecordEmerald, ses 11 membres et sa taille de 0x1444 octets),include/constants/global.het les en-têtes associés (SECRET_BASES_COUNT,TV_SHOWS_COUNT,POKE_NEWS_COUNT,SAVED_TRENDS_COUNT,APPRENTICE_COUNT),src/mauville_old_man.c(les cinq vieux hommes et la règle de sélection), etsrc/union_room_chat.c,include/union_room.hetinclude/constants/global.h(les chefs de groupe de la Salle Union, la taille des groupes, les sprites, les codes d’activité, les pages de clavier,MAX_MESSAGE_LENGTHetUNION_ROOM_KB_ROW_COUNT). ↩↩↩↩↩↩↩↩↩↩↩↩ -
Wikipedia, « Journey (2012 video game) », sections Gameplay et Development, chaque affirmation citant sa propre source, sauvegardé le 4 octobre 2026, https://en.wikipedia.org/wiki/Journey_(2012_video_game). La page Journey de thatgamecompany elle-même a aussi été sauvegardée et ne contient que de la navigation. ↩↩↩↩↩↩↩
-
Mesure de l’auteur,
measure_npc_cadence.pydans le même dossier, révisé et relancé le 5 octobre 2026, sortie enregistrée sousmeasure_npc_cadence.out; la révision ajoute seulement un décompte de chaque messagesaid(469 dans l’heure), à côté des 465 intervalles entre répliques consécutives d’un même collectionneur sur lesquels est calculée la moyenne de 30,7 secondes, et ses autres lignes sont inchangées (la version précédente est conservée avec un suffixe.pre-astra). Il importe les modules propres au serveur Kiradex,app.npcs(STEP_SECONDS,make_all) etapp.rooms(Plaza), depuis l’arbre de travail lu le 5 octobre 2026 (fichiers et empreintes dans la note 20), litTICK_SECONDSdansserver/app/main.py, et fait avancer quatre collectionneurs avec la graine 1 sur une horloge idéale de 0,5 s pendant 3 600 secondes simulées, en journalisant chaque messagemovedetsaid. Les intervalles de 1,5 s ou moins entre pas consécutifs sont comptés comme internes à un segment ; les écarts plus longs sont des pauses. Le test de la salle vide vérifie le retour anticipé deRoom.ticket appelle une foisadvance(10000.0)sur des collectionneurs neufs. Les chiffres de 25 et 75 % divisent le pas de 250 ms du client (PlazaRig.tilesPerSecond = 4) par l’intervalle mesuré de 1,0 s. Cette exécution remplace les 0,7 s et 36 % quemeasure_kiradex.pydéduit de la seule constante. ↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩ -
Modèle de l’auteur,
measure_remote_walk.pydans le même dossier, révisé et relancé le 5 octobre 2026, sortie enregistrée sousmeasure_remote_walk.out; la version précédente, qui faisait l’arithmétique du rig en flottants 64 bits, et sa sortie sont conservées avec un suffixe.pre-f32. La révision effectue chaque opération que le rig fait enFloatsur 32 bits (NumPyfloat32), dans l’ordre du code :progressest unFloat(PlazaRig.swiftligne 29),updatereçoitFloat(event.deltaTime)(PlazaStage.swiftligne 149), etadvance()ajoutedt * tilesPerSecond * (running ? runPace : 1) / length(ligne 660),runningn’étant défini que pour le joueur (ligne 614) ; les positions valent(Float(x) + 0.5) * 16(TileMap.swiftligne 235) et sont dessinées àfrom + (to - from) * progress, arrondies au pixel entier, les égalités s’éloignant de zéro (lignes 670 et 726). Il affiche la vérification que 15 images de 1/60 de seconde font exactement 1,0 en 32 bits et 0,9999999999999999 en 64. Il réimplémentePlazaRig.move(other:to:facing:)tel que lu le 5 octobre (chemin depuis la dernière tuile entière du marcheur ;progress = 0à chaque message ; un saut quand le chemin est vide ou dépasse 6 pas) et compte comme retour en arrière une remise à zéro alors qu’il reste des pas et que la progression dépasse 0,05, comme image en arrière une position de pixel dessinée inférieure à celle de l’image précédente, et le retard à partir de la position de pixel dessinée. Séparément, il modélise l’interpolation d’instantanés sur une horloge de rendu régulière,rt = now - delaypour des délais de 100, 250, 300, 325 et 350 ms, oùnowest l’horloge de l’émetteur, si bien que la règle modélisée est l’heure estimée du serveur moins le délai, et non la mise à jour la plus récente moins le délai ; cette moitié est un moteur de rendu proposé, pas le rig, et tourne en flottants 64 bits. Hypothèses : ledeltaTimede chaque image vaut exactement 1/60 de seconde ; pas de fused multiply-add ; une synchronisation d’horloge parfaite entre émetteur et moteur de rendu ; aucune latence aller de base, si bien qu’une mise à jour arrive à son horodatage plus la gigue ; une route droite et dégagée (la longueur du chemin est la distance de Manhattan ; les pas en diagonale, qui prennent √2 fois plus de temps dans le rig, ne sont pas modélisés) ; un émetteur qui envoie un déplacement par tuile achevée, aux 4 tuiles par seconde actuelles en marche et à la fréquence nominale de 6,4 en course pour les deux moitiés, et pour le tampon aussi selon le contrat de mouvement de la série, 3,75 et 7,5 tuiles par seconde ; une gigue uniforme de 0 à J ms pour J valant 0, 30 et 80 ; 60 images par seconde ; graine 1. Le rig tourne 12 secondes simulées par cas (10 d’envoi et 2 de stabilisation) et chaque exécution avec tampon 660 images (11 secondes), les images affamées n’étant comptées que sur les 600 dessinées pendant que l’émetteur émet encore. Un second script,measure_remote_walk_seeds.pydans le même dossier, exécuté le 5 octobre 2026, sortie enregistrée sousmeasure_remote_walk_seeds.out, charge la même fonction d’interpolation depuis le source demeasure_remote_walk.py, vérifie que la graine 1 reproduit ses 27, 6 et 0 images affamées, et relance le tampon à 3,75 et 7,5 tuiles par seconde sur les graines 1 à 200 : à 80 ms de gigue, en marche, 325 ms affament des images sur les 200 graines et plus de 10 sur 8 d’entre elles, 350 ms sur aucune, et tous les autres cas à 325 et 350 ms sur aucune. Il affiche la borne qui justifie les 350 ms : un pas à 3,75 tuiles par seconde dure 266,67 ms, plus 80 ms de gigue 346,67 ms, ce qui laisse 3,33 ms. Il décale aussi l’horloge de rendu comme une estimation d’horloge en avance sur celle du serveur ; dans ce modèle, dont les images et les pas s’alignent sur la grille de 1/60 s, 10 ms d’avance n’affament encore aucune image sur 200 graines et 25 ms d’avance se comportent comme 325 ms, si bien que les 3 ms du texte sont la garantie de la borne, et non le point où ce modèle commence à affamer. C’est un modèle, pas une capture sur deux appareils. ↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩ -
pret,
pokeemerald/data/maps/, les 16 fichiersmap.jsondes villes, dontLittlerootTown,PetalburgCityetMauvilleCity, etdata/maps/PetalburgCity/scripts.inc(le garçon de l’arène,LOCALID_GYM_BOY,MOVEMENT_TYPE_LOOK_AROUNDsans drapeau de masquage dansmap.json, conduit jusqu’à l’arène par les mouvementsPetalburgCity_Movement_BoyWalkToGym), commit731ad5b, consulté le 4 octobre 2026, https://github.com/pret/pokeemerald/tree/master/data/maps. ↩↩↩↩ -
Stardew Valley Wiki, « Modding:Schedule data », sauvegardé le 4 octobre 2026, https://stardewvalleywiki.com/Modding:Schedule_data. Le format des emplois du temps, les données brutes d’Abigail dans la version 1.5.1 du jeu, les formats de clé et leur ordre, et la note « Limitations ». ↩↩↩↩↩↩↩↩
-
Stardew Valley Wiki, « Friendship », sauvegardé le 4 octobre 2026, https://stardewvalleywiki.com/Friendship. Les points par cœur, les façons dont l’amitié monte et baisse, la table de baisse, les cadeaux, le multiplicateur d’anniversaire et les événements de cœur. ↩↩↩↩↩↩
-
Nookipedia, « Friendship », section New Horizons, sauvegardé le 4 octobre 2026, https://nookipedia.com/wiki/Friendship. ↩↩↩↩
-
Nookipedia, « Reaction », section New Horizons, sauvegardé le 4 octobre 2026, https://nookipedia.com/wiki/Reaction. Les nombres par version proviennent de
measure_daily.py(note 2). ↩↩↩↩↩ -
Serebii.net, « Join Avenue », section Pokémon Black 2 and White 2, sauvegardé le 4 octobre 2026, https://www.serebii.net/black2white2/joinavenue.shtml. Un site de fans, et la seule source utilisée pour cette fonctionnalité. ↩↩↩↩↩
-
Wikipedia, « Death Stranding », section Gameplay, citant ses propres sources, sauvegardé le 4 octobre 2026, https://en.wikipedia.org/wiki/Death_Stranding. ↩↩↩↩↩
-
Krews, Arcturus Morningstar, un émulateur open source du serveur de Habbo écrit par des fans,
src/main/java/com/eu/habbo/habbohotel/rooms/Room.java(IDLE_CYCLES = 240,IDLE_CYCLES_KICK = 480,scheduleAtFixedRate(this, 500, 500, TimeUnit.MILLISECONDS)), sauvegardé le 5 octobre 2026, https://git.krews.org/krews/Morningstar/-/blob/master/src/main/java/com/eu/habbo/habbohotel/rooms/Room.java. Des constantes d’émulateur, pas des chiffres publiés par Sulake ;RoomUnitn’a pas été lu. ↩↩↩↩↩↩↩ -
Glenn Fiedler, « Snapshot Interpolation », Gaffer on Games, 30 novembre 2014, sauvegardé le 4 octobre 2026, https://gafferongames.com/post/snapshot_interpolation/. ↩↩↩↩↩↩↩↩
-
Apple, « Game Center & Privacy », section « Children in Game Center » et section sur les amis, sauvegardé le 4 octobre 2026, https://www.apple.com/legal/privacy/data/en/game-center/. ↩↩↩↩↩↩↩↩
-
Apple Developer Documentation,
GKLocalPlayer.isMultiplayerGamingRestricted(iOS 13.0+), le JSON de documentation sauvegardé le 4 octobre 2026, https://developer.apple.com/documentation/gamekit/gklocalplayer/ismultiplayergamingrestricted. Les citations sont le texte de la section Discussion, la référence en ligne àtrueétant rendue par le mot, aplati parsources/extract_gk.pydans le dossier du brouillon. ↩↩↩↩↩↩↩↩↩↩↩↩ -
Federal Trade Commission, « Children’s Online Privacy Protection Rule », règle finale, Federal Register, 22 avril 2025, document 2025-05904, 90 FR 16918, sauvegardé le 4 octobre 2026, https://www.federalregister.gov/documents/2025/04/22/2025-05904/childrens-online-privacy-protection-rule. La section DATES et les 16 CFR 312.2 (définition des informations personnelles), 312.5(c)(7), 312.8 et 312.10 modifiés. Toute affirmation de cet article sur ce que la règle signifie pour Kiradex est la lecture de l’auteur, pas un conseil juridique. ↩↩↩↩↩↩↩↩↩↩↩
-
Lecture par l’auteur du dépôt Kiradex (privé), arbre de travail au 5 octobre 2026, en lecture seule, aucune commande git exécutée ; fichiers identifiés par les huit premiers chiffres hexadécimaux de leur SHA-256 :
server/app/main.py(87c6cc9f ;TICK_SECONDS = 0.5,SHOW_EVERY_SECONDS, les gestionnaires de messages, dont le relaismovedà la ligne 223 qui porte l’idet la tuile du marcheur),server/app/npcs.py(d84f12a5 ; la docstring du module,STEP_SECONDS = 0.7, les quatre définitions et leurs itinéraires, envies et répliques),server/app/rooms.py(dcd66866 ;Player.public()à la ligne 115, qui renvoie l’identifiant, le pseudonyme et la silhouette dans un seul objet, diffusé à la salle à l’arrivée à la ligne 203 demain.py;CAPACITY,MOVES_PER_SECOND,SAY_EVERY_SECONDS,Plaza, etRoom.tickavec sa docstring et son retour anticipé),server/app/lines.py(391f5391 ; les 23 répliques et la docstring indiquant que le serveur envoie la liste à l’arrivée). ↩↩↩↩↩↩↩↩↩↩↩ -
Mesure de l’auteur,
measure_kiradex.pydans le même dossier, relancé le 5 octobre 2026, sortie identique àmeasure_kiradex.out. Il importeapp.lines,app.roomsetapp.npcsdepuis l’arbre de travail de la note 20 et litPlazaRig.swiftetPlazaClient.swift(note 50) pour les constantes du client : le nombre de répliques prédéfinies, la capacité des salles, les limites de fréquence, le tick, le délai de répétition, la taille de la place et le point d’arrivée, les itinéraires et longueurs de boucle des quatre collectionneurs, les vitesses de marche et de course, le seuil de saut de 6 pas et le délai de reconnexion. Ses 0,7 s et 36 % dérivés sont remplacés par la note 6. ↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩ -
Blake Crosley, « Pixel-Art Motion: Walks, Cameras and Doors on iPhone », blakecrosley.com, 5 octobre 2026, https://blakecrosley.com/blog/pixel-art-motion-on-iphone. Sa note 6 modélise la marche de l’app à 60 Hz exacts : la course prend 10 images par tuile, 6,00 tuiles par seconde, contre les 6,4 qu’impliquent 4 tuiles par seconde multipliées par le facteur de course de 1,6, et 6,32 à 120 Hz ; sa section sur le code actuel lit dans
walk(to:)le retour en arrière provoqué par un second appui à mi-pas, et son cahier des charges fixe la règle selon laquelle un pas en cours n’est jamais remis à zéro ; l’élément 1 de son cahier des charges fixe la marche à 16 ticks par tuile et la course à 8 à 60 Hz, 3,75 et 7,5 tuiles par seconde, le contrat de mouvement de la série, et ses vérifications journalisent la position du joueur à chaque tick avec un argument de lancement-motionLog. ↩↩↩↩↩↩↩ -
Kiradex,
docs/WORLD.md(« Kiradex World: research and plan »), arbre de travail au 5 octobre 2026 (SHA-256 c7714bc1), en lecture seule : section 2 (la voie de la catégorie Enfants et de 5.1.4, classement 9+ ou 12+), section 3 (identité Game Center, contrôles Screen Time, pas de compteurs d’abonnés, répliques prédéfinies, l’examen par un avocat), section 5 (le serveur tel que construit le 2 octobre : FastAPI et WebSockets, présence uniquement, rien de stocké, huit déplacements par seconde, masquage sur l’appareil, « Not yet » (pas encore) incluant le mode junior selon Declared Age Range ; et le raisonnement qui y a mené, avec des clients envoyant position et orientation à 8 à 10 Hz), et « Decisions taken (Blake, October 2, 2026) », éléments 6 (classement et tranches d’âge) et 8 (pas d’avocat tant que l’app n’a pas trouvé son public). ↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩ -
Recherche de l’auteur dans
Kiradex/etserver/app/de l’arbre de travail Kiradex, le 5 octobre 2026, portant surisMultiplayerGamingRestricted,isUnderage,isPersonalizedCommunicationRestricted, l’API Declared Age Range et tout stockage de visites ou de conversations quotidiennes : aucun résultat. ↩↩↩ -
pret,
pokeemerald/include/constants/event_object_movement.h, commit731ad5b, consulté le 4 octobre 2026, https://github.com/pret/pokeemerald/blob/master/include/constants/event_object_movement.h. ↩ -
Les figures ont été dessinées par
figures/make_figures.py, conservé à côté du brouillon de l’article, le 5 octobre 2026, à partir des sorties enregistrées demeasure_npcs.py,measure_npc_cadence.py,measure_chat_trend.py,measure_record_mixing.py,measure_kiradex.pyetmeasure_remote_walk.py; chaque valeur est extraite de ces fichiers et comparée à une valeur attendue avant d’être dessinée : celle du dossier de recherche, sauf pour la figure de population des villes, qui ne trace plus que les personnes issues dumeasure_npcs.pyrévisé, avec une ligne pour les 100 personnes sans drapeau de masquage, et pour les 940 mots ouverts du carnet de répliques, issus dumeasure_chat_trend.pyrévisé. Après l’examen par le second moteur, la figure de l’expression à la mode trace les scores du jeu lui-même par jours entiers issus dumeasure_chat_trend.pyrévisé (un point par jour écoulé, et non une onde triangulaire continue), et la figure du passage d’un marcheur trace lemeasure_remote_walk.pyrévisé : le rig actuel dans sa propre arithmétique 32 bits, et le tampon aux 3,75 et 7,5 tuiles par seconde du contrat de mouvement avec des délais de 100, 300, 325 et 350 ms. La figure du carnet de répliques est un schéma de la proposition du cahier des charges, ses chiffres de comparaison étant extraits de la même façon. Aucun graphisme de jeu, sprite ou rendu de carte n’est utilisé. ↩↩↩↩↩ -
pret,
pokeemerald/src/event_object_movement.c(IsCoordOutsideObjectEventMovementRange,sMovementDelaysMedium,sMovementDelaysShort,sMovementDelaysLongavec son commentaire// Unused, l’attente fixe de 48 images des deux types rotatifs,MovementType_WanderAround_Step4,GetWalkNormalMovementAction, les tablessStep), commit731ad5b, consulté le 4 octobre 2026, https://github.com/pret/pokeemerald/blob/master/src/event_object_movement.c. ↩↩↩↩↩ -
pret,
pokeemerald/include/constants/flags.h(DAILY_FLAGS_STARTet les 12 drapeaux quotidiens), commit731ad5b, consulté le 4 octobre 2026, https://github.com/pret/pokeemerald/blob/master/include/constants/flags.h. ↩ -
Stardew Valley Wiki, « Villagers », oldid 191346, modifiée le 26 février 2026, sauvegardée le 4 octobre 2026, https://stardewvalleywiki.com/Villagers. Les 34 villageois à qui l’on peut offrir des cadeaux sont un décompte des listes de la page (6 célibataires masculins, 6 célibataires féminines, 22 non-candidats au mariage) ; la page « Friendship » du wiki compte un autre ensemble de 28 habitants de départ. ↩
-
Stardew Valley Wiki, « Pierre », sauvegardé le 4 octobre 2026, https://stardewvalleywiki.com/Pierre. L’emploi du temps ordinaire, les six variantes et le courrier à tout niveau de cœur et à trois cœurs. ↩↩↩
-
Nookipedia, « Hobby », sauvegardé le 4 octobre 2026, https://nookipedia.com/wiki/Hobby. ↩
-
Nookipedia, « Villager », les sections par jeu, sauvegardé le 4 octobre 2026, https://nookipedia.com/wiki/Villager. ↩↩↩↩↩↩↩
-
Nookipedia, « Villager », section Personalities, sauvegardé le 4 octobre 2026, https://nookipedia.com/wiki/Villager#Personalities. ↩
-
pret,
pokeemerald/src/record_mixing.c(struct PlayerRecordEmerald,ReceiveOldManData,ReceiveDewfordTrendData), commit731ad5b, consulté le 4 octobre 2026, https://github.com/pret/pokeemerald/blob/master/src/record_mixing.c. ↩ -
pret,
pokeemerald/src/mauville_old_man.c(la sélectionswitch ((trainerId % 10) / 2)et son commentaire,ResetHipsterFlag,ResetMauvilleOldManFlag,SetHipsterTaughtWord),pokeemerald/src/record_mixing.c(l’unique appel àResetMauvilleOldManFlag, à la fin deReceiveOldManData), ainsi quepokeemerald/data/scripts/mauville_man.inc(setflag FLAG_UNLOCKED_TRENDY_SAYINGS,special HasHipsterTaughtWord) etpokeemerald/data/maps/MauvilleCity_PokemonCenter_1F/map.json(l’événement d’objet dont le script estMauvilleCity_PokemonCenter_1F_EventScript_MauvilleOldMan), commit731ad5b, lus par l’auteur les 4 et 5 octobre 2026, https://github.com/pret/pokeemerald/blob/master/src/mauville_old_man.c. Que le Hipster soit présent d’emblée dans les parties dont l’ID de dresseur se termine par 2 ou 3 est l’arithmétique de l’auteur sur leswitch. ↩↩↩↩↩↩ -
Blake Crosley, « Pixel-Art Worlds on iPhone: What the 16-Bit Masters Knew », blakecrosley.com, 3 octobre 2026 (FAQ juridique mise à jour le 4 octobre 2026), https://blakecrosley.com/blog/pixel-art-world-on-iphone. Il énonce la règle de l’expression à la mode comme une expression chaque fois que le mélange de données amène le Hipster, et sa FAQ juridique cite, avec ses propres sources, les trois brevets invoqués contre le développeur de Palworld (viser et lancer un objet de capture, un indicateur de probabilité de capture, monter sur un personnage chevauchable). ↩↩
-
pret,
pokeemerald/src/dewford_trend.c(le commentaire d’en-tête surtrendinessetmaxTrendinesset sur la sauvegarde des expressions), commit731ad5b, consulté le 4 octobre 2026, https://github.com/pret/pokeemerald/blob/master/src/dewford_trend.c. ↩↩↩↩ -
Mesure de l’auteur,
measure_chat_trend.pydans le même dossier, révisé et relancé le 5 octobre 2026, sortie enregistrée sousmeasure_chat_trend.out. La révision retranche des mots ouverts les entrées marquées.enabled = FALSE(946 entrées, 940 activées), affiche la lignenumEnabledWordsdu groupe Dresseur danseasy_chat_groups.h(« Excludes Red, Green, Flame, Gold, Leaf, and Silver », exclut Red, Green, Flame, Gold, Leaf et Silver), et affiche la règle par entrée deIsEasyChatIndexAndGroupUnlocked, selon laquelle un nom de la liste de 202 entrées ne s’ouvre qu’une fois son espèce vue ; la version précédente et sa sortie sont conservées avec un suffixe.r1. Entrées : pretpokeemerald731ad5bsrc/data/easy_chat/(taille des groupes, entrées désactivées,numEnabledWords),src/easy_chat.c(leswitchde déblocage des groupes, la règle par entrée et les grilles de phrases),include/constants/global.h(MAIL_WORDS_COUNT,NUM_QUESTIONNAIRE_WORDS,SAVED_TRENDS_COUNT), etsrc/dewford_trend.c(SeedTrendRnget le pas quotidien). Une seconde révision, après l’examen par le second moteur (la version précédente et sa sortie conservées avec un suffixe.pre-astra), qualifie la distribution des pics d’approximation uniforme indépendante : elle est calculée à partir des trois tiragesRandom() % 98imbriqués, chacun pris comme un tirage uniforme indépendant sur 0 à 97. Elle ajoute la même distribution avec les poids du modulo sur 16 bits (Random()danssrc/random.crenvoie les 16 bits de poids fort, si bien que les restes compris entre 0 et 71 apparaissent 669 fois sur 65 536, et ceux compris entre 72 et 97 apparaissent 668 fois), ce qui donne une moyenne de 62,89 et 81,34 % à 80 ou moins, contre 62,90 et 81,33 %, toujours en supposant des tirages indépendants ; et elle transposeUpdateDewfordTrendPerDayavec un jour écoulé par appel, depuis un score de 0 en hausse, qui revient pour la première fois à cet état après 12, 128 et 254 jours pour les pics 30, 64 et 127 (la même longueur de cycle depuis chaque état de départ atteignable). Les durées de montée et de descente de 12, 25,6 et 50,8 jours valent deux fois le pic divisé par 5, une approximation continue. ↩↩↩↩↩↩↩↩↩↩↩↩ -
pret,
pokeemerald/src/union_room_chat.c,pokeemerald/include/union_room.hetpokeemerald/include/constants/global.h, commit731ad5b, consulté le 4 octobre 2026, https://github.com/pret/pokeemerald/blob/master/src/union_room_chat.c. La lecture expliquant pourquoi le chat tapé y était tolérable est celle de l’auteur. ↩ -
pret,
pokeemerald/src/easy_chat.cetpokeemerald/src/data/easy_chat/, commit731ad5b, consulté le 4 octobre 2026, https://github.com/pret/pokeemerald/blob/master/src/easy_chat.c et https://github.com/pret/pokeemerald/tree/master/src/data/easy_chat. ↩↩↩↩ -
Wikipedia, « Dark Souls (video game) », sections Multiplayer (citant sa source [5]) et Awards, sauvegardé le 4 octobre 2026, https://en.wikipedia.org/wiki/Dark_Souls_(video_game). ↩↩↩↩↩↩
-
Bandai Namco Entertainment Europe, « Dark Souls Remastered », Key features, sauvegardé le 5 octobre 2026, https://en.bandainamcoent.eu/dark-souls/dark-souls-remastered. La page de Bandai Namco America a été sauvegardée sous forme de coquille de script de 127 octets de texte ; la description de FromSoftware elle-même n’a pas pu être consultée. ↩
-
PlayStation, « Death Stranding », section « Unique social strand gameplay », sauvegardé le 4 octobre 2026, https://www.playstation.com/en-us/games/death-stranding/. ↩
-
Wikipedia, « Splatoon (video game) », sections Gameplay et Multiplayer, citant ses propres sources, sauvegardé le 4 octobre 2026, https://en.wikipedia.org/wiki/Splatoon_(video_game). Les pages Splatoon de Nintendo elle-même n’ont pas été consultées. ↩↩
-
The Pokémon Company International, pages de jeu de pokemon.com pour « Pokémon Black Version 2 and Pokémon White Version 2 » et « Pokémon Sun and Pokémon Moon », sauvegardées le 4 octobre 2026, https://www.pokemon.com/us/pokemon-video-games/pokemon-black-version-2-and-pokemon-white-version-2 et https://www.pokemon.com/us/pokemon-video-games/pokemon-sun-and-pokemon-moon ; aucune ne mentionne Join Avenue ou Festival Plaza. Bulbapedia n’a pas été essayé. ↩
-
Serebii.net, « Festival Plaza », section Pokémon Sun and Moon, sauvegardé le 4 octobre 2026, https://www.serebii.net/sunmoon/festivalplaza.shtml. Un site de fans, et la seule source utilisée pour cette fonctionnalité. ↩↩
-
Serebii.net, « Gyms », section Pokémon GO, sauvegardé le 4 octobre 2026, https://www.serebii.net/pokemongo/gyms.shtml. Un site de fans, et la seule source utilisée pour cette fonctionnalité. ↩↩
-
Solero, Houdini, un émulateur open source du serveur de Club Penguin écrit par des fans,
houdini/handlers/play/player.py(les gestionnairessp,ss,sj,sma,sl,sgetse, leurs délais,server_heartbeat, qui relève l’heure, dort 61 secondes et ferme chaque client dont le dernier heartbeat est antérieur à cette heure (if penguin.heartbeat < timer: await penguin.close(), lu dans le HTML sauvegardé ; l’extraction de texte sauvegardée déforme cette ligne), etserver_egg_timer, qui décompte chaque minute les minutes autorisées d’un joueur, avertit à 7 et à 5, et déconnecte à zéro), sauvegardé le 4 octobre 2026, https://github.com/solero/houdini/blob/master/houdini/handlers/play/player.py. Des éléments sur ce qu’attendait le client d’origine, pas un comportement publié par Disney. ↩↩↩↩↩↩↩ -
billsonnn, Nitro renderer, un client Habbo open source écrit par des fans,
src/nitro/room/object/logic/MovingObjectLogic.ts(DEFAULT_UPDATE_INTERVAL = 500et l’interpolation linéaire dansupdate), sauvegardé le 4 octobre 2026, https://github.com/billsonnn/nitro-renderer/blob/main/src/nitro/room/object/logic/MovingObjectLogic.ts. ↩↩↩ -
Lecture par l’auteur du dépôt Kiradex (privé), arbre de travail au 5 octobre 2026, en lecture seule :
Kiradex/World/PlazaRig.swift(SHA-256 819cd8d6 ;progressen tant queFloatà la ligne 29,tilesPerSecondà la ligne 101,move(other:to:facing:)aux lignes 526 à 542,runningdéfini uniquement pour le joueur à la ligne 614,advance()aux lignes 652 à 672,place()et son arrondi au pixel aux lignes 722 à 727, la listeidleEmotesavecdoze),Kiradex/World/TileMap.swift(db4272c2 ;tileSizede 16 à la ligne 60 etcentreà la ligne 235),Kiradex/World/PlazaClient.swift(5c491933 ; le délai de reconnexion à la ligne 165),Kiradex/World/PlazaStage.swift(8b4850af ; la phase de lumière du jour appliquée à la place, etrig.update(Float(event.deltaTime))à la ligne 149) etKiradex/World/Daylight.swift(536350dc ;Daylight.Phaseet ses plages horaires, etDaylight.now, qui prend l’heure deCalendar.current, le calendrier et le fuseau propres à l’appareil). Les horloges du serveur ont été examinées le même jour :server/app/main.pyetserver/app/rooms.pyutilisenttime.monotonic(), et rien dansserver/appne nomme de fuseau horaire. ↩↩↩↩↩↩↩↩↩ -
Apple Developer Documentation,
GKLocalPlayer.isPersonalizedCommunicationRestricted(iOS 14.0+), le JSON de documentation sauvegardé le 4 octobre 2026, https://developer.apple.com/documentation/gamekit/gklocalplayer/ispersonalizedcommunicationrestricted. Aplati pour la citation comme dans la note 18. Que les répliques prédéfinies propres à un jeu fassent partie des « custom communication features » (fonctionnalités de communication personnalisées) que la page demande à un jeu de désactiver, et que les emotes n’en fassent pas partie, sont des lectures de l’auteur. ↩↩↩↩↩↩↩↩ -
Apple Developer Documentation,
GKLocalPlayer.isUnderage(iOS 4.1+), le JSON de documentation sauvegardé le 4 octobre 2026, https://developer.apple.com/documentation/gamekit/gklocalplayer/isunderage. Aplati pour la citation comme dans la note 18. ↩↩↩↩ -
Assistance Apple, « Set up parental controls to manage your child’s iPhone or iPad », section « Set restrictions for Game Center », sauvegardé le 4 octobre 2026, https://support.apple.com/en-us/105121. ↩
-
Apple Newsroom, « Apple expands tools to help parents protect kids and teens online », 11 juin 2025, sauvegardé le 4 octobre 2026, https://www.apple.com/newsroom/2025/06/apple-expands-tools-to-help-parents-protect-kids-and-teens-online/. ↩↩↩
-
Apple, « App Review Guidelines », dernière mise à jour le 8 juin 2026, directives 1.2, 1.3 et 5.1.4, sauvegardé le 4 octobre 2026, https://developer.apple.com/app-store/review/guidelines/. ↩↩↩↩↩↩↩↩
-
Federal Trade Commission, « FTC Finalizes Changes to Children’s Privacy Rule Limiting Companies’ Ability to Monetize Kids’ Data », communiqué de presse, 16 janvier 2025, sauvegardé le 4 octobre 2026, https://www.ftc.gov/news-events/news/press-releases/2025/01/ftc-finalizes-changes-childrens-privacy-rule-limiting-companies-ability-monetize-kids-data. ↩
-
Lecture par l’auteur de la commande de démarrage du serveur Kiradex et du serveur web qu’elle lance, le 5 octobre 2026, en lecture seule :
server/Procfile(SHA-256 2e883a7e) etserver/railway.toml(17f8a3ba) démarrentuvicorn app.main:appavec--proxy-headers --forwarded-allow-ips='*'et aucune option de journalisation ;server/requirements.txt(71c30c3b) figeuvicorn[standard]==0.37.0. Dans cette version telle qu’installée dans l’environnement du serveur,uvicorn/config.py(379e9baf) metaccess_logà true par défaut ;uvicorn/protocols/http/httptools_impl.py(b6e4010a) eth11_impl.py(e1bf8ab3) journalisent alorsget_client_addr(self.scope)pour chaque requête ; etuvicorn/protocols/websockets/websockets_impl.py(029977b2) journalise'%s - "WebSocket %s" [accepted]'avec l’adresse du client au niveau INFO sur le loggeruvicorn.error, que--log-level warningrend muet. Une lecture du code ; aucun serveur n’a été lancé et aucun journal déployé n’a été consulté. ↩↩ -
Blake Crosley, « Pixel-Art People: Characters and a Creator on iPhone », blakecrosley.com, 3 octobre 2026, section 4 (les règles de PEGI) et sections 6 et 7 (la chaîne de silhouette, le manifeste et la forge qui dessine chaque silhouette), https://blakecrosley.com/blog/pixel-art-characters-on-iphone. ↩↩↩
-
PEGI, « What do the labels mean? », consulté le 3 octobre 2026, https://pegi.info/what-do-the-labels-mean, cité d’après l’article sur les personnages (note 58) ; non consulté de nouveau pour cet article. ↩↩↩