← Todos los artículos

Un pueblo de pixel art vivo sin nadie conectado: NPC y fantasmas

Un pueblo de pixel art se siente habitado sobre todo gracias a la gente que se queda quieta. En los 16 pueblos y ciudades de Pokémon Esmeralda, los 100 vecinos que no llevan flag de ocultación, y que por tanto están ahí en cada visita, se reparten así: 59 de pie en su puesto, mirando hacia un lado o mirando a su alrededor, 39 deambulando dentro de un recuadro a una o dos celdas de donde se los colocó, y 2 caminando en el sitio; si se suman los 58 que un flag de la historia puede retirar, en su mayoría miembros de un equipo, rivales y personajes con nombre, 54 de ellos de pie, el reparto queda en 113 de 158 (71,5 %), 43 (27,2 %) y 2. Un vecino que deambula da un paso de 16 fotogramas y luego espera 32, 64, 96 o 128, así que está en movimiento como mucho entre un 11 y un 33 por ciento del tiempo.1 El día se ajusta cuando el jugador vuelve, mediante una función que se ejecuta una sola vez con el número de días transcurridos, no con un reloj que corre mientras nadie juega.23 Cuando no hay nadie más, el canon llena el pueblo con los rastros de otras personas en ranuras pequeñas y fijas (el mezclado de datos de Esmeralda copia en tu partida 20 Bases Secretas, 5 frases de moda y el anciano de otro jugador) y deja que los desconocidos compartan presencia sin compartir palabras.45 Medí todo eso porque mi propio pueblo, Kiradex World, tiene que responder la misma pregunta en su primera mañana tranquila, y el propio código de su servidor, ejecutado sobre un reloj simulado, la responde mal en tres puntos: sus cuatro coleccionistas se detienen cuando la sala está vacía, dan un paso por segundo frente a los 0,7 segundos configurados y se quedan quietos el 75 por ciento de cada caminata, y, en un modelo del propio código de dibujo de la app, otro coleccionista aparece dibujado saltando hacia atrás cuando un movimiento llega a mitad de paso: en 45 de los 64 movimientos de una carrera, y en 7 y 16 fotogramas de una caminata de 40 tiles con 30 y 80 ms de jitter de red, aunque nunca en una caminata constante sin jitter.67 Esto es el canon medido, las referencias modernas, la presencia en vivo con sus números, las reglas para un mundo en el que puede haber niños, y el encargo.

Lo esencial

  • La mayor parte de un pueblo está de pie. Seis de cada diez de las 100 personas de los pueblos y ciudades de Esmeralda que no llevan flag de ocultación tienen tipos de movimiento por defecto estacionarios, y siete de cada diez de las 158 en total una vez que se cuentan las 58 que la historia puede retirar (un script de la historia todavía puede hacer caminar a una, como el niño del gimnasio de Petalburg, que lleva al jugador hasta el gimnasio); casi todas las demás deambulan dentro de recuadros de una o dos celdas al mismo ritmo que el jugador, 16 fotogramas (268 ms) por celda, y esperan entre 0,54 y 2,14 segundos entre pasos. Littleroot tiene 6 personas, Petalburg 7 y Mauville 10, de las cuales 2, 3 y 6 no llevan flag de ocultación.18
  • Una rutina son unos pocos puntos con hora y una clave; una memoria es un flag al día. Stardew Valley escribe el día de un aldeano como una cadena de puntos con hora (el día normal de Pierre tiene 7) y elige qué día se aplica entre 22 formatos de clave agrupados en tres, y gana la primera coincidencia: una clave especial que se comprueba para todos, después 5 formatos de matrimonio para un aldeano casado, que no usa ningún otro, o 16 normales para todos los demás; hablar con un aldeano una vez al día vale +20 de amistad. New Horizons da +1 sobre 255 por la primera conversación del día y enseña un gesto al día.29101112
  • Los rastros de otras personas llenan un pueblo vacío, en ranuras fijas, y se desgastan. El mezclado de datos de Esmeralda transporta 5.188 bytes del mundo de otro jugador; en la Avenida Unión, los fans ocupan las ranuras de tienda que los visitantes reales dejan vacías y valen el 75 % de un visitante (según el relato de Serebii); las estructuras de Death Stranding quedan «destroyed by Timefall after some time» (destruidas por el Timefall al cabo de un tiempo); Journey muestra a un desconocido cada vez, sin nombres hasta los créditos y con un solo tañido.413145
  • La presencia en vivo es un búfer, no una frecuencia de envío. El emulador de servidor de Habbo hecho por fans avanza cada sala en un ciclo de 500 ms; Gaffer on Games almacena en búfer «3X the packet send rate» (tres veces el intervalo de envío de paquetes); en un modelo de la caminata de Kiradex a los 3,75 y 7,5 tiles por segundo de la serie, dibujar a los demás coleccionistas con un reloj 350 ms por detrás del tiempo estimado del servidor da 0 fotogramas hacia atrás y 0 fotogramas sin datos con hasta 80 ms de jitter, mientras que con 100 ms se quedan sin datos entre 125 y 456 de los 600 fotogramas dibujados mientras el emisor está enviando.15167
  • Las reglas para niños tienen fechas. Game Center limita a los niños «to sending and receiving preset messages» (a enviar y recibir mensajes predefinidos); la documentación de Apple dice que un juego con una función multijugador propia «should disable it» (debería desactivarla) cuando Screen Time restringe el multijugador; la regla COPPA enmendada, de cumplimiento obligatorio desde el 22 de abril de 2026, exige una política escrita de retención de datos con un plazo de eliminación.171819
  • El Kiradex de hoy se aparta de su propio plan en cuatro puntos. Los coleccionistas de la plaza se detienen cuando no hay nadie en la sala, aunque server/app/npcs.py diga «A town is never empty» (un pueblo nunca está vacío); dan un paso cada 1,0 s frente a los 0,7 s configurados; la app envía un movimiento por tile (4 por segundo al caminar, entre 6,0 y 6,4 al correr) donde el razonamiento del plan hablaba de 8 a 10 Hz; y nada lee los flags de restricción de Game Center, aunque el plan construye la identidad y el control parental sobre Game Center.62021222324
  • Lo que esto le da a Kiradex. Un encargo con ocho vecinos cuyas rutinas se rigen por las franjas del día propias de la app, sobre un único reloj por sala y con posiciones calculadas a partir de ese reloj; las caminatas de los últimos ocho visitantes reproducidas como ecos sin nombre, con una figura neutra que elige el servidor, conservadas siete días y enviadas sin id; un saludo una vez al día que nunca se desgasta; un búfer de renderizado de 350 ms; un libro de frases de seis ramas con entre 8 y 12 frases completas cada una; y siete ajustes de seguridad, cada uno con una comprobación que un script, una prueba o una captura pueden aprobar o suspender.7119

1. Los vecinos, medidos: Esmeralda, Stardew Valley y Animal Crossing

Todo mundo social pequeño se topa con la misma pregunta en su primera noche: ¿qué ve un jugador cuando entra en la plaza y no hay nadie más? El canon tiene tres respuestas, y este artículo las recorre por orden. La primera son vecinos que llevan su propia vida, de modo que el pueblo está animado haya o no alguien conectado. La segunda son rastros de otras personas, dejados por jugadores que ahora no están. La tercera es la presencia en vivo bien hecha cuando sí hay gente, acotada por las reglas para un mundo en el que puede haber niños. La primera respuesta es la más antigua y la mejor medida, porque el código fuente de uno de sus maestros es público.

Qué hace la gente de Esmeralda

Pokémon Esmeralda se leyó a partir de la descompilación de pret, un clon superficial de pokeemerald en el commit 731ad5b, y se contó con un script, measure_npcs.py, que lee las constantes de tipo de movimiento y los eventos de objeto de cada mapa de pueblo y de ciudad.1 Esmeralda define 81 tipos de movimiento, de 0x00 a 0x50. Agrupados según lo que hace la persona en pantalla, 24 recorren un circuito fijo de cuatro tramos, 17 se quedan de pie mirando (en una dirección fija, alternando o mirando alrededor), 16 caminan, trotan o corren en el sitio, 8 copian al jugador, 5 deambulan al azar dentro de un rango, 4 van y vienen, 4 están ocultos o disfrazados, y los tres últimos son NONE, el jugador y el árbol de bayas, que es un objeto y no una persona.125

Los pueblos usan pocos de ellos. En los 16 mapas de pueblos y ciudades hay 172 eventos de objeto, y no todos son personas: 6 son objetos en Poké Ball, 2 son camiones de mudanza, 1 es un barco y 5 son criaturas. El script los clasifica por su graphics_id y cuenta por separado a las 158 personas.18 Solo 11 de los 81 tipos de movimiento aparecen entre las personas. 113 de las 158 (71,5 %) se quedan de pie mirando, 43 (27,2 %) deambulan dentro de un rango y 2 (1,3 %) caminan en el sitio. Los tipos individuales más comunes son FACE_DOWN con 32, FACE_RIGHT con 23, LOOK_AROUND con 20, FACE_UP con 19 y WANDER_AROUND con 17.18

Esas 158 no son todas residentes. 58 de ellas llevan un flag de ocultación, un flag de la historia que las retira del mapa, y 41 de esas 58 usan el sprite de un equipo villano, el del rival o el de un personaje con nombre, así que las 58 son sobre todo actores de las escenas de la historia; 54 de ellas están de pie. Las 100 personas sin flag de ocultación, las que están en el mapa en cada visita, se reparten de otra manera: 59 de pie mirando, 39 deambulando dentro de un rango y 2 caminando en el sitio. Así que los residentes que un jugador ve casi siempre son seis de cada diez de pie y casi cuatro de cada diez deambulando; los siete de cada diez del recuento total salen de sumar a los actores, que casi todos están de pie. Son tipos de movimiento por defecto, lo que hace una persona cuando ningún script la está moviendo; un script de la historia puede hacer caminar a una persona que está de pie, como el niño del gimnasio de Petalburg, que por defecto mira a su alrededor y no lleva flag de ocultación, y que lleva al jugador hasta el gimnasio. El recuento describe el pueblo en reposo, no cada escena que ocurre en él.18

Un gráfico de barras apiladas de las personas entre los eventos de objeto de los pueblos de Esmeralda, por tipo de movimiento. Los 16 pueblos y ciudades, 158 personas: 113 de pie mirando (71,5 por ciento), 43 deambulan en un recuadro (27,2 por ciento), 2 caminan en el sitio. Las 100 sin flag de ocultación: 59 de pie (59 por ciento), 39 deambulan (39 por ciento), 2 caminan en el sitio. Littleroot, 6 personas: 3 de pie, 3 deambulan. Petalburg, 7: 5 de pie, 2 deambulan. Mauville, 10: 8 de pie, 2 deambulan.

Seis de cada diez de los vecinos que siempre están en los mapas de Esmeralda tienen un tipo de movimiento por defecto estacionario, y siete de cada diez una vez que se cuentan los actores que la historia puede retirar; los que deambulan se mantienen en recuadros de una o dos celdas. Las escenas con script, que pueden hacer caminar a cualquiera, no se cuentan.26

Tres pueblos de tamaños distintos muestran la misma forma. La tabla cuenta solo personas; los eventos de objeto que quedan fuera son los dos camiones de Littleroot y tres objetos en Poké Ball, dos en Petalburg y uno en Mauville. La última columna cuenta a las personas sin flag de ocultación, según lo que hacen.1

Pueblo Personas De pie mirando Deambulan dentro de un recuadro Rangos de deambulación (x, y) Con flag de ocultación Sin flag de ocultación (de pie, deambulan)
Littleroot 6 3 (miran arriba) 3 (WANDER_AROUND) (1, 2), (2, 1), (2, 1) 4 2 (0, 2)
Petalburg 7 5 (2 miran alrededor, 2 miran arriba, 1 mira abajo) 2 (1 alrededor, 1 arriba y abajo) (1, 1), (0, 1) 4 3 (2, 1)
Mauville 10 8 (2 miran alrededor, 2 miran arriba, 2 miran a la izquierda, 1 mira a la derecha, 1 mira abajo) 2 (izquierda y derecha) (1, 1), (1, 0) 4 6 (4, 2)

El recuadro de quien deambula se impone celda a celda: antes de cada paso, IsCoordOutsideObjectEventMovementRange rechaza cualquier destino que quede fuera del rango del objeto respecto del punto donde se lo colocó, así que quien deambula orbita su celda de origen en lugar de desplazarse.27 Los flags de ocultación son la otra mitad de la población. Cuatro de las 6 personas de Littleroot, cuatro de las 7 de Petalburg y cuatro de las 10 de Mauville llevan un flag que las retira cuando la historia avanza, así que la población de un pueblo es una función del progreso del jugador: la gente se va y llega porque algo ha pasado.1

Con qué frecuencia se mueven

La temporización está en el mismo archivo. Un vecino que deambula o que mira a su alrededor espera 32, 64, 96 o 128 fotogramas, elegidos al azar de sMovementDelaysMedium, antes de su siguiente paso o giro: 0,54, 1,07, 1,61 o 2,14 segundos a los 59,7275 Hz de la Game Boy Advance, con una media de 1,34. Lo mismo hacen los dos tipos de mirada que alternan entre direcciones opuestas, FACE_DOWN_AND_UP y FACE_LEFT_AND_RIGHT. Los tipos de mirada que alternan entre dos direcciones contiguas o entre tres eligen de sMovementDelaysShort, 32, 48, 64 u 80 fotogramas, con una media de 0,94 segundos, y los dos tipos que rotan esperan 48 fotogramas fijos. Una tercera tabla, sMovementDelaysLong, está marcada como // Unused en el código fuente, y ningún tipo de movimiento la lee.127

El paso en sí es el del jugador. PlayerWalkNormal llama a GetWalkNormalMovementAction, la misma acción que usa el paso de quien deambula; MOVE_SPEED_NORMAL corresponde a sStep1Funcs, que mueve 1 pixel por fotograma durante 16 fotogramas, una celda de 16 pixeles en 268 ms, 3,73 celdas por segundo. Correr es MOVE_SPEED_FAST_1, sStep2Funcs, 8 fotogramas por celda, 134 ms, 7,47 celdas por segundo.127 Si se juntan las dos filas, quien deambula está en movimiento 268 ms de cada paso más una espera, es decir, de cada 0,81 a 2,41 segundos: entre un 11 y un 33 por ciento del tiempo, por paso dado. Es una cota superior. Cuando la dirección que elige está bloqueada, por una pared o por el borde de su recuadro, MovementType_WanderAround_Step4 lo devuelve a mirar y esperar otra vez sin moverse, así que su proporción real de tiempo en movimiento es menor. El resto del tiempo está de pie, o se gira.127

Un gráfico de línea de tiempo de seis segundos. Cuatro filas de un vecino de Esmeralda que deambula, una por cada duración de espera: con una espera de 32 fotogramas está en movimiento el 33 por ciento del tiempo, con 64 fotogramas el 20 por ciento, con 96 fotogramas el 14 por ciento, con 128 fotogramas el 11 por ciento. Una quinta fila, un coleccionista de Kiradex en un tramo de caminata, se mueve 250 ms de cada 1,0 s, el 25 por ciento.

Un vecino de Esmeralda que deambula se mueve a pasos sueltos entre esperas largas; los coleccionistas de Kiradex, medidos en la sección 6, se mueven a ráfagas de un tile mientras se supone que están caminando.26

Según mi lectura, tres detalles sostienen el efecto. Nada en el pueblo camina más rápido ni más despacio que tú, así que nada parece ser de otra naturaleza. Las pausas son más largas que los pasos, así que el pueblo es una sucesión de quietud puntuada por movimiento, y por eso nunca parece abarrotado con 6 a 10 personas dentro. Y la población está escrita en la historia mediante los flags de ocultación, así que el pueblo cambia porque el jugador hizo algo, no porque saltó un temporizador.

En Esmeralda, el día se ajusta a la llegada

Esmeralda lleva la cuenta de los días, pero no con un reloj que corre mientras nadie juega. Reserva 64 ranuras de flags diarios a partir de DAILY_FLAGS_START y usa 12: nueve regalos de bayas (el de un vestíbulo de concursos, el del Maestro de las Bayas y el de su mujer, los de cinco personas en rutas o pueblos, el de la floristería), el flag diario de la Base Secreta, el billete de lotería y FLAG_DAILY_APPRENTICE_LEAVES.228 Cuando el jugador vuelve, UpdatePerDay se ejecuta una vez con el número de días que han pasado, y también se ejecuta desde DoTimeBasedEvents durante la partida; llama, por orden, a ClearDailyFlags, UpdateDewfordTrendPerDay, UpdateTVShowsPerDay, UpdateWeatherPerDay, UpdatePartyPokerusTime, UpdateMirageRnd, UpdateBirchState, UpdateFrontierManiac, UpdateFrontierGambler, SetShoalItemFlag y SetRandomLotteryNumber.23 La moda, la televisión y el tiempo atmosférico avanzan todos según los días transcurridos, calculados en el momento del regreso.3 No pasó nada mientras el cartucho estaba apagado; el pueblo se comporta como si hubiera pasado.

Stardew Valley: un horario es una cadena

Stardew Valley es la referencia moderna de vecinos con vida propia. La página «Villagers» de su wiki enumera 6 solteros, 6 solteras, 22 aldeanos con los que no es posible casarse y 12 a los que no se les pueden dar regalos, es decir, 34 aldeanos que aceptan regalos, y dice «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» (cada aldeano tiene una rutina diaria, así que se lo puede encontrar en distintas zonas del pueblo según la hora del día dentro del juego y el tiempo).229

La rutina son datos. Cada aldeano tiene un archivo en Content/Characters/schedules/, y cada entrada es una cadena de puntos separados por barras, cada punto <time> [location] <tileX> <tileY> [facing] [animation] [dialogue], con la hora en formato de 24 horas sin dos puntos y la orientación 0 para arriba, 1 derecha, 2 abajo y 3 izquierda.9 El miércoles de Abigail, tal como lo da la página, es 1000 ArchaeologyHouse 11 9 0/1800 Town 47 87 0/2200 SeedShop 1 9 3 abigail_sleep: tres puntos, una caminata entre cada uno y una animación en el último.9 Pierre, que lleva el almacén general, tiene 7 puntos con hora en un día normal (6:00 AM en su mostrador, 7:00 AM en los pasillos, 8:30 AM de nuevo en el mostrador, y luego 5:00 PM, 7:00 PM, 9:00 PM y 11:00 PM entre los pasillos, la cocina, una estantería y la cama), y su página enumera 6 variantes de su horario: la lluvia verde, el autobús restaurado el 15 de primavera, el Festival del Desierto, la lluvia, el viernes y el día normal.230

