feat: Started on palette implementation
This commit is contained in:
		@@ -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
									
								
							
							
						
						
									
										51
									
								
								world/palette.go
									
									
									
									
									
										Normal 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
 | 
			
		||||
		Reference in New Issue
	
	Block a user