Coordenadas negativas quebram a matemática de chunks em dois lugares, não em um
A divisão por truncamento coloca o bloco -1 no chunk 0 em vez de -1, e um % simples dá um deslocamento dentro do chunk de -1 em vez de 15. Ambos estão errados, e ambos parecem corretos até você ir para o oeste do spawn.
Todo cálculo de chunk é trivial no quadrante positivo e errado nos outros três. Há exatamente dois lugares onde ele erra, eles são independentes um do outro, 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 em vez de 16:
region = floor(chunk / 32) -> r.<x>.<z>.mca
regionOff = ((chunk % 32) + 32) % 32
Então uma região é 32 × 32 chunks, o que é 512 × 512 blocos.
Onde cada uma morde
Divisão. A maioria das linguagens trunca em direção a zero, e floor arredonda em direção ao infinito negativo. Elas concordam para positivos e discordam para todo negativo que não é um múltiplo exato:
- bloco
−1→floor(−1/16) = −1✓, mastrunc(−1/16) = 0✗
O bloco -1 está 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 dos outros, % mantém o sinal do operando esquerdo:
- 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 um erro ou lê silenciosamente a célula errada.
Um exemplo prático
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 alcance o suficiente para parecer obviamente quebrada. A região -3 abrange os chunks de -96 a -65, e o chunk -81 fica 15 de seu início — que é exatamente o que o resto corrigido retorna.
A conversão do Nether é com perda em uma direção
Do Overworld para o Nether divide por 8, e também arredonda para baixo (floor):
netherX = floor(overworldX / 8)
Voltar multiplica por 8. Isso não é uma viagem de ida e volta. floor descarta o resto, então o retorno o aterrissa em um múltiplo de 8:
- Overworld
1000→ Nether125→ de volta para1000✓ - Overworld
1007→ Nether125→ de volta para1000✗ — sete blocos a menos
O erro é de 0 a 7 blocos por eixo, então até 7 em X e 7 em Z de uma vez. Essa é a razão pela qual a ligação precisa de portais requer que a coordenada do Nether seja anotada em vez de ser recalculada: uma vez que você dividiu, a posição do Overworld de onde ela veio não é mais recuperável.
Para um hub no Nether, isso raramente importa — 7 blocos está dentro do raio de captura do próprio portal. Para ligar dois portais que não devem roubar o tráfego um do outro, isso importa muito.
Coordenadas negativas do Overworld pioram as coisas da maneira familiar: Overworld −1 dá Nether floor(−1/8) = −1, enquanto o truncamento dá 0 e o envia para o lado errado do eixo.