HashMap palette implement
This commit is contained in:
@ -140,7 +140,7 @@ func loadAllChunks(dim *server.SimpleDim, file string, rx, rz int) error {
|
|||||||
if err := c.Load(data); err != nil {
|
if err := c.Load(data); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
chunk := level.ChunkFromSave(&c, 256)
|
chunk := level.ChunkFromSave(&c)
|
||||||
dim.LoadChunk(level.ChunkPos{X: rx<<5 + x, Z: rz<<5 + z}, chunk)
|
dim.LoadChunk(level.ChunkPos{X: rx<<5 + x, Z: rz<<5 + z}, chunk)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
126
level/chunk.go
126
level/chunk.go
@ -2,6 +2,7 @@ package level
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"math/bits"
|
"math/bits"
|
||||||
"strings"
|
"strings"
|
||||||
@ -124,64 +125,99 @@ var biomesIDs = map[string]int{
|
|||||||
"end_barrens": 60,
|
"end_barrens": 60,
|
||||||
}
|
}
|
||||||
|
|
||||||
func ChunkFromSave(c *save.Chunk, secs int) *Chunk {
|
// ChunkFromSave convert save.Chunk to level.Chunk.
|
||||||
|
func ChunkFromSave(c *save.Chunk) *Chunk {
|
||||||
|
secs := len(c.Sections)
|
||||||
sections := make([]Section, secs)
|
sections := make([]Section, secs)
|
||||||
for _, v := range c.Sections {
|
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 {
|
|
||||||
b, ok := block.FromID[v.Name]
|
|
||||||
if !ok {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
if v.Properties.Data != nil {
|
|
||||||
err := v.Properties.Unmarshal(&b)
|
|
||||||
if err != nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
s := block.ToStateID[b]
|
|
||||||
if !block.IsAir(s) {
|
|
||||||
blockCount++
|
|
||||||
}
|
|
||||||
stateRawPalette[i] = s
|
|
||||||
}
|
|
||||||
|
|
||||||
biomesData := *(*[]uint64)((unsafe.Pointer)(&v.Biomes.Data))
|
|
||||||
biomesPalette := v.Biomes.Palette
|
|
||||||
biomesRawPalette := make([]int, len(biomesPalette))
|
|
||||||
for i, v := range biomesPalette {
|
|
||||||
biomesRawPalette[i] = biomesIDs[strings.TrimPrefix(v, "minecraft:")]
|
|
||||||
}
|
|
||||||
|
|
||||||
i := int32(v.Y) - c.YPos
|
i := int32(v.Y) - c.YPos
|
||||||
sections[i].BlockCount = blockCount
|
// TODO: the error is ignored
|
||||||
sections[i].States = NewStatesPaletteContainerWithData(16*16*16, stateData, stateRawPalette)
|
sections[i].BlockCount, sections[i].States, _ = readStatesPalette(v.BlockStates.Palette, v.BlockStates.Data)
|
||||||
sections[i].Biomes = NewBiomesPaletteContainerWithData(4*4*4, biomesData, biomesRawPalette)
|
sections[i].Biomes, _ = readBiomesPalette(v.Biomes.Palette, v.Biomes.Data)
|
||||||
}
|
|
||||||
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))
|
motionBlocking := *(*[]uint64)(unsafe.Pointer(&c.Heightmaps.MotionBlocking))
|
||||||
|
motionBlockingNoLeaves := *(*[]uint64)(unsafe.Pointer(&c.Heightmaps.MotionBlockingNoLeaves))
|
||||||
|
oceanFloor := *(*[]uint64)(unsafe.Pointer(&c.Heightmaps.OceanFloor))
|
||||||
worldSurface := *(*[]uint64)(unsafe.Pointer(&c.Heightmaps.WorldSurface))
|
worldSurface := *(*[]uint64)(unsafe.Pointer(&c.Heightmaps.WorldSurface))
|
||||||
|
|
||||||
|
bitsForHeight := bits.Len( /* chunk height in blocks */ uint(secs) * 16)
|
||||||
return &Chunk{
|
return &Chunk{
|
||||||
Sections: sections,
|
Sections: sections,
|
||||||
HeightMaps: HeightMaps{
|
HeightMaps: HeightMaps{
|
||||||
MotionBlocking: NewBitStorage(bits.Len(uint(secs)), 16*16, motionBlocking),
|
MotionBlocking: NewBitStorage(bitsForHeight, 16*16, motionBlocking),
|
||||||
WorldSurface: NewBitStorage(bits.Len(uint(secs)), 16*16, worldSurface),
|
MotionBlockingNoLeaves: NewBitStorage(bitsForHeight, 16*16, motionBlockingNoLeaves),
|
||||||
|
OceanFloor: NewBitStorage(bitsForHeight, 16*16, oceanFloor),
|
||||||
|
WorldSurface: NewBitStorage(bitsForHeight, 16*16, worldSurface),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func readStatesPalette(palette []save.BlockState, data []int64) (blockCount int16, paletteData *PaletteContainer, err error) {
|
||||||
|
stateData := *(*[]uint64)((unsafe.Pointer)(&data))
|
||||||
|
statePalette := make([]int, len(palette))
|
||||||
|
for i, v := range palette {
|
||||||
|
b, ok := block.FromID[v.Name]
|
||||||
|
if !ok {
|
||||||
|
return 0, nil, fmt.Errorf("unknown block id: %v", v.Name)
|
||||||
|
}
|
||||||
|
if v.Properties.Data != nil {
|
||||||
|
if err := v.Properties.Unmarshal(&b); err != nil {
|
||||||
|
return 0, nil, fmt.Errorf("unmarshal block properties fail: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
s, ok := block.ToStateID[b]
|
||||||
|
if !ok {
|
||||||
|
return 0, nil, fmt.Errorf("unknown block: %v", b)
|
||||||
|
}
|
||||||
|
if !block.IsAir(s) {
|
||||||
|
blockCount++
|
||||||
|
}
|
||||||
|
statePalette[i] = s
|
||||||
|
}
|
||||||
|
paletteData = NewStatesPaletteContainerWithData(16*16*16, stateData, statePalette)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func readBiomesPalette(palette []string, data []int64) (*PaletteContainer, error) {
|
||||||
|
biomesData := *(*[]uint64)((unsafe.Pointer)(&data))
|
||||||
|
biomesRawPalette := make([]int, len(palette))
|
||||||
|
var ok bool
|
||||||
|
for i, v := range palette {
|
||||||
|
biomesRawPalette[i], ok = biomesIDs[strings.TrimPrefix(v, "minecraft:")]
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("unknown biomes: %s", v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NewBiomesPaletteContainerWithData(4*4*4, biomesData, biomesRawPalette), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
//// ChunkToSave convert level.Chunk to save.Chunk
|
||||||
|
//func ChunkToSave(c *Chunk, dst *save.Chunk) {
|
||||||
|
// secs := len(c.Sections)
|
||||||
|
// sections := make([]save.Section, secs)
|
||||||
|
// for i, v := range c.Sections {
|
||||||
|
// sections[i] = save.Section{
|
||||||
|
// Y: int8(int32(i) + dst.YPos),
|
||||||
|
// BlockStates: struct {
|
||||||
|
// Palette []save.BlockState `nbt:"palette"`
|
||||||
|
// Data []int64 `nbt:"data"`
|
||||||
|
// }{},
|
||||||
|
// Biomes: struct {
|
||||||
|
// Palette []string `nbt:"palette"`
|
||||||
|
// Data []int64 `nbt:"data"`
|
||||||
|
// }{},
|
||||||
|
// SkyLight: nil,
|
||||||
|
// BlockLight: nil,
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// dst.Sections = sections
|
||||||
|
//}
|
||||||
|
|
||||||
|
//func writeStatesPalette(paletteData *PaletteContainer) (palette []save.BlockState, data []int64) {
|
||||||
|
// paletteData.palette.export()
|
||||||
|
//}
|
||||||
|
|
||||||
func (c *Chunk) WriteTo(w io.Writer) (int64, error) {
|
func (c *Chunk) WriteTo(w io.Writer) (int64, error) {
|
||||||
data, err := c.Data()
|
data, err := c.Data()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -259,6 +295,8 @@ func (c *Chunk) PutData(data []byte) error {
|
|||||||
|
|
||||||
type HeightMaps struct {
|
type HeightMaps struct {
|
||||||
MotionBlocking *BitStorage
|
MotionBlocking *BitStorage
|
||||||
|
MotionBlockingNoLeaves *BitStorage
|
||||||
|
OceanFloor *BitStorage
|
||||||
WorldSurface *BitStorage
|
WorldSurface *BitStorage
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,12 +34,20 @@ func NewStatesPaletteContainerWithData(length int, data []uint64, pat []int) *Pa
|
|||||||
p = &singleValuePalette{pat[0]}
|
p = &singleValuePalette{pat[0]}
|
||||||
case 1, 2, 3, 4:
|
case 1, 2, 3, 4:
|
||||||
n = 4
|
n = 4
|
||||||
fallthrough
|
|
||||||
case 5, 6, 7, 8:
|
|
||||||
p = &linearPalette{
|
p = &linearPalette{
|
||||||
values: pat,
|
values: pat,
|
||||||
bits: n,
|
bits: n,
|
||||||
}
|
}
|
||||||
|
case 5, 6, 7, 8:
|
||||||
|
ids := make(map[state]int)
|
||||||
|
for i, v := range pat {
|
||||||
|
ids[v] = i
|
||||||
|
}
|
||||||
|
p = &hashPalette{
|
||||||
|
ids: ids,
|
||||||
|
values: pat,
|
||||||
|
bits: n,
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
p = &globalPalette{}
|
p = &globalPalette{}
|
||||||
}
|
}
|
||||||
@ -207,8 +215,11 @@ func (b biomesCfg) create(bits int) palette {
|
|||||||
|
|
||||||
type palette interface {
|
type palette interface {
|
||||||
pk.Field
|
pk.Field
|
||||||
|
// id return the index of state v in the palette and true if existed.
|
||||||
|
// otherwise return the new bits for resize and false.
|
||||||
id(v state) (int, bool)
|
id(v state) (int, bool)
|
||||||
value(i int) state
|
value(i int) state
|
||||||
|
export() []state
|
||||||
}
|
}
|
||||||
|
|
||||||
type singleValuePalette struct {
|
type singleValuePalette struct {
|
||||||
@ -230,6 +241,10 @@ func (s *singleValuePalette) value(i int) state {
|
|||||||
panic("singleValuePalette: " + strconv.Itoa(i) + " out of bounds")
|
panic("singleValuePalette: " + strconv.Itoa(i) + " out of bounds")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *singleValuePalette) export() []state {
|
||||||
|
return []int{s.v}
|
||||||
|
}
|
||||||
|
|
||||||
func (s *singleValuePalette) ReadFrom(r io.Reader) (n int64, err error) {
|
func (s *singleValuePalette) ReadFrom(r io.Reader) (n int64, err error) {
|
||||||
var i pk.VarInt
|
var i pk.VarInt
|
||||||
n, err = i.ReadFrom(r)
|
n, err = i.ReadFrom(r)
|
||||||
@ -269,6 +284,10 @@ func (l *linearPalette) value(i int) state {
|
|||||||
panic("linearPalette: " + strconv.Itoa(i) + " out of bounds")
|
panic("linearPalette: " + strconv.Itoa(i) + " out of bounds")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (l *linearPalette) export() []state {
|
||||||
|
return l.values
|
||||||
|
}
|
||||||
|
|
||||||
func (l *linearPalette) ReadFrom(r io.Reader) (n int64, err error) {
|
func (l *linearPalette) ReadFrom(r io.Reader) (n int64, err error) {
|
||||||
var size, value pk.VarInt
|
var size, value pk.VarInt
|
||||||
if n, err = size.ReadFrom(r); err != nil {
|
if n, err = size.ReadFrom(r); err != nil {
|
||||||
@ -304,6 +323,71 @@ func (l *linearPalette) WriteTo(w io.Writer) (n int64, err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type hashPalette struct {
|
||||||
|
ids map[state]int
|
||||||
|
values []state
|
||||||
|
bits int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *hashPalette) id(v state) (int, bool) {
|
||||||
|
if i, ok := h.ids[v]; ok {
|
||||||
|
return i, true
|
||||||
|
}
|
||||||
|
if cap(h.values)-len(h.values) > 0 {
|
||||||
|
h.ids[v] = len(h.values)
|
||||||
|
h.values = append(h.values, v)
|
||||||
|
return len(h.values) - 1, true
|
||||||
|
}
|
||||||
|
return h.bits + 1, false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *hashPalette) value(i int) state {
|
||||||
|
if i >= 0 && i < len(h.values) {
|
||||||
|
return h.values[i]
|
||||||
|
}
|
||||||
|
panic("hashPalette: " + strconv.Itoa(i) + " out of bounds")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *hashPalette) export() []state {
|
||||||
|
return h.values
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *hashPalette) ReadFrom(r io.Reader) (n int64, err error) {
|
||||||
|
var size, value pk.VarInt
|
||||||
|
if n, err = size.ReadFrom(r); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if int(size) > cap(h.values) {
|
||||||
|
h.values = make([]state, size)
|
||||||
|
} else {
|
||||||
|
h.values = h.values[:size]
|
||||||
|
}
|
||||||
|
for i := 0; i < int(size); i++ {
|
||||||
|
if nn, err := value.ReadFrom(r); err != nil {
|
||||||
|
return n + nn, err
|
||||||
|
} else {
|
||||||
|
n += nn
|
||||||
|
}
|
||||||
|
h.values[i] = state(value)
|
||||||
|
h.ids[state(value)] = i
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *hashPalette) WriteTo(w io.Writer) (n int64, err error) {
|
||||||
|
if n, err = pk.VarInt(len(h.values)).WriteTo(w); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for _, v := range h.values {
|
||||||
|
if nn, err := pk.VarInt(v).WriteTo(w); err != nil {
|
||||||
|
return n + nn, err
|
||||||
|
} else {
|
||||||
|
n += nn
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
type globalPalette struct{}
|
type globalPalette struct{}
|
||||||
|
|
||||||
func (g *globalPalette) id(v state) (int, bool) {
|
func (g *globalPalette) id(v state) (int, bool) {
|
||||||
@ -314,6 +398,10 @@ func (g *globalPalette) value(i int) state {
|
|||||||
return i
|
return i
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (g *globalPalette) export() []state {
|
||||||
|
return []state{}
|
||||||
|
}
|
||||||
|
|
||||||
func (g *globalPalette) ReadFrom(_ io.Reader) (int64, error) {
|
func (g *globalPalette) ReadFrom(_ io.Reader) (int64, error) {
|
||||||
return 0, nil
|
return 0, nil
|
||||||
}
|
}
|
||||||
|
@ -25,6 +25,14 @@ type Chunk struct {
|
|||||||
WorldSurface []int64 `nbt:"WORLD_SURFACE"`
|
WorldSurface []int64 `nbt:"WORLD_SURFACE"`
|
||||||
}
|
}
|
||||||
Sections []Section `nbt:"sections"`
|
Sections []Section `nbt:"sections"`
|
||||||
|
|
||||||
|
BlockTicks nbt.RawMessage `nbt:"block_ticks"`
|
||||||
|
FluidTicks nbt.RawMessage `nbt:"fluid_ticks"`
|
||||||
|
PostProcessing nbt.RawMessage
|
||||||
|
InhabitedTime int64
|
||||||
|
IsLightOn byte `nbt:"isLightOn"`
|
||||||
|
LastUpdate int64
|
||||||
|
Status string
|
||||||
}
|
}
|
||||||
|
|
||||||
type Section struct {
|
type Section struct {
|
||||||
@ -37,8 +45,8 @@ type Section struct {
|
|||||||
Palette []string `nbt:"palette"`
|
Palette []string `nbt:"palette"`
|
||||||
Data []int64 `nbt:"data"`
|
Data []int64 `nbt:"data"`
|
||||||
} `nbt:"biomes"`
|
} `nbt:"biomes"`
|
||||||
SkyLight []byte
|
SkyLight []int8
|
||||||
BlockLight []byte
|
BlockLight []int8
|
||||||
}
|
}
|
||||||
|
|
||||||
type BlockState struct {
|
type BlockState struct {
|
||||||
|
Reference in New Issue
Block a user