feat: Finished and added tests for palette implementation
This commit is contained in:
		@@ -5,47 +5,82 @@ package world
 | 
			
		||||
//
 | 
			
		||||
// 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
 | 
			
		||||
type SectionPalette struct {
 | 
			
		||||
	ids map[PaletteIndex]BlockID
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// `Compact` removes all duplicate states from a palette and returns a new palette
 | 
			
		||||
func (p SectionPalette) Compact() SectionPalette {
 | 
			
		||||
	ids := make(map[BlockID]bool)
 | 
			
		||||
func NewSectionPalette() SectionPalette {
 | 
			
		||||
	return SectionPalette{
 | 
			
		||||
		ids: make(map[PaletteIndex]BlockID),
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// `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
 | 
			
		||||
 | 
			
		||||
	// Filter out the duplicate block ids
 | 
			
		||||
	for _, blockId := range p {
 | 
			
		||||
		ids[blockId] = true
 | 
			
		||||
	for index, blockId := range p.ids {
 | 
			
		||||
		newIds[blockId] = index
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var np SectionPalette
 | 
			
		||||
 | 
			
		||||
	for blockId := range ids {
 | 
			
		||||
		np = append(np, blockId)
 | 
			
		||||
	// If there was not a resize, return instantly
 | 
			
		||||
	if len(newIds) != len(p.ids) {
 | 
			
		||||
		wasResized = true
 | 
			
		||||
	} else {
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return np
 | 
			
		||||
	ids := make(map[PaletteIndex]BlockID)
 | 
			
		||||
 | 
			
		||||
	for blockId, index := range newIds {
 | 
			
		||||
		ids[index] = blockId
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	p.ids = ids
 | 
			
		||||
 | 
			
		||||
	return wasResized
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// `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 {
 | 
			
		||||
func (p *SectionPalette) IndexFor(state BlockID) PaletteIndex {
 | 
			
		||||
	var maxIndex PaletteIndex
 | 
			
		||||
 | 
			
		||||
	// If the state is already in the palette, return it
 | 
			
		||||
	for index, blockId := range p {
 | 
			
		||||
	for index, blockId := range p.ids {
 | 
			
		||||
		if index > maxIndex {
 | 
			
		||||
			maxIndex = index
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if state == blockId {
 | 
			
		||||
			return PaletteIndex(index)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Otherwise, insert it into the palette and return the index
 | 
			
		||||
	p = append(p, state)
 | 
			
		||||
	p.ids[maxIndex+1] = state
 | 
			
		||||
 | 
			
		||||
	return PaletteIndex(len(p) - 1)
 | 
			
		||||
	return maxIndex + 1
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// `State` returns the state for a palette's index
 | 
			
		||||
func (p SectionPalette) State(index PaletteIndex) BlockID {
 | 
			
		||||
	return p[index]
 | 
			
		||||
	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
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type PaletteIndex byte
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										64
									
								
								world/palette_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								world/palette_test.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,64 @@
 | 
			
		||||
package world
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"runtime/debug"
 | 
			
		||||
	"testing"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func newPaletteWith(ids []BlockID) *SectionPalette {
 | 
			
		||||
	p := NewSectionPalette()
 | 
			
		||||
 | 
			
		||||
	for _, id := range ids {
 | 
			
		||||
		p.IndexFor(id)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return &p
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func checkPaletteEqual(t *testing.T, p *SectionPalette, index PaletteIndex, expected BlockID) {
 | 
			
		||||
	if p.State(index) != expected {
 | 
			
		||||
		debug.PrintStack()
 | 
			
		||||
		t.Fatalf("Expected to get state %v at index %v, got %v", expected, index, p.State(index))
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestInsertPalette(t *testing.T) {
 | 
			
		||||
	p := NewSectionPalette()
 | 
			
		||||
 | 
			
		||||
	ids := []BlockID{Empty, Generic}
 | 
			
		||||
 | 
			
		||||
	for _, id := range ids {
 | 
			
		||||
		index := p.IndexFor(id)
 | 
			
		||||
		if id != p.State(index) {
 | 
			
		||||
			t.Fatalf("Fetching index for id %v: got index %v which returned %v", id, index, p.State(index))
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestReplaceCompactPalettte(t *testing.T) {
 | 
			
		||||
	p := newPaletteWith([]BlockID{Empty, Generic})
 | 
			
		||||
 | 
			
		||||
	zeroIndex := p.IndexFor(Empty)
 | 
			
		||||
	checkPaletteEqual(t, p, zeroIndex, Empty)
 | 
			
		||||
 | 
			
		||||
	// Zero out the chunk
 | 
			
		||||
	genIndex := p.IndexFor(Generic)
 | 
			
		||||
	checkPaletteEqual(t, p, genIndex, Generic)
 | 
			
		||||
	p.ReplaceIndex(genIndex, Empty)
 | 
			
		||||
 | 
			
		||||
	// Check that everything now returns zero
 | 
			
		||||
	checkPaletteEqual(t, p, zeroIndex, Empty)
 | 
			
		||||
	checkPaletteEqual(t, p, genIndex, Empty)
 | 
			
		||||
 | 
			
		||||
	// Test for compaction
 | 
			
		||||
	wasCompacted := p.Compact()
 | 
			
		||||
	if !wasCompacted {
 | 
			
		||||
		t.Fatalf("Palette should have been compacted")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Test to see that we don't compact again
 | 
			
		||||
	wasCompacted = p.Compact()
 | 
			
		||||
	if wasCompacted {
 | 
			
		||||
		t.Fatalf("Palette should have not been compacted again")
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user