diff --git a/level/packet.go b/level/packet.go index 1090d48..94cdcce 100644 --- a/level/packet.go +++ b/level/packet.go @@ -13,6 +13,7 @@ import ( const ( ChunkWidth = 16 + ChunkColumns = ChunkWidth * ChunkWidth BlocksPerChunkSection = ChunkWidth * ChunkWidth * ChunkWidth BiomesPerChunkSection = 4 * 4 * 4 ) @@ -182,10 +183,10 @@ func UnpackBlockData(r io.Reader) (blocks []int32, err error) { func PackBlockData(blocks []int32, version string, w io.Writer) (err error) { unique := util.GetUniqueSlice(blocks) - bpe := uint8(math.Ceil(math.Log2(float64(len(unique))))) + bpe := util.BpeByNum(float64(len(unique))) if bpe > 8 { - bpe = uint8(math.Ceil(math.Log2(float64(len(data.BlocksForVersion(version)))))) + bpe = util.BpeByNum(float64(len(data.BlocksForVersion(version)))) } err = binary.Write(w, binary.BigEndian, bpe) diff --git a/level/storage.go b/level/storage.go index 987c458..2fda630 100644 --- a/level/storage.go +++ b/level/storage.go @@ -18,6 +18,9 @@ type Storage[T comparable] struct { } var CannotGrowPalletErr = errors.New("cannot grow pallet") +var CannotGrowPalletNoPossibleBpeErr = errors.New("cannot grow pallet, no possible bpe provided") +var Bpe0ButNot1LenPaletteErr = errors.New("bpe 0 but not 1, len palette") +var InvalidPaletteIndexErr = errors.New("invalid palette index") func NewStorage[T comparable](len int, possibleBpe []uint8) (s *Storage[T]) { s = new(Storage[T]) @@ -27,6 +30,30 @@ func NewStorage[T comparable](len int, possibleBpe []uint8) (s *Storage[T]) { return } +func ImportStorage[T comparable](data []uint64, bpe uint8, palette []T, len int, possibleBpe []uint8) (s *Storage[T], err error) { + s = new(Storage[T]) + s.Resize(bpe) + s.Data = data + s.Palette = palette + s.Len = len + s.PossibleBitsPerEntryValues = possibleBpe + err = s.CheckData() + return +} + +func (s *Storage[T]) CheckData() (err error) { + if s.BitsPerEntry == 0 && len(s.Palette) != 1 { + err = Bpe0ButNot1LenPaletteErr + return + } + for i := range s.Len { + if s.GetLow(i) >= uint32(len(s.Palette)) { + err = InvalidPaletteIndexErr + return + } + } + return +} func (s *Storage[T]) Resize(bpe uint8) { if bpe == 0 { s.Data = nil @@ -62,6 +89,11 @@ func (s *Storage[T]) Resize(bpe uint8) { func (s *Storage[T]) GrowPallet(v T) (index int, err error) { index = len(s.Palette) if index+1 > s.MaxAtCurrentBpe { + if s.PossibleBitsPerEntryValues == nil { + err = CannotGrowPalletNoPossibleBpeErr + return + } + bpei := slices.Index(s.PossibleBitsPerEntryValues, s.BitsPerEntry) if bpei == len(s.PossibleBitsPerEntryValues)-1 { err = CannotGrowPalletErr @@ -110,3 +142,11 @@ func (s *Storage[T]) SetLow(i int, v uint32) { s.Data[i/s.ElementsPerLong] &= ^(s.Mask << ((i % s.ElementsPerLong) * int(s.BitsPerEntry))) s.Data[i/s.ElementsPerLong] |= uint64(v) << ((i % s.ElementsPerLong) * int(s.BitsPerEntry)) } + +func (s *Storage[T]) RealValues() []T { + ret := make([]T, s.Len) + for i := range s.Len { + ret[i] = s.Get(i) + } + return ret +} diff --git a/level/storage_test.go b/level/storage_test.go index b0d0908..37caed0 100644 --- a/level/storage_test.go +++ b/level/storage_test.go @@ -1,9 +1,11 @@ package level_test import ( + "fmt" "testing" "github.com/admin-else/strom/level" + "github.com/admin-else/strom/util" ) var possibleBpe = []uint8{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15} @@ -133,3 +135,52 @@ func TestResizeElementsPerLong(t *testing.T) { t.Errorf("ElementsPerLong = %d, want 16 (Resize stores old ElementsPerLong)", s.ElementsPerLong) } } + +func TestImportData(t *testing.T) { + data := []uint64{ + 2924043581155788451, + 3014291839833165474, + 2924008396783439527, + 3014291770978157730, + 2905993930227668138, + 2978157076574191776, + 2888296810347582631, + 2941952219986869920, + 3122589749976320164, + 2833795322612367018, + 3086525630071259805, + 2833830575707083949, + 3014115504847927964, + 2851845594302469291, + 2905958400778123933, + 3014291839833162913, + 2815745670742620830, + 2942057979530264736, + 2815745670876841123, + 2887944277684467868, + 2815745740402934945, + 2887944277549201564, + 3032094718851891360, + 2887908817896552616, + 2887944277684469920, + 2869788867884569248, + 2869894626083422368, + 2834183176950988960, + 2869894625949204127, + 3032376331669946015, + 2869894694802636456, + 2996136153003671199, + 2869929879174992040, + 2869894625948941983, + 2887944277684735139, + 2869894625948941983, + 22322953887, + } + n := int32(384 + 1) + bpe := util.BpeByNum(float64(n)) // overworld world height + s, err := level.ImportStorage[int32](data, bpe, util.SliceRange(0, n), level.ChunkColumns, nil) + if err != nil { + t.Fatal(err) + } + fmt.Println(s.RealValues()) +} diff --git a/util/math.go b/util/math.go index 3c8e383..dd659bc 100644 --- a/util/math.go +++ b/util/math.go @@ -1,5 +1,11 @@ package util +import "math" + func FloorDiv(a, b int32) int32 { return (a - ((a%b + b) % b)) / b } + +func BpeByNum(x float64) uint8 { + return uint8(math.Ceil(math.Log2(x))) +} diff --git a/util/slices.go b/util/slices.go index 9b10379..e942f55 100644 --- a/util/slices.go +++ b/util/slices.go @@ -65,3 +65,19 @@ func MinSlice[T cmp.Ordered](s []T) (ret T) { } return } + +type Numeric interface { + ~int | ~int8 | ~int16 | ~int32 | ~int64 | + ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr | + ~float32 | ~float64 +} + +func SliceRange[T Numeric](s, e T) (ret []T) { + if s > e { + return + } + for v := s; v < e; v++ { + ret = append(ret, v) + } + return +}