La inteligencia está en las claves. Qué horario se aplica un día dado lo deciden 22 formatos de clave en tres grupos, cada uno probado en un orden fijo, y gana la primera coincidencia. Una clave especial, GreenRain, se comprueba «checked first, regardless of marriage status» (primero, sea cual sea el estado civil). Un aldeano casado prueba después solo los 5 formatos de matrimonio, desde marriage_<festivalID> pasando por una fecha, marriageJob y el día de la semana: «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» (los NPC casados no usan ninguna otra clave de horario; si las claves de matrimonio no coinciden, ese día no tendrán horario). Todos los demás aldeanos prueban los 16 formatos normales, desde <festivalID>, <season>_<dayofmonth>, <dayofmonth>_<hearts>, <dayofmonth>, bus, rain2 (con una «50% chance of applying on rainy days», un 50 % de probabilidad de aplicarse en días de lluvia) y rain, pasando por las claves de día de la semana y corazones y el día de la semana, hasta <season>, spring y por último default.29 Así que, según mi lectura, un aldeano tiene muchos días posibles, los mismos pocos puntos se recombinan en una vida, y las claves de corazones hacen que un aldeano al que le caes bien tenga un día distinto. La propia nota de la página sobre limitaciones dice cómo se calcula el día: cuando se añade un NPC a una partida guardada existente, «they generally don’t follow their schedule correctly until you’ve slept once in-game (which triggers their first day update)» (por lo general no siguen bien su horario hasta que has dormido una vez dentro del juego, lo que desencadena su primera actualización de día).9 Igual que en Esmeralda, el día de Stardew se calcula en el límite del día, no avanza de forma continua.

La amistad es la memoria diaria, y tiene un coste. Un corazón son 250 puntos; «talking to them once per day (+20)» (hablar con ellos una vez al día, +20) es el primer punto de la lista de la wiki sobre cómo subirla; un aldeano acepta un regalo al día y dos a la semana, con el regalo de cumpleaños multiplicado por 8; y no hablarle cuesta puntos cada día, 2 para la mayoría de los aldeanos y 10 después de un ramo, hasta que el medidor está lleno o llega a su tope, y 20 para el cónyuge, cuyo desgaste nunca se detiene.10 Los eventos de corazón, las escenas con script, se abren en umbrales de corazones, y «most events can be viewed anytime (with some time restrictions) or out of order» (la mayoría de los eventos se pueden ver en cualquier momento, con algunas restricciones horarias, o fuera de orden).10 El aldeano también actúa sobre ti mientras no estás: con 3 corazones, Pierre «will send you a recipe in the mail» (te enviará una receta por correo), y con cualquier nivel por encima de cero puede enviarte 250 g o más.30

Animal Crossing: el vecino que sabe que pasaste

New Horizons reduce a un único punto al vecino que sabe que hoy hablaste con él. La amistad va de 0 a 255 y empieza en 25; lo primero de la lista de Nookipedia sobre qué la sube es «+1 point» (+1 punto) por «speaking to the villager for the first time each day» (hablar con el vecino por primera vez cada día); un vecino acepta un regalo al día; y con 150 puntos un vecino tiene un 6 % de probabilidad de darte su foto a cambio de un regalo, que sube un 0,04 % por punto hasta el 10,2 % con 255.11 Según mi lectura, es un flag más que un medidor, porque el jugador nunca lo ve moverse.

La vida visible de los vecinos es pequeña y propia. Cada uno tiene una de seis aficiones (Education, Fashion, Fitness, Music, Nature, Play: educación, moda, ejercicio, música, naturaleza y juego), y en New Horizons «a villager always has one hobby that doesn’t change» (un vecino siempre tiene una afición que no cambia); los vecinos persiguen insectos y peces pero «still will not catch either of them» (aun así no atrapan ninguno de los dos), hacen ejercicio, leen y cantan al ritmo de un reproductor de música cercano, y desde la actualización 2.0 «invite the player to their house, ask the player for an invitation» (invitan al jugador a su casa, le piden una invitación) o se presentan para «a random visit» (una visita al azar).3132 Ocho personalidades dan forma a lo que dicen, cuatro para los vecinos (perezoso, atlético, gruñón y presumido) y cuatro para las vecinas (normal, alegre, esnob y hermana mayor), de las cuales «Smug and big sister were introduced in New Leaf, with the other six being present since Doubutsu no Mori» (presumido y hermana mayor se introdujeron en New Leaf; las otras seis existen desde Doubutsu no Mori).33

Los pueblos siguieron siendo pequeños a lo largo de la serie.32

Juego Vecinos al empezar Máximo de vecinos
Animal Crossing 6 15
Wild World 3 8
City Folk 6 10
New Leaf 5 10
New Horizons 2 (uno atlético y una hermana mayor, entre 83 posibles) 10

Wild World también cambió el ritmo: allí «the villagers walk at a much slower pace than the player» (los vecinos caminan a un ritmo mucho más lento que el jugador), algo que City Folk mantuvo.32 Es lo contrario de la regla de Esmeralda, y según mi lectura las dos funcionan por la misma razón: un vecino que pasea despacio se lee como residente, y un vecino que da pasos a tu ritmo y luego espera también. Lo que rompe el efecto es alguien que no se mueve a ninguno de los dos ritmos, que es el problema de Kiradex de la sección 6.

La expresión predefinida de la serie es el gesto (Reaction), y es en sí un regalo de los vecinos con una ración diaria. New Horizons tenía 44 gestos en la 1.0.0 y 44 más con la 2.0, 88 en total, y «The player can learn one Reaction per day» (el jugador puede aprender un gesto al día), algunos solo de ciertas personalidades o con una amistad alta.212

2. Los rastros de otras personas: qué llena un pueblo cuando nadie está conectado

Los vecinos mantienen animado un pueblo, pero son las mismas personas todos los días. La segunda respuesta es aquella a la que recurrió cada juego estudiado cuando le preocupaba un mundo vacío: llenarlo de rastros de personas reales, dejados por jugadores que no necesitan estar conectados ahora. Esmeralda lo hizo con un cable link.

El mezclado de datos: el mundo de otro jugador, en ranuras fijas

Cuando dos jugadores de Esmeralda mezclan datos (record mixing), cada partida le envía a la otra una estructura fija, PlayerRecordEmerald, con 11 tipos de registro en 0x1444 bytes, 5.188 en total.434 Las cifras que importan para la sensación de que otros estuvieron aquí son las ranuras: 20 Bases Secretas, 25 ranuras de televisión (5 normales y 20 más), 16 noticias, 5 frases de moda y 2 aprendices de los 4 que guarda una partida.4 Según mi lectura, ese es el sentido de las ranuras: tu pueblo cambió porque otra persona había jugado, con las bases de un amigo, sus programas y su frase trasladados a tu partida.

El caso más limpio es una sola persona. El Centro Pokémon de Mauville alberga a un anciano (Old Man), que es uno de cinco (el Bardo, el Hipster, el Comerciante, el Cuentacuentos y el Giddy). Cuál le toca a una partida nueva lo decide (trainerId % 10) / 2, con el propio comentario del código «Determine man based on the last digit of the player’s trainer ID» (decidir el hombre según el último dígito del ID de entrenador del jugador), y cuando se mezclan datos, ReceiveOldManData copia el anciano del compañero sobre el tuyo.435 El residente de tu pueblo es, literalmente, el vecino de otro jugador.

El Hipster raciona el vocabulario por contacto. Su script activa FLAG_UNLOCKED_TRENDY_SAYINGS y enseña una palabra si su taughtWord es falso, y después lo pone en verdadero; la única llamada que lo vuelve a poner en falso, ResetHipsterFlag a través de ResetMauvilleOldManFlag, se hace desde exactamente un sitio, el final de ReceiveOldManData en record_mixing.c.35 Así que una frase de moda (Trendy Saying) se desbloquea una vez cada vez que el mezclado de datos trae al Hipster, más una vez para el jugador que empieza con él, que según la regla de selección es un jugador cuyo ID de entrenador termina en 2 o en 3. El primer artículo de esta serie enuncia la regla del mismo modo.3635 El vocabulario crece conociendo gente, no esperando.

La moda, en aritmética

La frase de moda, dos palabras de Easy Chat que el pueblo de Dewford trata como el dicho del momento, es el único rastro que Esmeralda puntúa. Su comentario en el código dice que una frase que está «boring» (aburrida) va a «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)» (perder popularidad con el tiempo hasta llegar a 0; entonces deja de aburrir y gana popularidad hasta llegar a maxTrendiness, vuelve a aburrir y el ciclo se repite).37 El pico de una frase se sortea entre 30 y 127 mediante hasta tres extracciones anidadas de Random() % 98. Si se toma cada extracción como independiente y uniforme sobre sus 98 valores, la media del pico es 62,9 y el 81,3 % de los picos son 80 o menos; su puntuación inicial es uniforme entre 30 y el pico, con una media de 46,5; y la puntuación se mueve 5 por cada día transcurrido, ajustada en UpdatePerDay como todo lo demás.383 Esas cifras son una aproximación del código, no su salida exacta: Random() devuelve 16 bits, así que un resto de 0 a 71 sale 669 veces de cada 65.536 y uno de 72 a 97, 668 veces, y las extracciones sucesivas salen de un mismo generador, no de dados independientes. Ponderar los restos de esa manera, sin dejar de tomar las extracciones como independientes, no mueve ninguna de las dos cifras en el primer decimal.3837 Como tasa continua, una frase con pico 30 sube de cero a su pico y vuelve a bajar en 12 días, una con pico 64 en 25,6 y una con pico 127 en 50,8. El juego mueve la puntuación en días enteros, y una puntuación que superaría su pico o el cero rebota por el resto, así que las puntuaciones diarias no se repiten con esos periodos fraccionarios: portada día a día desde una puntuación de cero, subiendo, la secuencia exacta se repite por primera vez a los 12, 128 y 254 días.3837 Se guardan hasta 5 modas, y al mezclar datos «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» (sus propias modas se sustituyen por las del compañero de mezcla, salvo que la frase sea la misma, en cuyo caso se usa la versión con mayor popularidad).3837

Un gráfico de líneas de la puntuación de moda de Esmeralda a lo largo de 60 días, un punto por día entero, para tres picos, cada uno empezando en 0 y moviéndose 5 al día, rebotando en el pico y en cero. El pico 30 sube y baja cada 12 días y se repite exactamente. El pico 64 sube y baja aproximadamente cada 25,6 días, una aproximación continua; sus puntuaciones diarias solo se repiten exactamente al cabo de 128 días. El pico 127 sube y baja aproximadamente cada 50,8 días; sus puntuaciones diarias se repiten al cabo de 254.

Una moda es un zigzag lento muestreado una vez al día: el 81,3 % de los picos son 80 o menos, una subida y bajada de unos 32 días o menos.2638

Según mi lectura, esta es la forma adecuada para un rastro que tiene que evitar que un pueblo se vuelva rancio: sube, baja, su vida queda fijada al nacer, y el contacto con otro jugador puede sustituirlo por algo más fresco.

Easy Chat frente al Club Unión

Esmeralda tenía dos maneras de que los jugadores dijeran cosas, y son los dos extremos del argumento de seguridad de este artículo. El Club Unión (Union Room), su sala de espera inalámbrica local, muestra 8 líderes de grupo, admite 5 jugadores por grupo inalámbrico (RFU_CHILD_MAX, 4, más uno), dibuja 40 sprites y define 30 códigos de actividad. Su chat es escrito: cuatro páginas de teclado (UPPER, LOWER, EMOJI, REGISTER), 15 caracteres por mensaje (MAX_MESSAGE_LENGTH) y 10 frases registradas que se guardan en la partida (UNION_ROOM_KB_ROW_COUNT).439 Mi lectura es que el chat escrito era tolerable ahí porque todos los que estaban en la sala se encontraban dentro de tu alcance inalámbrico.

Todo lo demás que se decían los jugadores pasaba por Easy Chat, el sistema de palabras predefinidas del juego. Tiene 22 grupos y 1.815 entradas en total. Abiertos desde el principio están Trainer (27, 6 de ellas desactivadas), Status (109), Battle (63), Greetings (42), People (75), Voices (63), Speech (60), Endings (69), Feelings (69), Conditions (69), Actions (78), Lifestyle (45), Hobbies (54), Time (45), Misc (42) y Adjectives (36), además de una lista de 202 nombres, cada uno de los cuales se abre solo cuando el jugador ha visto esa especie; bloqueados quedan Events (29) y dos listas de movimientos (154 y 200) hasta terminar el juego, la frase de moda (33) hasta el flag del Hipster, y una lista nacional de 251 nombres.3840 Dejando fuera las 6 entradas desactivadas de Trainer, que ningún jugador puede elegir, son 940 palabras, sin contar nombres, abiertas desde la primera hora. Un switch de easy_chat.c decide qué grupos se desbloquean, y un segundo decide cada entrada: un nombre, según si se ha visto su especie; cualquier otra palabra, según su campo enabled.3840 Las frases son cuadrículas fijas: un perfil es de 2 por 2, 4 casillas; la apertura de un combate, de 2 por 3, 6; el correo, de 2 por 5, 10 casillas que admiten hasta 9 palabras; la frase de moda y el buen dicho, de 2 por 1; el cuestionario, de 2 por 2, 4 palabras.3840

Un vocabulario combinable de 940 palabras es expresivo y, según mi lectura, también es un vocabulario con el que un niño decidido puede deletrear cosas. Ese es el intercambio que el encargo de Kiradex rechaza en la sección 7: frases completas, nunca palabras.

Rastros de desconocidos en otros juegos

Todos los demás juegos estudiados a los que les preocupaba un mundo vacío recurrieron a otros jugadores, la mayoría a los rastros que dejan los jugadores. Las fuentes tienen distinta solidez, y cada párrafo nombra la suya.

Dark Souls (FromSoftware, 2011). Wikipedia, citando su propia fuente: «The player can see ghostly images of other players, activate bloodstains that show how other players died, and leave messages using preset phrases» (el jugador puede ver imágenes fantasmales de otros jugadores, activar manchas de sangre que muestran cómo murieron otros jugadores y dejar mensajes con frases predefinidas).41 The Daily Telegraph le dio el premio «Best Integration of Online Features» (mejor integración de funciones en línea).41 La página de Bandai Namco Europe para la versión remasterizada enumera «The Way of the Multiplayer (up to 6 players with dedicated servers)» (el camino del multijugador, hasta 6 jugadores con servidores dedicados) entre sus características principales y no dice nada más sobre la capa de fantasmas y mensajes; no se llegó a la descripción de la propia FromSoftware.42 La página no dice si las imágenes fantasmales reproducen a jugadores que ya se fueron o muestran a jugadores conectados en ese momento; las enumera, junto con las manchas de sangre y los mensajes, entre las «online features» (funciones en línea) que el juego «integrates» (integra) en «the single-player world» (el mundo de un solo jugador), y pone el «Direct multiplayer» (multijugador directo), las invocaciones y las invasiones, en la frase siguiente.41

Journey (thatgamecompany, 2012). De nuevo Wikipedia: «In each level, the player may come across one other player temporarily connected to their game» (en cada nivel, el jugador puede encontrarse con otro jugador conectado temporalmente a su partida); los dos «cannot communicate via speech or text and cannot see each other’s names until after the game’s credits» (no pueden comunicarse por voz ni por texto y no ven el nombre del otro hasta después de los créditos); «The only form of communication between the two is a musical chime» (la única forma de comunicación entre los dos es un tañido musical). Los desarrolladores «felt having text or voice communication or showing usernames would allow players’ biases and preconceptions to come between them and the other player» (sentían que la comunicación por texto o voz, o mostrar los nombres de usuario, dejaría que los prejuicios y las ideas preconcebidas se interpusieran entre los jugadores y el otro).5 Ese es el argumento de seguridad en forma de diseño, hecho para adultos.

Death Stranding (Kojima Productions, 2019). La página 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» (dona recursos valiosos para reconstruir estructuras en tu mundo y en el de otros, y da «me gusta» en apoyo de las estructuras de otros jugadores que aparecen en el tuyo).43 Wikipedia añade que los jugadores «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» (pueden dejar suministros, estructuras y mensajes que otros jugadores pueden ver y usar, aunque las estructuras acabarán destruidas por el Timefall al cabo de un tiempo), y que «The player does not directly encounter other players in the world» (el jugador no se encuentra directamente con otros jugadores en el mundo).14 Los rastros se desgastan, así que el mundo no se colmata.

Splatoon (Nintendo, 2015). Las publicaciones de Miiverse de los jugadores «appear in-game as graffiti on various buildings» (aparecen en el juego como grafitis en varios edificios), según Wikipedia, citando su fuente. Los grafitis salían de las publicaciones en la comunidad de Miiverse del juego, así que, según mi lectura, el rastro dependía del servicio Miiverse de Nintendo y no del juego en línea del propio título.44

Las tres funciones posteriores de Pokémon se apoyan en una sola fuente, Serebii, un sitio de fans con muchos años de trayectoria; las páginas de pokemon.com de Pokémon Edición Negra 2 y Edición Blanca 2 y de Pokémon Sol y Pokémon Luna no mencionan la Avenida Unión ni la Festi Plaza, y no se guardó ninguna página del editor sobre los gimnasios de GO, así que lee cada uno de los tres párrafos siguientes como el relato de Serebii y no como el del editor.45

Avenida Unión (Join Avenue; Pokémon Edición Negra 2 y Edición Blanca 2, 2012). Según Serebii, la avenida «starts off as an empty pathway» (empieza como un camino vacío), y llega gente que abre tiendas, lo que «is done automatically whenever you connect with someone» (ocurre automáticamente cada vez que te conectas con alguien), por PassBy, infrarrojos, el Club Unión, Wi-Fi, la GTS y más. Hay ocho tiendas; «every 10th person shown to the shop, the shop will rank up» (cada décima persona que se lleva a la tienda, la tienda sube de rango), hasta el rango 10, con «discounts of 1% for every rank up» (descuentos del 1 % por cada subida de rango) hasta «a 40% discount» (un 40 % de descuento); los visitantes normales valen «from 100 to 200 points» (de 100 a 200 puntos); y tras el Alto Mando «various fans will come and visit» (vendrán de visita varios fans), y «If you help a fan rather than another player, they will give 75% of the normal popularity points» (si ayudas a un fan en lugar de a otro jugador, te dará el 75 % de los puntos de popularidad normales).13 Según mi lectura, es la formulación más limpia del canon de una regla de reserva: los suplentes llenan las ranuras que la gente real deja vacías, y valen un poco menos.

Festi Plaza (Festival Plaza; Pokémon Sol y Pokémon Luna, 2016). Según Serebii, la plaza «will propogate itself with players you will find online and locally» (sic) (se irá poblando con jugadores que encuentres en línea y en local), y «This is not limited to people on your friend list» (no se limita a la gente de tu lista de amigos); los invitados que quieren algo lo dicen, pagan Festimonedas cuando los ayudas, y a un invitado ayudado se lo puede hacer VIP, lo que lo hace «more likely to appear in your plaza in the future» (más propenso a aparecer en tu plaza en el futuro); el rango de la plaza cuesta 6 monedas en el nivel 1 y sube hasta 300 a partir del nivel 101.46 Presencia a través de avatares: con lo que interactúas es con el avatar de otro jugador, y Serebii describe a las personas que hay detrás como «all players that are also playing online» (todos jugadores que también están jugando en línea), que «when they see you» (cuando te ven) pueden «challenge you to battles or request trades» (retarte a combates o pedirte intercambios). Según ese relato, las figuras de la plaza representan a jugadores que están ellos mismos en línea; junto con Journey, es una de las dos funciones de esta lista que las fuentes describen como presencia en vivo y no como rastro.46

Los gimnasios de Pokémon GO (la renovación de 2017). Según Serebii, un gimnasio admite hasta seis defensores; cada combate perdido baja la motivación de un defensor y «Once their Motivation has dropped to 0, then they are removed from the Gym» (una vez que su motivación ha bajado a 0, se los retira del gimnasio); las bayas la restauran; y un defensor gana 1 moneda por cada 10 minutos, «capped at 50 Coins earned a day» (con un tope de 50 monedas ganadas al día).47 El lugar mantiene a la vista al compañero de otro jugador mientras este no está, y se desgasta salvo que la comunidad lo alimente.

