From 1bce3797790ddbbd16ff94251e678a4a8632ff74 Mon Sep 17 00:00:00 2001 From: Tnze Date: Sun, 19 Dec 2021 19:41:24 +0800 Subject: [PATCH] fix bugs in PaletteContainer --- examples/frameworkServer/main.go | 13 +++- examples/genmaps/genmaps.go | 3 +- {save => level}/bitstorage.go | 36 ++++++--- {save => level}/bitstorage_test.go | 2 +- {save => level}/palette.go | 117 ++++++++++------------------- server/dimension.go | 39 +++++++--- 6 files changed, 104 insertions(+), 106 deletions(-) rename {save => level}/bitstorage.go (90%) rename {save => level}/bitstorage_test.go (98%) rename {save => level}/palette.go (61%) diff --git a/examples/frameworkServer/main.go b/examples/frameworkServer/main.go index 337c3dc..7123897 100644 --- a/examples/frameworkServer/main.go +++ b/examples/frameworkServer/main.go @@ -2,13 +2,12 @@ package main import ( _ "embed" + "github.com/Tnze/go-mc/chat" + "github.com/Tnze/go-mc/server" "image" _ "image/png" "log" "os" - - "github.com/Tnze/go-mc/chat" - "github.com/Tnze/go-mc/server" ) const MaxPlayer = 20 @@ -23,7 +22,13 @@ func main() { log.Fatalf("Set server info error: %v", err) } defaultDimension := server.NewSimpleDim(16) - defaultDimension.LoadChunk(server.ChunkPos{X: 0, Z: 0}, server.EmptyChunk(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) s := server.Server{ ListPingHandler: serverInfo, LoginHandler: &server.MojangLoginHandler{ diff --git a/examples/genmaps/genmaps.go b/examples/genmaps/genmaps.go index 07f31b4..be8ff84 100644 --- a/examples/genmaps/genmaps.go +++ b/examples/genmaps/genmaps.go @@ -3,6 +3,7 @@ package main import ( "flag" "fmt" + "github.com/Tnze/go-mc/level" "image" "image/color" "image/draw" @@ -189,7 +190,7 @@ func drawSection(s *save.Chunk, img *image.RGBA) { // decode status data := *(*[]uint64)(unsafe.Pointer(&s.BlockStates)) // convert []int64 into []uint64 - bs := save.NewBitStorage(bpb, 4096, data) + bs := level.NewBitStorage(bpb, 4096, data) for y := 0; y < 16; y++ { layerImg := image.NewRGBA(image.Rect(0, 0, 16, 16)) for i := 16*16 - 1; i >= 0; i-- { diff --git a/save/bitstorage.go b/level/bitstorage.go similarity index 90% rename from save/bitstorage.go rename to level/bitstorage.go index 249fadc..194572f 100644 --- a/save/bitstorage.go +++ b/level/bitstorage.go @@ -1,4 +1,4 @@ -package save +package level import ( "fmt" @@ -29,7 +29,13 @@ type BitStorage struct { // The "data" is optional for initializing. Panic if data != nil && len(data) != calcBitStorageSize(bits, length). func NewBitStorage(bits, length int, data []uint64) (b *BitStorage) { if bits == 0 { - return nil + return &BitStorage{ + data: nil, + mask: 0, + bits: 0, + length: length, + valuesPerLong: 0, + } } b = &BitStorage{ @@ -76,13 +82,15 @@ func (b *BitStorage) calcIndex(n int) (c, o int) { // Swap sets v into [i], and return the previous [i] value. func (b *BitStorage) Swap(i, v int) (old int) { - if b == nil || i < 0 || i > b.length-1 { - panic(indexOutOfBounds) + if b.valuesPerLong == 0 { + return 0 } if v < 0 || uint64(v) > b.mask { panic(valueOutOfBounds) } - + if i < 0 || i > b.length-1 { + panic(indexOutOfBounds) + } c, offset := b.calcIndex(i) l := b.data[c] old = int(l >> offset & b.mask) @@ -92,12 +100,15 @@ func (b *BitStorage) Swap(i, v int) (old int) { // Set sets v into [i]. func (b *BitStorage) Set(i, v int) { - if b == nil || i < 0 || i > b.length-1 { - panic(indexOutOfBounds) + if b.valuesPerLong == 0 { + return } if v < 0 || uint64(v) > b.mask { panic(valueOutOfBounds) } + if i < 0 || i > b.length-1 { + panic(indexOutOfBounds) + } c, offset := b.calcIndex(i) l := b.data[c] @@ -106,7 +117,10 @@ func (b *BitStorage) Set(i, v int) { // Get gets [i] value. func (b *BitStorage) Get(i int) int { - if b == nil || i < 0 || i > b.length-1 { + if b.valuesPerLong == 0 { + return 0 + } + if i < 0 || i > b.length-1 { panic(indexOutOfBounds) } @@ -117,9 +131,6 @@ func (b *BitStorage) Get(i int) int { // Len is the number of stored values. func (b *BitStorage) Len() int { - if b == nil { - return 0 - } return b.length } @@ -155,6 +166,9 @@ func (b *BitStorage) ReadFrom(r io.Reader) (int64, error) { } func (b *BitStorage) WriteTo(w io.Writer) (int64, error) { + if b == nil { + return pk.VarInt(0).WriteTo(w) + } n, err := pk.VarInt(len(b.data)).WriteTo(w) if err != nil { return n, err diff --git a/save/bitstorage_test.go b/level/bitstorage_test.go similarity index 98% rename from save/bitstorage_test.go rename to level/bitstorage_test.go index 8896da5..bd0231b 100644 --- a/save/bitstorage_test.go +++ b/level/bitstorage_test.go @@ -1,4 +1,4 @@ -package save +package level import ( pk "github.com/Tnze/go-mc/net/packet" diff --git a/save/palette.go b/level/palette.go similarity index 61% rename from save/palette.go rename to level/palette.go index c449549..58e6935 100644 --- a/save/palette.go +++ b/level/palette.go @@ -1,4 +1,4 @@ -package save +package level import ( "io" @@ -7,42 +7,38 @@ import ( pk "github.com/Tnze/go-mc/net/packet" ) -type BlockState interface { -} +type state = int type PaletteContainer struct { bits int - maps IdMaps - config func(maps IdMaps, bits int) palette + config func(bits int) palette palette palette data *BitStorage } -func NewStatesPaletteContainer(maps IdMaps, length int) *PaletteContainer { +func NewStatesPaletteContainer(length int, defaultValue state) *PaletteContainer { return &PaletteContainer{ bits: 0, - maps: maps, config: createStatesPalette, - palette: createStatesPalette(maps, 0), + palette: &singleValuePalette{v: defaultValue}, data: NewBitStorage(0, length, nil), } } -func NewBiomesPaletteContainer(maps IdMaps, length int) *PaletteContainer { +func NewBiomesPaletteContainer(length int, defaultValue state) *PaletteContainer { return &PaletteContainer{ bits: 0, - maps: maps, config: createBiomesPalette, - palette: createBiomesPalette(maps, 0), + palette: &singleValuePalette{v: defaultValue}, data: NewBitStorage(0, length, nil), } } -func (p *PaletteContainer) Get(i int) BlockState { +func (p *PaletteContainer) Get(i int) state { return p.palette.value(p.data.Get(i)) } -func (p *PaletteContainer) Set(i int, v BlockState) { +func (p *PaletteContainer) Set(i int, v state) { if vv, ok := p.palette.id(v); ok { p.data.Set(i, vv) } else { @@ -50,14 +46,13 @@ func (p *PaletteContainer) Set(i int, v BlockState) { oldLen := p.data.Len() newPalette := PaletteContainer{ bits: vv, - maps: p.maps, config: p.config, - palette: p.config(p.maps, vv), + palette: p.config(vv), data: NewBitStorage(vv, oldLen+1, nil), } // copy for i := 0; i < oldLen; i++ { - raw := p.palette.value(i) + raw := p.data.Get(i) if vv, ok := newPalette.palette.id(raw); !ok { panic("not reachable") } else { @@ -80,7 +75,7 @@ func (p *PaletteContainer) ReadFrom(r io.Reader) (n int64, err error) { if err != nil { return } - p.palette = p.config(p.maps, int(bits)) + p.palette = p.config(int(bits)) nn, err := p.palette.ReadFrom(r) n += nn @@ -96,47 +91,28 @@ func (p *PaletteContainer) ReadFrom(r io.Reader) (n int64, err error) { return n, nil } -func createStatesPalette(maps IdMaps, bits int) palette { +func createStatesPalette(bits int) palette { switch bits { case 0: - return &singleValuePalette{ - maps: maps, - v: nil, - } + return &singleValuePalette{v: -1} case 1, 2, 3, 4: - return &linearPalette{ - maps: maps, - bits: 4, - } + return &linearPalette{bits: 4, values: make([]state, 0, 1<<4)} case 5, 6, 7, 8: // TODO: HashMapPalette - return &linearPalette{ - maps: maps, - bits: bits, - } + return &linearPalette{bits: bits, values: make([]state, 0, 1<= 0 && i < len(l.values) { return l.values[i] } - return nil + panic("linearPalette: " + strconv.Itoa(i) + " out of bounds") } func (l *linearPalette) ReadFrom(r io.Reader) (n int64, err error) { @@ -235,7 +200,7 @@ func (l *linearPalette) ReadFrom(r io.Reader) (n int64, err error) { } else { n += nn } - l.values[i] = l.maps.getValue(int(value)) + l.values[i] = state(value) } return } @@ -245,7 +210,7 @@ func (l *linearPalette) WriteTo(w io.Writer) (n int64, err error) { return } for _, v := range l.values { - if nn, err := pk.VarInt(l.maps.getID(v)).WriteTo(w); err != nil { + if nn, err := pk.VarInt(v).WriteTo(w); err != nil { return n + nn, err } else { n += nn @@ -254,15 +219,13 @@ func (l *linearPalette) WriteTo(w io.Writer) (n int64, err error) { return } -type globalPalette struct { - maps IdMaps +type globalPalette struct{} + +func (g *globalPalette) id(v state) (int, bool) { + return v, true } -func (g *globalPalette) id(v BlockState) (int, bool) { - return g.maps.getID(v), true -} - -func (g *globalPalette) value(i int) BlockState { +func (g *globalPalette) value(i int) state { return g.value(i) } diff --git a/server/dimension.go b/server/dimension.go index 7b9d0eb..181328d 100644 --- a/server/dimension.go +++ b/server/dimension.go @@ -2,12 +2,13 @@ package server import ( "bytes" - "github.com/Tnze/go-mc/data/packetid" - pk "github.com/Tnze/go-mc/net/packet" - "github.com/Tnze/go-mc/save" "io" "math/bits" "sync" + + "github.com/Tnze/go-mc/data/packetid" + "github.com/Tnze/go-mc/level" + pk "github.com/Tnze/go-mc/net/packet" ) type Dimension interface { @@ -24,14 +25,28 @@ type DimInfo struct { type ChunkPos struct{ X, Z int } type Chunk struct { sync.Mutex - sections []Section - HeightMaps *save.BitStorage + Sections []Section + HeightMaps *level.BitStorage } type Section struct { blockCount int16 - States *save.PaletteContainer - Biomes *save.PaletteContainer + 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) { @@ -55,13 +70,13 @@ func EmptyChunk(secs int) *Chunk { for i := range sections { sections[i] = Section{ blockCount: 0, - States: save.NewStatesPaletteContainer(nil, 16*16*16), - Biomes: save.NewBiomesPaletteContainer(nil, 4*4*4), + States: level.NewStatesPaletteContainer(16*16*16, 0), + Biomes: level.NewBiomesPaletteContainer(4*4*4, 0), } } return &Chunk{ - sections: sections, - HeightMaps: save.NewBitStorage(bits.Len(uint(secs)*16), 16*16, nil), + Sections: sections, + HeightMaps: level.NewBitStorage(bits.Len(uint(secs)*16), 16*16, nil), } } @@ -82,7 +97,7 @@ func (c *Chunk) WriteTo(w io.Writer) (int64, error) { func (c *Chunk) Data() ([]byte, error) { var buff bytes.Buffer - for _, section := range c.sections { + for _, section := range c.Sections { _, err := section.WriteTo(&buff) if err != nil { return nil, err