simple conversion between save.Chunk and level.Chunk
This commit is contained in:
@ -4,12 +4,12 @@
|
||||
package block
|
||||
|
||||
import (
|
||||
"math"
|
||||
"math/bits"
|
||||
)
|
||||
|
||||
// BitsPerBlock indicates how many bits are needed to represent all possible
|
||||
// block states. This value is used to determine the size of the global palette.
|
||||
var BitsPerBlock = int(math.Ceil(math.Log2(float64(len(StateID)))))
|
||||
var BitsPerBlock = bits.Len(uint(len(StateID)))
|
||||
|
||||
// ID describes the numeric ID of a block.
|
||||
type ID uint32
|
||||
|
@ -24,12 +24,12 @@ const (
|
||||
package block
|
||||
|
||||
import (
|
||||
"math"
|
||||
"math/bits"
|
||||
)
|
||||
|
||||
// BitsPerBlock indicates how many bits are needed to represent all possible
|
||||
// block states. This value is used to determine the size of the global palette.
|
||||
var BitsPerBlock = int(math.Ceil(math.Log2(float64(len(StateID)))))
|
||||
var BitsPerBlock = bits.Len(uint(len(StateID)))
|
||||
|
||||
// ID describes the numeric ID of a block.
|
||||
type ID uint32
|
||||
|
@ -3,6 +3,9 @@ package main
|
||||
import (
|
||||
_ "embed"
|
||||
"github.com/Tnze/go-mc/chat"
|
||||
"github.com/Tnze/go-mc/level"
|
||||
"github.com/Tnze/go-mc/save"
|
||||
"github.com/Tnze/go-mc/save/region"
|
||||
"github.com/Tnze/go-mc/server"
|
||||
"image"
|
||||
_ "image/png"
|
||||
@ -21,14 +24,9 @@ func main() {
|
||||
if err != nil {
|
||||
log.Fatalf("Set server info error: %v", err)
|
||||
}
|
||||
defaultDimension := server.NewSimpleDim(16)
|
||||
chunk00 := server.EmptyChunk(16)
|
||||
for s := 0; s < 16; s++ {
|
||||
for i := 0; i < 16*16; i++ {
|
||||
chunk00.Sections[s].SetBlock(i, 1)
|
||||
}
|
||||
}
|
||||
defaultDimension.LoadChunk(server.ChunkPos{X: 0, Z: 0}, chunk00)
|
||||
defaultDimension := server.NewSimpleDim(256)
|
||||
chunk00 := level.ChunkFromSave(readChunk00(), 256)
|
||||
defaultDimension.LoadChunk(level.ChunkPos{X: 0, Z: 0}, chunk00)
|
||||
s := server.Server{
|
||||
ListPingHandler: serverInfo,
|
||||
LoginHandler: &server.MojangLoginHandler{
|
||||
@ -61,3 +59,22 @@ func readIcon() image.Image {
|
||||
}
|
||||
return icon
|
||||
}
|
||||
|
||||
func readChunk00() *save.Chunk {
|
||||
r, err := region.Open("./save/testdata/region/r.0.0.mca")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer r.Close()
|
||||
|
||||
var c save.Chunk
|
||||
data, err := r.ReadSector(0, 0)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
err = c.Load(data)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return &c
|
||||
}
|
||||
|
@ -2,9 +2,10 @@ package level
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
pk "github.com/Tnze/go-mc/net/packet"
|
||||
"io"
|
||||
"math"
|
||||
|
||||
pk "github.com/Tnze/go-mc/net/packet"
|
||||
)
|
||||
|
||||
const indexOutOfBounds = "index out of bounds"
|
||||
|
264
level/chunk.go
Normal file
264
level/chunk.go
Normal file
@ -0,0 +1,264 @@
|
||||
package level
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
"math/bits"
|
||||
"strings"
|
||||
"sync"
|
||||
"unsafe"
|
||||
|
||||
"github.com/Tnze/go-mc/data/block"
|
||||
pk "github.com/Tnze/go-mc/net/packet"
|
||||
"github.com/Tnze/go-mc/save"
|
||||
)
|
||||
|
||||
type ChunkPos struct{ X, Z int }
|
||||
type Chunk struct {
|
||||
sync.Mutex
|
||||
Sections []Section
|
||||
HeightMaps HeightMaps
|
||||
}
|
||||
type HeightMaps struct {
|
||||
MotionBlocking *BitStorage
|
||||
WorldSurface *BitStorage
|
||||
}
|
||||
|
||||
func EmptyChunk(secs int) *Chunk {
|
||||
sections := make([]Section, secs)
|
||||
for i := range sections {
|
||||
sections[i] = Section{
|
||||
blockCount: 0,
|
||||
States: NewStatesPaletteContainer(16*16*16, 0),
|
||||
Biomes: NewBiomesPaletteContainer(4*4*4, 0),
|
||||
}
|
||||
}
|
||||
return &Chunk{
|
||||
Sections: sections,
|
||||
HeightMaps: HeightMaps{
|
||||
MotionBlocking: NewBitStorage(bits.Len(uint(secs)*16), 16*16, nil),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
var biomesIDs = map[string]int{"ocean": 0,
|
||||
"deep_ocean": 24,
|
||||
"frozen_ocean": 10,
|
||||
"deep_frozen_ocean": 50,
|
||||
"cold_ocean": 46,
|
||||
"deep_cold_ocean": 49,
|
||||
"lukewarm_ocean": 45,
|
||||
"deep_lukewarm_ocean": 48,
|
||||
"warm_ocean": 44,
|
||||
"river": 7,
|
||||
"frozen_river": 11,
|
||||
"beach": 16,
|
||||
"stony_shore": 25,
|
||||
"snowy_beach": 26,
|
||||
"forest": 4,
|
||||
"flower_forest": 132,
|
||||
"birch_forest": 27,
|
||||
"old_growth_birch_forest": 155,
|
||||
"dark_forest": 29,
|
||||
"jungle": 21,
|
||||
"sparse_jungle": 23,
|
||||
"bamboo_jungle": 168,
|
||||
"taiga": 5,
|
||||
"snowy_taiga": 30,
|
||||
"old_growth_pine_taiga": 32,
|
||||
"old_growth_spruce_taiga": 160,
|
||||
"mushroom_fields": 14,
|
||||
"swamp": 6,
|
||||
"savanna": 35,
|
||||
"savanna_plateau": 36,
|
||||
"windswept_savanna": 163,
|
||||
"plains": 1,
|
||||
"sunflower_plains": 129,
|
||||
"desert": 2,
|
||||
"snowy_plains": 12,
|
||||
"ice_spikes": 140,
|
||||
"windswept_hills": 3,
|
||||
"windswept_forest": 34,
|
||||
"windswept_gravelly_hills": 131,
|
||||
"badlands": 37,
|
||||
"wooded_badlands": 38,
|
||||
"eroded_badlands": 165,
|
||||
"dripstone_caves": 174,
|
||||
"lush_caves": 175,
|
||||
"nether_wastes": 8,
|
||||
"crimson_forest": 171,
|
||||
"warped_forest": 172,
|
||||
"soul_sand_valley": 170,
|
||||
"basalt_deltas": 173,
|
||||
"the_end": 9,
|
||||
"small_end_islands": 40,
|
||||
"end_midlands": 41,
|
||||
"end_highlands": 42,
|
||||
"end_barrens": 43,
|
||||
"the_void": 127,
|
||||
"meadow": 177,
|
||||
"grove": 178,
|
||||
"snowy_slopes": 179,
|
||||
"frozen_peaks": 180,
|
||||
"jagged_peaks": 181,
|
||||
"stony_peaks": 182,
|
||||
}
|
||||
|
||||
func ChunkFromSave(c *save.Chunk, secs int) *Chunk {
|
||||
sections := make([]Section, secs)
|
||||
for _, v := range c.Sections {
|
||||
var blockCount int16
|
||||
stateData := *(*[]uint64)((unsafe.Pointer)(&v.BlockStates.Data))
|
||||
statePalette := v.BlockStates.Palette
|
||||
stateRawPalette := make([]int, len(statePalette))
|
||||
for i, v := range statePalette {
|
||||
// TODO: Consider the properties of block, not only index the block name
|
||||
stateRawPalette[i] = int(stateIDs[strings.TrimPrefix(v.Name, "minecraft:")])
|
||||
if v.Name != "minecraft:air" {
|
||||
blockCount++
|
||||
}
|
||||
}
|
||||
|
||||
biomesData := *(*[]uint64)((unsafe.Pointer)(&v.BlockStates.Data))
|
||||
biomesPalette := v.Biomes.Palette
|
||||
biomesRawPalette := make([]int, len(biomesPalette))
|
||||
for i, v := range biomesPalette {
|
||||
biomesRawPalette[i] = biomesIDs[strings.TrimPrefix(v, "minecraft:")]
|
||||
}
|
||||
|
||||
i := int32(int8(v.Y)) - c.YPos
|
||||
sections[i].blockCount = blockCount
|
||||
sections[i].States = NewStatesPaletteContainerWithData(16*16*16, stateData, stateRawPalette)
|
||||
sections[i].Biomes = NewBiomesPaletteContainerWithData(16*16*16*2, biomesData, biomesRawPalette)
|
||||
}
|
||||
for i := range sections {
|
||||
if sections[i].States == nil {
|
||||
sections[i] = Section{
|
||||
blockCount: 0,
|
||||
States: NewStatesPaletteContainer(16*16*16, 0),
|
||||
Biomes: NewBiomesPaletteContainer(4*4*4, 0),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
motionBlocking := *(*[]uint64)(unsafe.Pointer(&c.Heightmaps.MotionBlocking))
|
||||
worldSurface := *(*[]uint64)(unsafe.Pointer(&c.Heightmaps.WorldSurface))
|
||||
return &Chunk{
|
||||
Sections: sections,
|
||||
HeightMaps: HeightMaps{
|
||||
MotionBlocking: NewBitStorage(bits.Len(uint(secs)), 16*16, motionBlocking),
|
||||
WorldSurface: NewBitStorage(bits.Len(uint(secs)), 16*16, worldSurface),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: This map should be moved to data/block.
|
||||
var stateIDs = make(map[string]uint32)
|
||||
|
||||
func init() {
|
||||
for i, v := range block.StateID {
|
||||
name := block.ByID[v].Name
|
||||
if _, ok := stateIDs[name]; !ok {
|
||||
stateIDs[name] = i
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Chunk) WriteTo(w io.Writer) (int64, error) {
|
||||
data, err := c.Data()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return pk.Tuple{
|
||||
// Heightmaps
|
||||
pk.NBT(struct {
|
||||
MotionBlocking []uint64 `nbt:"MOTION_BLOCKING"`
|
||||
WorldSurface []uint64 `nbt:"WORLD_SURFACE"`
|
||||
}{
|
||||
MotionBlocking: c.HeightMaps.MotionBlocking.Raw(),
|
||||
WorldSurface: c.HeightMaps.MotionBlocking.Raw(),
|
||||
}),
|
||||
pk.ByteArray(data),
|
||||
pk.VarInt(0), // TODO: Block Entity
|
||||
&lightData{
|
||||
SkyLightMask: make(pk.BitSet, (16*16*16-1)>>6+1),
|
||||
BlockLightMask: make(pk.BitSet, (16*16*16-1)>>6+1),
|
||||
SkyLight: []pk.ByteArray{},
|
||||
BlockLight: []pk.ByteArray{},
|
||||
},
|
||||
}.WriteTo(w)
|
||||
}
|
||||
|
||||
func (c *Chunk) Data() ([]byte, error) {
|
||||
var buff bytes.Buffer
|
||||
for _, section := range c.Sections {
|
||||
_, err := section.WriteTo(&buff)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return buff.Bytes(), nil
|
||||
}
|
||||
|
||||
type Section struct {
|
||||
blockCount int16
|
||||
States *PaletteContainer
|
||||
Biomes *PaletteContainer
|
||||
}
|
||||
|
||||
func (s *Section) GetBlock(i int) int {
|
||||
return s.States.Get(i)
|
||||
}
|
||||
func (s *Section) SetBlock(i int, v int) {
|
||||
// TODO: Handle cave air and void air
|
||||
if s.States.Get(i) != 0 {
|
||||
s.blockCount--
|
||||
}
|
||||
if v != 0 {
|
||||
s.blockCount++
|
||||
}
|
||||
s.States.Set(i, v)
|
||||
}
|
||||
|
||||
func (s *Section) WriteTo(w io.Writer) (int64, error) {
|
||||
return pk.Tuple{
|
||||
pk.Short(s.blockCount),
|
||||
s.States,
|
||||
s.Biomes,
|
||||
}.WriteTo(w)
|
||||
}
|
||||
|
||||
func (s *Section) ReadFrom(r io.Reader) (int64, error) {
|
||||
return pk.Tuple{
|
||||
pk.Short(s.blockCount),
|
||||
s.States,
|
||||
s.Biomes,
|
||||
}.ReadFrom(r)
|
||||
}
|
||||
|
||||
type lightData struct {
|
||||
SkyLightMask pk.BitSet
|
||||
BlockLightMask pk.BitSet
|
||||
SkyLight []pk.ByteArray
|
||||
BlockLight []pk.ByteArray
|
||||
}
|
||||
|
||||
func bitSetRev(set pk.BitSet) pk.BitSet {
|
||||
rev := make(pk.BitSet, len(set))
|
||||
for i := range rev {
|
||||
rev[i] = ^set[i]
|
||||
}
|
||||
return rev
|
||||
}
|
||||
|
||||
func (l *lightData) WriteTo(w io.Writer) (int64, error) {
|
||||
return pk.Tuple{
|
||||
pk.Boolean(true), // Trust Edges
|
||||
l.SkyLightMask,
|
||||
l.BlockLightMask,
|
||||
bitSetRev(l.SkyLightMask),
|
||||
bitSetRev(l.BlockLightMask),
|
||||
pk.Array(l.SkyLight),
|
||||
pk.Array(l.BlockLight),
|
||||
}.WriteTo(w)
|
||||
}
|
@ -12,7 +12,7 @@ type state = int
|
||||
|
||||
type PaletteContainer struct {
|
||||
bits int
|
||||
config func(bits int) palette
|
||||
config paletteCfg
|
||||
palette palette
|
||||
data *BitStorage
|
||||
}
|
||||
@ -20,34 +20,63 @@ type PaletteContainer struct {
|
||||
func NewStatesPaletteContainer(length int, defaultValue state) *PaletteContainer {
|
||||
return &PaletteContainer{
|
||||
bits: 0,
|
||||
config: createStatesPalette,
|
||||
config: statesCfg{},
|
||||
palette: &singleValuePalette{v: defaultValue},
|
||||
data: NewBitStorage(0, length, nil),
|
||||
}
|
||||
}
|
||||
|
||||
func NewStatesPaletteContainerWithData(length int, data []uint64, palette []int) *PaletteContainer {
|
||||
n := bits.Len(uint(len(palette)))
|
||||
return &PaletteContainer{
|
||||
bits: n,
|
||||
config: createStatesPalette,
|
||||
palette: &linearPalette{
|
||||
values: palette,
|
||||
func NewStatesPaletteContainerWithData(length int, data []uint64, pat []int) *PaletteContainer {
|
||||
var p palette
|
||||
var n int
|
||||
if len(pat) == 1 {
|
||||
p = &singleValuePalette{pat[0]}
|
||||
n = 0
|
||||
} else {
|
||||
n = statesCfg{}.bits(bits.Len(uint(len(pat))))
|
||||
p = &linearPalette{
|
||||
values: pat,
|
||||
bits: n,
|
||||
},
|
||||
data: NewBitStorage(n, length, data),
|
||||
}
|
||||
}
|
||||
return &PaletteContainer{
|
||||
bits: n,
|
||||
config: statesCfg{},
|
||||
palette: p,
|
||||
data: NewBitStorage(n, length, data),
|
||||
}
|
||||
}
|
||||
|
||||
func NewBiomesPaletteContainer(length int, defaultValue state) *PaletteContainer {
|
||||
return &PaletteContainer{
|
||||
bits: 0,
|
||||
config: createBiomesPalette,
|
||||
config: biomesCfg{},
|
||||
palette: &singleValuePalette{v: defaultValue},
|
||||
data: NewBitStorage(0, length, nil),
|
||||
}
|
||||
}
|
||||
|
||||
func NewBiomesPaletteContainerWithData(length int, data []uint64, pat []int) *PaletteContainer {
|
||||
var p palette
|
||||
var n int
|
||||
if len(pat) == 1 {
|
||||
p = &singleValuePalette{pat[0]}
|
||||
n = 0
|
||||
} else {
|
||||
n = biomesCfg{}.bits(bits.Len(uint(len(pat))))
|
||||
p = &linearPalette{
|
||||
values: pat,
|
||||
bits: n,
|
||||
}
|
||||
}
|
||||
return &PaletteContainer{
|
||||
bits: n,
|
||||
config: biomesCfg{},
|
||||
palette: p,
|
||||
data: NewBitStorage(n, length, data),
|
||||
}
|
||||
}
|
||||
|
||||
func (p *PaletteContainer) Get(i int) state {
|
||||
return p.palette.value(p.data.Get(i))
|
||||
}
|
||||
@ -61,7 +90,7 @@ func (p *PaletteContainer) Set(i int, v state) {
|
||||
newPalette := PaletteContainer{
|
||||
bits: vv,
|
||||
config: p.config,
|
||||
palette: p.config(vv),
|
||||
palette: p.config.create(vv),
|
||||
data: NewBitStorage(vv, oldLen+1, nil),
|
||||
}
|
||||
// copy
|
||||
@ -89,7 +118,7 @@ func (p *PaletteContainer) ReadFrom(r io.Reader) (n int64, err error) {
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
p.palette = p.config(int(bits))
|
||||
p.palette = p.config.create(int(bits))
|
||||
|
||||
nn, err := p.palette.ReadFrom(r)
|
||||
n += nn
|
||||
@ -105,7 +134,27 @@ func (p *PaletteContainer) ReadFrom(r io.Reader) (n int64, err error) {
|
||||
return n, nil
|
||||
}
|
||||
|
||||
func createStatesPalette(bits int) palette {
|
||||
type paletteCfg interface {
|
||||
bits(int) int
|
||||
create(bits int) palette
|
||||
}
|
||||
|
||||
type statesCfg struct{}
|
||||
|
||||
func (s statesCfg) bits(bits int) int {
|
||||
switch bits {
|
||||
case 0:
|
||||
return 0
|
||||
case 1, 2, 3, 4:
|
||||
return 4
|
||||
case 5, 6, 7, 8:
|
||||
return bits
|
||||
default:
|
||||
return bits
|
||||
}
|
||||
}
|
||||
|
||||
func (s statesCfg) create(bits int) palette {
|
||||
switch bits {
|
||||
case 0:
|
||||
return &singleValuePalette{v: -1}
|
||||
@ -119,7 +168,19 @@ func createStatesPalette(bits int) palette {
|
||||
}
|
||||
}
|
||||
|
||||
func createBiomesPalette(bits int) palette {
|
||||
type biomesCfg struct{}
|
||||
|
||||
func (b biomesCfg) bits(bits int) int {
|
||||
switch bits {
|
||||
case 0:
|
||||
return 0
|
||||
case 1, 2, 3:
|
||||
return bits
|
||||
default:
|
||||
return bits
|
||||
}
|
||||
}
|
||||
func (b biomesCfg) create(bits int) palette {
|
||||
switch bits {
|
||||
case 0:
|
||||
return &singleValuePalette{v: -1}
|
||||
|
@ -1,18 +1,9 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
"math/bits"
|
||||
"strings"
|
||||
"sync"
|
||||
"unsafe"
|
||||
|
||||
"github.com/Tnze/go-mc/data/block"
|
||||
"github.com/Tnze/go-mc/data/packetid"
|
||||
"github.com/Tnze/go-mc/level"
|
||||
pk "github.com/Tnze/go-mc/net/packet"
|
||||
"github.com/Tnze/go-mc/save"
|
||||
)
|
||||
|
||||
type Level interface {
|
||||
@ -26,160 +17,19 @@ type LevelInfo struct {
|
||||
HashedSeed uint64
|
||||
}
|
||||
|
||||
type ChunkPos struct{ X, Z int }
|
||||
type Chunk struct {
|
||||
sync.Mutex
|
||||
Sections []Section
|
||||
HeightMaps *level.BitStorage
|
||||
}
|
||||
|
||||
func EmptyChunk(secs int) *Chunk {
|
||||
sections := make([]Section, secs)
|
||||
for i := range sections {
|
||||
sections[i] = Section{
|
||||
blockCount: 0,
|
||||
States: level.NewStatesPaletteContainer(16*16*16, 0),
|
||||
Biomes: level.NewBiomesPaletteContainer(4*4*4, 0),
|
||||
}
|
||||
}
|
||||
return &Chunk{
|
||||
Sections: sections,
|
||||
HeightMaps: level.NewBitStorage(bits.Len(uint(secs)*16), 16*16, nil),
|
||||
}
|
||||
}
|
||||
|
||||
func ChunkFromSave(c *save.Chunk) *Chunk {
|
||||
sections := make([]Section, len(c.Sections))
|
||||
for i := range sections {
|
||||
data := *(*[]uint64)((unsafe.Pointer)(&c.Sections[i].BlockStates.Data))
|
||||
palette := c.Sections[i].BlockStates.Palette
|
||||
rawPalette := make([]int, len(palette))
|
||||
for i, v := range palette {
|
||||
// TODO: Consider the properties of block, not only index the block name
|
||||
rawPalette[i] = int(stateIDs[strings.TrimPrefix(v.Name, "minecraft:")])
|
||||
}
|
||||
sections[i].States = level.NewStatesPaletteContainerWithData(16*16*16, data, rawPalette)
|
||||
}
|
||||
return &Chunk{
|
||||
Sections: sections,
|
||||
HeightMaps: nil,
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: This map should be moved to data/block.
|
||||
var stateIDs map[string]uint32
|
||||
|
||||
func init() {
|
||||
for i, v := range block.StateID {
|
||||
name := block.ByID[v].Name
|
||||
if _, ok := stateIDs[name]; !ok {
|
||||
stateIDs[name] = i
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Chunk) WriteTo(w io.Writer) (int64, error) {
|
||||
data, err := c.Data()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return pk.Tuple{
|
||||
// Heightmaps
|
||||
pk.NBT(struct {
|
||||
MotionBlocking []uint64 `nbt:"MOTION_BLOCKING"`
|
||||
}{c.HeightMaps.Raw()}),
|
||||
pk.ByteArray(data),
|
||||
pk.VarInt(0), // TODO: Block Entity
|
||||
}.WriteTo(w)
|
||||
}
|
||||
|
||||
func (c *Chunk) Data() ([]byte, error) {
|
||||
var buff bytes.Buffer
|
||||
for _, section := range c.Sections {
|
||||
_, err := section.WriteTo(&buff)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return buff.Bytes(), nil
|
||||
}
|
||||
|
||||
type Section struct {
|
||||
blockCount int16
|
||||
States *level.PaletteContainer
|
||||
Biomes *level.PaletteContainer
|
||||
}
|
||||
|
||||
func (s *Section) GetBlock(i int) int {
|
||||
return s.States.Get(i)
|
||||
}
|
||||
func (s *Section) SetBlock(i int, v int) {
|
||||
// TODO: Handle cave air and void air
|
||||
if s.States.Get(i) != 0 {
|
||||
s.blockCount--
|
||||
}
|
||||
if v != 0 {
|
||||
s.blockCount++
|
||||
}
|
||||
s.States.Set(i, v)
|
||||
}
|
||||
|
||||
func (s *Section) WriteTo(w io.Writer) (int64, error) {
|
||||
return pk.Tuple{
|
||||
pk.Short(s.blockCount),
|
||||
s.States,
|
||||
s.Biomes,
|
||||
}.WriteTo(w)
|
||||
}
|
||||
|
||||
func (s *Section) ReadFrom(r io.Reader) (int64, error) {
|
||||
return pk.Tuple{
|
||||
pk.Short(s.blockCount),
|
||||
s.States,
|
||||
s.Biomes,
|
||||
}.ReadFrom(r)
|
||||
}
|
||||
|
||||
type lightData struct {
|
||||
SkyLightMask pk.BitSet
|
||||
BlockLightMask pk.BitSet
|
||||
SkyLight []pk.ByteArray
|
||||
BlockLight []pk.ByteArray
|
||||
}
|
||||
|
||||
func bitSetRev(set pk.BitSet) pk.BitSet {
|
||||
rev := make(pk.BitSet, len(set))
|
||||
for i := range rev {
|
||||
rev[i] = ^set[i]
|
||||
}
|
||||
return rev
|
||||
}
|
||||
|
||||
func (l *lightData) WriteTo(w io.Writer) (int64, error) {
|
||||
return pk.Tuple{
|
||||
pk.Boolean(true), // Trust Edges
|
||||
l.SkyLightMask,
|
||||
l.BlockLightMask,
|
||||
bitSetRev(l.SkyLightMask),
|
||||
bitSetRev(l.BlockLightMask),
|
||||
pk.Array(l.SkyLight),
|
||||
pk.Array(l.BlockLight),
|
||||
}.WriteTo(w)
|
||||
}
|
||||
|
||||
type SimpleDim struct {
|
||||
numOfSection int
|
||||
Columns map[ChunkPos]*Chunk
|
||||
Columns map[level.ChunkPos]*level.Chunk
|
||||
}
|
||||
|
||||
func NewSimpleDim(secs int) *SimpleDim {
|
||||
return &SimpleDim{
|
||||
numOfSection: secs,
|
||||
Columns: make(map[ChunkPos]*Chunk),
|
||||
Columns: make(map[level.ChunkPos]*level.Chunk),
|
||||
}
|
||||
}
|
||||
|
||||
func (s *SimpleDim) LoadChunk(pos ChunkPos, c *Chunk) {
|
||||
func (s *SimpleDim) LoadChunk(pos level.ChunkPos, c *level.Chunk) {
|
||||
s.Columns[pos] = c
|
||||
}
|
||||
|
||||
@ -197,12 +47,6 @@ func (s *SimpleDim) PlayerJoin(p *Player) {
|
||||
packetid.ClientboundLevelChunkWithLight,
|
||||
pk.Int(pos.X), pk.Int(pos.Z),
|
||||
column,
|
||||
&lightData{
|
||||
SkyLightMask: make(pk.BitSet, (16*16*16-1)>>6+1),
|
||||
BlockLightMask: make(pk.BitSet, (16*16*16-1)>>6+1),
|
||||
SkyLight: []pk.ByteArray{},
|
||||
BlockLight: []pk.ByteArray{},
|
||||
},
|
||||
)
|
||||
column.Unlock()
|
||||
|
||||
@ -214,7 +58,7 @@ func (s *SimpleDim) PlayerJoin(p *Player) {
|
||||
|
||||
err := p.WritePacket(Packet757(pk.Marshal(
|
||||
packetid.ClientboundPlayerPosition,
|
||||
pk.Double(0), pk.Double(0), pk.Double(0),
|
||||
pk.Double(0), pk.Double(143), pk.Double(0),
|
||||
pk.Float(0), pk.Float(0),
|
||||
pk.Byte(0),
|
||||
pk.VarInt(0),
|
||||
|
Reference in New Issue
Block a user