El patrón común, según mi lectura de los ocho: un número pequeño y fijo de ranuras (8 tiendas, 6 defensores, 1 compañero, 20 bases), rastros que se desgastan o rotan (el Timefall, la motivación, el ciclo de la moda), suplentes que valen menos que las personas y, salvo los combates y las peticiones de intercambio de la Festi Plaza, ningún canal en vivo entre desconocidos más allá de una frase predefinida o un tañido.

3. La presencia en vivo: frecuencias, búferes y el paso de otro jugador

La tercera respuesta es la que a la gente se le ocurre primero: cuando hay otros jugadores conectados, mostrarlos, moviéndose, en la misma plaza. Dos mundos sociales 2D pequeños, Habbo y Club Penguin, muestran los dos extremos de la presencia sobre cuadrícula. Ninguna de las dos empresas publicó sus frecuencias. Lo que tengo son dos servidores de código abierto hechos por fans y un cliente también hecho por fans, escritos para ser compatibles con los clientes originales, así que los números que siguen son evidencia de lo que esperaban esos clientes, no cifras publicadas por Sulake ni por Disney.154849

Habbo: un paso por ciclo del servidor

Arcturus Morningstar, una reimplementación de código abierto del servidor de Habbo, ejecuta cada sala en un ciclo fijo de 500 ms (scheduleAtFixedRate(this, 500, 500, TimeUnit.MILLISECONDS)) y llama al cycle de cada unidad que camina una vez por ciclo de sala; marca un avatar como inactivo en IDLE_CYCLES = 240, 120 segundos, y expulsa a quien no es dueño de la sala en IDLE_CYCLES_KICK = 480, 240 segundos.15 Nitro, un cliente de Habbo de código abierto, mueve un objeto de la sala con un DEFAULT_UPDATE_INTERVAL fijo de 500 ms: en cada actualización del servidor toma el desplazamiento hasta la nueva posición e interpola linealmente según el tiempo transcurrido sobre 500, limitado al final, y después pone el desplazamiento a cero.49 Que un ciclo sea exactamente un tile es mi lectura de las dos cosas juntas (un periodo de servidor de 500 ms dibujado como una interpolación de 500 ms); no leí el RoomUnit del servidor para confirmarlo. Si la lectura se sostiene, el renderizado va un periodo de servidor por detrás por construcción, así que nunca se queda sin datos mientras el servidor mantenga el ritmo.

Club Penguin: un destino, no un flujo

Houdini, un servidor de Club Penguin de código abierto del proyecto Solero, muestra un diseño distinto. Un movimiento es un mensaje sp que lleva un destino, x e y, retransmitido a la sala sin cambios, y el cliente camina hasta allí por su cuenta. Una línea de chat seguro es un mensaje ss que lleva un número, y los demás tipos de habla predefinida viajan del mismo modo: sj para un chiste, sma para el mensaje de una mascota, sl para una línea de escenario, sg para la frase de un guía turístico, se para un emote, cada uno retransmitido como un id.48 El servidor limita los emotes y las acciones a uno por segundo y los cambios de fotograma a uno cada medio segundo, y una tarea de latido revisa los clientes conectados cada 61 segundos y cierra los que no enviaron ningún latido en ese tiempo.48 El movimiento es por clic en un destino, no por tile, y el habla es un número que se busca al otro lado, y según mi lectura por eso un filtro de palabras nunca tuvo que ver la mayor parte de lo que se decía.

Ninguno de los dos mundos envía a las 10 a 60 actualizaciones por segundo de las demostraciones de física que se citan más abajo.16 En un mundo donde la gente camina de tile en tile, el paso o el destino es la actualización.

Gaffer on Games: renderizar por detrás, entre dos puntos conocidos

El método que rige el lado del cliente lo expone Glenn Fiedler en «Snapshot Interpolation» (Gaffer on Games, 30 de noviembre de 2014). Almacena en búfer lo que llega y renderiza entre dos actualizaciones retrasadas: «In effect, we’ve traded a small amount of added latency for smoothness» (en la práctica, hemos cambiado un poco de latencia añadida por suavidad).16 Su regla práctica para el retraso es «enough delay so that I can lose two packets in a row and still have something to interpolate towards» (retraso suficiente para poder perder dos paquetes seguidos y seguir teniendo algo hacia lo que interpolar); con un 2 a 5 % de pérdida de paquetes, lo que mejor funciona «is 3X the packet send rate. At 10 packets per-second this is 300ms» (es tres veces el intervalo de envío; a 10 paquetes por segundo, 300 ms), más un fotograma o dos para el jitter, así que sus demostraciones iban a 350 ms. A «30 snapshots per-second» (30 instantáneas por segundo) la misma protección cuesta 150 ms, y «60 packets per-second needs only 85ms» (60 paquetes por segundo solo necesitan 85 ms).16 La extrapolación, adivinar hacia delante, «doesn’t work very well for rigid bodies because their motion is non-linear and unpredictable» (no funciona muy bien con cuerpos rígidos porque su movimiento es no lineal e impredecible).16

La plaza de Kiradex funciona sobre WebSockets con un servidor FastAPI,23 y los WebSockets van sobre TCP, donde no se pierde nada pero un paquete retransmitido llega tarde. Según mi lectura, eso hace que el presupuesto de un mundo sobre WebSocket sea de jitter y no de pérdida, y convierte a quien camina sobre una cuadrícula en el caso fácil para el método de Fiedler: quien camina sobre una cuadrícula se mueve en línea recta entre centros de tile y se detiene en seco, así que no hay nada que extrapolar ni nada no lineal que ocultar.

Un modelo del paso de otro jugador

Para dimensionar el búfer de Kiradex, simulé a otro coleccionista pasando de largo, con la lógica del propio rig de la app tal como la leí el 5 de octubre. El script, measure_remote_walk.py, modela dos cosas. El comportamiento de hoy, con la aritmética del propio rig: el progress de un paso es un Float de 32 bits, que avanza cada fotograma Float(deltaTime) por 4 tiles por segundo; cada movimiento entrante vuelve a planificar desde el último tile entero del caminante y pone a cero el paso en curso, incluso a mitad de paso; una ruta de más de 6 tiles es un salto; y el caminante se dibuja en pixeles enteros. El rig dibuja a todos los demás coleccionistas a los 4 tiles por segundo de la caminata, porque solo la caminata del propio jugador se marca alguna vez como carrera. Y la alternativa: interpolación de instantáneas sobre un reloj de renderizado constante, el tiempo estimado del servidor menos un retraso de 100 a 350 ms, dibujando entre las dos actualizaciones recibidas cuyas marcas de tiempo encuadran el reloj de renderizado.750 Para el rig de hoy, el emisor envía un movimiento por cada tile completado a las frecuencias medidas hoy: cada 250 ms al caminar a 4 tiles por segundo, y cada 156 ms al correr a 6,4, que es la velocidad nominal de la carrera (el artículo de movimiento de esta serie modela la carrera de la app a 6,0 tiles por segundo a 60 Hz, porque se descarta el exceso de cada tile). Para el búfer, el emisor también se mueve según el contrato de movimiento de la serie, el encargo del artículo de movimiento de 16 ticks por tile al caminar y 8 al correr a 60 Hz, 3,75 y 7,5 tiles por segundo, que es hacia lo que construye la sección 7. La red añade un jitter uniforme de 0, 30 u 80 ms, y se dibujan 60 fotogramas por segundo durante 10 segundos de caminata.72122

La aritmética importa. En 32 bits, 15 fotogramas de 1/60 de segundo a 4 tiles por segundo suman exactamente 1,0, así que un paso dura 15 fotogramas, exactamente los 250 ms del emisor; en aritmética de 64 bits la misma suma da 0,9999999999999999, el paso dura 16 fotogramas, y un modelo escrito así encuentra retrocesos bruscos en una caminata constante que la propia aritmética del rig no produce.7

Esto es un modelo, y sus supuestos son la razón para tratar sus números como una guía de dimensionado y no como un resultado. Supone una calle recta y despejada, así que la longitud de una ruta es la distancia Manhattan; un paso en diagonal, que en el rig tarda √2 veces más, no está modelado; el jitter es uniforme; el deltaTime de cada fotograma es exactamente 1/60 de segundo, cuando el de un teléfono varía; las operaciones de 32 bits se ejecutan en el orden del código, sin multiplicación y suma fusionadas; nada en él se capturó de dos dispositivos. Así que si una caminata constante sin jitter llega a dar un retroceso brusco en un teléfono es una pregunta que el modelo no puede zanjar: un tiempo de fotograma que se aparte un pelo de 1/60 puede dejar un paso a un redondeo de llegar a 1,0. La puesta a cero en sí, que se dispara siempre que un movimiento llega a mitad de paso, es una lectura del código fuente, no un resultado del modelo. La mitad del búfer también supone dos cosas de las que depende su resultado: que la estimación del reloj del servidor que hace el renderizador es exacta, y que una actualización no tarda en llegar nada más allá de su jitter. Un cliente real tiene que estimar el reloj del servidor, y cualquier error en esa estimación, o cualquier retraso constante en un sentido que no tenga en cuenta, sale directamente del búfer.7

Dos paneles de barras agrupadas sobre seis casos, caminando y corriendo, cada uno con 0, 30 y 80 ms de jitter. A la izquierda, el rig de hoy, con el emisor a 4 tiles por segundo caminando y a 6,4 nominales corriendo: 0, 7 y 16 fotogramas dibujados moviéndose hacia atrás al caminar, 45 en los tres casos de carrera. A la derecha, con un búfer, a los 3,75 y 7,5 tiles por segundo del contrato de movimiento, fotogramas sin nada hacia lo que dibujar de un total de 600: caminando, 355, 400 y 456 con 100 ms de retraso, 0, 0 y 27 con 300 ms, 0, 0 y 6 con 325 ms, y 0 con 350 ms; corriendo, 125, 188 y 304 con 100 ms y 0 con 300 ms o más. Todas las ejecuciones con búfer dibujan 0 fotogramas hacia atrás.

En el modelo, el rig de hoy dibuja a un coleccionista que pasa moviéndose hacia atrás cuando un movimiento llega a mitad de paso, en todas las carreras y en cualquier caminata con jitter; a las velocidades del contrato de movimiento, un búfer de 350 ms nunca lo hace y nunca se queda sin datos.26

El rig de hoy, caminando sin jitter, dibuja al caminante limpiamente: cada paso termina en el fotograma anterior a la llegada del siguiente movimiento, así que hay 0 retrocesos bruscos, 0 saltos y 0 fotogramas hacia atrás en 40 tiles. El jitter lo rompe. Con 30 ms, 13 movimientos llegan a mitad de paso y lo ponen a cero, 7 de ellos lo bastante tarde dentro del paso como para dibujar al caminante hacia atrás, y 1 ruta es lo bastante larga como para saltar; con 80 ms, 25 puestas a cero, 16 fotogramas hacia atrás y 2 saltos. Al correr, el emisor va más rápido que los 4 tiles por segundo a los que el rig lo dibuja, así que con cualquier jitter probado 45 de los 64 movimientos llegan a mitad de paso, cada uno dibujando un fotograma hacia atrás, con 9 saltos. Cada vez que da un retroceso brusco, el caminante dibujado se queda por detrás del emisor hasta entre 5,9 y 6,7 tiles antes de que un salto lo adelante; en la caminata constante nunca llega a estar un tile entero por detrás (0,94 como máximo).7 Un retroceso brusco dibuja al caminante hacia atrás tanto como hubiera dibujado del paso, hasta 14 pixeles en un tile de 16 pixeles en estas ejecuciones.750

Con un búfer, el caminante nunca se mueve hacia atrás: 0 fotogramas hacia atrás en las 60 ejecuciones con búfer, cuatro velocidades por tres jitters por cinco retrasos. La única pregunta es con qué frecuencia el renderizador no tiene nada hacia lo que dibujar, contado sobre los 600 fotogramas dibujados mientras el emisor sigue enviando. A la caminata del contrato de movimiento, 3,75 tiles por segundo, un reloj de renderizado 300 ms por detrás deja sin datos 0, 0 y 27 fotogramas con 0, 30 y 80 ms de jitter; con 325 ms, 0, 0 y 6; con 350 ms, ninguno. Con 100 ms por detrás se quedan sin datos entre 125 y 456 fotogramas en todos los casos a esas velocidades. Corriendo a 7,5, con 300 ms o más se quedan sin datos 0 fotogramas con cualquier jitter probado. A los 4 y 6,4 tiles por segundo de hoy, el mismo modelo deja sin datos 0, 0 y 7 al caminar con 300 ms, y ninguno con 325 o 350.7 Según mi lectura, un reloj de renderizado 350 ms por detrás del tiempo estimado del servidor es el número, y la razón es una cota, no un recuento. Con un movimiento por tile, la actualización que necesita un fotograma lleva una marca de tiempo como mucho un paso posterior al reloj de renderizado y llega como mucho el peor jitter después de su marca. A 3,75 tiles por segundo un paso es 1/3,75 de segundo, 266,7 ms, y un paso más 80 ms de jitter son 346,7 ms, así que con un reloj exacto un retraso de 350 ms no deja sin datos ningún fotograma para ninguna extracción de jitter de hasta 80 ms, con 3,3 ms de margen.7 Esos 3 ms son todo el margen para la estimación del reloj: una estimación que vaya más de unos 3 ms por delante del reloj del servidor pierde la garantía y puede dejar fotogramas sin datos. Los recuentos anteriores salen de una sola extracción de jitter, la semilla 1, y 325 ms cumplió en esa extracción el umbral que fija la sección 7.4, por 4 fotogramas, pero no en todas: al repetir con las semillas 1 a 200, caminando a 3,75 tiles por segundo con 80 ms de jitter, 325 ms dejó fotogramas sin datos en las 200 y más de 10 en 8 de ellas, mientras que 350 ms no dejó ninguno en ninguna.7 350 ms es también el retraso con el que funcionaban las propias demostraciones de Fiedler. Con un movimiento por tile es un poco más que un paso de caminata de retraso, siendo un paso 267 ms a 3,75 tiles por segundo, que es el «3X the packet send rate» (tres veces el intervalo de envío) de Fiedler dado la vuelta para un mundo donde los paquetes son pasos y, sobre TCP, llegan tarde en lugar de no llegar.16

4. El oficio, como reglas con números

Cada regla de abajo remite a una medición o a una fuente citada más arriba. Cuando la regla es mi síntesis de varias fuentes, la columna de la fuente dice cuáles.

Elemento Regla Fuente
Quién se mueve De los vecinos siempre presentes, unos seis de cada diez tienen un tipo de movimiento por defecto estacionario, de pie en un puesto mirando hacia un lado o mirando alrededor, y casi cuatro de cada diez deambulan dentro de un recuadro de una o dos celdas alrededor de su puesto. Los actores de la historia que van y vienen están casi siempre de pie, lo que lleva el recuento total a siete de cada diez y uno de cada cuatro. Las 100 personas de Esmeralda sin flag de ocultación: 59 de pie, 39 deambulan, 2 caminan en el sitio; las 158 en total: 113 y 43; rangos de 1 o 2 celdas1
Ritmo Un vecino da pasos al ritmo del jugador y luego espera más de lo que tardó el paso: un paso de 268 ms, luego 0,54, 1,07, 1,61 o 2,14 s, elegidos al azar. Un paseo más lento también funciona (Wild World); un ritmo que no es ni lo uno ni lo otro, no. La acción de caminata compartida de Esmeralda y su tabla de esperas1; Wild World32
Proporción de movimiento Quien deambula está en movimiento como mucho entre un 11 y un 33 por ciento del tiempo, por paso dado; un paso bloqueado solo mira y espera. Esmeralda, aritmética sobre las dos filas anteriores; una cota superior127
Población Entre seis y diez personas hacen un pueblo; los pueblos enteros de Animal Crossing llegan como máximo a entre 8 y 15. Littleroot 6 personas, Petalburg 7, Mauville 10, de las cuales 2, 3 y 6 no llevan flag de ocultación1; los pueblos de Animal Crossing, de 8 a 15 como máximo32
Cambio Algunos vecinos se van y llegan con el progreso del jugador, mediante un flag. 12 de las 23 personas de los tres pueblos llevan flag de ocultación1
Rutina Un día son de tres a siete puntos con hora; una clave elige qué día se aplica, en un orden fijo de especificidad, y gana la primera coincidencia. El miércoles de Abigail, 3 puntos; el día normal de Pierre, 7; 22 formatos de clave92
El día Ajusta el día cuando el jugador vuelve, con una ejecución que recibe el número de días transcurridos; nunca hagas correr un temporizador mientras nadie juega. UpdatePerDay3; la primera actualización de día de Stardew9
Memoria Recuerda la primera conversación del día con un flag por vecino; que la recompensa sea pequeña. +1 sobre 255 en New Horizons11; +20 frente a 250 por corazón en Stardew10
Palabras nuevas Raciona la expresión nueva a una al día, o a una por encuentro. Un gesto al día12; una frase de moda por cada llegada del Hipster35
Rastros Los rastros de los demás vienen en ranuras pequeñas y fijas, y se desgastan o rotan. 20 bases y 5 modas4; 8 tiendas13; 6 defensores47; el Timefall14; una subida y bajada de la moda de 12 a unos 50,8 días38
Suplentes Los suplentes llenan las ranuras que la gente deja vacías, y cuentan menos. Los fans de la Avenida Unión al 75 %, según el relato de Serebii13
Desconocidos Los desconocidos comparten presencia, no palabras: sin nombres, un tañido o una frase predefinida. Journey5; Dark Souls41; Game Center para niños17
Habla Las frases predefinidas viajan como ids y sirven para responder, no solo para saludar; una frase completa no puede deletrear nada de lo que sí puede una lista de palabras. Los ids ss de Club Penguin48; las 940 palabras abiertas de Easy Chat en cuadrículas de 2 a 10 casillas38
Actualizaciones Una actualización por paso sobre una cuadrícula; renderiza a los caminantes remotos con un reloj un poco más de un paso de caminata por detrás del tiempo estimado del servidor, y nunca pongas a cero un paso en curso. El ciclo de 500 ms de Habbo y su interpolación (emulador y cliente de fans)1549; el modelo a 3,75 y 7,5 tiles por segundo, suponiendo una sincronización de reloj exacta y sin latencia de base: 350 ms por detrás da 0 fotogramas hacia atrás y 0 sin datos con hasta 80 ms de jitter7
Inactividad Marca a un jugador como inactivo tras dos minutos sin entrada, y cierra una conexión que ha dejado de responder a su latido. Arcturus: inactivo a los 240 ciclos (120 s), y quien no es dueño y está inactivo, expulsado a los 480 (240 s)15; Houdini cierra cualquier cliente que no envió ningún latido en una ventana de 61 s48. Los 240 s sin ping del encargo unen ambas cosas, adaptación mía
Restricciones Cuando Game Center indica que el multijugador está restringido, incluido el modo solo amigos, el multijugador propio desaparece, y según mi lectura eso incluye las repeticiones de las caminatas de jugadores reales: ese jugador solo tiene vecinos. La documentación de Apple de isMultiplayerGamingRestricted18; considerar los ecos como multijugador es mi lectura (sección 7.6)
Comunicación Cuando Game Center indica que la comunicación personalizada está restringida, o que el jugador es menor de edad, la comunicación propia desaparece. La documentación de Apple de isPersonalizedCommunicationRestricted51
Retención Conserva los datos de los niños solo mientras lo exija su finalidad escrita, con el plazo de eliminación en el aviso. 16 CFR 312.10 enmendado; cumplimiento desde el 22 de abril de 202619

