Negatieve coördinaten breken chunk-berekeningen op twee plekken, niet één
Afkappende deling plaatst blok −1 in chunk 0 in plaats van −1, en een gewone % geeft een in-chunk-offset van −1 in plaats van 15. Beide kloppen niet, en beide lijken juist totdat je ten westen van de spawn gaat.
Elke chunk-berekening is triviaal in het positieve kwadrant en fout in de andere drie. Er zijn precies twee plekken waar het misgaat, ze staan los van elkaar, en beide leveren aannemelijk lijkende antwoorden op.
De twee bewerkingen
chunk = floor(block / 16) not trunc(block / 16)
offset = ((block % 16) + 16) % 16 not block % 16
Region-coördinaten zijn hetzelfde paar, één niveau hoger, met 32 in plaats van 16:
region = floor(chunk / 32) -> r.<x>.<z>.mca
regionOff = ((chunk % 32) + 32) % 32
Een region is dus 32 × 32 chunks, wat 512 × 512 blokken is.
Waar ze elk misgaan
Deling. De meeste talen kappen af richting nul, en floor rounds toward negative infinity. They agree for positives and disagree for every negative that is not an exact multiple:
- blok
−1→floor(−1/16) = −1✓, buttrunc(−1/16) = 0✗
Blok −1 ligt één blok ten westen van de oorsprong en hoort bij chunk −1. Afkapping plaatst het in chunk 0, naast blok +1. Elke negatieve chunk-index valt één te hoog uit.
Restwaarde. In JavaScript, Java, C en de meeste andere, % keeps the sign of the left operand:
- blok
−1→ correct offset15, but−1 % 16 = −1✗
Een offset van −1 is helemaal geen positie binnen een chunk van 16 breed. Een blok-array hiermee indexeren veroorzaakt een fout of leest stilletjes de verkeerde cel uit.
Een uitgewerkt voorbeeld
Blok −1290 op één as:
| stap | correct | naïef |
|---|---|---|
| chunk | floor(−1290/16) = −81 | trunc = −80 ✗ |
| offset in chunk | 6 | −1290 % 16 = −10 ✗ |
| region | floor(−81/32) = −3 | trunc = −2 ✗ |
| offset in region | 15 | −81 % 32 = −17 ✗ |
Vier waarden, vier foute antwoorden, waarvan er geen een zover buiten het bereik valt dat het overduidelijk kapot lijkt. Region −3 beslaat chunks −96 tot en met −65, en chunk −81 zit 15 vanaf het begin — wat precies is wat de gecorrigeerde rest oplevert.
De Nether-conversie kent dataverlies in één richting
Bovenwereld naar Nether deelt door 8 en rondt ook naar beneden af:
netherX = floor(overworldX / 8)
Terugkeren vermenigvuldigt met 8. Dat is niet een retourtje. floor throws away the remainder, so returning lands you on a multiple of 8:
- Bovenwereld
1000→ Nether125→ back to1000✓ - Bovenwereld
1007→ Nether125→ back to1000✗ — seven blocks short
De afwijking is 0 tot 7 blokken per as, dus tot 7 op X en 7 op Z tegelijk. Dat is precies de reden waarom je voor een nauwkeurige portaalkoppeling de Nether-coördinaat moet noteren in plaats van opnieuw af te leiden: zodra je hebt gedeeld, is de oorspronkelijke positie in de Bovenwereld niet meer te herleiden.
Voor een Nether-hub maakt dit zelden uit — 7 blokken valt binnen het detectiebereik van het portaal zelf. Voor het koppelen van twee portalen die elkaars verkeer niet mogen kapen, maakt het heel veel uit.
Negatieve Bovenwereld-coördinaten maken het op de bekende manier erger: Bovenwereld −1 gives Nether floor(−1/8) = −1, while truncation gives 0 and sends you to the wrong side of the axis.