2023-12-10 22:37:37 -08:00
|
|
|
package world
|
|
|
|
|
|
|
|
// `SectionPalette` is a "palette", which is a sort of look-up-table (LUT) between
|
|
|
|
// an index into the LUT, and the resulting `BlockID`
|
|
|
|
//
|
|
|
|
// This palette is unique to each section, and allows ranges of blocks to be
|
|
|
|
// changed in constant time, with the downside of having to "compact" the palette
|
2023-12-11 00:23:31 -08:00
|
|
|
type SectionPalette struct {
|
|
|
|
ids map[PaletteIndex]BlockID
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewSectionPalette() SectionPalette {
|
|
|
|
return SectionPalette{
|
|
|
|
ids: make(map[PaletteIndex]BlockID),
|
|
|
|
}
|
|
|
|
}
|
2023-12-10 22:37:37 -08:00
|
|
|
|
2023-12-11 00:23:31 -08:00
|
|
|
// `Compact` removes all duplicate states from a palette and returns if the
|
|
|
|
// palette was modified
|
|
|
|
func (p *SectionPalette) Compact() bool {
|
|
|
|
newIds := make(map[BlockID]PaletteIndex)
|
|
|
|
|
|
|
|
var wasResized bool
|
2023-12-10 22:37:37 -08:00
|
|
|
|
|
|
|
// Filter out the duplicate block ids
|
2023-12-11 00:23:31 -08:00
|
|
|
for index, blockId := range p.ids {
|
|
|
|
newIds[blockId] = index
|
|
|
|
}
|
|
|
|
|
|
|
|
// If there was not a resize, return instantly
|
|
|
|
if len(newIds) != len(p.ids) {
|
|
|
|
wasResized = true
|
|
|
|
} else {
|
|
|
|
return false
|
2023-12-10 22:37:37 -08:00
|
|
|
}
|
|
|
|
|
2023-12-11 00:23:31 -08:00
|
|
|
ids := make(map[PaletteIndex]BlockID)
|
2023-12-10 22:37:37 -08:00
|
|
|
|
2023-12-11 00:23:31 -08:00
|
|
|
for blockId, index := range newIds {
|
|
|
|
ids[index] = blockId
|
2023-12-10 22:37:37 -08:00
|
|
|
}
|
|
|
|
|
2023-12-11 00:23:31 -08:00
|
|
|
p.ids = ids
|
|
|
|
|
|
|
|
return wasResized
|
2023-12-10 22:37:37 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
// `IndexFor` returns the palette index for a specified block id
|
|
|
|
//
|
|
|
|
// If the block id does not exist, it is placed in the palette and the index
|
|
|
|
// is returned
|
2023-12-11 00:23:31 -08:00
|
|
|
func (p *SectionPalette) IndexFor(state BlockID) PaletteIndex {
|
|
|
|
var maxIndex PaletteIndex
|
|
|
|
|
2023-12-10 22:37:37 -08:00
|
|
|
// If the state is already in the palette, return it
|
2023-12-11 00:23:31 -08:00
|
|
|
for index, blockId := range p.ids {
|
|
|
|
if index > maxIndex {
|
|
|
|
maxIndex = index
|
|
|
|
}
|
|
|
|
|
2023-12-10 22:37:37 -08:00
|
|
|
if state == blockId {
|
|
|
|
return PaletteIndex(index)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Otherwise, insert it into the palette and return the index
|
2023-12-11 00:23:31 -08:00
|
|
|
p.ids[maxIndex+1] = state
|
2023-12-10 22:37:37 -08:00
|
|
|
|
2023-12-11 00:23:31 -08:00
|
|
|
return maxIndex + 1
|
2023-12-10 22:37:37 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
// `State` returns the state for a palette's index
|
|
|
|
func (p SectionPalette) State(index PaletteIndex) BlockID {
|
2023-12-11 00:23:31 -08:00
|
|
|
return p.ids[index]
|
|
|
|
}
|
|
|
|
|
|
|
|
// `ReplaceIndex` replaces the block state at the given palette' index
|
|
|
|
//
|
|
|
|
// This function is used to quickly zero a section with a given block state in
|
|
|
|
// constant time, and should not be used for any other purpose. Otherwise, set
|
|
|
|
// the block state within the section to the result of `IndexFor`.
|
|
|
|
func (p *SectionPalette) ReplaceIndex(index PaletteIndex, state BlockID) {
|
|
|
|
p.ids[index] = state
|
2023-12-10 22:37:37 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
type PaletteIndex byte
|