Adding modding folder with a hacked build.
This commit is contained in:
@@ -0,0 +1,176 @@
|
||||
package compression
|
||||
|
||||
import (
|
||||
"context"
|
||||
"math/bits"
|
||||
"sort"
|
||||
)
|
||||
|
||||
type paletteLookupEntry struct {
|
||||
start int
|
||||
size int
|
||||
}
|
||||
|
||||
// PaletteLookup is a dictionary of tile delta data, found in a palette buffer.
|
||||
type PaletteLookup struct {
|
||||
buffer []byte
|
||||
entries map[TilePaletteKey]paletteLookupEntry
|
||||
}
|
||||
|
||||
// Buffer returns the underlying slice.
|
||||
func (lookup *PaletteLookup) Buffer() []byte {
|
||||
return lookup.buffer
|
||||
}
|
||||
|
||||
// Lookup finds the given tile again and returns the properties where and how to reproduce it.
|
||||
func (lookup *PaletteLookup) Lookup(tile tileDelta) (index int, pal []byte, mask uint64) {
|
||||
key := TilePaletteKeyFrom(tile[:])
|
||||
entry, inLookup := lookup.entries[key]
|
||||
if inLookup {
|
||||
index = entry.start
|
||||
pal = lookup.buffer[entry.start : entry.start+entry.size]
|
||||
} else {
|
||||
pal = key.Buffer()
|
||||
}
|
||||
var mapped [256]byte
|
||||
for mappedIndex := len(pal) - 1; mappedIndex >= 0; mappedIndex-- {
|
||||
mapped[pal[mappedIndex]] = byte(mappedIndex)
|
||||
}
|
||||
bitSize := uint(bits.Len(uint(len(pal) - 1)))
|
||||
for tileIndex := PixelPerTile - 1; tileIndex >= 0; tileIndex-- {
|
||||
mask <<= bitSize
|
||||
mask |= uint64(mapped[tile[tileIndex]])
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// PaletteLookupGenerator creates palette lookups based on a set of registered tiles.
|
||||
type PaletteLookupGenerator struct {
|
||||
keyUses map[TilePaletteKey]int
|
||||
}
|
||||
|
||||
// Generate creates a lookup based on all currently registered tile deltas.
|
||||
func (gen *PaletteLookupGenerator) Generate(ctx context.Context) (PaletteLookup, error) {
|
||||
var lookup PaletteLookup
|
||||
lookup.entries = make(map[TilePaletteKey]paletteLookupEntry)
|
||||
|
||||
remainder := make(map[TilePaletteKey]struct{})
|
||||
for key := range gen.keyUses {
|
||||
remainder[key] = struct{}{}
|
||||
}
|
||||
|
||||
type sizedEntry struct {
|
||||
entries map[TilePaletteKey]paletteLookupEntry
|
||||
lastOffset int
|
||||
}
|
||||
sizedEntries := make(map[int]*sizedEntry)
|
||||
knownSizes := []int{4, 8, 16}
|
||||
for _, size := range knownSizes {
|
||||
sizedEntries[size] = &sizedEntry{
|
||||
entries: make(map[TilePaletteKey]paletteLookupEntry),
|
||||
}
|
||||
}
|
||||
|
||||
toDeleteCache := make([]TilePaletteKey, 0, len(remainder))
|
||||
addToBuffer := func(data []byte) {
|
||||
lookup.buffer = append(lookup.buffer, data...)
|
||||
|
||||
newSize := len(lookup.buffer)
|
||||
|
||||
for _, fitSize := range knownSizes {
|
||||
fitLimit := newSize - fitSize
|
||||
entry := sizedEntries[fitSize]
|
||||
|
||||
// remove all entries beyond a certain limit. as these bytes don't change, retrying won't help.
|
||||
toDelete := toDeleteCache[0:0]
|
||||
limit := newSize - 16 - len(data)
|
||||
for key, entry := range entry.entries {
|
||||
if entry.start < limit {
|
||||
toDelete = append(toDelete, key)
|
||||
}
|
||||
}
|
||||
for _, key := range toDelete {
|
||||
delete(entry.entries, key)
|
||||
}
|
||||
|
||||
// find any new keys
|
||||
for start := entry.lastOffset; start < fitLimit; start++ {
|
||||
tempKey := TilePaletteKeyFrom(lookup.buffer[start : start+fitSize])
|
||||
if _, existing := entry.entries[tempKey]; !existing {
|
||||
entry.entries[tempKey] = paletteLookupEntry{
|
||||
start: start,
|
||||
size: fitSize,
|
||||
}
|
||||
}
|
||||
}
|
||||
if fitLimit > 0 {
|
||||
entry.lastOffset = fitLimit
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
addEarlyEntry := func(key TilePaletteKey, limitSize int) bool {
|
||||
for _, fitSize := range knownSizes {
|
||||
if key.size <= fitSize && fitSize <= limitSize {
|
||||
entry := sizedEntries[fitSize]
|
||||
for tempKey, paletteEntry := range entry.entries {
|
||||
if tempKey.Contains(&key) && (!key.HasColor(0x00) || (lookup.buffer[paletteEntry.start] == 0x00)) {
|
||||
lookup.entries[key] = paletteEntry
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
sizeLimitForSize := map[int]int{3: 4, 4: 8, 5: 8, 6: 8, 7: 8, 8: 8, 9: 16, 10: 16, 11: 16, 12: 16, 13: 16, 14: 16, 15: 16, 16: 16}
|
||||
for size := PixelPerTile; (size > 2) && (ctx.Err() == nil); size-- {
|
||||
keysInSize := make([]TilePaletteKey, 0, len(remainder))
|
||||
for key := range remainder {
|
||||
if key.size == size {
|
||||
keysInSize = append(keysInSize, key)
|
||||
}
|
||||
}
|
||||
sort.Slice(keysInSize, func(a, b int) bool { return keysInSize[a].LessThan(&keysInSize[b]) })
|
||||
|
||||
// fmt.Printf("Working on key size %v, have %v sized, %v total remaining\n", size, len(keysInSize), len(remainder))
|
||||
for _, sizedKey := range keysInSize {
|
||||
if ctx.Err() != nil {
|
||||
return PaletteLookup{}, ctx.Err()
|
||||
}
|
||||
|
||||
{
|
||||
var earlyRemoved []TilePaletteKey
|
||||
for key := range remainder {
|
||||
if addEarlyEntry(key, sizeLimitForSize[size]) {
|
||||
earlyRemoved = append(earlyRemoved, key)
|
||||
}
|
||||
}
|
||||
for _, key := range earlyRemoved {
|
||||
delete(remainder, key)
|
||||
}
|
||||
}
|
||||
if _, stillRemaining := remainder[sizedKey]; stillRemaining {
|
||||
bytes := sizedKey.Buffer()
|
||||
lookup.entries[sizedKey] = paletteLookupEntry{start: len(lookup.buffer), size: len(bytes)}
|
||||
addToBuffer(bytes)
|
||||
|
||||
delete(remainder, sizedKey)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return lookup, ctx.Err()
|
||||
}
|
||||
|
||||
// Add registers a further delta to the generator.
|
||||
func (gen *PaletteLookupGenerator) Add(delta tileDelta) {
|
||||
key := TilePaletteKeyFrom(delta[:])
|
||||
if key.size > 2 {
|
||||
if gen.keyUses == nil {
|
||||
gen.keyUses = make(map[TilePaletteKey]int)
|
||||
}
|
||||
gen.keyUses[key]++
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user