5. A la manera de Apple: los flags de Game Center, los rangos de edad, las Directrices y la COPPA

Un pueblo en el que pueden entrar niños está acotado por reglas de Apple y de la Comisión Federal de Comercio de Estados Unidos (FTC), y la mayoría tienen fechas. Esta sección recoge las palabras de Apple y de la FTC, con la disponibilidad cuando Apple la publica. Todo lo que digo sobre lo que una regla significa para Kiradex es una lectura, señalada como tal, y nada de ello es asesoramiento legal.

Los tres flags de restricción de Game Center

El jugador local de Game Center lleva tres booleanos que un juego puede leer antes de abrir nada social. Su disponibilidad sale de la documentación de Apple tal como se guardó el 4 de octubre de 2026, y cada explicación se cita textualmente.185152

Propiedad iOS Lo que dice 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 esta propiedad es verdadera, el jugador local no puede unirse a partidas multijugador. Si tu juego usa una función multijugador propia, deberías desactivarla.)
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 esta propiedad o la de menor de edad es verdadera, el jugador local no puede incluir mensajes personalizados en las invitaciones ni activar la comunicación por voz en partidas multijugador. Si tu juego incluye funciones de comunicación propias, deberías desactivarlas.)
GKLocalPlayer.isUnderage 4.1 «If this property is true, Game Center disables some features for the local player.» (Si esta propiedad es verdadera, Game Center desactiva algunas funciones para el jugador local.)

La página del primer flag añade el detalle que más importa: el valor viene de Screen Time, que permite a un padre o una madre autorizar partidas multijugador con todo el mundo, solo con amigos o con nadie, y «when you configure the setting to friends only, this property returns true for restricted» (cuando configuras el ajuste en solo amigos, esta propiedad devuelve verdadero, es decir, restringido).18 Así que un niño al que solo se le permite jugar con amigos sigue figurando como restringido, y a un juego con su propia plaza se le pide que la apague. La página del segundo flag tiene dos frases de alcance distinto. La primera nombra lo que bloquea el propio Game Center, los mensajes personalizados en las invitaciones y la voz; la segunda pide al juego que desactive «any custom communication features» (cualquier función de comunicación propia) que tenga, sin excepción para las predefinidas. Según mi lectura, un menú de frases completas predefinidas es una función de comunicación propia, y el encargo lo trata como tal.51

Game Center para niños, y Screen Time

La página de privacidad de Game Center de Apple fija la regla que Kiradex ya adoptó para todo el mundo: «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» (al comunicarse con otros jugadores en Game Center, los niños no pueden enviar ni recibir texto escrito por el usuario; solo pueden enviar y recibir mensajes predefinidos; el chat de voz dentro del juego está desactivado para los niños).17 También dice «Children’s accounts never make real names visible to friends» (las cuentas de niños nunca muestran nombres reales a los amigos), y que un padre o una madre puede usar Screen Time para bloquear «multiplayer functionality, the ability to add friends, and the ability to connect with friends playing the same game» (la función multijugador, la posibilidad de añadir amigos y la posibilidad de conectarse con amigos que juegan al mismo juego).17 La página de soporte de Apple sobre Screen Time enumera las restricciones de Game Center por su nombre, entre ellas «Connect with Friends» y «Private Messaging», cada una «Allowed or Blocked» (permitida o bloqueada).53

Declared Age Range

El 11 de junio de 2025, Apple anunció que una Child Account (cuenta infantil) «is required for children under 13» (es obligatoria para los menores de 13 años), y que «App developers will be able to request this information through the new Declared Age Range API» (los desarrolladores de apps podrán solicitar esta información mediante la nueva API Declared Age Range), con los padres eligiendo compartir el rango de edad de un niño «always, for each app request, or never» (siempre, en cada solicitud de una app o nunca), «in a way that does not reveal the child’s birth date» (de una forma que no revela la fecha de nacimiento del niño).54 El mismo anuncio decía que las clasificaciones por edad se «expanded to five categories» (ampliarían a cinco categorías) antes de terminar ese año, con 13+, 16+ y 18+ para adolescentes.54 El plan del mundo de Kiradex nombra esa API como el interruptor de sus reglas juveniles y deja constancia de la decisión del 2 de octubre: menores de 13 según el rango declarado, ninguna plaza; de 13 a 15, la plaza con reglas juveniles; de 16 en adelante, o sin declarar, la plaza completa.23 Para este artículo no consulté la página de referencia de la propia API, así que aquí no se indica su versión mínima de iOS.

Las Directrices de revisión de la App Store

Tres directrices acotan una plaza social, citadas de la versión que Apple fecha como «Last Updated: June 8, 2026» (última actualización: 8 de junio de 2026).55

  • 1.2, contenido generado por los usuarios. Las apps «with user-generated content or social networking services must include» (con contenido generado por los usuarios o servicios de redes sociales deben incluir) un método para filtrar material objetable, «A mechanism to report offensive content and timely responses to concerns» (un mecanismo para denunciar contenido ofensivo y respuestas oportunas a las quejas), «The ability to block abusive users from the service» (la posibilidad de bloquear en el servicio a los usuarios abusivos) y «Published contact information so users can easily reach you» (información de contacto publicada para que los usuarios puedan comunicarse contigo fácilmente). Las apps que acaban «used primarily for pornographic content, Chatroulette-style experiences, random or anonymous chat» (usadas principalmente para contenido pornográfico, experiencias al estilo de Chatroulette, chat aleatorio o anónimo) y el resto de esa lista «do not belong on the App Store and may be removed without notice» (no tienen cabida en la App Store y pueden retirarse sin previo aviso).55
  • 1.3, la categoría Niños. Las apps de esa categoría «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» (no deben incluir enlaces fuera de la app, oportunidades de compra ni otras distracciones para los niños, salvo en un área designada tras un control parental), y «should not include third-party analytics or third-party advertising» (no deberían incluir analítica ni publicidad de terceros), con excepciones acotadas.55
  • 5.1.4, niños. Las apps que «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» (recopilen, transmitan o puedan compartir información personal de un menor, como nombre, dirección, correo, ubicación, fotos, videos, dibujos, la posibilidad de chatear, otros datos personales o identificadores persistentes combinados con cualquiera de ellos, deben incluir una política de privacidad y cumplir todas las leyes aplicables de privacidad infantil), y «the parental gate requirement for the Kid’s Category is generally not the same as securing parental consent» (el requisito de control parental de la categoría Niños por lo general no equivale a obtener el consentimiento parental) conforme a esas leyes.55

El plan de Kiradex toma el segundo de los dos caminos que su documento de diseño extrae de las Directrices: fuera de la categoría Niños, con clasificación 9+ o 12+ (la clasificación aún no está elegida), conforme a la 5.1.4.23 Según mi lectura, «the ability to chat» (la posibilidad de chatear) de la lista de la 5.1.4 significa que una plaza de frases predefinidas sigue necesitando la política de privacidad, se ahorre lo que se ahorre en lo demás.

La COPPA enmendada

La Regla de Protección de la Privacidad Infantil en Línea (COPPA) enmendada de la FTC se publicó en el Federal Register el 22 de abril de 2025 (documento 2025-05904, 90 FR 16918). La regla «is effective June 23, 2025» (entra en vigor el 23 de junio de 2025), y «Except with respect to § 312.11(d)(1), (d)(4), and (g), regulated entities have until April 22, 2026 to comply» (salvo en lo relativo al § 312.11(d)(1), (d)(4) y (g), las entidades reguladas tienen hasta el 22 de abril de 2026 para cumplir).19 El comunicado de la FTC del 16 de enero de 2025, aprobado por 5 votos a 0, resumía el cambio: un consentimiento parental verificable aparte para divulgar a terceros información de niños «related to targeted advertising or other purposes» (relacionada con publicidad dirigida u otros fines), y una retención «for as long as reasonably necessary to fulfill a specific purpose» (durante el tiempo razonablemente necesario para cumplir un fin concreto), de modo que «operators cannot retain the information indefinitely» (los operadores no pueden conservar la información indefinidamente).56

Tres pasajes del texto de la regla afectan a una plaza que recuerde algo.

  • Retención, § 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.» (La información personal recopilada en línea de un niño no puede conservarse indefinidamente; como mínimo, el operador debe establecer, aplicar y mantener una política escrita de retención de datos que indique los fines de la recopilación, la necesidad empresarial de conservarla y un plazo para eliminarla.) La política va en el aviso en línea.19
  • Identificadores persistentes, § 312.2. La información personal incluye «A persistent identifier that can be used to recognize a user over time and across different websites or online services» (un identificador persistente que puede usarse para reconocer a un usuario a lo largo del tiempo y en distintos sitios web o servicios en línea), como «a customer number held in a cookie, an Internet Protocol (IP) address, a processor or device serial number, or unique device identifier» (un número de cliente guardado en una cookie, una dirección IP, un número de serie de procesador o de dispositivo, o un identificador único de dispositivo).19
  • Operaciones internas, § 312.5(c)(7). No hace falta consentimiento «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» (cuando un operador recopila un identificador persistente y ninguna otra información personal, y ese identificador se usa con el único fin de dar soporte a las operaciones internas del sitio web o servicio en línea), con aviso.19

El § 312.8 enmendado exige además un programa escrito de seguridad de la información para los datos de los niños.19 Mi lectura de lo que esto significa para una plaza que reproduce las caminatas de los visitantes está en el encargo, señalada como tal; la sección 3 de WORLD.md pide que un abogado lea el diseño final, y las decisiones del 2 de octubre lo aplazan hasta que la app tenga tracción, así que la lectura se mantiene hasta entonces.23

Lo que cuesta

Nada de esta sección se midió en un dispositivo. Leer tres booleanos de GKLocalPlayer tras la autenticación no está cronometrado aquí; tampoco la memoria ni la CPU de un búfer de renderizado de 350 ms para hasta 39 coleccionistas más en una sala de 40.21 Según mi lectura, ninguna de las dos cosas puede pesar al lado del dibujo de un fotograma, pero es una lectura, y las comprobaciones del encargo son de comportamiento, no de tiempos.

6. El caso práctico: la plaza de Kiradex, medida sobre su propio código

Kiradex World es el pueblo de pixel art dentro de Kiradex, mi app para coleccionar cartas: una plaza de 40 por 30 dibujada con tiles de 16 pixeles, servida por un pequeño servidor FastAPI y WebSocket que mantiene la presencia en memoria y no almacena nada, salvo lo que su servidor web registra por defecto (sección 7.6, ajuste 6).212357 Leí el servidor y el código del mundo de la app el 5 de octubre desde el árbol de trabajo, sin cambiar nada, y ejecuté las propias clases del servidor sobre un reloj simulado con dos scripts, así que los números de esta sección son el comportamiento del código y no mi lectura de él.21620 El repositorio es privado, así que los archivos se nombran por su ruta. Son diferencias entre el plan de docs/WORLD.md, los docstrings del propio código y lo que hace el código; ninguna es un defecto que alguien haya ocultado, y el plan ya enumera parte de la cuarta como pendiente de construir.

Qué hay

El servidor tiene 23 frases predefinidas, 14 para los jugadores (índices 0 a 13) y 9 para los coleccionistas propios del pueblo (14 a 22); salas de 40; un límite de 8 movimientos por segundo y una frase cada 2,0 segundos por jugador; un reloj del pueblo que hace tick cada 0,5 s (TICK_SECONDS en server/app/main.py); un tiempo de espera de 60 segundos para enseñarle una carta al mismo coleccionista; y la llegada en el tile (19, 13) de la plaza de 40 por 30.2120 Cuatro coleccionistas con script viven en el servidor para que todos los de una sala vean a los mismos: Moss, Prism, Comet y Dawn, cada uno con 4 puntos de paso en circuitos de 18, 22, 30 y 32 tiles, un tipo de carta que a cada uno le gustaría que le enseñaran (vintage, holo, cualquiera, japonesa) y 2 o 3 frases cada uno. server/app/npcs.py fija STEP_SECONDS = 0.7, detiene a cada coleccionista en un punto de paso entre 3 y 8 segundos con distribución uniforme, y le hace decir una frase cada 20 a 40 segundos con distribución uniforme, la primera tras 8 a 20.2120

Según mi lectura, es el instinto correcto: vecinos en el servidor y no en cada teléfono, frases con un reloj lento y un deseo cada uno, para que una colección tenga dónde importar. Medido, hay tres cosas que lo socavan, y una cuarta que es una brecha entre el plan y el código.

1. La caminata va a trompicones

measure_npc_cadence.py importa server/app/npcs.py y rooms.py, construye la plaza y los cuatro coleccionistas, y los hace avanzar con el tick real de 0,5 s durante una hora simulada.6 Cada uno de los 6.253 intervalos entre pasos dentro de un tramo es exactamente 1,0 segundo, no 0,7: un paso se dispara en el primer tick igual o posterior a su next_move, así que 0,7 segundos se redondean hacia arriba a dos ticks. Eso es 1,0 tile por segundo frente a los 1,43 que implica la constante. Las pausas antes de un tramo promedian 6,75 segundos (de 4,5 a 9,0, sobre 1.202 pausas), y las frases quedan de media a 30,7 segundos unas de otras en los 465 intervalos entre frases consecutivas de un mismo coleccionista (469 frases en la hora).6

El cliente dibuja cualquier paso en 250 ms: PlazaRig.swift fija tilesPerSecond en 4 en la línea 101.50 Así que un coleccionista que camina a un tile por segundo se dibuja en movimiento el 25 por ciento de cada tramo y quieto el otro 75 por ciento, entre cada par de tiles.6 Los vecinos de Esmeralda que deambulan dan pasos al ritmo del jugador y luego esperan; los coleccionistas de Kiradex se mueven al ritmo del jugador a ráfagas de un tile mientras se supone que están caminando, lo que se lee, según mi lectura, ni como el paseo de un residente ni como una caminata (la fila inferior de la figura de línea de tiempo de la sección 1).

2. Otro coleccionista que pasa da un retroceso brusco

Cuando el servidor retransmite el movimiento de otro coleccionista, PlazaRig.move(other:to:facing:) (líneas 526 a 542 de PlazaRig.swift) planifica una ruta desde el último tile entero del caminante, asigna esa ruta a los pasos del caminante y fija progress = 0 con cada mensaje, incluso cuando un paso está dibujado a medias; una ruta de más de 6 tiles es un salto.50 El modelo de la sección 3, en la propia aritmética de 32 bits del rig, le pone números. Una caminata constante sin jitter nunca da un retroceso brusco, porque cada paso termina justo antes de que llegue el siguiente movimiento. Con 30 u 80 ms de jitter, una caminata de 40 tiles se pone a cero a mitad de paso 13 o 25 veces, 7 o 16 de ellas dibujadas hacia atrás. Al correr, el rig dibuja al caminante a los 4 tiles por segundo de la caminata, así que 45 de 64 movimientos llegan a mitad de paso con cualquier jitter probado, con 9 saltos; y cada vez que da un retroceso brusco, el caminante dibujado se queda hasta entre 5,9 y 6,7 tiles por detrás del emisor.7 Movimiento en pixel art, un artículo anterior de esta serie, lee en el código el mismo retroceso brusco para el segundo toque del propio jugador a mitad de paso; la regla que fija su encargo, nunca poner a cero un paso en curso, es la que este encargo aplica a los demás coleccionistas.22

3. El pueblo se detiene cuando está vacío

El docstring del módulo server/app/npcs.py dice de los coleccionistas: «A town is never empty, and it has somewhere for a collection to matter» (un pueblo nunca está vacío, y tiene un lugar donde una colección importa).20 Room.tick en server/app/rooms.py dice lo contrario en su propio docstring, «A room with nobody in it stands still» (una sala sin nadie dentro se queda quieta), y lo cumple: cuando la sala no tiene jugadores, retorna de inmediato, así que los coleccionistas se congelan donde estuvieran.206 El script mide lo que ve entonces el primero en llegar: llevar a coleccionistas recién creados hasta 10.000 segundos simulados en un solo tick produce cuatro frases a la vez, una de cada coleccionista, de pie donde estaba; entre medias no pasó nada.6 Y como el servidor no almacena nada, el primer coleccionista que entra en una mañana tranquila ve a las mismas cuatro personas y ninguna señal de que alguien más haya estado alguna vez. Una búsqueda en Kiradex/ y server/app/ no encuentra nada que registre una visita o una conversación diaria.24

4. Las frecuencias, y los flags de Game Center

Hay dos diferencias entre docs/WORLD.md y el código. La sección 5 del plan conserva, como el razonamiento que llevó al servidor, un diseño en el que los clientes envían posición y orientación a 8 a 10 Hz.23 La app envía en su lugar un move por cada tile completado: hoy 4 por segundo al caminar, y 6,4 al correr a la velocidad nominal de la carrera (6,0 a 60 Hz en el modelo del código del artículo de movimiento), por debajo del límite de 8 por segundo del servidor en ambos casos; el contrato de movimiento de la serie, 16 ticks por tile al caminar y 8 al correr a 60 Hz, los dejaría en 3,75 y 7,5, todavía por debajo (sección 7.4).2122 Según mi lectura, enviar por tile es el mejor diseño para una cuadrícula, y el encargo lo mantiene; la línea del plan es la que hay que actualizar.

La sección 3 del plan construye la identidad sobre Game Center para 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)» (el Game Center de un niño lo controla el padre o la madre en Screen Time: multijugador sí o no, añadir amigos sí o no, compartir la lista de amigos con los juegos sí o no).23 Nada en Kiradex/ ni en server/app/ lee GKLocalPlayer.isMultiplayerGamingRestricted, isUnderage ni isPersonalizedCommunicationRestricted, ni llama a la API Declared Age Range.24 La sección 5 del plan ya enumera «junior mode by Declared Age Range» (modo juvenil según Declared Age Range) entre lo pendiente de construir.23 Los flags de Game Center son la parte que no enumera: el ajuste de multijugador de Screen Time gobierna el multijugador propio de Game Center, y la documentación de Apple pide a un juego con «a custom multiplayer feature» (una función multijugador propia) que la desactive por su cuenta, así que mientras la app no lea el flag, el ajuste de un padre o una madre no llega a la plaza.18

El cliente se reconecta tras perder el socket con un retroceso exponencial de min(30, 2^attempts) segundos (PlazaClient.swift, línea 165), y ocultar a un coleccionista se hace en el dispositivo, por id.215023 Las dos cosas se quedan como están en el encargo, que añade un uso de la lista de ocultos: viaja con cada solicitud de los ecos de la plaza, para que el servidor pueda dejar fuera las caminatas de los coleccionistas que este jugador ha ocultado (sección 7.2).

7. El encargo: qué construye Kiradex y qué comprobaciones debe superar

