github.com/df-mc/dragonfly@v0.9.13/server/world/chunk/palette.go (about) 1 package chunk 2 3 import ( 4 "math" 5 ) 6 7 // paletteSize is the size of a palette. It indicates the amount of bits occupied per value stored. 8 type paletteSize byte 9 10 // Palette is a palette of values that every PalettedStorage has. Storages hold 'pointers' to indices 11 // in this palette. 12 type Palette struct { 13 last uint32 14 lastIndex int16 15 size paletteSize 16 17 // values is a map of values. A PalettedStorage points to the index to this value. 18 values []uint32 19 } 20 21 // newPalette returns a new Palette with size and a slice of added values. 22 func newPalette(size paletteSize, values []uint32) *Palette { 23 return &Palette{size: size, values: values, last: math.MaxUint32} 24 } 25 26 // Len returns the amount of unique values in the Palette. 27 func (palette *Palette) Len() int { 28 return len(palette.values) 29 } 30 31 // Add adds a values to the Palette. It does not first check if the value was already set in the Palette. 32 // The index at which the value was added is returned. Another bool is returned indicating if the Palette 33 // was resized as a result of adding the value. 34 func (palette *Palette) Add(v uint32) (index int16, resize bool) { 35 i := int16(len(palette.values)) 36 palette.values = append(palette.values, v) 37 38 if palette.needsResize() { 39 palette.increaseSize() 40 return i, true 41 } 42 return i, false 43 } 44 45 // Replace calls the function passed for each value present in the Palette. The value returned by the 46 // function replaces the value present at the index of the value passed. 47 func (palette *Palette) Replace(f func(v uint32) uint32) { 48 // Reset last runtime ID as it now has a different offset. 49 palette.last = math.MaxUint32 50 for index, v := range palette.values { 51 palette.values[index] = f(v) 52 } 53 } 54 55 // Index loops through the values of the Palette and looks for the index of the given value. If the value could 56 // not be found, -1 is returned. 57 func (palette *Palette) Index(runtimeID uint32) int16 { 58 if runtimeID == palette.last { 59 // Fast path out. 60 return palette.lastIndex 61 } 62 // Slow path in a separate function allows for inlining the fast path. 63 return palette.indexSlow(runtimeID) 64 } 65 66 // indexSlow searches the index of a value in the Palette's values by iterating through the Palette's values. 67 func (palette *Palette) indexSlow(runtimeID uint32) int16 { 68 l := len(palette.values) 69 for i := 0; i < l; i++ { 70 if palette.values[i] == runtimeID { 71 palette.last = runtimeID 72 v := int16(i) 73 palette.lastIndex = v 74 return v 75 } 76 } 77 return -1 78 } 79 80 // Value returns the value in the Palette at a specific index. 81 func (palette *Palette) Value(i uint16) uint32 { 82 return palette.values[i] 83 } 84 85 // needsResize checks if the Palette, and with it the holding PalettedStorage, needs to be resized to a bigger 86 // size. 87 func (palette *Palette) needsResize() bool { 88 return len(palette.values) > (1 << palette.size) 89 } 90 91 var sizes = [...]paletteSize{0, 1, 2, 3, 4, 5, 6, 8, 16} 92 var offsets = [...]int{0: 0, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 8: 7, 16: 8} 93 94 // increaseSize increases the size of the Palette to the next palette size. 95 func (palette *Palette) increaseSize() { 96 palette.size = sizes[offsets[palette.size]+1] 97 } 98 99 // padded returns true if the Palette size is 3, 5 or 6. 100 func (p paletteSize) padded() bool { 101 return p == 3 || p == 5 || p == 6 102 } 103 104 // paletteSizeFor finds a suitable paletteSize for the amount of values passed n. 105 func paletteSizeFor(n int) paletteSize { 106 for _, size := range sizes { 107 if n <= (1 << size) { 108 return size 109 } 110 } 111 // Should never happen. 112 return 0 113 } 114 115 // uint32s returns the amount of uint32s needed to represent a storage with this palette size. 116 func (p paletteSize) uint32s() (n int) { 117 uint32Count := 0 118 if p != 0 { 119 // indicesPerUint32 is the amount of indices that may be stored in a single uint32. 120 indicesPerUint32 := 32 / int(p) 121 // uint32Count is the amount of uint32s required to store all indices: 4096 indices need to be stored in 122 // total. 123 uint32Count = 4096 / indicesPerUint32 124 } 125 if p.padded() { 126 // We've got one of the padded sizes, so the storage has another uint32 to be able to store 127 // every index. 128 uint32Count++ 129 } 130 return uint32Count 131 }