From 7746dd8ee93be781aabb5fea4a729ef4b74f77db Mon Sep 17 00:00:00 2001 From: adman Date: Mon, 27 Apr 2026 00:17:56 +0200 Subject: [PATCH] real storage --- level/rrrr.go | 153 ++++++++++++++++++++++++++++++++++++++++++ level/storage2.go | 13 ++++ level/storage_test.go | 4 +- 3 files changed, 168 insertions(+), 2 deletions(-) create mode 100644 level/rrrr.go create mode 100644 level/storage2.go diff --git a/level/rrrr.go b/level/rrrr.go new file mode 100644 index 0000000..267e5ae --- /dev/null +++ b/level/rrrr.go @@ -0,0 +1,153 @@ +package level + +import ( + "errors" + "math" + "slices" +) + +type RealStorageFormat struct { + AvailableBpes []uint8 + BiggestDirect bool + Len int32 +} + +var BpeNotAvailableErr = errors.New("bpe not available") +var OutOfBoundsErr = errors.New("out of bounds") +var AvailableBpeMustBeLenOneErr = errors.New("available bpe must be 1") +var NoAvailableBpeErr = errors.New("no available bpe") + +func (r RealStorageFormat) Import(data []uint64, bpe uint8, palette []int32) (s *RealStorage, err error) { + if !slices.Contains(r.AvailableBpes, bpe) { + err = BpeNotAvailableErr + return + } + s = new(RealStorage) + s.format = r + s.resize(bpe) + s.data = data + s.palette = palette + return +} + +func (r RealStorageFormat) ImportDataDirect(data []uint64) (s *RealStorage, err error) { + if len(r.AvailableBpes) != 1 { + err = AvailableBpeMustBeLenOneErr + return + } + return r.Import(data, r.AvailableBpes[0], nil) +} + +type RealStorage struct { + format RealStorageFormat + data []uint64 + bpe uint8 + palette []int32 + + elementsPerLong, maxAtCurrentBpe int32 + + mask uint64 +} + +func (r *RealStorage) doWeResizeDirect(bpe uint8) bool { + if !r.format.BiggestDirect || r.format.AvailableBpes == nil { + return false + } + return slices.Index(r.format.AvailableBpes, bpe) == len(r.format.AvailableBpes)-1 +} + +// only resizes upwards +func (r *RealStorage) resize(bpe uint8) { + if bpe == 0 { + r.data = nil + r.bpe = 0 + r.elementsPerLong = 0 + r.mask = 0 + r.maxAtCurrentBpe = 1 + return + } + elementsPerLong := int32(64 / int(bpe)) + numberOfLongs := int(math.Ceil(float64(r.format.Len) / float64(elementsPerLong))) + newData := make([]uint64, numberOfLongs) + mask := (uint64(1) << uint32(bpe)) - 1 + maxAtCurrentBpe := int32(1 << bpe) + if r.bpe == 0 { + r.data = newData + r.bpe = bpe + r.elementsPerLong = elementsPerLong + r.mask = mask + r.maxAtCurrentBpe = maxAtCurrentBpe + return + } + resizeDirect := r.doWeResizeDirect(bpe) + for i := range r.format.Len { + var v int32 + if resizeDirect { + v, _ = r.Get(i) + } else { + v = int32((r.data[i/r.elementsPerLong] >> ((i % r.elementsPerLong) * int32(r.bpe))) & r.mask) + } + newData[i/elementsPerLong] |= uint64(v) << ((i % elementsPerLong) * int32(bpe)) + } + r.data = newData + r.bpe = bpe + r.elementsPerLong = elementsPerLong + r.mask = mask + r.maxAtCurrentBpe = maxAtCurrentBpe + return + +} + +func (r *RealStorage) Get(i int32) (s int32, err error) { + if i < 0 || i >= r.format.Len { + err = OutOfBoundsErr + return + } + v := int32((r.data[i/r.elementsPerLong] >> ((i % r.elementsPerLong) * int32(r.bpe))) & r.mask) + if r.palette == nil { // direct + s = v + return + } + s = r.palette[v] // should allways be true cause data checking + return +} + +func (r *RealStorage) set(i int32, v int32) { + shift := (i % r.elementsPerLong) * int32(r.bpe) + r.data[i/r.elementsPerLong] = (r.data[i/r.elementsPerLong] & ^(r.mask << shift)) | (uint64(v) << shift) +} + +func (r *RealStorage) Set(i int32, v int32) (err error) { + if i < 0 || i >= r.format.Len { + err = OutOfBoundsErr + return + } + if r.palette != nil { + iv := slices.Index(r.palette, v) + if iv == -1 { + iv, err = r.appendPalette(v) + } + } + return +} + +func (r *RealStorage) appendPalette(v int32) (i int, err error) { + i = len(r.palette) + 1 + if i <= int(r.maxAtCurrentBpe) { + r.palette = append(r.palette, v) + return + } + if r.format.AvailableBpes == nil { + err = NoAvailableBpeErr + return + } + + bpei := slices.Index(r.format.AvailableBpes, r.bpe) + if bpei == len(r.format.AvailableBpes)-1 { + err = CannotGrowPalletErr + return + } + newBpe := r.format.AvailableBpes[bpei+1] + r.resize(newBpe) + return +} diff --git a/level/storage2.go b/level/storage2.go new file mode 100644 index 0000000..0fb72eb --- /dev/null +++ b/level/storage2.go @@ -0,0 +1,13 @@ +package level + +// This is the func to generate a block storage or whatever like block storagw would be +// Len=4096 +// DynamicResolver=dynamicblockresolver1.21.11 +// PossibleBpes=0, 4, 5, 6,7, 8, 9, 15 +// T=*BlockState +func NewStorageFormat() { + +} + +// StorageFormat.ImportLongArrays(bpe, r) -> *Storage +// StorageFormat.ImportReaderReader(bpe, r) -> *Storage diff --git a/level/storage_test.go b/level/storage_test.go index 37caed0..7976706 100644 --- a/level/storage_test.go +++ b/level/storage_test.go @@ -82,7 +82,7 @@ func TestResizePreservesData(t *testing.T) { for i, want := range []int32{10, 20, 30, 40} { got := s.Get(i) if got != want { - t.Errorf("Get(%d) = %d, want %d (Resize repacks with old BPE)", i, got, want) + t.Errorf("Get(%d) = %d, want %d (resize repacks with old BPE)", i, got, want) } } } @@ -132,7 +132,7 @@ func TestResizeElementsPerLong(t *testing.T) { s.Set(4, 50) if s.ElementsPerLong != 16 { - t.Errorf("ElementsPerLong = %d, want 16 (Resize stores old ElementsPerLong)", s.ElementsPerLong) + t.Errorf("ElementsPerLong = %d, want 16 (resize stores old ElementsPerLong)", s.ElementsPerLong) } }