1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
|
package mcmap
import (
"errors"
"github.com/kch42/gonbt/nbt"
"time"
)
func calcBlockOffset(x, y, z int) int {
if (x < 0) || (y < 0) || (z < 0) || (x >= ChunkSizeXZ) || (y >= ChunkSizeY) || (z >= ChunkSizeXZ) {
return -1
}
return x | (z << 4) | (y << 8)
}
func offsetToPos(off int) (x, y, z int) {
x = off & 0xf
z = (off >> 4) & 0xf
y = (off >> 8) & 0xff
return
}
// BlockToChunk calculates the chunk (cx, cz) and the block position in this chunk(rbx, rbz) of a block position given global coordinates.
func BlockToChunk(bx, bz int) (cx, cz, rbx, rbz int) {
cx = bx << 4
cz = bz << 4
rbx = ((cx % ChunkSizeXZ) + ChunkSizeXZ) % ChunkSizeXZ
rbz = ((cz % ChunkSizeXZ) + ChunkSizeXZ) % ChunkSizeXZ
return
}
// ChunkToBlock calculates the global position of a block, given the chunk position (cx, cz) and the plock position in that chunk (rbx, rbz).
func ChunkToBlock(cx, cz, rbx, rbz int) (bx, bz int) {
bx = cx*ChunkSizeXZ + rbx
bz = cz*ChunkSizeXZ + rbz
return
}
// Chunk represents a 16*16*256 Chunk of the region.
type Chunk struct {
Entities []nbt.TagCompound
x, z int32
lastUpdate int64
populated bool
inhabitedTime int64
ts time.Time
heightMap []int32 // Ordered ZX
modified bool
blocks []Block // Ordered YZX
biomes []Biome // Ordered XZ
reg *Region
}
// MarkModified needs to be called, if some data of the chunk was modified.
func (c *Chunk) MarkModified() { c.modified = true }
// Coords returns the Chunk's coordinates.
func (c *Chunk) Coords() (X, Z int32) { return c.x, c.z }
// Block gives you a reference to the Block located at x, y, z. If you modify the block data, you need to call the MarkModified() function of the chunk.
//
// x and z must be in [0, 15], y in [0, 255]. Otherwise a nil pointer is returned.
func (c *Chunk) Block(x, y, z int) *Block {
off := calcBlockOffset(x, y, z)
if off < 0 {
return nil
}
return &(c.blocks[off])
}
// Height returns the height at x, z.
//
// x and z must be in [0, 15]. Height will panic, if this is violated!
func (c *Chunk) Height(x, z int) int {
if (x < 0) || (x >= ChunkSizeXZ) || (z < 0) || (z >= ChunkSizeXZ) {
panic(errors.New("x or z parameter was out of range"))
}
return int(c.heightMap[z*ChunkSizeXZ+x])
}
// Biome gets the Biome at x,z.
func (c *Chunk) Biome(x, z int) Biome { return c.biomes[x*ChunkSizeXZ+z] }
// SetBiome sets the biome at x,z.
func (c *Chunk) SetBiome(x, z int, bio Biome) { c.biomes[x*ChunkSizeXZ+z] = bio }
// MarkUnused marks the chunk as unused. If all chunks of a superchunk are marked as unused, the superchunk will be unloaded and saved (if needed).
//
// You must not use the chunk any longer, after you called this function.
//
// If the chunk was modified, call MarkModified BEFORE.
func (c *Chunk) MarkUnused() error { return c.reg.unloadChunk(int(c.x), int(c.z)) }
// TODO: func (c *Chunk) RecalcHeightMap()
|