El encargo conserva lo que la plaza ya tiene (los coleccionistas propios del servidor, solo frases predefinidas, un movimiento por tile, la presencia en memoria) y añade las tres respuestas en el orden en que las da el canon: vecinos cuya vida no se detiene, rastros de personas que estuvieron allí y una presencia dibujada sin retrocesos bruscos. Cada punto tiene una comprobación que un script, una prueba o una captura pueden aprobar o suspender. Las coordenadas de tile son las de la plaza, con x hacia la derecha e y hacia abajo.21

La línea sobre lo que se toma prestado es la que traza el primer artículo de esta serie para las patentes y para la expresión: ninguna criatura, ningún nombre de lugar de Pokémon, ninguna palabra de la franquicia usada como nombre de una función, y nada que apunte y lance para capturar, muestre una probabilidad de captura, envíe a un compañero a combatir o se monte en algo para viajar.36 Cada elemento de abajo son vecinos que caminan, están de pie y dicen frases completas predefinidas, y repeticiones pálidas de las caminatas de otros coleccionistas. Los sistemas de los juegos se nombran más arriba como hechos sobre obras publicadas; las funciones de Kiradex reciben aquí nombres propios de Kiradex: los vecinos, los ecos, el saludo del día, el libro de frases y la plaza tranquila. La sección 3 de docs/WORLD.md ya llama transeúnte a todo coleccionista en vivo que no es amigo; ese término se queda, y las repeticiones se llaman ecos para que nunca se confundan.23 Las notas legales son lecturas, no asesoramiento.

7.1 Vecinos con rutinas

  • Población. Ampliar los coleccionistas propios de la plaza de 4 a 8, cada uno con un puesto.21 El reparto sigue al de las personas siempre presentes de Esmeralda, 59 de 100 de pie y 41 no (39 deambulando, 2 caminando en el sitio), que con ocho se redondea a cinco de pie y tres en movimiento. Cinco están de pie en sus puestos y se giran: el mostrador de la tienda, la puerta del salón, la fuente y dos tenderetes. Dos deambulan dentro de un recuadro de 2 celdas alrededor de un puesto, como hacen los vecinos de Esmeralda que deambulan. El tercero que se mueve no sale del reparto de Esmeralda, cuyos 158 vecinos están todos de pie, deambulan en un recuadro o caminan en el sitio, sin ninguno en una ruta: es uno de los cuatro circuitos de puntos de paso de hoy, que se conserva, recorriendo una ronda entre puestos, así que los cuatro circuitos de hoy pasan a ser uno.121 Los cuatro coleccionistas nuevos los dibuja el propio sistema de figuras de la app, con nombres sacados de las propias listas de palabras de la app, como los cuatro de hoy.20
  • Esperas. Un coleccionista en su puesto se gira, y uno que deambula da un paso, tras una espera de 1, 2, 3 o 4 ticks del reloj de 0,5 s del servidor, elegida al azar: 0,5, 1,0, 1,5 o 2,0 segundos, los 0,54, 1,07, 1,61 y 2,14 de Esmeralda redondeados al tick más cercano. Una espera en ticks enteros no se vuelve a redondear por el tick, que es el fallo que la sección 6 midió en el paso.16
  • El reloj de la sala. Cada sala funciona con un único reloj: la hora del servidor en UTC, leída en la zona horaria propia de la sala, una zona IANA por sala en la configuración del servidor. El servidor envía ambas cosas al llegar, en welcome y en la respuesta de la plaza tranquila ({"zone": "<IANA name>", "clock": <server ms>}), y mientras la plaza está abierta la app toma de ahí su franja del día y no del teléfono, para que todos los de una sala vean a los mismos vecinos bajo la misma luz. Hoy Daylight.now toma la hora de Calendar.current, el calendario y la zona propios del teléfono, y el servidor solo lleva un reloj monótono y no nombra ninguna zona.50 Qué zona usa una sala, y a qué sala se envía a un coleccionista, es configuración que este encargo deja abierta; una sola zona para todas las salas es el comienzo más sencillo. Fuera de la plaza, el reloj del teléfono sigue siendo el del coleccionista.
  • Rutinas. El día de cada vecino son de 3 a 7 puntos con hora escritos como una sola cadena en los datos del servidor, elegidos por una clave probada en orden: una fecha, un día de la semana, una franja del día y luego el valor por defecto, todos leídos en el reloj de la sala.9 Las franjas del día son las de la propia app, de Daylight.Phase en Kiradex/World/Daylight.swift: la mañana de 6 a 9, el día de 9 a 17, la tarde de 17 a 20 y la noche el resto.50 De noche según el reloj de la sala, los cinco de los puestos y los dos que deambulan entran en casa por sus propias puertas, como termina el viernes de Pierre en Stardew Valley, desde la taberna («Returns home to sleep.», vuelve a casa a dormir), y el que camina por el circuito conservado acorta su ronda.30
  • El ritmo. Arreglar la caminata a trompicones con uno de dos cambios. El preferido: el servidor envía un tramo una sola vez, {"t": "walk", "id": ..., "path": [...], "at": <server ms>}, y el cliente lo recorre a partir de at al paso de caminata del jugador según el contrato de movimiento de la serie, 16 ticks por tile a 60 Hz, 3,75 tiles por segundo (4 en el rig de hoy).22 El mínimo: un intervalo de paso del servidor que sea un número entero de ticks, STEP_SECONDS = 0.5, con el cliente dibujando el paso de un vecino a lo largo de esos mismos 0,5 segundos, 2 tiles por segundo, el paseo de un residente y no la caminata del jugador.632
  • El tiempo cuando la sala está vacía. El tile de un vecino es una función pura del reloj de la sala: la ruta, la franja del día y una semilla, calculado cuando se pide, no avanzado por Room.tick. La semilla es un único valor global en la configuración del servidor, no uno por sala o por zona, así que dos salas con la misma zona muestran a los mismos vecinos en los mismos tiles. El primer coleccionista que entra a las 07:40 según el reloj de la sala ve a Moss donde estaría Moss a las 07:40, y lo mismo le pasa a un coleccionista que entra en la misma sala desde un teléfono configurado en otra zona.63

Comprobaciones. (a) El ritmo, por diseño. Para el tramo preferido, una prueba de cliente le pasa un walk con script con una ruta recta de 5 tiles y una marca at, registra la posición del vecino en cada tick, igual que el -motionLog del encargo de movimiento registra la del jugador, y comprueba que arranca en el tick en que cae at según la estimación del cliente del reloj de la sala, visita los tiles de la ruta en orden, se mueve exactamente 1 pixel en cada tick y nunca hacia atrás, tarda 16 ticks por tile y está en el último tile 80 ticks después de at; una prueba de servidor comprueba que cada tramo se envía una sola vez, entero, con su marca. Para la alternativa mínima, una prueba de servidor hace funcionar a los vecinos durante una hora simulada con el tick de 0,5 s y comprueba que cada intervalo entre pasos dentro de un tramo es igual al configurado; hoy measure_npc_cadence.py encuentra 1,0 s frente a los 0,7 s configurados. Para cualquiera de los dos, una prueba de servidor comprueba que cada espera es un número entero de ticks.622 (b) Una prueba abre dos salas con la misma zona separadas por 600 segundos, ambas con la única semilla global, y comprueba que los tiles de los vecinos son idénticos en el mismo instante del servidor; una prueba de cliente con la zona del teléfono distinta de la de la sala comprueba que la franja del día de la plaza sigue el reloj de la sala. (c) Una prueba fija el reloj del servidor en un instante UTC que corresponde a las 03:00 en la zona de la sala y comprueba que los cinco de los puestos y los dos que deambulan no están en el mapa de la plaza y que el que camina por el circuito conservado sí está. (d) Una prueba de servidor cuenta a los ocho por tipo y encuentra 5 en puestos, 2 que deambulan y 1 en el circuito conservado.

7.2 Ecos: las últimas ocho caminatas

  • Mecánica. La plaza conserva las últimas 8 visitas.413 Una visita es la ruta recorrida, como pares de tile y tiempo, desde la llegada hasta la primera puerta que se toma o hasta 60 segundos, lo que sea más corto; la figura del caminante no se guarda. Cuando una sala tiene menos de 8 coleccionistas en vivo, los ecos llenan el hueco: cada uno reproduce su caminata a su propio ritmo y se desvanece en la puerta que tomó. Un eco no tiene placa con nombre, no sostiene ninguna carta, no tiene zona táctil y no dice nada. Es una caminata, no una persona.5
  • Apariencia. La figura de un eco nunca se deriva de la figura del caminante. El servidor le da a cada uno una de cuatro figuras neutras, las piezas por defecto del manifiesto en cuatro tintes neutros, hechas por la forja para los ecos y dibujadas pálidas (una de las rampas de tinte de la forja con una opacidad fija). Cuál de las cuatro se elige lo decide un hash con clave de la sal propia de la caminata, con el secreto del servidor, que el servidor guarda y nunca envía, así que dos caminatas del mismo coleccionista reciben figuras sin relación entre sí. Un coleccionista también puede llevar piezas por defecto, así que un caminante que resulte llevar una de las cuatro puede coincidir con su eco por casualidad, y la coincidencia no transmite nada: la figura no dice nada de quién caminó.58
  • Desgaste. Un eco se descarta a los 7 días o cuando llegan 8 visitas más recientes, lo que ocurra primero.14
  • Quién ve los ecos. Los coleccionistas de la plaza en vivo, siempre que haya menos de 8 de ellos. Nadie cuyo isMultiplayerGamingRestricted sea verdadero: su plaza tranquila son solo vecinos, porque según mi lectura un eco forma parte del multijugador de la plaza (7.6, ajuste 1).18
  • Ocultación. Ocultar a un coleccionista oculta también sus ecos, y el filtrado lo hace el servidor. Cada caminata guardada lleva una sal aleatoria y una etiqueta: un hash con clave (un HMAC) del id del caminante y esa sal, con un secreto que solo tiene el servidor, así que dos caminatas del mismo coleccionista llevan etiquetas sin relación entre sí. Una solicitud de ecos lleva los ids que el solicitante ha ocultado; el servidor recalcula la etiqueta de cada id oculto para cada caminata guardada, deja fuera las caminatas que coinciden y descarta la lista cuando responde a la solicitud o, en una conexión en vivo, cuando se cierra el socket. Lo que llega a un cliente es una figura neutra, la ruta y la hora: ningún id, ninguna etiqueta, ninguna sal y nada tomado de la figura del caminante. Eso elimina el identificador y la apariencia, que hoy viajan juntos en cada llegada (Player.public() en server/app/rooms.py envía el id, el nombre y la figura en un solo objeto, y server/app/main.py lo difunde a la sala). No elimina la caminata. Una ruta, su ritmo y su hora pueden señalar a un coleccionista para alguien que estaba en la plaza a esa hora o que sabe adónde va siempre un amigo, y un cliente que estaba en la sala durante esa misma caminata recibió cada tile con el id del caminante en moved. Los ecos no tienen nombre, pero no son anónimos.2320
  • Qué guarda, y la lectura de la COPPA. Ningún nombre, ningún id de Game Center, ningún id de dispositivo, ninguna figura del caminante, ninguna región y ninguna hora más fina que la hora en punto: los tiles, los tiempos de cada paso relativos al inicio de la caminata, la hora, la sal, que también elige la figura neutra, y la etiqueta que aplica una ocultación. Lectura, no asesoramiento: la etiqueta se deriva de un identificador persistente, así que la trato como tal. Se queda en el servidor, nunca se envía y se usa con el único fin de aplicar una ocultación, lo que leo como el uso para operaciones internas que describe el § 312.5(c)(7), con aviso. La caminata tal como se envía, sin identificador y con una figura que eligió el servidor, la leo como fuera de la definición de información personal de la regla. El punto débil de esa lectura es que una caminata es comportamiento, y alguien que vio la plaza a esa hora puede vincularla a un coleccionista; la hora sin más precisión, el tope de 60 segundos y los siete días lo estrechan, pero no lo cierran. Los ids ocultos que lleva una solicitud se usan para esa solicitud y ni se registran ni se conservan. La política escrita de retención del aviso de privacidad dice 7 días, como pide el § 312.10.19 Esto hace que el servidor pase de no guardar nada a guardar caminatas durante una semana, y la lectura es una para el abogado que el plan aplaza hasta que haya tracción.23
  • A quién se registra. A nadie menor de 13: según la decisión del 2 de octubre no tienen plaza.23 A nadie cuyo isMultiplayerGamingRestricted sea verdadero (no tiene una plaza en vivo por la que caminar, ajuste 1), a nadie cuyo isUnderage sea verdadero, que el ajuste 2 ya trata como señal de un niño, y a nadie de 13 a 15 según el rango declarado, que es la primera de las reglas juveniles que el plan deja por escribir.185223
  • No debe parecerse a. Una mancha de sangre, una muerte reproducida, una señal de invocación, un muro de publicaciones de jugadores. Un eco nunca es una criatura y nunca combate.4144

Comprobaciones. (a) Una prueba de servidor registra 10 visitas y comprueba que se conservan 8 y se descarta la más antigua, y que ninguna sobrevive a un reloj adelantado 7 días. (b) Una prueba de esquema comprueba que una caminata guardada tiene exactamente los campos ruta, hora, sal y etiqueta, sin ninguna cadena de nombre, id o figura, y que los ecos que recibe un cliente tienen exactamente los campos figura, ruta y hora: ningún campo de hash, etiqueta, sal ni id. Comprueba que la cadena de figura del eco es la de las cuatro que elige el hash con clave de la sal de la caminata, la misma lleve lo que lleve el caminante, y, para un caminante con una figura ajena a las cuatro neutras, que no es la del caminante. (c) Una prueba de interfaz sin compañeros en vivo muestra hasta 8 ecos, y ninguno responde a un toque. (d) Una prueba con el flag de multijugador restringido, otra con isUnderage y otra con la franja de 13 a 15 comprueban que el servidor no registra ninguna visita de ese cliente. (e) Una prueba de servidor guarda caminatas de dos coleccionistas, solicita ecos con uno de ellos oculto, comprueba que las caminatas de ese coleccionista quedan fuera y, después, que el id oculto no aparece en ningún lugar del estado del servidor.

7.3 El saludo del día

  • Mecánica. Cada vecino recuerda si hoy hablaste con él.1110 La primera conversación del día local elige una frase de saludo («¡Otra vez por aquí!» y otras de su tipo, escritas para Kiradex y añadidas después del índice 22 en server/app/lines.py); las conversaciones posteriores del mismo día eligen una frase normal.21 Cada tercer día en que has hablado con el mismo vecino lo sube un escalón en una escalera oculta de clientes habituales, contada desde tu primera conversación y nunca reiniciada, y en cada escalón dice una frase nueva. No se muestra ningún medidor.
  • Sin desgaste. No se pierde nada por faltar un día, ni un mes. La amistad de Stardew se desgasta por cada día que no hablas; esta nunca, porque PEGI clasifica las «daily quests, log-in streak or event-based rewards that expire after a while» (misiones diarias, rachas de inicio de sesión o recompensas por eventos que caducan al cabo de un tiempo) como PEGI 7, y como PEGI 12 cuando «players are punished by losing rewards or game status when they do not return in time» (se castiga a los jugadores con la pérdida de recompensas o de estatus en el juego cuando no vuelven a tiempo).105958
  • Dónde vive. En el dispositivo: un diccionario que asocia el id de cada vecino con la última fecha local en que hablaste con él y el número de días en que lo hiciste, dentro del perfil del coleccionista, para que el servidor siga sin almacenamiento por jugador.

Comprobaciones. (a) Una prueba unitaria habla con un vecino dos veces el 2026-10-05 y una vez el 2026-10-06 y obtiene dos saludos de primera vez del día y una frase normal. (b) Una prueba unitaria adelanta y atrasa la fecha del dispositivo y no encuentra nunca un escalón retirado. (c) Una búsqueda en server/app no encuentra ningún almacenamiento por jugador añadido para esta función. (d) Una prueba unitaria con primeras conversaciones en tres días separados por semanas encuentra al vecino un escalón más arriba.

7.4 Presencia sin retrocesos bruscos

  • Envío. Un move por cada tile completado, como hoy. La referencia de hoy es 4 por segundo al caminar y entre 6,0 y 6,4 al correr (la carrera tal como se modela a 60 Hz y a su velocidad nominal); según el contrato de movimiento de la serie, los 16 ticks por tile al caminar y 8 al correr a 60 Hz del encargo de movimiento, son 3,75 y 7,5, y ese contrato es hacia el que construye este encargo. Los dos quedan por debajo del límite de 8 por segundo.2122 El servidor añade su propia marca de tiempo en milisegundos a cada moved que retransmite.
  • Renderizado. Cada cliente mantiene una estimación del reloj del servidor a partir de las marcas que recibe, y dibuja a cada uno de los demás coleccionistas con un reloj de renderizado 350 ms por detrás de esa estimación: de forma lineal entre las dos marcas recibidas que encuadran el reloj de renderizado, con el ciclo de caminata impulsado por la distancia recorrida. Nunca poner a cero un paso en curso. Cuando el búfer se vacía, quedarse en el último tile; quien camina sobre una cuadrícula se detiene en seco, así que no se extrapola nada. Saltar solo cuando un caminante va más de 6 tiles o 2 segundos por detrás.716 Los 350 ms salen de una cota, comprobada en un modelo que suponía una estimación de reloj exacta y ningún retraso en un sentido más allá del jitter (sección 3): a la caminata del contrato de movimiento, 3,75 tiles por segundo, un paso es 266,7 ms, un paso más 80 ms de jitter son 346,7 ms, y un retraso al menos así de largo no deja sin datos ningún fotograma para ninguna extracción de jitter. Eso deja unos 3 ms para el error de la estimación del reloj; una estimación que vaya por delante del reloj del servidor más que eso puede dejar fotogramas sin datos. 325 ms superó la comprobación (a) en la primera extracción de jitter del modelo, con 6 fotogramas sin datos a 80 ms, pero no la superó en 8 de 200 extracciones; 350 ms no dejó ninguno sin datos en ninguna.7 Es un valor de partida que una captura en dispositivos debe confirmar, no un resultado.
  • Inactividad. Marcar a un coleccionista como inactivo tras 120 segundos sin entrada, mostrado con el ciclo de reposo doze que ya tiene el rig, igual que Arcturus marca un avatar como inactivo a los 240 ciclos de 500 ms.1550 Cerrar el socket tras 240 segundos sin ping. Esa regla es una adaptación mía de dos fuentes: la comprobación del ping es la de Houdini, que cierra cualquier cliente que no envió ningún latido durante una ventana de 61 segundos, y los 240 segundos son el tiempo tras el cual Arcturus expulsa a quien no es dueño y está inactivo, aunque Arcturus cuenta ciclos sin acción, no pings que faltan.4815

Comprobaciones. (a) Portar la lógica nueva a measure_remote_walk.py, con el reloj de renderizado tomado de la estimación del cliente del reloj del servidor y no del reloj propio del emisor, y, con el emisor a 3,75 y 7,5 tiles por segundo, exigir 0 fotogramas hacia atrás en los seis casos, 0 fotogramas sin datos con 0 y 30 ms de jitter, y como mucho 10 fotogramas sin datos de los 600 dibujados mientras el emisor está enviando con 80 ms. El modelo con un reloj exacto da 0 fotogramas sin datos en los seis casos con 350 ms, en cada una de 200 extracciones de jitter.7 (b) Una prueba de interfaz con un compañero con script que cruza la plaza caminando hacia la derecha no captura ningún fotograma en el que la x del compañero disminuya. (c) Una prueba de servidor comprueba que cada moved retransmitido lleva una marca. (d) Una prueba de servidor adelanta el reloj 241 segundos sin ping y comprueba que el socket está cerrado.

