feat: Started on palette implementation

This commit is contained in:
Nicholas Novak
2023-12-10 22:37:37 -08:00
parent 88100b58ea
commit 255475c77c
4 changed files with 89 additions and 15 deletions

View File

@@ -16,15 +16,17 @@ const (
// `ChunkData` represents the contents of a "chunk", which is a column of voxels
// in world space
type ChunkData struct {
Pos ChunkPos `json:"pos"`
// The position of the chunk, in world space
Pos ChunkPos `json:"pos"`
// The column of sections
Sections [ChunkSectionCount]ChunkSection `json:"sections"`
}
// `ChunkSection' is a fixed-size cube that stores the data in a chunk
type ChunkSection struct {
// The count of full blocks in the chunk
BlockCount uint `json:"block_count"`
BlockStates [16 * 16 * 16]BlockID `json:"block_states"`
// A look-up-table of each section index to its value
Palette SectionPalette `json:"palette"`
BlockStates [16 * 16 * 16]PaletteIndex `json:"block_states"`
}
func rem_euclid(a, b int) int {
@@ -39,18 +41,12 @@ func IndexOfBlock(pos BlockPos) int {
return (baseY * chunkSliceSize) + (baseZ * 16) + baseX
}
func (cs *ChunkSection) UpdateBlockAtIndex(index int, targetState BlockID) {
// TODO: Keep track of the block count
cs.BlockStates[index] = targetState
}
func (cs *ChunkSection) UpdateBlock(pos BlockPos, targetState BlockID) {
cs.BlockStates[IndexOfBlock(pos)] = targetState
cs.BlockStates[IndexOfBlock(pos)] = cs.Palette.IndexFor(targetState)
}
func (cs *ChunkSection) FetchBlock(pos BlockPos) BlockID {
return cs.BlockStates[IndexOfBlock(pos)]
return cs.Palette.State(cs.BlockStates[IndexOfBlock(pos)])
}
func (cd *ChunkData) SectionFor(pos BlockPos) *ChunkSection {
@@ -68,6 +64,8 @@ func (cd *ChunkData) IndexToBlockPos(index int) BlockPos {
}
}
// Conversion from Minecraft chunks
func extractPaletteIndexes(compressed int64) [16]byte {
var outputs [16]byte
var outputIndex int
@@ -113,13 +111,12 @@ func (cd *ChunkData) FromMCAChunk(other save.Chunk) {
if section.BlockStates.Palette[paletteIndex].Name == "minecraft:air" {
state = Empty
} else {
cd.Sections[sectionIndex].BlockCount += 1
state = Generic
}
// TODO: Remove this workaround for larger bit sizes in palettes
if blockIndex < 4096 {
currentSection.BlockStates[blockIndex] = state
currentSection.BlockStates[blockIndex] = currentSection.Palette.IndexFor(state)
}
}

51
world/palette.go Normal file
View File

@@ -0,0 +1,51 @@
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
type SectionPalette []BlockID
// `Compact` removes all duplicate states from a palette and returns a new palette
func (p SectionPalette) Compact() SectionPalette {
ids := make(map[BlockID]bool)
// Filter out the duplicate block ids
for _, blockId := range p {
ids[blockId] = true
}
var np SectionPalette
for blockId := range ids {
np = append(np, blockId)
}
return np
}
// `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
func (p SectionPalette) IndexFor(state BlockID) PaletteIndex {
// If the state is already in the palette, return it
for index, blockId := range p {
if state == blockId {
return PaletteIndex(index)
}
}
// Otherwise, insert it into the palette and return the index
p = append(p, state)
return PaletteIndex(len(p) - 1)
}
// `State` returns the state for a palette's index
func (p SectionPalette) State(index PaletteIndex) BlockID {
return p[index]
}
type PaletteIndex byte