1 package minecraft 2 3 import ( 4 "vimagination.zapto.org/minecraft/nbt" 5 ) 6 7 func yzx(x, y, z int32) uint32 { 8 return (uint32(y&15) << 8) | (uint32(z&15) << 4) | uint32(x&15) 9 } 10 11 func getNibble(arr nbt.ByteArray, x, y, z int32) byte { 12 coord := yzx(x, y, z) 13 data := byte(arr[coord>>1]) 14 if coord&1 == 0 { 15 return data & 15 16 } 17 return data >> 4 18 } 19 20 func setNibble(arr nbt.ByteArray, x, y, z int32, data byte) { 21 coord := yzx(x, y, z) 22 oldData := byte(arr[coord>>1]) 23 if coord&1 == 0 { 24 oldData = oldData&240 | data&15 25 } else { 26 oldData = oldData&15 | data<<4 27 } 28 arr[coord>>1] = int8(oldData) 29 } 30 31 type section struct { 32 section nbt.Compound 33 blocks nbt.ByteArray 34 add nbt.ByteArray 35 data nbt.ByteArray 36 blockLight nbt.ByteArray 37 skyLight nbt.ByteArray 38 } 39 40 func newSection(y int32) *section { 41 s := new(section) 42 s.blocks = make(nbt.ByteArray, 4096) 43 s.add = make(nbt.ByteArray, 2048) 44 s.data = make(nbt.ByteArray, 2048) 45 s.blockLight = make(nbt.ByteArray, 2048) 46 s.skyLight = make(nbt.ByteArray, 2048) 47 for i := 0; i < 2048; i++ { 48 s.skyLight[i] = -1 49 } 50 s.section = nbt.Compound{ 51 nbt.NewTag("Blocks", s.blocks), 52 nbt.NewTag("Add", s.add), 53 nbt.NewTag("Data", s.data), 54 nbt.NewTag("BlockLight", s.blockLight), 55 nbt.NewTag("SkyLight", s.skyLight), 56 nbt.NewTag("Y", nbt.Byte(y>>4)), 57 } 58 return s 59 } 60 61 func loadSection(c nbt.Compound) (*section, error) { 62 s := new(section) 63 s.section = c 64 blocks := c.Get("Blocks") 65 if blocks.TagID() == 0 { 66 return nil, MissingTagError{"[SECTION]->Blocks"} 67 } else if blocks.TagID() != nbt.TagByteArray { 68 return nil, WrongTypeError{"Blocks", nbt.TagByteArray, blocks.TagID()} 69 } 70 s.blocks = blocks.Data().(nbt.ByteArray) 71 if len(s.blocks) != 4096 { 72 return nil, ErrOOB 73 } 74 add := c.Get("Add") 75 if add.TagID() != 0 { 76 if add.TagID() != nbt.TagByteArray { 77 return nil, WrongTypeError{"Add", nbt.TagByteArray, add.TagID()} 78 } 79 s.add = add.Data().(nbt.ByteArray) 80 } else { 81 s.add = make(nbt.ByteArray, 2048) 82 c.Set(nbt.NewTag("Add", s.add)) 83 } 84 if len(s.add) != 2048 { 85 return nil, ErrOOB 86 } 87 data := c.Get("Data") 88 if data.TagID() == 0 { 89 return nil, MissingTagError{"[SECTION]->Data"} 90 } else if data.TagID() != nbt.TagByteArray { 91 return nil, WrongTypeError{"Data", nbt.TagByteArray, data.TagID()} 92 } 93 s.data = data.Data().(nbt.ByteArray) 94 if len(s.data) != 2048 { 95 return nil, ErrOOB 96 } 97 blockLight := c.Get("BlockLight") 98 if blockLight.TagID() == 0 { 99 return nil, MissingTagError{"[SECTION]->BlockLight"} 100 } else if blockLight.TagID() != nbt.TagByteArray { 101 return nil, WrongTypeError{"BlockLight", nbt.TagByteArray, blockLight.TagID()} 102 } 103 s.blockLight = blockLight.Data().(nbt.ByteArray) 104 if len(s.blockLight) != 2048 { 105 return nil, ErrOOB 106 } 107 skyLight := c.Get("SkyLight") 108 if skyLight.TagID() == 0 { 109 return nil, MissingTagError{"[SECTION]->SkyLight"} 110 } else if skyLight.TagID() != nbt.TagByteArray { 111 return nil, WrongTypeError{"SkyLight", nbt.TagByteArray, skyLight.TagID()} 112 } 113 s.skyLight = skyLight.Data().(nbt.ByteArray) 114 if len(s.skyLight) != 2048 { 115 return nil, ErrOOB 116 } 117 y := c.Get("Y") 118 if y.TagID() == 0 { 119 return nil, MissingTagError{"[SECTION]->Y"} 120 } else if y.TagID() != nbt.TagByte { 121 return nil, WrongTypeError{"Y", nbt.TagByte, y.TagID()} 122 } 123 return s, nil 124 } 125 126 func (s *section) GetBlock(x, y, z int32) Block { 127 return Block{ 128 ID: uint16(getNibble(s.add, x, y, z))<<8 | uint16(byte(s.blocks[yzx(x, y, z)])), 129 Data: getNibble(s.data, x, y, z), 130 } 131 } 132 133 func (s *section) SetBlock(x, y, z int32, b Block) { 134 s.blocks[yzx(x, y, z)] = int8(b.ID & 255) 135 setNibble(s.add, x, y, z, byte(b.ID>>8)) 136 setNibble(s.data, x, y, z, b.Data) 137 } 138 139 func (s *section) GetOpacity(x, y, z int32) uint8 { 140 return s.GetBlock(x, y, z).Opacity() 141 } 142 143 func (s *section) GetBlockLight(x, y, z int32) uint8 { 144 return getNibble(s.blockLight, x, y, z) 145 } 146 147 func (s *section) SetBlockLight(x, y, z int32, l uint8) { 148 setNibble(s.blockLight, x, y, z, l) 149 } 150 151 func (s *section) GetSkyLight(x, y, z int32) uint8 { 152 return getNibble(s.skyLight, x, y, z) 153 } 154 155 func (s *section) SetSkyLight(x, y, z int32, l uint8) { 156 setNibble(s.skyLight, x, y, z, l) 157 } 158 159 func (s *section) SetY(y int32) { 160 s.section.Set(nbt.NewTag("Y", nbt.Byte(y>>4))) 161 } 162