7.5 El libro de frases

  • Forma. Seis ramas, cada una con entre 8 y 12 frases en el lanzamiento, de 48 a 72 en total, cada frase a dos toques (rama y luego frase): Saludos, Respuestas (una era favorita, cuánto tiempo llevas coleccionando, qué expansión), Coleccionismo, Intercambios (acordar un intercambio, nunca ponerle precio), Ánimos y Despedidas. Hoy hay 14 frases de jugador en una sola lista.21 Los emotes siguen siendo una fila aparte. Un jugador para el que Game Center indica comunicación restringida, o que es menor de edad, no recibe el libro de frases en absoluto (7.6, ajuste 2).
  • Crecimiento. Hasta 30 frases más desbloqueadas jugando, como mucho una al día, a partir de la escalera de habituales de 7.3 y de los niveles.1235 El servidor guarda la lista y puede retirar una frase en menos de una hora, ya que envía la lista al llegar.20
  • Frente al canon. Easy Chat abre 940 palabras y las compone en cuadrículas de 2 a 10 casillas; New Horizons tiene 88 gestos; el Club Unión de Esmeralda admitía 15 caracteres escritos.38124 Las frases de Kiradex son frases completas, nunca compuestas a partir de palabras, así que ninguna secuencia de elecciones puede deletrear un nombre, un número o un lugar.
  • No debe parecerse a. La estructura de grupos de Easy Chat ni su cuadrícula de palabras, la lista de frases de moda ni ninguna palabra de la franquicia.40

Un esquema del libro de frases propuesto: un nodo raíz con seis ramas, Saludos, Respuestas, Coleccionismo, Intercambios, Ánimos y Despedidas, cada una con ocho casillas de frase ocupadas y cuatro libres, de 8 a 12 frases por rama. Notas debajo: hoy, 14 frases de jugador en una sola lista; el Easy Chat de Esmeralda, 940 palabras abiertas en cuadrículas de 2 a 10 casillas; el Club Unión de Esmeralda, mensajes escritos de 15 caracteres y 10 frases registradas.

El libro de frases propuesto: la única figura de este artículo que es una propuesta y no una medición.26

Comprobaciones. (a) Una prueba sobre lines.py comprueba 6 ramas con entre 8 y 12 frases cada una en el lanzamiento, y que cada frase está como mucho a 2 toques de la raíz. (b) Una prueba comprueba que ninguna frase contiene un dígito ni un hueco libre. (c) Una prueba lee las listas de palabras de Easy Chat de pret y no encuentra ninguna frase igual a una entrada ni ninguna entrada de dos o más palabras dentro de una frase. (d) Una prueba unitaria desbloquea una frase en cada uno de dos días consecutivos y rechaza un segundo desbloqueo el mismo día.

7.6 Ajustes de seguridad, cada uno con una comprobación

  1. La restricción de Game Center apaga a los demás coleccionistas, en vivo y en repetición. Cuando GKLocalPlayer.local.isMultiplayerGamingRestricted es verdadero, incluido el modo solo amigos, la plaza se abre como la plaza tranquila: solo vecinos, sin ecos y sin WebSocket. Los vecinos y el reloj de la sala llegan en una sola solicitud que no lleva id de cuenta, ni id de dispositivo, ni ids ocultos; el servidor usa la dirección IP de la solicitud solo para responderla, y el servidor de la plaza no la registra; los registros de solicitudes del propio proveedor en el borde no se verifican aquí (ajuste 6).18 Lectura: la página dice «If your game uses a custom multiplayer feature, you should disable it» (si tu juego usa una función multijugador propia, deberías desactivarla), y un eco es la repetición de la caminata de un coleccionista real, un rastro de otro jugador del tipo que repasa la sección 2, y uno que quien lo ve puede reconocer (7.2). Wikipedia describe las imágenes fantasmales de otros jugadores de Dark Souls bajo el encabezado Multiplayer del juego, sin decir si son grabaciones o jugadores conectados en ese momento. Esa fuente es ambigua: el texto bajo el encabezado dice que el juego «integrates online features into the single-player world» (integra funciones en línea en el mundo de un solo jugador) y presenta el «Direct multiplayer» (multijugador directo) como las invocaciones cooperativas y las invasiones, aparte de los fantasmas. El encargo toma igualmente el lado prudente: según mi lectura, los ecos forman parte de la función multijugador propia de la plaza, y un jugador cuyo padre o madre restringió el multijugador no ve ninguno.1841 Lo que permitiría devolverle los ecos a este jugador es que App Review, o Apple por escrito, interpretara una caminata reproducida con una figura neutra, sin ningún identificador asociado, como algo distinto del multijugador; este encargo no lo da por supuesto. Comprobación: una prueba de interfaz con el flag simulado en verdadero comprueba que no se abre ningún WebSocket, que no se dibuja ningún eco y que la plaza dice que está tranquila; una prueba de servidor llama a la ruta de la plaza tranquila y no encuentra ningún eco en la respuesta ni ninguna dirección IP en el registro del servidor.
  2. Comunicación propia desactivada. Cuando isPersonalizedCommunicationRestricted o isUnderage es verdadero, lo predeterminado es solo emotes: el libro de frases se oculta, no se envía ningún say, las frases de los demás coleccionistas no se dibujan para este jugador, y nunca hay voz, ni mensaje de invitación, ni campo de texto.5152 Lectura: la página dice «If your game includes any custom communication features, you should disable them» (si tu juego incluye funciones de comunicación propias, deberías desactivarlas), y un libro de frases predefinidas es una función de comunicación propia. Que Game Center permita a los niños mensajes predefinidos en sus propias funciones no exime a las de un juego.5117 Mantengo los emotes porque un saludo con la mano o un gesto de asentimiento no transmite nada que un niño pudiera usar para contactar con alguien, pero un emote es una forma de comunicación (el relato de Wikipedia sobre Journey llama a su tañido «The only form of communication between the two», la única forma de comunicación entre los dos), y este es el paso más débil de la lectura: si App Review considera también los emotes una función de comunicación propia, desaparecen y la plaza es solo presencia para este jugador.5 Mantener las frases para este jugador sería una excepción que necesita el acuerdo de Apple por escrito; este encargo no la toma. Comprobación: una búsqueda en Kiradex/World de TextField, TextEditor y UITextField no devuelve nada, y una prueba de interfaz con cada flag simulado en verdadero muestra la fila de emotes, ningún libro de frases, no envía ningún say y no dibuja ninguna frase de otro coleccionista.
  3. Franjas de edad según Declared Age Range, como se decidió el 2 de octubre. Menores de 13: sin plaza, solo un nombre generado. De 13 a 15: la plaza con reglas juveniles, la primera de las cuales es que sus caminatas nunca se registran. De 16 en adelante, o sin declarar: la plaza completa.2354 Comprobación: una prueba unitaria de la tabla de modos para las tres franjas y los tres flags de Game Center.
  4. Denunciar y ocultar llegan a los ecos. Ocultar a un coleccionista oculta su figura en vivo y, filtrados en el servidor en cada solicitud como en 7.2, sus ecos; la denuncia sigue en el panel de cada coleccionista.55 Un eco lleva una figura neutra y no tiene panel, así que un jugador no puede distinguir el eco de un coleccionista oculto para ocultarlo; eso lo hace el filtro del servidor. Una ocultación alcanza las caminatas guardadas antes y después de ella; no puede alcanzar lo que otro jugador vio en vivo ni lo que reconoce en una caminata. Comprobación: la prueba de servidor de 7.2(e), y una prueba de interfaz que oculta a un compañero con script, reproduce su caminata grabada y comprueba que no se dibuja.
  5. Sin emparejamientos aleatorios, sin chat anónimo. Los desconocidos solo comparten la plaza; nada empareja a dos desconocidos en un espacio privado.55 Comprobación: una prueba sobre los manejadores de server/app/main.py no encuentra ningún mensaje que abra un canal entre dos coleccionistas que no sean amigos en Game Center.
  6. La retención, por escrito. El aviso de privacidad incorpora la política escrita de retención de datos: la presencia, solo en memoria; los ecos, 7 días, cada uno con un hash con clave del id del caminante que se queda en el servidor, se usa solo para aplicar ocultaciones y nunca se envía; los ids ocultos que lleva una solicitud, no se conservan; la dirección IP de una conexión, usada solo para responderla y enrutar la respuesta, lo que leo como soporte a las operaciones internas conforme al § 312.5(c)(7), y no registrada por el servidor de la plaza; las denuncias, registradas por motivo y sala.19 Hoy el servidor arranca uvicorn 0.37.0 con sus valores por defecto (server/Procfile, --proxy-headers), y leyendo el propio código de uvicorn, esos valores por defecto escriben en el registro la dirección reenviada del cliente en cada solicitud HTTP (el registro de accesos está activado salvo que se desactive) y en cada WebSocket aceptado (una línea INFO en uvicorn.error); el encargo lo arranca con --no-access-log --log-level warning.57 Comprobación: la URL del aviso es accesible desde Ajustes, la prueba de servidor de 7.2(a) mantiene los 7 días, y una prueba que abre un WebSocket y llama a la ruta de la plaza tranquila con el comando de arranque de producción no encuentra ninguna dirección IP en el registro capturado. Los registros de solicitudes del proveedor en el borde quedan fuera de esa prueba y no están verificados aquí: si registran la dirección del cliente, y durante cuánto tiempo, hay que confirmarlo con el proveedor antes de redactar el aviso.
  7. Nada de analítica ni publicidad de terceros en el mundo.55 Comprobación: una auditoría de dependencias del target de la app no encuentra ningún SDK de analítica ni de publicidad.

Qué rechazar

  • Un temporizador de juego propio. Screen Time ya limita el tiempo en una app, y el servidor de Club Penguin descontaba los minutos permitidos de un niño y lo desconectaba al llegar a cero; el límite de la plataforma es el que un padre o una madre ya conoce.1748
  • Recuentos de seguidores, y cualquier recuento de quién le gusta a quién; el plan ya los descarta.23
  • Una lista de visitantes con nombres, una página de quién pasó por aquí. Un eco no tiene nombre a propósito: no lleva id ni nada tomado de la figura del caminante. No es anónimo: alguien que estaba en la plaza a esa hora, o que conoce las costumbres de un amigo, todavía puede reconocer una caminata, y por eso un eco lleva la hora y ningún tiempo más fino, y por eso no hay ninguna lista de la que leer ecos.
  • Un eco que se pueda tocar, con el que hablar o al que seguir.
  • Un medidor del saludo del día, o cualquier cosa que se pierda por no volver.59

Fuera de este encargo

  • Salas que la gente decora. Los muebles, las gorras y visitar las salas de otros coleccionistas corresponden a un próximo artículo de esta serie.
  • El texto de las frases nuevas. El encargo fija la forma del libro de frases; las frases se escriben para Kiradex y se localizan por separado.
  • El juego en grupo. Los intercambios, la exhibición de cartas y la pantalla de intercambio que el plan enumera como pendientes de construir quedan fuera de este encargo.23
  • Nada de los juegos medidos. Ninguna criatura, nombre de lugar, marca, tile ni sonido de Pokémon, Stardew Valley, Animal Crossing, Dark Souls, Journey, Death Stranding, Splatoon, Habbo ni Club Penguin.
  • Tiempos en un dispositivo. Las comprobaciones son de comportamiento, capturas y un modelo; nada de esto promete un tiempo de fotograma.

Conclusiones clave

Si dibujas el arte

  • Dibuja más gente de pie que caminando. Seis de cada diez de los vecinos que siempre están en los mapas de Esmeralda están de pie en un puesto, la mayoría mirando hacia un lado y algunos mirando alrededor (siete de cada diez si se cuentan los actores de la historia); dale a cada figura de pie una orientación y una mirada alrededor, y reserva los ciclos de caminata para los casi cuatro de cada diez que deambulan.1
  • Haz que el eco de la caminata de otro jugador se lea como un rastro, no como una persona: pálido, sin nombre, sin sostener nada, desvaneciéndose en una puerta. Nada en su dibujo debería invitar a tocarlo.5

Si construyes el motor

  • Ajusta el día del pueblo a la llegada, con una ejecución que recibe el número de días transcurridos, y calcula el tile de un vecino a partir de un único reloj que comparten todos los de la sala, no a partir del de cada teléfono; un bucle de servidor que retorna cuando la sala está vacía congela el pueblo, como el de Kiradex que medí.36
  • Haz que el intervalo de paso del servidor sea un número entero de ticks y dibuja cada paso a lo largo del intervalo que se le dio; un paso de 0,7 s sobre un tick de 0,5 s cae cada 1,0 s y se dibuja en 0,25 s, una caminata que está quieta el 75 por ciento del tiempo.6
  • Envía una actualización por tile, ponle la marca en el servidor y dibuja a los demás caminantes con un reloj 350 ms por detrás del tiempo estimado del servidor sin poner nunca a cero un paso en curso; en el modelo, a los 3,75 y 7,5 tiles por segundo de la serie y con una estimación de reloj exacta, eso da 0 fotogramas hacia atrás y 0 sin datos con hasta 80 ms de jitter.7
  • Lee isMultiplayerGamingRestricted, isPersonalizedCommunicationRestricted e isUnderage antes de abrir un socket; el modo solo amigos figura como restringido, y según mi lectura un jugador restringido tampoco debería ver repeticiones de otros jugadores.185152

Si diseñas el bucle

  • Guarda los rastros de los demás en unas pocas ranuras fijas que se desgasten: ocho caminatas durante siete días bastan para decir que alguien estuvo aquí. Aplica las ocultaciones en el servidor, envía un rastro sin id y con una figura neutra en lugar de la del propio caminante, y di con claridad que una caminata todavía puede reconocerla alguien que la vio.414
  • Recuerda el saludo del día con un flag y no quites nunca nada por un día perdido; PEGI clasifica las rachas que caducan.59
  • Dales a los desconocidos frases, no palabras: un libro de frases completas no se puede usar para deletrear nada, y Game Center ya limita a los niños a mensajes predefinidos. Cuando Game Center diga que la comunicación está restringida, retira también el libro de frases.381751

Preguntas frecuentes

¿Cómo se consigue que un pueblo de un juego se sienta vivo sin otros jugadores conectados?

Dale vecinos con sus propias rutinas y rastros de personas que estuvieron allí. En los 16 pueblos y ciudades de Pokémon Esmeralda, 59 de los 100 vecinos sin flag de ocultación están de pie en sus puestos, 39 deambulan en recuadros de una o dos celdas y 2 caminan en el sitio (71,5 %, 27,2 % y 1,3 % de las 158 en total, contando a los actores de la historia que un flag puede retirar, que casi siempre están de pie), dan pasos al ritmo del jugador y esperan entre 0,54 y 2,14 segundos entre pasos; los aldeanos de Stardew Valley siguen días de unos pocos puntos con hora elegidos mediante 22 formatos de clave; y el mezclado de datos de Esmeralda copia en tu pueblo las bases, las frases de moda y el residente de otro jugador.124

¿Con qué frecuencia deberían moverse los NPC en un juego de pixel art con vista cenital?

En Esmeralda, quien deambula da un paso de 16 fotogramas (268 ms, la misma acción que la caminata del jugador) y luego espera 32, 64, 96 o 128 fotogramas, así que está en movimiento como mucho entre un 11 y un 33 por ciento del tiempo, por paso dado, y menos cuando el paso que elige está bloqueado; la mayoría de los vecinos tienen un tipo de movimiento por defecto que nunca da un paso, aunque un script de la historia todavía puede hacer caminar a uno. Wild World, de Animal Crossing, fue en la dirección contraria y ralentizó a sus vecinos por debajo del ritmo del jugador. Lo que se ve mal es un ritmo que no es ni lo uno ni lo otro: los coleccionistas de Kiradex se mueven a la velocidad del jugador a ráfagas de un tile con paradas de 0,75 segundos entre tiles.1326

¿Qué es el mezclado de datos en Pokémon Esmeralda?

Un intercambio por cable link en el que cada partida le envía a la otra una estructura fija de 11 tipos de registro en 5.188 bytes, entre ellos 20 Bases Secretas, 25 ranuras de televisión, 16 noticias y 5 frases de moda. El anciano de Mauville del compañero sustituye al tuyo, y la llegada del Hipster es lo único que le permite enseñar otra frase de moda.435

¿Cuánto retraso de interpolación necesita un juego multijugador en 2D?

La regla de Glenn Fiedler es lo suficiente para sobrevivir a dos paquetes perdidos, unos tres intervalos de envío, más un fotograma o dos para el jitter.16 Sobre WebSockets, que funcionan sobre TCP, no se pierde nada y un paquete tardío se retransmite, así que según mi lectura el presupuesto es de jitter y no de paquetes perdidos, y puede bastar un búfer de un poco más de un intervalo. Para un mundo sobre cuadrícula que envía una actualización por tile, un modelo de la caminata de Kiradex a los 3,75 tiles por segundo de la serie al caminar y 7,5 al correr encontró que un reloj de renderizado 350 ms por detrás del tiempo estimado del servidor da 0 fotogramas hacia atrás y 0 fotogramas sin datos con hasta 80 ms de jitter; en una extracción de jitter, 300 ms deja sin datos 27 de 600 fotogramas al caminar con 80 ms y 325 ms, 6, mientras que 100 ms deja sin datos entre 125 y 456 en todos los casos, y en 200 extracciones 350 ms no deja ninguno sin datos en ninguna. Los 350 ms se apoyan en una cota: un paso de 266,7 ms a 3,75 tiles por segundo más 80 ms de jitter son 346,7 ms. Es un modelo con una calle recta, jitter uniforme, una estimación de reloj exacta y sin latencia de base, no una captura en un dispositivo.7

¿Pueden los niños usar el chat en un juego de iOS?

Game Center dice que los niños «cannot send or receive user-inputted text» (no pueden enviar ni recibir texto escrito por el usuario) y están «restricted to sending and receiving preset messages» (limitados a enviar y recibir mensajes predefinidos), con el chat de voz desactivado. La documentación de Apple le dice a un juego con «any custom communication features» (cualquier función de comunicación propia) que las desactive cuando isPersonalizedCommunicationRestricted o isUnderage es verdadero, y la directriz 1.2 exige filtrado, denuncias, bloqueo y datos de contacto publicados para el contenido generado por los usuarios. Esa frase no exime a los mensajes predefinidos, así que, según mi lectura, las frases predefinidas propias de un juego desaparecen cuando cualquiera de los dos flags es verdadero, aunque Game Center permita a los niños mensajes predefinidos en sus propias funciones; el encargo de Kiradex mantiene solo los emotes para ese jugador, y esa lectura es mía, no del texto de Apple.175155

¿Permite la COPPA guardar los movimientos de otros jugadores para reproducirlos como fantasmas?

