Les coordonnées négatives cassent le calcul des chunks à deux endroits, pas un seul
La division tronquée place le bloc −1 dans le chunk 0 au lieu de −1, et un % simple donne un décalage intra-chunk de −1 au lieu de 15. Les deux sont faux, et les deux semblent corrects tant qu'on reste à l'est du point d'apparition.
Tout calcul de chunk est trivial dans le quadrant positif et faux dans les trois autres. Il y a exactement deux endroits où ça dérape, ils sont indépendants l'un de l'autre, et tous deux produisent des résultats qui paraissent plausibles.
Les deux opérations
chunk = floor(block / 16) not trunc(block / 16)
offset = ((block % 16) + 16) % 16 not block % 16
Les coordonnées de région sont la même paire, un niveau au-dessus, avec 32 au lieu de 16 :
region = floor(chunk / 32) -> r.<x>.<z>.mca
regionOff = ((chunk % 32) + 32) % 32
Une région fait donc 32 × 32 chunks, soit 512 × 512 blocs.
Où chacune mord
La division. La plupart des langages tronquent vers zéro, et floor arrondit vers moins l'infini. Elles concordent pour les positifs et divergent pour tout négatif qui n'est pas un multiple exact :
- bloc
−1→floor(−1/16) = −1✓, maistrunc(−1/16) = 0✗
Le bloc −1 est un bloc à l'ouest de l'origine et appartient au chunk −1. La troncature le place dans le chunk 0, aux côtés du bloc +1. Tout indice de chunk négatif ressort majoré de un.
Le reste. En JavaScript, en Java, en C et dans la plupart des autres, % conserve le signe de l'opérande gauche :
- bloc
−1→ décalage correct15, mais−1 % 16 = −1✗
Un décalage de −1 n'est pas une position à l'intérieur d'un chunk de largeur 16. Indexer un tableau de blocs avec cette valeur lève une exception ou lit silencieusement la mauvaise case.
Un exemple détaillé
Bloc −1290 sur un axe :
| étape | correct | naïf |
|---|---|---|
| chunk | floor(−1290/16) = −81 | trunc = −80 ✗ |
| décalage dans le chunk | 6 | −1290 % 16 = −10 ✗ |
| région | floor(−81/32) = −3 | trunc = −2 ✗ |
| décalage dans la région | 15 | −81 % 32 = −17 ✗ |
Quatre valeurs, quatre réponses fausses, aucune suffisamment hors plage pour paraître manifestement cassée. La région −3 couvre les chunks −96 à −65, et le chunk −81 se situe à 15 de son début — exactement ce que renvoie le reste corrigé.
La conversion du Nether perd de l'information dans un sens
De l'Overworld vers le Nether, on divise par 8, et on arrondit aussi vers le bas :
netherX = floor(overworldX / 8)
Au retour, on multiplie votre position exacte par 8, donc tout le bloc 125 du Nether se retrouve quelque part entre 1000 et 1007, selon l'endroit où vous vous tenez dans ce bloc. Ce n'est pas un aller-retour pour les coordonnées de bloc. floor jette le reste :
- Overworld
1000→ Nether125→ retour à1000✓ - Overworld
1007→ Nether125→ la coordonnée de bloc indique1000✗ — sept blocs de moins
L'erreur va de 0 à 7 blocs par axe, donc jusqu'à 7 en X et 7 en Z simultanément. C'est toute la raison pour laquelle une liaison précise de portails exige d'écrire la coordonnée du Nether plutôt que de la recalculer : une fois la division faite, la position d'Overworld d'origine n'est plus récupérable.
Pour un hub du Nether, ça compte rarement — 7 blocs, c'est dans le rayon de capture d'un portail. Pour relier deux portails qui ne doivent pas se voler leur trafic, ça compte énormément.
Les coordonnées négatives d'Overworld empirent les choses de la manière habituelle : Overworld −1 donne Nether floor(−1/8) = −1, tandis que la troncature donne 0 et vous envoie du mauvais côté de l'axe.