Tọa độ âm làm sai lệch phép tính khối (chunk maths) ở hai chỗ, không phải một
Phép chia làm tròn xuống (truncating division) đặt khối −1 vào khối 0 thay vì −1, và phép toán % thông thường cho ra độ lệch trong khối là −1 thay vì 15. Cả hai đều sai, và cả hai đều trông có vẻ đúng cho đến khi bạn đi về phía tây của điểm xuất hiện.
Mọi phép tính khối (chunk) đều đơn giản ở góc phần tư dương và sai ở ba góc phần tư còn lại. Có chính xác hai chỗ nó bị sai, chúng độc lập với nhau và cả hai đều cho ra kết quả có vẻ hợp lý.
Hai phép toán
chunk = floor(block / 16) not trunc(block / 16)
offset = ((block % 16) + 16) % 16 not block % 16
Tọa độ vùng (region) là cùng một cặp, một cấp cao hơn, với 32 thay vì 16:
region = floor(chunk / 32) -> r.<x>.<z>.mca
regionOff = ((chunk % 32) + 32) % 32
Vì vậy, một vùng là 32 × 32 khối, tức là 512 × 512 khối vật lý (block).
Mỗi lỗi ảnh hưởng ở đâu
Phép chia. Hầu hết các ngôn ngữ lập trình đều làm tròn về 0, và floor làm tròn về âm vô hạn. Chúng khớp với các số dương và không khớp với mọi số âm không phải là bội số chính xác:
- khối
−1→floor(−1/16) = −1✓, nhưngtrunc(−1/16) = 0✗
Khối −1 là một khối về phía tây của gốc tọa độ và thuộc về khối −1. Phép làm tròn đặt nó vào khối 0, cùng với khối +1. Mọi chỉ số khối âm đều cao hơn một đơn vị.
Phép lấy phần dư. Trong JavaScript, Java, C và hầu hết các ngôn ngữ khác, % giữ dấu của toán hạng bên trái:
- khối
−1→ độ lệch chính xác15, nhưng−1 % 16 = −1✗
Độ lệch −1 hoàn toàn không phải là một vị trí bên trong một khối rộng 16. Việc lập chỉ mục một mảng khối với nó sẽ gây lỗi hoặc âm thầm đọc sai ô.
Một ví dụ minh họa
Khối −1290 trên một trục:
| bước | đúng | sai |
|---|---|---|
| khối | floor(−1290/16) = −81 | trunc = −80 ✗ |
| độ lệch trong khối | 6 | −1290 % 16 = −10 ✗ |
| vùng | floor(−81/32) = −3 | trunc = −2 ✗ |
| độ lệch trong vùng | 15 | −81 % 32 = −17 ✗ |
Bốn giá trị, bốn câu trả lời sai, không có cái nào nằm ngoài phạm vi đủ để trông có vẻ bị hỏng rõ ràng. Vùng −3 trải dài từ khối −96 đến −65, và khối −81 nằm cách điểm bắt đầu của nó 15 đơn vị — đây chính xác là những gì phần dư đã được sửa trả về.
Chuyển đổi Nether bị mất dữ liệu theo một hướng
Từ Overworld sang Nether chia cho 8, và nó cũng làm tròn xuống:
netherX = floor(overworldX / 8)
Quay lại thì nhân với 8. Đó không phải là một chuyến đi khứ hồi. floor bỏ qua phần dư, vì vậy việc quay lại sẽ đưa bạn đến một bội số của 8:
- Overworld
1000→ Nether125→ trở lại1000✓ - Overworld
1007→ Nether125→ trở lại1000✗ — thiếu bảy khối
Lỗi là từ 0 đến 7 khối trên mỗi trục, vì vậy có thể lên đến 7 trên X và 7 trên Z cùng một lúc. Đó là toàn bộ lý do tại sao việc liên kết cổng chính xác cần tọa độ Nether được ghi lại thay vì tính toán lại: một khi bạn đã chia, vị trí overworld mà nó đến không còn có thể phục hồi được nữa.
Đối với một trung tâm Nether, điều này hiếm khi quan trọng — 7 khối nằm trong bán kính bắt giữ của chính một cổng. Đối với việc liên kết hai cổng mà không được phép cướp lưu lượng của nhau, điều này rất quan trọng.
Tọa độ overworld âm làm cho mọi thứ tồi tệ hơn theo cách quen thuộc: overworld −1 cho Nether floor(−1/8) = −1, trong khi phép làm tròn cho 0 và đưa bạn đến sai phía của trục.