No soy abogado, y esto es una lectura, no asesoramiento. La regla enmendada cuenta como información personal «A persistent identifier that can be used to recognize a user over time» (un identificador persistente que puede usarse para reconocer a un usuario a lo largo del tiempo), permite a un operador usar un identificador persistente por sí solo «for the sole purpose of providing support for the internal operations» (con el único fin de dar soporte a las operaciones internas) con aviso, y desde el 22 de abril de 2026 exige una política escrita de retención con un plazo de eliminación. El diseño de Kiradex guarda una caminata sin nombre, sin id de cuenta, sin id de dispositivo y sin la figura del caminante, más un hash con clave del id del caminante que se queda en el servidor, se usa solo para aplicar las ocultaciones de otros jugadores y nunca se envía; el eco se dibuja con una de cuatro figuras neutras que elige el servidor, y ambas cosas se conservan siete días y figuran en esa política. Trato el hash como un identificador persistente usado para operaciones internas, y la caminata tal como se envía como fuera de la definición, pero una caminata es comportamiento que alguien que vio la plaza a esa hora podría vincular a un coleccionista, así que los ecos no tienen nombre pero no son anónimos, y un abogado debería revisar el diseño final.19

Relacionados en este sitio: Mundos de pixel art en el iPhone es la primera guía de esta serie, con los sistemas de tiles y la plaza en la que vive el pueblo de este artículo, y su FAQ legal traza la línea de las patentes que sigue el encargo; Personas en pixel art: personajes y un creador en el iPhone construyó los coleccionistas y la forja cuyas figuras neutras llevan los ecos, y cita la regla de PEGI que impide que el saludo del día se desgaste; Estructuras en pixel art: casas, salones e interiores en el iPhone construyó las puertas por las que los vecinos vuelven a casa de noche; Movimiento en pixel art: caminatas, cámaras y puertas en el iPhone mide las caminatas de las portátiles, modela la de la app y fija la regla de no poner nunca a cero un paso que el encargo aplica a los demás coleccionistas; e iPhone Duo para desarrolladores trata el dispositivo para el que se dibuja la plaza.

