Coordenadas negativas quebram o cálculo de chunks em dois lugares, não em um
A divisão truncada coloca o bloco −1 no chunk 0 em vez do −1, e um % simples gera um deslocamento dentro do chunk de −1 em vez de 15. Os dois estão errados, e os dois parecem certos até você ir para oeste do spawn.
Todo cálculo de chunk é trivial no quadrante positivo e errado nos outros três. Existem exatamente dois lugares onde ele dá errado, eles são independentes entre si, e ambos produzem respostas que parecem plausíveis.
As duas operações
chunk = floor(block / 16) not trunc(block / 16)
offset = ((block % 16) + 16) % 16 not block % 16
As coordenadas de região são o mesmo par, um nível acima, com 32 no lugar de 16:
region = floor(chunk / 32) -> r.<x>.<z>.mca
regionOff = ((chunk % 32) + 32) % 32
Então uma região tem 32 × 32 chunks, o que dá 512 × 512 blocos.
Onde cada uma morde
Divisão. A maioria das linguagens trunca em direção ao zero, e floor arredonda em direção ao infinito negativo. Elas concordam para positivos e discordam para todo negativo que não seja múltiplo exato:
- bloco
−1→floor(−1/16) = −1✓, mastrunc(−1/16) = 0✗
O bloco −1 fica um bloco a oeste da origem e pertence ao chunk −1. O truncamento o coloca no chunk 0, junto com o bloco +1. Todo índice de chunk negativo sai um a mais.
Resto. Em JavaScript, Java, C e na maioria das outras, % mantém o sinal do operando da esquerda:
- bloco
−1→ deslocamento correto15, mas−1 % 16 = −1✗
Um deslocamento de −1 não é uma posição dentro de um chunk de 16 de largura. Indexar um array de blocos com ele ou lança uma exceção ou lê silenciosamente a célula errada.
Um exemplo resolvido
Bloco −1290 em um eixo:
| passo | correto | ingênuo |
|---|---|---|
| chunk | floor(−1290/16) = −81 | trunc = −80 ✗ |
| deslocamento no chunk | 6 | −1290 % 16 = −10 ✗ |
| região | floor(−81/32) = −3 | trunc = −2 ✗ |
| deslocamento na região | 15 | −81 % 32 = −17 ✗ |
Quatro valores, quatro respostas erradas, nenhuma delas fora do intervalo o suficiente para parecer obviamente quebrada. A região −3 abrange os chunks −96 a −65, e o chunk −81 fica 15 a partir do seu início — que é exatamente o que o resto corrigido retorna.
A conversão do Nether perde informação em uma direção
Da Superfície para o Nether divide por 8, e também arredonda para baixo:
netherX = floor(overworldX / 8)
Na volta, sua posição exata é multiplicada por 8, então o bloco 125 do Nether inteiro mapeia de volta para algum lugar entre 1000–1007, dependendo de onde dentro desse bloco você está. Isso não é uma ida e volta para coordenadas de bloco. floor joga fora o resto:
- Superfície
1000→ Nether125→ de volta para1000✓ - Superfície
1007→ Nether125→ a coordenada de bloco diz1000✗ — sete blocos a menos
O erro é de 0 a 7 blocos por eixo, então até 7 no X e 7 no Z ao mesmo tempo. É exatamente por isso que a ligação precisa de portais exige anotar a coordenada do Nether em vez de recalculá-la: depois que você dividiu, a posição na Superfície de onde ela veio não é mais recuperável.
Para um hub do Nether isso raramente importa — 7 blocos está dentro do próprio raio de captura de um portal. Para ligar dois portais que não podem roubar o tráfego um do outro, importa muito.
Coordenadas negativas na Superfície pioram isso do jeito conhecido: Superfície −1 dá Nether floor(−1/8) = −1, enquanto o truncamento dá 0 e te manda para o lado errado do eixo.