refactor shit
This commit is contained in:
@@ -1,101 +0,0 @@
|
|||||||
package level
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"errors"
|
|
||||||
|
|
||||||
"github.com/admin-else/strom/data"
|
|
||||||
"github.com/admin-else/strom/util"
|
|
||||||
)
|
|
||||||
|
|
||||||
type ChunkBuilder struct {
|
|
||||||
Biomes, Blocks [][]int32
|
|
||||||
Bottom, Top int32
|
|
||||||
Version string
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewChunkBuilder(bottom, top int32, version string) *ChunkBuilder {
|
|
||||||
return &ChunkBuilder{Bottom: bottom, Top: top, Version: version}
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewOverworldChunkBuilder(version string) *ChunkBuilder {
|
|
||||||
return NewChunkBuilder(-64, 320, version)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (cb *ChunkBuilder) ColumnHeight() int32 {
|
|
||||||
absBottom := cb.Bottom
|
|
||||||
if absBottom < 0 {
|
|
||||||
absBottom *= -1
|
|
||||||
}
|
|
||||||
return absBottom + cb.Top
|
|
||||||
}
|
|
||||||
|
|
||||||
func (cb *ChunkBuilder) FillAllById(block, biome int32) {
|
|
||||||
numSections := cb.ColumnHeight() / ChunkWidth
|
|
||||||
blockSection := util.MakeSingleValuedSlice(block, BlocksPerChunkSection)
|
|
||||||
biomeSection := util.MakeSingleValuedSlice(biome, BiomesPerChunkSection)
|
|
||||||
cb.Blocks = make([][]int32, numSections)
|
|
||||||
cb.Biomes = make([][]int32, numSections)
|
|
||||||
for i := range cb.Blocks {
|
|
||||||
|
|
||||||
// Otherwise setting one block will set it also in all other sections because the slice is the same
|
|
||||||
var blocks = make([]int32, BlocksPerChunkSection)
|
|
||||||
copy(blocks, blockSection)
|
|
||||||
|
|
||||||
var biomes = make([]int32, BiomesPerChunkSection)
|
|
||||||
copy(biomes, biomeSection)
|
|
||||||
|
|
||||||
cb.Blocks[i] = blocks
|
|
||||||
cb.Biomes[i] = biomes
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (cb *ChunkBuilder) FillAll(biome, block string) (err error) {
|
|
||||||
blockData, ok := data.LookupBlockByName(cb.Version, block)
|
|
||||||
if !ok {
|
|
||||||
err = data.UnknownBlockNameErr
|
|
||||||
return
|
|
||||||
}
|
|
||||||
biomeData, ok := data.LookupBiomeByName(cb.Version, biome)
|
|
||||||
if !ok {
|
|
||||||
err = data.UnknownBiomeNameErr
|
|
||||||
return
|
|
||||||
}
|
|
||||||
cb.FillAllById(blockData.DefaultState, biomeData.Id)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var InvalidChunkPositionErr = errors.New("invalid chunk position")
|
|
||||||
|
|
||||||
func (cb *ChunkBuilder) SetBlockId(x, y, z, id int32) (err error) {
|
|
||||||
if x < 0 || x >= ChunkWidth || z < 0 || z >= ChunkWidth || y < cb.Bottom || y >= cb.Top {
|
|
||||||
err = InvalidChunkPositionErr
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
y += cb.Bottom * -1
|
|
||||||
section := util.FloorDiv(y, ChunkWidth)
|
|
||||||
i := (y%ChunkWidth)*ChunkWidth*ChunkWidth + z*ChunkWidth + x
|
|
||||||
cb.Blocks[section][i] = id
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (cb *ChunkBuilder) SetBlock(x, y, z int32, block string) (err error) {
|
|
||||||
blockData, ok := data.LookupBlockByName(cb.Version, block)
|
|
||||||
if !ok {
|
|
||||||
err = data.UnknownBlockNameErr
|
|
||||||
return
|
|
||||||
}
|
|
||||||
return cb.SetBlockId(x, y, z, blockData.DefaultState)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (cb *ChunkBuilder) Build() (data []byte, err error) {
|
|
||||||
b := bytes.NewBuffer(nil)
|
|
||||||
err = PackSections(cb.Blocks, cb.Biomes, cb.Version, b)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
data = b.Bytes()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
+12
-12
@@ -6,7 +6,7 @@ import (
|
|||||||
"slices"
|
"slices"
|
||||||
)
|
)
|
||||||
|
|
||||||
type RealStorageFormat struct {
|
type StorageFormat struct {
|
||||||
AvailableBpes []uint8
|
AvailableBpes []uint8
|
||||||
BiggestDirect bool
|
BiggestDirect bool
|
||||||
Len int32
|
Len int32
|
||||||
@@ -21,7 +21,7 @@ var RealInvalidPaletteIndexErr = errors.New("invalid palette index")
|
|||||||
var AvailableBpeMustBeSortedErr = errors.New("available bpe must be sorted")
|
var AvailableBpeMustBeSortedErr = errors.New("available bpe must be sorted")
|
||||||
var DirectModeCantResizeErr = errors.New("direct mode cannot resize")
|
var DirectModeCantResizeErr = errors.New("direct mode cannot resize")
|
||||||
|
|
||||||
func (r RealStorageFormat) Import(data []uint64, bpe uint8, palette []int32) (s *RealStorage, err error) {
|
func (r StorageFormat) Import(data []uint64, bpe uint8, palette []int32) (s *Storage, err error) {
|
||||||
if !slices.IsSorted(r.AvailableBpes) {
|
if !slices.IsSorted(r.AvailableBpes) {
|
||||||
err = AvailableBpeMustBeSortedErr
|
err = AvailableBpeMustBeSortedErr
|
||||||
return
|
return
|
||||||
@@ -31,7 +31,7 @@ func (r RealStorageFormat) Import(data []uint64, bpe uint8, palette []int32) (s
|
|||||||
err = BpeNotAvailableErr
|
err = BpeNotAvailableErr
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
s = new(RealStorage)
|
s = new(Storage)
|
||||||
s.format = r
|
s.format = r
|
||||||
s.resize(bpe)
|
s.resize(bpe)
|
||||||
if bpe == 0 && len(palette) != 1 {
|
if bpe == 0 && len(palette) != 1 {
|
||||||
@@ -45,7 +45,7 @@ func (r RealStorageFormat) Import(data []uint64, bpe uint8, palette []int32) (s
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r RealStorageFormat) ImportDataDirect(data []uint64) (s *RealStorage, err error) {
|
func (r StorageFormat) ImportDataDirect(data []uint64) (s *Storage, err error) {
|
||||||
if len(r.AvailableBpes) != 1 {
|
if len(r.AvailableBpes) != 1 {
|
||||||
err = AvailableBpeMustBeLenOneErr
|
err = AvailableBpeMustBeLenOneErr
|
||||||
return
|
return
|
||||||
@@ -53,8 +53,8 @@ func (r RealStorageFormat) ImportDataDirect(data []uint64) (s *RealStorage, err
|
|||||||
return r.Import(data, r.AvailableBpes[0], nil)
|
return r.Import(data, r.AvailableBpes[0], nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
type RealStorage struct {
|
type Storage struct {
|
||||||
format RealStorageFormat
|
format StorageFormat
|
||||||
data []uint64
|
data []uint64
|
||||||
bpe uint8
|
bpe uint8
|
||||||
palette []int32
|
palette []int32
|
||||||
@@ -64,7 +64,7 @@ type RealStorage struct {
|
|||||||
mask uint64
|
mask uint64
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *RealStorage) doWeResizeDirect(bpe uint8) bool {
|
func (r *Storage) doWeResizeDirect(bpe uint8) bool {
|
||||||
if !r.format.BiggestDirect || r.format.AvailableBpes == nil {
|
if !r.format.BiggestDirect || r.format.AvailableBpes == nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@@ -72,7 +72,7 @@ func (r *RealStorage) doWeResizeDirect(bpe uint8) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// only resizes upwards
|
// only resizes upwards
|
||||||
func (r *RealStorage) resize(bpe uint8) {
|
func (r *Storage) resize(bpe uint8) {
|
||||||
if bpe == 0 {
|
if bpe == 0 {
|
||||||
r.data = nil
|
r.data = nil
|
||||||
r.bpe = 0
|
r.bpe = 0
|
||||||
@@ -116,7 +116,7 @@ func (r *RealStorage) resize(bpe uint8) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *RealStorage) Get(i int32) (s int32, err error) {
|
func (r *Storage) Get(i int32) (s int32, err error) {
|
||||||
if i < 0 || i >= r.format.Len {
|
if i < 0 || i >= r.format.Len {
|
||||||
err = OutOfBoundsErr
|
err = OutOfBoundsErr
|
||||||
return
|
return
|
||||||
@@ -144,12 +144,12 @@ func (r *RealStorage) Get(i int32) (s int32, err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *RealStorage) set(i int32, v int32) {
|
func (r *Storage) set(i int32, v int32) {
|
||||||
shift := (i % r.elementsPerLong) * int32(r.bpe)
|
shift := (i % r.elementsPerLong) * int32(r.bpe)
|
||||||
r.data[i/r.elementsPerLong] = (r.data[i/r.elementsPerLong] & ^(r.mask << shift)) | (uint64(v) << shift)
|
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) {
|
func (r *Storage) Set(i int32, v int32) (err error) {
|
||||||
if i < 0 || i >= r.format.Len {
|
if i < 0 || i >= r.format.Len {
|
||||||
err = OutOfBoundsErr
|
err = OutOfBoundsErr
|
||||||
return
|
return
|
||||||
@@ -165,7 +165,7 @@ func (r *RealStorage) Set(i int32, v int32) (err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *RealStorage) appendPalette(v int32) (i int, err error) {
|
func (r *Storage) appendPalette(v int32) (i int, err error) {
|
||||||
i = len(r.palette)
|
i = len(r.palette)
|
||||||
if r.palette == nil {
|
if r.palette == nil {
|
||||||
err = DirectModeCantResizeErr
|
err = DirectModeCantResizeErr
|
||||||
|
|||||||
+36
-36
@@ -6,23 +6,23 @@ import (
|
|||||||
"github.com/admin-else/strom/level"
|
"github.com/admin-else/strom/level"
|
||||||
)
|
)
|
||||||
|
|
||||||
func heightmapFormat() level.RealStorageFormat {
|
func heightmapFormat() level.StorageFormat {
|
||||||
return level.RealStorageFormat{
|
return level.StorageFormat{
|
||||||
AvailableBpes: []uint8{9},
|
AvailableBpes: []uint8{9},
|
||||||
BiggestDirect: true,
|
BiggestDirect: true,
|
||||||
Len: 256,
|
Len: 256,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func blockStorageFormat() level.RealStorageFormat {
|
func blockStorageFormat() level.StorageFormat {
|
||||||
return level.RealStorageFormat{
|
return level.StorageFormat{
|
||||||
AvailableBpes: []uint8{0, 4, 5, 6, 7, 8, 15},
|
AvailableBpes: []uint8{0, 4, 5, 6, 7, 8, 15},
|
||||||
BiggestDirect: true,
|
BiggestDirect: true,
|
||||||
Len: 4096,
|
Len: 4096,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRealStorageImportDataDirect(t *testing.T) {
|
func TestStorageImportDataDirect(t *testing.T) {
|
||||||
format := heightmapFormat()
|
format := heightmapFormat()
|
||||||
data := make([]uint64, 256)
|
data := make([]uint64, 256)
|
||||||
data[0] = 42
|
data[0] = 42
|
||||||
@@ -41,8 +41,8 @@ func TestRealStorageImportDataDirect(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRealStorageImportDataDirectMultipleBpe(t *testing.T) {
|
func TestStorageImportDataDirectMultipleBpe(t *testing.T) {
|
||||||
format := level.RealStorageFormat{
|
format := level.StorageFormat{
|
||||||
AvailableBpes: []uint8{4, 8},
|
AvailableBpes: []uint8{4, 8},
|
||||||
BiggestDirect: true,
|
BiggestDirect: true,
|
||||||
Len: 256,
|
Len: 256,
|
||||||
@@ -54,8 +54,8 @@ func TestRealStorageImportDataDirectMultipleBpe(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRealStorageImportUnsortedBpe(t *testing.T) {
|
func TestStorageImportUnsortedBpe(t *testing.T) {
|
||||||
format := level.RealStorageFormat{
|
format := level.StorageFormat{
|
||||||
AvailableBpes: []uint8{9, 4},
|
AvailableBpes: []uint8{9, 4},
|
||||||
BiggestDirect: true,
|
BiggestDirect: true,
|
||||||
Len: 256,
|
Len: 256,
|
||||||
@@ -67,7 +67,7 @@ func TestRealStorageImportUnsortedBpe(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRealStorageImportBpeNotAvailable(t *testing.T) {
|
func TestStorageImportBpeNotAvailable(t *testing.T) {
|
||||||
format := heightmapFormat()
|
format := heightmapFormat()
|
||||||
|
|
||||||
_, err := format.Import([]uint64{1}, 4, nil)
|
_, err := format.Import([]uint64{1}, 4, nil)
|
||||||
@@ -76,7 +76,7 @@ func TestRealStorageImportBpeNotAvailable(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRealStorageGetSet(t *testing.T) {
|
func TestStorageGetSet(t *testing.T) {
|
||||||
format := blockStorageFormat()
|
format := blockStorageFormat()
|
||||||
s, err := format.Import(nil, 4, []int32{0, 1, 2, 3})
|
s, err := format.Import(nil, 4, []int32{0, 1, 2, 3})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -98,7 +98,7 @@ func TestRealStorageGetSet(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRealStorageOutOfBounds(t *testing.T) {
|
func TestStorageOutOfBounds(t *testing.T) {
|
||||||
format := blockStorageFormat()
|
format := blockStorageFormat()
|
||||||
s, err := format.Import(nil, 4, []int32{0, 1})
|
s, err := format.Import(nil, 4, []int32{0, 1})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -116,8 +116,8 @@ func TestRealStorageOutOfBounds(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRealStorageBpeZero(t *testing.T) {
|
func TestStorageBpeZero(t *testing.T) {
|
||||||
format := level.RealStorageFormat{
|
format := level.StorageFormat{
|
||||||
AvailableBpes: []uint8{0, 4, 8},
|
AvailableBpes: []uint8{0, 4, 8},
|
||||||
BiggestDirect: true,
|
BiggestDirect: true,
|
||||||
Len: 64,
|
Len: 64,
|
||||||
@@ -139,8 +139,8 @@ func TestRealStorageBpeZero(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRealStorageBpeZeroPaletteLen(t *testing.T) {
|
func TestStorageBpeZeroPaletteLen(t *testing.T) {
|
||||||
format := level.RealStorageFormat{
|
format := level.StorageFormat{
|
||||||
AvailableBpes: []uint8{0, 4, 8},
|
AvailableBpes: []uint8{0, 4, 8},
|
||||||
BiggestDirect: true,
|
BiggestDirect: true,
|
||||||
Len: 64,
|
Len: 64,
|
||||||
@@ -152,8 +152,8 @@ func TestRealStorageBpeZeroPaletteLen(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRealStorageResize(t *testing.T) {
|
func TestStorageResize(t *testing.T) {
|
||||||
format := level.RealStorageFormat{
|
format := level.StorageFormat{
|
||||||
AvailableBpes: []uint8{4, 8},
|
AvailableBpes: []uint8{4, 8},
|
||||||
BiggestDirect: false,
|
BiggestDirect: false,
|
||||||
Len: 16,
|
Len: 16,
|
||||||
@@ -179,8 +179,8 @@ func TestRealStorageResize(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRealStorageResizePreservesData(t *testing.T) {
|
func TestStorageResizePreservesData(t *testing.T) {
|
||||||
format := level.RealStorageFormat{
|
format := level.StorageFormat{
|
||||||
AvailableBpes: []uint8{4, 5, 6, 8},
|
AvailableBpes: []uint8{4, 5, 6, 8},
|
||||||
BiggestDirect: false,
|
BiggestDirect: false,
|
||||||
Len: 8,
|
Len: 8,
|
||||||
@@ -207,8 +207,8 @@ func TestRealStorageResizePreservesData(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRealStoragePaletteGrowth(t *testing.T) {
|
func TestStoragePaletteGrowth(t *testing.T) {
|
||||||
format := level.RealStorageFormat{
|
format := level.StorageFormat{
|
||||||
AvailableBpes: []uint8{4, 5, 6, 8},
|
AvailableBpes: []uint8{4, 5, 6, 8},
|
||||||
BiggestDirect: false,
|
BiggestDirect: false,
|
||||||
Len: 16,
|
Len: 16,
|
||||||
@@ -239,8 +239,8 @@ func TestRealStoragePaletteGrowth(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRealStorageNoAvailableBpe(t *testing.T) {
|
func TestStorageNoAvailableBpe(t *testing.T) {
|
||||||
format := level.RealStorageFormat{
|
format := level.StorageFormat{
|
||||||
AvailableBpes: []uint8{4},
|
AvailableBpes: []uint8{4},
|
||||||
BiggestDirect: false,
|
BiggestDirect: false,
|
||||||
Len: 16,
|
Len: 16,
|
||||||
@@ -257,8 +257,8 @@ func TestRealStorageNoAvailableBpe(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRealStorageBiggestDirect(t *testing.T) {
|
func TestStorageBiggestDirect(t *testing.T) {
|
||||||
format := level.RealStorageFormat{
|
format := level.StorageFormat{
|
||||||
AvailableBpes: []uint8{4, 8},
|
AvailableBpes: []uint8{4, 8},
|
||||||
BiggestDirect: true,
|
BiggestDirect: true,
|
||||||
Len: 64,
|
Len: 64,
|
||||||
@@ -284,8 +284,8 @@ func TestRealStorageBiggestDirect(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRealStorageDirectModeNoPalette(t *testing.T) {
|
func TestStorageDirectModeNoPalette(t *testing.T) {
|
||||||
format := level.RealStorageFormat{
|
format := level.StorageFormat{
|
||||||
AvailableBpes: []uint8{9},
|
AvailableBpes: []uint8{9},
|
||||||
BiggestDirect: true,
|
BiggestDirect: true,
|
||||||
Len: 256,
|
Len: 256,
|
||||||
@@ -308,8 +308,8 @@ func TestRealStorageDirectModeNoPalette(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRealStorageInvalidPaletteIndex(t *testing.T) {
|
func TestStorageInvalidPaletteIndex(t *testing.T) {
|
||||||
format := level.RealStorageFormat{
|
format := level.StorageFormat{
|
||||||
AvailableBpes: []uint8{4, 8},
|
AvailableBpes: []uint8{4, 8},
|
||||||
BiggestDirect: false,
|
BiggestDirect: false,
|
||||||
Len: 16,
|
Len: 16,
|
||||||
@@ -327,7 +327,7 @@ func TestRealStorageInvalidPaletteIndex(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRealStorageOverwrite(t *testing.T) {
|
func TestStorageOverwrite(t *testing.T) {
|
||||||
format := blockStorageFormat()
|
format := blockStorageFormat()
|
||||||
s, err := format.Import(nil, 4, []int32{0, 1, 2})
|
s, err := format.Import(nil, 4, []int32{0, 1, 2})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -347,7 +347,7 @@ func TestRealStorageOverwrite(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRealStorageSetOutOfBounds(t *testing.T) {
|
func TestStorageSetOutOfBounds(t *testing.T) {
|
||||||
format := blockStorageFormat()
|
format := blockStorageFormat()
|
||||||
s, err := format.Import(nil, 4, []int32{0, 1})
|
s, err := format.Import(nil, 4, []int32{0, 1})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -365,8 +365,8 @@ func TestRealStorageSetOutOfBounds(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRealStorageGetAfterResize(t *testing.T) {
|
func TestStorageGetAfterResize(t *testing.T) {
|
||||||
format := level.RealStorageFormat{
|
format := level.StorageFormat{
|
||||||
AvailableBpes: []uint8{4, 5, 6, 8},
|
AvailableBpes: []uint8{4, 5, 6, 8},
|
||||||
BiggestDirect: false,
|
BiggestDirect: false,
|
||||||
Len: 32,
|
Len: 32,
|
||||||
@@ -392,8 +392,8 @@ func TestRealStorageGetAfterResize(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRealStorageResizeDirect(t *testing.T) {
|
func TestStorageResizeDirect(t *testing.T) {
|
||||||
format := level.RealStorageFormat{
|
format := level.StorageFormat{
|
||||||
AvailableBpes: []uint8{4, 8},
|
AvailableBpes: []uint8{4, 8},
|
||||||
BiggestDirect: true,
|
BiggestDirect: true,
|
||||||
Len: 64,
|
Len: 64,
|
||||||
|
|||||||
@@ -1,219 +0,0 @@
|
|||||||
package level
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"math"
|
|
||||||
"slices"
|
|
||||||
)
|
|
||||||
|
|
||||||
type DynamicPalletLookup[T comparable] interface {
|
|
||||||
GetIndex(T) uint32
|
|
||||||
GetT(uint33 uint32) T
|
|
||||||
Resize(storage *Storage[T]) error
|
|
||||||
}
|
|
||||||
|
|
||||||
type Storage[T comparable] struct {
|
|
||||||
Palette []T
|
|
||||||
CustomPallet DynamicPalletLookup[T]
|
|
||||||
Data []uint64
|
|
||||||
PossibleBitsPerEntryValues []uint8 // These should be sorted
|
|
||||||
BitsPerEntry uint8
|
|
||||||
Len int
|
|
||||||
MaxAtCurrentBpe int
|
|
||||||
ElementsPerLong int
|
|
||||||
Mask uint64
|
|
||||||
}
|
|
||||||
|
|
||||||
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])
|
|
||||||
s.Len = len
|
|
||||||
s.PossibleBitsPerEntryValues = possibleBpe
|
|
||||||
s.Resize(possibleBpe[0])
|
|
||||||
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 ImportStoragePaletteFunc[T comparable](data []uint64, bpe uint8, paletteF DynamicPalletLookup[T], len int, possibleBpe []uint8) (s *Storage[T], err error) {
|
|
||||||
s = new(Storage[T])
|
|
||||||
s.Resize(bpe)
|
|
||||||
s.Data = data
|
|
||||||
s.CustomPallet = paletteF
|
|
||||||
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
|
|
||||||
s.BitsPerEntry = 0
|
|
||||||
s.ElementsPerLong = 0
|
|
||||||
s.Mask = 0
|
|
||||||
s.MaxAtCurrentBpe = 1
|
|
||||||
return
|
|
||||||
}
|
|
||||||
elementsPerLong := int(64 / int(bpe))
|
|
||||||
numberOfLongs := int(math.Ceil(float64(s.Len) / float64(elementsPerLong)))
|
|
||||||
newData := make([]uint64, numberOfLongs)
|
|
||||||
if s.BitsPerEntry == 0 {
|
|
||||||
s.Data = newData
|
|
||||||
s.BitsPerEntry = bpe
|
|
||||||
s.ElementsPerLong = elementsPerLong
|
|
||||||
s.Mask = (uint64(1) << uint32(bpe)) - 1
|
|
||||||
s.MaxAtCurrentBpe = 1 << s.BitsPerEntry
|
|
||||||
return
|
|
||||||
}
|
|
||||||
for i := range s.Len {
|
|
||||||
v := s.GetLow(i)
|
|
||||||
newData[i/elementsPerLong] |= uint64(v) << ((i % elementsPerLong) * int(bpe))
|
|
||||||
}
|
|
||||||
s.Data = newData
|
|
||||||
s.BitsPerEntry = bpe
|
|
||||||
s.ElementsPerLong = elementsPerLong
|
|
||||||
s.Mask = (uint64(1) << uint32(bpe)) - 1
|
|
||||||
s.MaxAtCurrentBpe = 1 << s.BitsPerEntry
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
return
|
|
||||||
}
|
|
||||||
newBpe := s.PossibleBitsPerEntryValues[bpei+1]
|
|
||||||
s.Resize(newBpe)
|
|
||||||
}
|
|
||||||
s.Palette = append(s.Palette, v)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Storage[T]) Set(i int, v T) (err error) {
|
|
||||||
pi := slices.Index(s.Palette, v)
|
|
||||||
if pi != -1 {
|
|
||||||
if s.BitsPerEntry == 0 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
s.SetLow(i, uint32(pi))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
pi, err = s.GrowPallet(v)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
s.SetLow(i, uint32(pi))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Storage[T]) Get(i int) (v T) {
|
|
||||||
if s.BitsPerEntry == 0 {
|
|
||||||
return s.Palette[0]
|
|
||||||
}
|
|
||||||
return s.Palette[s.GetLow(i)]
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Storage[T]) GetLow(i int) (j uint32) {
|
|
||||||
j = uint32((s.Data[i/s.ElementsPerLong] >> ((i % s.ElementsPerLong) * int(s.BitsPerEntry))) & s.Mask)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Storage[T]) SetMany(i, j int, v T) (err error) {
|
|
||||||
if i == 0 && j == s.Len-1 && slices.Contains(s.PossibleBitsPerEntryValues, 0) {
|
|
||||||
s.Resize(0)
|
|
||||||
s.Palette = []T{v}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
pi := slices.Index(s.Palette, v)
|
|
||||||
if pi != -1 {
|
|
||||||
if s.BitsPerEntry == 0 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
s.SetLow(i, uint32(pi))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
pi, err = s.GrowPallet(v)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
s.SetManyLow(i, j, uint32(pi))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Storage[T]) SetManyLow(i, j int, v uint32) {
|
|
||||||
n := j - i
|
|
||||||
if n > s.ElementsPerLong*2 {
|
|
||||||
for k := i; k < j; k++ {
|
|
||||||
s.SetLow(k, v)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
for i%s.ElementsPerLong == 0 {
|
|
||||||
s.SetLow(i, v)
|
|
||||||
i++
|
|
||||||
}
|
|
||||||
|
|
||||||
var vFilled uint64
|
|
||||||
for k := range s.ElementsPerLong {
|
|
||||||
vFilled |= uint64(v) << (k * int(s.BitsPerEntry))
|
|
||||||
}
|
|
||||||
|
|
||||||
t := i / s.ElementsPerLong
|
|
||||||
for k := range (j - i) / s.ElementsPerLong {
|
|
||||||
s.Data[t+k] = vFilled
|
|
||||||
}
|
|
||||||
|
|
||||||
for j%s.ElementsPerLong != 0 {
|
|
||||||
s.SetLow(j, v)
|
|
||||||
j--
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
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
|
|
||||||
@@ -1,186 +0,0 @@
|
|||||||
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}
|
|
||||||
|
|
||||||
func FuzzStorage(f *testing.F) {
|
|
||||||
f.Add([]byte{4, 0, 1})
|
|
||||||
f.Add([]byte{4, 0, 1, 0, 2, 0, 1})
|
|
||||||
f.Add([]byte{8, 0, 10, 1, 20, 2, 30, 3, 40, 4, 50})
|
|
||||||
f.Add([]byte{4, 0, 5, 1, 10, 2, 15, 3, 20, 0, 25})
|
|
||||||
f.Add([]byte{2, 0, 1, 1, 2, 0, 3, 1, 4})
|
|
||||||
f.Add([]byte{8, 0, 42, 1, 42, 2, 42, 3, 42})
|
|
||||||
|
|
||||||
f.Fuzz(func(t *testing.T, data []byte) {
|
|
||||||
if len(data) < 1 {
|
|
||||||
t.Skip()
|
|
||||||
}
|
|
||||||
|
|
||||||
length := int(data[0])%64 + 1
|
|
||||||
s := level.NewStorage[int32](length, possibleBpe)
|
|
||||||
|
|
||||||
ref := make([]int32, length)
|
|
||||||
refSet := make([]bool, length)
|
|
||||||
|
|
||||||
for i := 1; i+1 < len(data); i += 2 {
|
|
||||||
idx := int(data[i]) % length
|
|
||||||
val := int32(data[i+1])
|
|
||||||
|
|
||||||
err := s.Set(idx, val)
|
|
||||||
if err == level.CannotGrowPalletErr {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
ref[idx] = val
|
|
||||||
refSet[idx] = true
|
|
||||||
}
|
|
||||||
|
|
||||||
for i := range length {
|
|
||||||
if !refSet[i] {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
got := s.Get(i)
|
|
||||||
if got != ref[i] {
|
|
||||||
t.Errorf("Get(%d) = %d, want %d", i, got, ref[i])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSetOverwrite(t *testing.T) {
|
|
||||||
s := level.NewStorage[int32](8, []uint8{2, 4})
|
|
||||||
|
|
||||||
s.Set(0, 1)
|
|
||||||
s.Set(0, 2)
|
|
||||||
s.Set(0, 1)
|
|
||||||
|
|
||||||
got := s.Get(0)
|
|
||||||
if got != 1 {
|
|
||||||
t.Errorf("Get(0) = %d, want 1 (|= does not clear old bits)", got)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestResizePreservesData(t *testing.T) {
|
|
||||||
s := level.NewStorage[int32](8, []uint8{2, 4})
|
|
||||||
|
|
||||||
s.Set(0, 10)
|
|
||||||
s.Set(1, 20)
|
|
||||||
s.Set(2, 30)
|
|
||||||
s.Set(3, 40)
|
|
||||||
s.Set(4, 50)
|
|
||||||
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestBpeZeroSingleValue(t *testing.T) {
|
|
||||||
s := level.NewStorage[int32](64, possibleBpe)
|
|
||||||
s.Palette = append(s.Palette, 42)
|
|
||||||
|
|
||||||
for i := range 64 {
|
|
||||||
if s.Get(i) != 42 {
|
|
||||||
t.Errorf("Get(%d) = %d, want 42 (BPE 0 should always return first palette entry)", i, s.Get(i))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
s.Set(30, 42)
|
|
||||||
s.Set(0, 42)
|
|
||||||
|
|
||||||
for i := range 64 {
|
|
||||||
if s.Get(i) != 42 {
|
|
||||||
t.Errorf("Get(%d) = %d, want 42 after Set same value", i, s.Get(i))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestBpeZeroGrowPallet(t *testing.T) {
|
|
||||||
s := level.NewStorage[int32](64, possibleBpe)
|
|
||||||
s.Palette = append(s.Palette, 10)
|
|
||||||
|
|
||||||
s.Set(0, 10)
|
|
||||||
s.Set(1, 20)
|
|
||||||
|
|
||||||
if s.Get(0) != 10 {
|
|
||||||
t.Errorf("Get(0) = %d, want 10 after grow from BPE 0", s.Get(0))
|
|
||||||
}
|
|
||||||
if s.Get(1) != 20 {
|
|
||||||
t.Errorf("Get(1) = %d, want 20 after grow from BPE 0", s.Get(1))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestResizeElementsPerLong(t *testing.T) {
|
|
||||||
s := level.NewStorage[int32](8, []uint8{2, 4})
|
|
||||||
|
|
||||||
s.Set(0, 10)
|
|
||||||
s.Set(1, 20)
|
|
||||||
s.Set(2, 30)
|
|
||||||
s.Set(3, 40)
|
|
||||||
s.Set(4, 50)
|
|
||||||
|
|
||||||
if s.ElementsPerLong != 16 {
|
|
||||||
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())
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user