Fuentes


  1. Medición del autor, measure_npcs.py en la carpeta de evidencias del autor para este artículo, revisado y vuelto a ejecutar el 5 de octubre de 2026, salida guardada como measure_npcs.out. Entradas: la descompilación pokeemerald de pret, un clon superficial en el commit 731ad5b (master, 1 de octubre de 2026): include/constants/event_object_movement.h (los 81 tipos de movimiento), los 16 archivos data/maps/*/map.json de pueblos y ciudades (eventos de objeto, ids de gráficos, tipos de movimiento, rangos, flags de ocultación) y src/event_object_movement.c (las tablas de pasos, las tres tablas de esperas cronometradas a 59,7275 Hz, qué tipo de movimiento fija qué espera, y MovementType_WanderAround_Step4). La revisión clasifica los eventos de objeto por graphics_id en personas, objetos (6 ITEM_BALL, 2 TRUCK, 1 MR_BRINEYS_BOAT) y criaturas (5), y se detiene si aparece un id de gráfico que no ha clasificado; los eventos VAR_0 y VAR_3, cuyo sprite sale de una variable, se cuentan como personas porque todos llevan el flag de ocultación de un rival. La versión anterior contaba como vecinos los 172 eventos de objeto; ella y su salida se conservan junto a la actual con el sufijo .r1, y la salida de la revisión repite sin cambios las líneas anteriores. La primera revisión y su salida se conservan con el sufijo .r2; el script actual, una segunda revisión, divide a las 158 personas según el flag de ocultación de su evento de objeto: las 58 que tienen uno (54 de pie, 4 deambulan; 41 de ellas usan el sprite de un equipo villano, del rival o de un personaje con nombre, según una lista fija de ids de gráficos del script) y las 100 que no tienen ninguno (59 de pie, 39 deambulan, 2 caminan en el sitio), y vuelve a contar a las personas sin flag de ocultación de los tres pueblos (Littleroot 2, Petalburg 3, Mauville 6); su salida repite sin cambios todas las líneas anteriores. Una persona sin flag de ocultación está en el mapa en cada carga; llamar actores de la historia a las 58 es mi lectura de sus sprites y de los nombres de sus flags, no un campo de los datos. Las proporciones de movimiento (del 11 al 33 por ciento) son aritmética sobre las filas de pasos y esperas, 16 fotogramas sobre 16 más 32 a 128, por paso dado: una cota superior, porque quien deambula y encuentra bloqueada la dirección elegida mira y espera otra vez sin moverse. ↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩

  2. Medición del autor, measure_daily.py en la misma carpeta, vuelto a ejecutar el 5 de octubre de 2026, salida idéntica a measure_daily.out. Entradas: include/constants/flags.h y src/clock.c de pokeemerald de pret en 731ad5b; las páginas guardadas de la Stardew Valley Wiki «Villagers» (oldid 191346, editada el 26 de febrero de 2026), «Pierre» y «Modding:Schedule data» (los 22 formatos de clave contados en las tablas de la página); y la página «Reaction» de Nookipedia (los recuentos de New Horizons por versión). ↩↩↩↩↩↩↩↩↩↩↩

  3. pret, pokeemerald/src/clock.c (DoTimeBasedEvents, y UpdatePerDay, que se ejecuta una vez con daysSince, los días transcurridos desde su última ejecución), commit 731ad5b; DoTimeBasedEvents también se llama al cargar mapas en src/overworld.c y desde una tarea periódica de campo en src/field_tasks.c, consultado el 4 de octubre de 2026, https://github.com/pret/pokeemerald/blob/master/src/clock.c. ↩↩↩↩↩↩↩

  4. Medición del autor, measure_record_mixing.py en la misma carpeta, vuelto a ejecutar el 5 de octubre de 2026, salida idéntica a measure_record_mixing.out. Entradas: src/record_mixing.c de pokeemerald de pret en 731ad5b (struct PlayerRecordEmerald, sus 11 miembros y su tamaño de 0x1444 bytes), include/constants/global.h y las cabeceras relacionadas (SECRET_BASES_COUNT, TV_SHOWS_COUNT, POKE_NEWS_COUNT, SAVED_TRENDS_COUNT, APPRENTICE_COUNT), src/mauville_old_man.c (los cinco ancianos y la regla de selección), y src/union_room_chat.c, include/union_room.h e include/constants/global.h (los líderes, el tamaño de grupo, los sprites, los códigos de actividad, las páginas de teclado, MAX_MESSAGE_LENGTH y UNION_ROOM_KB_ROW_COUNT del Club Unión). ↩↩↩↩↩↩↩↩↩↩↩↩

  5. Wikipedia, «Journey (2012 video game)», secciones Gameplay y Development, cada afirmación citando su propia fuente, guardada el 4 de octubre de 2026, https://en.wikipedia.org/wiki/Journey_(2012_video_game). También se guardó la página propia de Journey de thatgamecompany, que solo contiene navegación. ↩↩↩↩↩↩↩

  6. Medición del autor, measure_npc_cadence.py en la misma carpeta, revisado y vuelto a ejecutar el 5 de octubre de 2026, salida guardada como measure_npc_cadence.out; la revisión solo añade un recuento de cada mensaje said (469 en la hora), junto a los 465 intervalos entre frases consecutivas de un mismo coleccionista sobre los que se calcula la media de 30,7 segundos, y sus demás líneas no cambian (la versión anterior se conserva con el sufijo .pre-astra). Importa los propios app.npcs (STEP_SECONDS, make_all) y app.rooms (Plaza) del servidor de Kiradex desde el árbol de trabajo leído el 5 de octubre de 2026 (archivos y hashes en la nota 20), lee TICK_SECONDS de server/app/main.py, y hace avanzar a cuatro coleccionistas con la semilla 1 sobre un reloj ideal de 0,5 s durante 3.600 segundos simulados, registrando cada mensaje moved y said. Los intervalos de 1,5 s o menos entre pasos consecutivos se cuentan como dentro de un tramo; los huecos más largos son pausas. La prueba de sala vacía comprueba el retorno temprano de Room.tick y llama una vez a advance(10000.0) sobre coleccionistas recién creados. Las cifras del 25 y el 75 por ciento dividen el paso de 250 ms del cliente (PlazaRig.tilesPerSecond = 4) entre el intervalo medido de 1,0 s. Esta ejecución sustituye los 0,7 s y el 36 por ciento que measure_kiradex.py deriva solo de la constante. ↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩

  7. Modelo del autor, measure_remote_walk.py en la misma carpeta, revisado y vuelto a ejecutar el 5 de octubre de 2026, salida guardada como measure_remote_walk.out; la versión anterior, que hacía la aritmética del rig en flotantes de 64 bits, y su salida se conservan con el sufijo .pre-f32. La revisión hace en 32 bits (float32 de NumPy) cada operación que el rig hace en Float, en el orden del código: progress es un Float (PlazaRig.swift, línea 29), update recibe Float(event.deltaTime) (PlazaStage.swift, línea 149), y advance() suma dt * tilesPerSecond * (running ? runPace : 1) / length (línea 660), con running fijado solo en el jugador (línea 614); las posiciones son (Float(x) + 0.5) * 16 (TileMap.swift, línea 235) y se dibujan en from + (to - from) * progress, redondeadas a pixeles enteros, con los empates alejándose de cero (líneas 670 y 726). Imprime la comprobación de que 15 fotogramas de 1/60 de segundo suman exactamente 1,0 en 32 bits y 0,9999999999999999 en 64. Reimplementa PlazaRig.move(other:to:facing:) tal como se leyó el 5 de octubre (ruta desde el último tile entero del caminante; progress = 0 con cada mensaje; un salto cuando la ruta está vacía o tiene más de 6 pasos) y cuenta como retroceso brusco una puesta a cero mientras quedan pasos y el progreso supera 0,05, como fotograma hacia atrás una posición en pixeles dibujada menor que la del fotograma anterior, y el retraso a partir de la posición en pixeles dibujada. Por separado, modela la interpolación de instantáneas sobre un reloj de renderizado constante, rt = now - delay para retrasos de 100, 250, 300, 325 y 350 ms, donde now es el reloj del emisor, así que la regla modelada es el tiempo estimado del servidor menos el retraso, no la actualización más reciente menos el retraso; esta mitad es un renderizador propuesto, no el rig, y funciona con flotantes de 64 bits. Supuestos: el deltaTime de cada fotograma es exactamente 1/60 de segundo; sin multiplicación y suma fusionadas; sincronización de reloj perfecta entre emisor y renderizador; sin latencia de base en un sentido, así que una actualización llega en su marca más el jitter; una calle recta y despejada (la longitud de la ruta es la distancia Manhattan; los pasos en diagonal, que en el rig tardan √2 veces más, no están modelados); un emisor que emite un movimiento por cada tile completado, a los 4 tiles por segundo de hoy al caminar y a los 6,4 nominales de la carrera para ambas mitades, y para el búfer también al contrato de movimiento de la serie, 3,75 y 7,5 tiles por segundo; jitter uniforme de 0 a J ms para J de 0, 30 y 80; 60 fotogramas por segundo; semilla 1. El rig funciona 12 segundos simulados por caso (10 de envío y 2 para asentarse) y cada ejecución con búfer 660 fotogramas (11 segundos), contando los fotogramas sin datos solo sobre los 600 dibujados mientras el emisor sigue enviando. Un segundo script, measure_remote_walk_seeds.py en la misma carpeta, ejecutado el 5 de octubre de 2026, salida guardada como measure_remote_walk_seeds.out, carga la misma función de interpolación desde el código fuente de measure_remote_walk.py, comprueba que la semilla 1 reproduce sus 27, 6 y 0 fotogramas sin datos, y repite el búfer a 3,75 y 7,5 tiles por segundo con las semillas 1 a 200: con 80 ms de jitter, caminando, 325 ms deja fotogramas sin datos con las 200 semillas y más de 10 con 8, 350 ms ninguno con ninguna, y todos los demás casos a 325 y 350 ms, ninguno. Imprime la cota que hay detrás de los 350 ms: un paso a 3,75 tiles por segundo son 266,67 ms, más 80 ms de jitter, 346,67 ms, lo que deja 3,33 ms. También desplaza el reloj de renderizado como una estimación de reloj que va por delante del reloj del servidor; en este modelo, cuyos fotogramas y pasos se alinean en la rejilla de 1/60 s, 10 ms por delante sigue sin dejar ningún fotograma sin datos en 200 semillas y 25 ms por delante se comporta como 325 ms, así que los 3 ms del texto son la garantía de la cota, no el punto en el que este modelo empieza a quedarse sin datos. Es un modelo, no una captura de dos dispositivos. ↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩

  8. pret, pokeemerald/data/maps/, los 16 archivos map.json de pueblos y ciudades, entre ellos LittlerootTown, PetalburgCity y MauvilleCity, y data/maps/PetalburgCity/scripts.inc (el niño del gimnasio, LOCALID_GYM_BOY, MOVEMENT_TYPE_LOOK_AROUND sin flag de ocultación en map.json, llevado al gimnasio por los movimientos PetalburgCity_Movement_BoyWalkToGym), commit 731ad5b, consultado el 4 de octubre de 2026, https://github.com/pret/pokeemerald/tree/master/data/maps. ↩↩↩↩

  9. Stardew Valley Wiki, «Modding:Schedule data», guardada el 4 de octubre de 2026, https://stardewvalleywiki.com/Modding:Schedule_data. El formato de los horarios, los datos en bruto de Abigail en la versión 1.5.1 del juego, los formatos de clave y su orden, y la nota «Limitations». ↩↩↩↩↩↩↩↩

  10. Stardew Valley Wiki, «Friendship», guardada el 4 de octubre de 2026, https://stardewvalleywiki.com/Friendship. Los puntos por corazón, las formas en que la amistad sube y baja, la tabla de desgaste, los regalos, el multiplicador de cumpleaños y los eventos de corazón. ↩↩↩↩↩↩

  11. Nookipedia, «Friendship», la sección de New Horizons, guardada el 4 de octubre de 2026, https://nookipedia.com/wiki/Friendship. ↩↩↩↩

  12. Nookipedia, «Reaction», la sección de New Horizons, guardada el 4 de octubre de 2026, https://nookipedia.com/wiki/Reaction. Los recuentos por versión salen de measure_daily.py (nota 2). ↩↩↩↩↩

  13. Serebii.net, «Join Avenue», sección de Pokémon Black 2 y White 2, guardada el 4 de octubre de 2026, https://www.serebii.net/black2white2/joinavenue.shtml. Un sitio de fans y la única fuente usada para esta función. ↩↩↩↩↩

  14. Wikipedia, «Death Stranding», sección Gameplay, citando sus propias fuentes, guardada el 4 de octubre de 2026, https://en.wikipedia.org/wiki/Death_Stranding. ↩↩↩↩↩

  15. Krews, Arcturus Morningstar, un emulador de código abierto del servidor de Habbo escrito por fans, src/main/java/com/eu/habbo/habbohotel/rooms/Room.java (IDLE_CYCLES = 240, IDLE_CYCLES_KICK = 480, scheduleAtFixedRate(this, 500, 500, TimeUnit.MILLISECONDS)), guardado el 5 de octubre de 2026, https://git.krews.org/krews/Morningstar/-/blob/master/src/main/java/com/eu/habbo/habbohotel/rooms/Room.java. Constantes del emulador, no cifras publicadas por Sulake; RoomUnit no se leyó. ↩↩↩↩↩↩↩

  16. Glenn Fiedler, «Snapshot Interpolation», Gaffer on Games, 30 de noviembre de 2014, guardado el 4 de octubre de 2026, https://gafferongames.com/post/snapshot_interpolation/. ↩↩↩↩↩↩↩↩

  17. Apple, «Game Center & Privacy», sección «Children in Game Center» y la sección de amigos, guardada el 4 de octubre de 2026, https://www.apple.com/legal/privacy/data/en/game-center/. ↩↩↩↩↩↩↩↩

  18. Documentación para desarrolladores de Apple, GKLocalPlayer.isMultiplayerGamingRestricted (iOS 13.0+), el JSON de la documentación guardado el 4 de octubre de 2026, https://developer.apple.com/documentation/gamekit/gklocalplayer/ismultiplayergamingrestricted. Las citas son el texto de Discussion con la referencia en línea a true convertida en la palabra, aplanado por sources/extract_gk.py en la carpeta del borrador. ↩↩↩↩↩↩↩↩↩↩↩↩

  19. Comisión Federal de Comercio, «Children’s Online Privacy Protection Rule», regla final, Federal Register, 22 de abril de 2025, documento 2025-05904, 90 FR 16918, guardada el 4 de octubre de 2026, https://www.federalregister.gov/documents/2025/04/22/2025-05904/childrens-online-privacy-protection-rule. La sección DATES y los 16 CFR 312.2 (definición de información personal), 312.5(c)(7), 312.8 y 312.10 enmendados. Toda afirmación de este artículo sobre lo que la regla significa para Kiradex es la lectura del autor, no asesoramiento legal. ↩↩↩↩↩↩↩↩↩↩↩

  20. Lectura del autor del repositorio de Kiradex (privado), árbol de trabajo del 5 de octubre de 2026, solo lectura, sin ejecutar ningún comando de git; archivos identificados por los primeros ocho dígitos hexadecimales de su SHA-256: server/app/main.py (87c6cc9f; TICK_SECONDS = 0.5, SHOW_EVERY_SECONDS, los manejadores de mensajes, entre ellos la retransmisión de moved en la línea 223, que lleva el id y el tile del caminante), server/app/npcs.py (d84f12a5; el docstring del módulo, STEP_SECONDS = 0.7, las cuatro definiciones y sus rutas, deseos y frases), server/app/rooms.py (dcd66866; Player.public() en la línea 115, que devuelve el id, el nombre y la figura en un solo objeto, difundido a la sala al llegar en la línea 203 de main.py; CAPACITY, MOVES_PER_SECOND, SAY_EVERY_SECONDS, Plaza, y Room.tick con su docstring y su retorno temprano), server/app/lines.py (391f5391; las 23 frases y el docstring que dice que el servidor envía la lista al llegar). ↩↩↩↩↩↩↩↩↩↩↩

  21. Medición del autor, measure_kiradex.py en la misma carpeta, vuelto a ejecutar el 5 de octubre de 2026, salida idéntica a measure_kiradex.out. Importa app.lines, app.rooms y app.npcs del árbol de trabajo de la nota 20 y lee PlazaRig.swift y PlazaClient.swift (nota 50) para las constantes del cliente: el número de frases predefinidas, la capacidad de la sala, los límites de frecuencia, el tick, el tiempo de espera, el tamaño de la plaza y el punto de llegada, las rutas de los cuatro coleccionistas y la longitud de sus circuitos, las velocidades de caminata y carrera, el umbral de salto de 6 pasos y el retroceso de reconexión. Sus 0,7 s y 36 por ciento derivados quedan sustituidos por la nota 6. ↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩

  22. Blake Crosley, «Pixel-Art Motion: Walks, Cameras and Doors on iPhone», blakecrosley.com, 5 de octubre de 2026, https://blakecrosley.com/blog/pixel-art-motion-on-iphone. Su nota 6 modela la caminata de la app a 60 Hz exactos: la carrera tarda 10 fotogramas por tile, 6,00 tiles por segundo, frente a los 6,4 que implican 4 tiles por segundo por el 1,6 de la carrera, y 6,32 a 120 Hz; su sección sobre el código actual lee en walk(to:) el retroceso brusco con un segundo toque a mitad de paso, y su encargo fija la regla de que un paso en curso nunca se pone a cero; el punto 1 de su encargo fija la caminata en 16 ticks por tile y la carrera en 8 a 60 Hz, 3,75 y 7,5 tiles por segundo, el contrato de movimiento de la serie, y sus comprobaciones registran la posición del jugador en cada tick con un argumento de lanzamiento -motionLog. ↩↩↩↩↩↩↩

  23. Kiradex, docs/WORLD.md («Kiradex World: research and plan»), árbol de trabajo del 5 de octubre de 2026 (SHA-256 c7714bc1), solo lectura: sección 2 (el camino de la categoría Niños y de la 5.1.4, con clasificación 9+ o 12+), sección 3 (identidad con Game Center, controles de Screen Time, sin recuentos de seguidores, frases predefinidas, la lectura del abogado), sección 5 (el servidor tal como se construyó el 2 de octubre: FastAPI y WebSockets, solo presencia, nada almacenado, ocho movimientos por segundo, ocultación en el dispositivo, «Not yet» (todavía no) incluido el modo juvenil según Declared Age Range; y el razonamiento que llevó a él, con los clientes enviando posición y orientación a 8 a 10 Hz), y los puntos 6 (clasificación y franjas de edad) y 8 (ningún abogado hasta que haya tracción) de «Decisions taken (Blake, October 2, 2026)». ↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩

  24. Búsqueda del autor en Kiradex/ y server/app/ del árbol de trabajo de Kiradex, 5 de octubre de 2026, de isMultiplayerGamingRestricted, isUnderage, isPersonalizedCommunicationRestricted, la API Declared Age Range y cualquier almacenamiento de visitas o conversaciones diarias: ninguna coincidencia. ↩↩↩

  25. pret, pokeemerald/include/constants/event_object_movement.h, commit 731ad5b, consultado el 4 de octubre de 2026, https://github.com/pret/pokeemerald/blob/master/include/constants/event_object_movement.h. ↩

  26. Las figuras las dibujó figures/make_figures.py, guardado junto al borrador del artículo, el 5 de octubre de 2026, a partir de las salidas guardadas de measure_npcs.py, measure_npc_cadence.py, measure_chat_trend.py, measure_record_mixing.py, measure_kiradex.py y measure_remote_walk.py; cada valor se extrae de esos archivos y se contrasta con un valor esperado antes de dibujarlo: el del dossier de investigación, salvo en la figura de la población de los pueblos, que ahora representa solo personas a partir del measure_npcs.py revisado, con una fila para las 100 personas sin flag de ocultación, y en las 940 palabras abiertas del libro de frases, a partir del measure_chat_trend.py revisado. Tras la revisión del segundo motor, la figura de la moda representa las puntuaciones en días enteros del propio juego a partir del measure_chat_trend.py revisado (un punto por día transcurrido, no una onda triangular continua), y la figura de la caminata remota representa el measure_remote_walk.py revisado: el rig de hoy en su propia aritmética de 32 bits, y el búfer a los 3,75 y 7,5 tiles por segundo del contrato de movimiento con retrasos de 100, 300, 325 y 350 ms. La figura del libro de frases es un esquema de la propuesta del encargo, con sus números de comparación extraídos de la misma manera. No se usa arte, sprite ni render de mapas de ningún juego. ↩↩↩↩↩

  27. pret, pokeemerald/src/event_object_movement.c (IsCoordOutsideObjectEventMovementRange, sMovementDelaysMedium, sMovementDelaysShort, sMovementDelaysLong con su comentario // Unused, la espera fija de 48 fotogramas de los dos tipos que rotan, MovementType_WanderAround_Step4, GetWalkNormalMovementAction, las tablas sStep), commit 731ad5b, consultado el 4 de octubre de 2026, https://github.com/pret/pokeemerald/blob/master/src/event_object_movement.c. ↩↩↩↩↩

  28. pret, pokeemerald/include/constants/flags.h (DAILY_FLAGS_START y los 12 flags diarios), commit 731ad5b, consultado el 4 de octubre de 2026, https://github.com/pret/pokeemerald/blob/master/include/constants/flags.h. ↩

  29. Stardew Valley Wiki, «Villagers», oldid 191346, editada el 26 de febrero de 2026, guardada el 4 de octubre de 2026, https://stardewvalleywiki.com/Villagers. Los 34 aldeanos que aceptan regalos son un recuento de las listas de la página (6 solteros, 6 solteras, 22 que no son candidatos al matrimonio); la página «Friendship» de la wiki cuenta un conjunto distinto de 28 vecinos iniciales. ↩

  30. Stardew Valley Wiki, «Pierre», guardada el 4 de octubre de 2026, https://stardewvalleywiki.com/Pierre. El horario normal, las seis variantes del horario, y el correo con cualquier nivel de corazones y con tres corazones. ↩↩↩

  31. Nookipedia, «Hobby», guardada el 4 de octubre de 2026, https://nookipedia.com/wiki/Hobby. ↩

  32. Nookipedia, «Villager», las secciones de cada juego, guardada el 4 de octubre de 2026, https://nookipedia.com/wiki/Villager. ↩↩↩↩↩↩↩

  33. Nookipedia, «Villager», sección Personalities, guardada el 4 de octubre de 2026, https://nookipedia.com/wiki/Villager#Personalities. ↩

  34. pret, pokeemerald/src/record_mixing.c (struct PlayerRecordEmerald, ReceiveOldManData, ReceiveDewfordTrendData), commit 731ad5b, consultado el 4 de octubre de 2026, https://github.com/pret/pokeemerald/blob/master/src/record_mixing.c. ↩

  35. pret, pokeemerald/src/mauville_old_man.c (la selección switch ((trainerId % 10) / 2) y su comentario, ResetHipsterFlag, ResetMauvilleOldManFlag, SetHipsterTaughtWord), pokeemerald/src/record_mixing.c (la única llamada a ResetMauvilleOldManFlag, al final de ReceiveOldManData), así como pokeemerald/data/scripts/mauville_man.inc (setflag FLAG_UNLOCKED_TRENDY_SAYINGS, special HasHipsterTaughtWord) y pokeemerald/data/maps/MauvilleCity_PokemonCenter_1F/map.json (el evento de objeto cuyo script es MauvilleCity_PokemonCenter_1F_EventScript_MauvilleOldMan), commit 731ad5b, leído por el autor el 4 y el 5 de octubre de 2026, https://github.com/pret/pokeemerald/blob/master/src/mauville_old_man.c. Que el Hipster aparezca al empezar en las partidas cuyo ID de entrenador termina en 2 o en 3 es aritmética del autor sobre el switch. ↩↩↩↩↩↩

  36. Blake Crosley, «Pixel-Art Worlds on iPhone: What the 16-Bit Masters Knew», blakecrosley.com, 3 de octubre de 2026 (FAQ legal actualizada el 4 de octubre de 2026), https://blakecrosley.com/blog/pixel-art-world-on-iphone. Enuncia la regla de la frase de moda como una cada vez que el mezclado de datos trae al Hipster, y su FAQ legal nombra las tres patentes invocadas contra el desarrollador de Palworld (apuntar y lanzar un objeto de captura, un indicador de probabilidad de captura, montarse en un personaje que se puede montar) con sus propias fuentes. ↩↩

  37. pret, pokeemerald/src/dewford_trend.c (el comentario de cabecera sobre trendiness y maxTrendiness y sobre el guardado de las modas), commit 731ad5b, consultado el 4 de octubre de 2026, https://github.com/pret/pokeemerald/blob/master/src/dewford_trend.c. ↩↩↩↩

  38. Medición del autor, measure_chat_trend.py en la misma carpeta, revisado y vuelto a ejecutar el 5 de octubre de 2026, salida guardada como measure_chat_trend.out. La revisión resta de las palabras abiertas las entradas marcadas .enabled = FALSE (946 entradas, 940 activadas), imprime la línea numEnabledWords del grupo Trainer de easy_chat_groups.h («Excludes Red, Green, Flame, Gold, Leaf, and Silver», excluye Red, Green, Flame, Gold, Leaf y Silver), e imprime la regla por entrada de IsEasyChatIndexAndGroupUnlocked, según la cual un nombre de la lista de 202 entradas solo se abre cuando se ha visto su especie; la versión anterior y su salida se conservan con el sufijo .r1. Entradas: src/data/easy_chat/ de pokeemerald de pret en 731ad5b (tamaños de los grupos, entradas desactivadas, numEnabledWords), src/easy_chat.c (el switch de desbloqueo de grupos, la regla por entrada y las cuadrículas de frases), include/constants/global.h (MAIL_WORDS_COUNT, NUM_QUESTIONNAIRE_WORDS, SAVED_TRENDS_COUNT) y src/dewford_trend.c (SeedTrendRng y el paso diario). Una segunda revisión, tras la revisión del segundo motor (la versión anterior y su salida se conservan con el sufijo .pre-astra), etiqueta la distribución de los picos como una aproximación uniforme e independiente: se calcula a partir de las tres extracciones anidadas de Random() % 98, tomando cada una como una extracción uniforme e independiente entre 0 y 97. Añade la misma distribución con los pesos del módulo de 16 bits (Random() en src/random.c devuelve los 16 bits altos, así que los restos de 0 a 71 aparecen 669 veces de cada 65.536 y los de 72 a 97, 668 veces), que da una media de 62,89 y un 81,34 % con 80 o menos frente a 62,90 y 81,33 %, todavía suponiendo extracciones independientes; y porta UpdateDewfordTrendPerDay con un día transcurrido por llamada, desde una puntuación de 0 subiendo, que vuelve por primera vez a ese estado al cabo de 12, 128 y 254 días para los picos 30, 64 y 127 (la misma longitud de ciclo desde cualquier estado inicial alcanzable). Las duraciones de subida y bajada de 12, 25,6 y 50,8 días son el doble del pico dividido entre 5, una aproximación continua. ↩↩↩↩↩↩↩↩↩↩↩↩

  39. pret, pokeemerald/src/union_room_chat.c, pokeemerald/include/union_room.h y pokeemerald/include/constants/global.h, commit 731ad5b, consultado el 4 de octubre de 2026, https://github.com/pret/pokeemerald/blob/master/src/union_room_chat.c. La lectura de por qué el chat escrito era tolerable allí es del autor. ↩

  40. pret, pokeemerald/src/easy_chat.c y pokeemerald/src/data/easy_chat/, commit 731ad5b, consultado el 4 de octubre de 2026, https://github.com/pret/pokeemerald/blob/master/src/easy_chat.c y https://github.com/pret/pokeemerald/tree/master/src/data/easy_chat. ↩↩↩↩

  41. Wikipedia, «Dark Souls (video game)», secciones Multiplayer (citando su fuente [5]) y Awards, guardada el 4 de octubre de 2026, https://en.wikipedia.org/wiki/Dark_Souls_(video_game). ↩↩↩↩↩↩

  42. Bandai Namco Entertainment Europe, «Dark Souls Remastered», Key features, guardada el 5 de octubre de 2026, https://en.bandainamcoent.eu/dark-souls/dark-souls-remastered. La página de Bandai Namco America se guardó como un armazón de script con 127 bytes de texto; no se llegó a la descripción de la propia FromSoftware. ↩

  43. PlayStation, «Death Stranding», sección «Unique social strand gameplay», guardada el 4 de octubre de 2026, https://www.playstation.com/en-us/games/death-stranding/. ↩

  44. Wikipedia, «Splatoon (video game)», secciones Gameplay y Multiplayer, citando sus propias fuentes, guardada el 4 de octubre de 2026, https://en.wikipedia.org/wiki/Splatoon_(video_game). No se consultaron las páginas de Splatoon de la propia Nintendo. ↩↩

  45. The Pokémon Company International, páginas de juegos de pokemon.com de «Pokémon Black Version 2 and Pokémon White Version 2» y «Pokémon Sun and Pokémon Moon», guardadas el 4 de octubre de 2026, https://www.pokemon.com/us/pokemon-video-games/pokemon-black-version-2-and-pokemon-white-version-2 y https://www.pokemon.com/us/pokemon-video-games/pokemon-sun-and-pokemon-moon; ninguna menciona Join Avenue ni Festival Plaza. No se probó Bulbapedia. ↩

  46. Serebii.net, «Festival Plaza», sección de Pokémon Sun y Moon, guardada el 4 de octubre de 2026, https://www.serebii.net/sunmoon/festivalplaza.shtml. Un sitio de fans y la única fuente usada para esta función. ↩↩

  47. Serebii.net, «Gyms», sección de Pokémon GO, guardada el 4 de octubre de 2026, https://www.serebii.net/pokemongo/gyms.shtml. Un sitio de fans y la única fuente usada para esta función. ↩↩

  48. Solero, Houdini, un emulador de código abierto del servidor de Club Penguin escrito por fans, houdini/handlers/play/player.py (los manejadores sp, ss, sj, sma, sl, sg y se, sus tiempos de espera, server_heartbeat, que toma la hora, duerme 61 segundos y cierra todos los clientes cuyo último latido es anterior a esa hora (if penguin.heartbeat < timer: await penguin.close(), leído del HTML guardado; la extracción de texto guardada desfigura esa línea), y server_egg_timer, que descuenta cada minuto los minutos permitidos de un jugador, avisa a los 7 y a los 5, y lo desconecta al llegar a cero), guardado el 4 de octubre de 2026, https://github.com/solero/houdini/blob/master/houdini/handlers/play/player.py. Evidencia de lo que esperaba el cliente original, no del comportamiento publicado por Disney. ↩↩↩↩↩↩↩

  49. billsonnn, Nitro renderer, un cliente de Habbo de código abierto escrito por fans, src/nitro/room/object/logic/MovingObjectLogic.ts (DEFAULT_UPDATE_INTERVAL = 500 y la interpolación de update), guardado el 4 de octubre de 2026, https://github.com/billsonnn/nitro-renderer/blob/main/src/nitro/room/object/logic/MovingObjectLogic.ts. ↩↩↩

  50. Lectura del autor del repositorio de Kiradex (privado), árbol de trabajo del 5 de octubre de 2026, solo lectura: Kiradex/World/PlazaRig.swift (SHA-256 819cd8d6; progress como Float en la línea 29, tilesPerSecond en la línea 101, move(other:to:facing:) en las líneas 526 a 542, running fijado solo en el jugador en la línea 614, advance() en las líneas 652 a 672, place() y su redondeo a pixeles en las líneas 722 a 727, la lista idleEmotes con doze), Kiradex/World/TileMap.swift (db4272c2; tileSize de 16 en la línea 60 y centre en la línea 235), Kiradex/World/PlazaClient.swift (5c491933; la espera de reconexión en la línea 165), Kiradex/World/PlazaStage.swift (8b4850af; la fase de luz diurna aplicada a la plaza, y rig.update(Float(event.deltaTime)) en la línea 149) y Kiradex/World/Daylight.swift (536350dc; Daylight.Phase y sus rangos horarios, y Daylight.now, que toma la hora de Calendar.current, el calendario y la zona propios del dispositivo). Los relojes del servidor se buscaron el mismo día: server/app/main.py y server/app/rooms.py usan time.monotonic() y nada en server/app nombra una zona horaria. ↩↩↩↩↩↩↩↩↩

  51. Documentación para desarrolladores de Apple, GKLocalPlayer.isPersonalizedCommunicationRestricted (iOS 14.0+), el JSON de la documentación guardado el 4 de octubre de 2026, https://developer.apple.com/documentation/gamekit/gklocalplayer/ispersonalizedcommunicationrestricted. Aplanado para la cita como en la nota 18. Que las frases predefinidas propias de un juego estén entre las «custom communication features» (funciones de comunicación propias) que la página pide desactivar a un juego, y que los emotes no lo estén, son lecturas del autor. ↩↩↩↩↩↩↩↩

  52. Documentación para desarrolladores de Apple, GKLocalPlayer.isUnderage (iOS 4.1+), el JSON de la documentación guardado el 4 de octubre de 2026, https://developer.apple.com/documentation/gamekit/gklocalplayer/isunderage. Aplanado para la cita como en la nota 18. ↩↩↩↩

  53. Soporte de Apple, «Set up parental controls to manage your child’s iPhone or iPad», sección «Set restrictions for Game Center», guardada el 4 de octubre de 2026, https://support.apple.com/en-us/105121. ↩

  54. Apple Newsroom, «Apple expands tools to help parents protect kids and teens online», 11 de junio de 2025, guardada el 4 de octubre de 2026, https://www.apple.com/newsroom/2025/06/apple-expands-tools-to-help-parents-protect-kids-and-teens-online/. ↩↩↩

  55. Apple, «App Review Guidelines», última actualización el 8 de junio de 2026, directrices 1.2, 1.3 y 5.1.4, guardadas el 4 de octubre de 2026, https://developer.apple.com/app-store/review/guidelines/. ↩↩↩↩↩↩↩↩

  56. Comisión Federal de Comercio, «FTC Finalizes Changes to Children’s Privacy Rule Limiting Companies’ Ability to Monetize Kids’ Data», comunicado de prensa, 16 de enero de 2025, guardado el 4 de octubre de 2026, https://www.ftc.gov/news-events/news/press-releases/2025/01/ftc-finalizes-changes-childrens-privacy-rule-limiting-companies-ability-monetize-kids-data. ↩

  57. Lectura del autor del comando de arranque del servidor de Kiradex y del servidor web que ejecuta, 5 de octubre de 2026, solo lectura: server/Procfile (SHA-256 2e883a7e) y server/railway.toml (17f8a3ba) arrancan uvicorn app.main:app con --proxy-headers --forwarded-allow-ips='*' y sin opciones de registro; server/requirements.txt (71c30c3b) fija uvicorn[standard]==0.37.0. En esa versión, tal como está instalada en el entorno del servidor, uvicorn/config.py (379e9baf) pone access_log en verdadero por defecto; uvicorn/protocols/http/httptools_impl.py (b6e4010a) y h11_impl.py (e1bf8ab3) registran get_client_addr(self.scope) en cada solicitud cuando lo está; y uvicorn/protocols/websockets/websockets_impl.py (029977b2) registra '%s - "WebSocket %s" [accepted]' con la dirección del cliente en nivel INFO en el logger uvicorn.error, que --log-level warning silencia. Una lectura del código; no se ejecutó ningún servidor ni se vio ningún registro desplegado. ↩↩

  58. Blake Crosley, «Pixel-Art People: Characters and a Creator on iPhone», blakecrosley.com, 3 de octubre de 2026, sección 4 (las reglas de PEGI) y secciones 6 y 7 (la cadena de figura, el manifiesto y la forja que dibuja cada figura), https://blakecrosley.com/blog/pixel-art-characters-on-iphone. ↩↩↩

  59. PEGI, «What do the labels mean?», consultado el 3 de octubre de 2026, https://pegi.info/what-do-the-labels-mean, tal como se cita en el artículo sobre personajes (nota 58); no se volvió a consultar para este artículo. ↩↩↩

Artículos relacionados

Pixel-Art Structures: Houses, Halls and Interiors on iPhone

How Pokémon, the SNES RPGs and Stardew build houses, interiors and floors, measured from source, and how Kiradex's town …

80 min de lectura

Rutas en pixel art: conexiones de mapa y distritos en el iPhone

Cómo construyen Pokémon, Stardew y Animal Crossing la tierra entre pueblos, medido en el código: rutas, costuras, garita…

125 min de lectura

Prepara tu app para el iPhone Duo: un ejemplo práctico

Cómo preparar y enviar una app para el iPhone Duo: el sello del SDK que activa el diseño, una app real en cada pose, cap…

68 min de lectura