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
 | 
					// 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
 | 
					// 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 NewSectionPalette() SectionPalette {
 | 
				
			||||||
func (p SectionPalette) Compact() SectionPalette {
 | 
						return SectionPalette{
 | 
				
			||||||
	ids := make(map[BlockID]bool)
 | 
							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
 | 
						// Filter out the duplicate block ids
 | 
				
			||||||
	for _, blockId := range p {
 | 
						for index, blockId := range p.ids {
 | 
				
			||||||
		ids[blockId] = true
 | 
							newIds[blockId] = index
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var np SectionPalette
 | 
						// If there was not a resize, return instantly
 | 
				
			||||||
 | 
						if len(newIds) != len(p.ids) {
 | 
				
			||||||
	for blockId := range ids {
 | 
							wasResized = true
 | 
				
			||||||
		np = append(np, blockId)
 | 
						} 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
 | 
					// `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
 | 
					// If the block id does not exist, it is placed in the palette and the index
 | 
				
			||||||
// is returned
 | 
					// 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
 | 
						// 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 {
 | 
							if state == blockId {
 | 
				
			||||||
			return PaletteIndex(index)
 | 
								return PaletteIndex(index)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Otherwise, insert it into the palette and return the 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
 | 
					// `State` returns the state for a palette's index
 | 
				
			||||||
func (p SectionPalette) State(index PaletteIndex) BlockID {
 | 
					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
 | 
					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