diff --git a/ankabuffer.go b/ankabuffer.go index 73183f1..30dc779 100644 --- a/ankabuffer.go +++ b/ankabuffer.go @@ -14,13 +14,13 @@ type Chunk struct { } type File struct { - Name string `json:"name"` - Size int64 `json:"size"` - Hash string `json:"hash"` - Chunks []Chunk `json:"chunks"` - Executable bool `json:"executable"` - Symlink string `json:",omitempty"` - ReverseBundle *Bundle `json:"reverse_bundle"` // bundle that contains this file + Name string `json:"name"` + Size int64 `json:"size"` + Hash string `json:"hash"` + Chunks []Chunk `json:"chunks"` + Executable bool `json:"executable"` + Symlink string `json:",omitempty"` + ReverseBundles []Bundle `json:"reverse_bundles"` // bundle that contains this file } type Bundle struct { @@ -56,14 +56,9 @@ func ParseManifest(data []byte) *Manifest { manifest := Manifest{} manifest.Fragments = make(map[string]Fragment) + bundleLookup := make(map[string]Bundle) for i := 0; i < flatbManifest.FragmentsLength(); i++ { fragment := AnkamaGames.Fragment{} - flatbManifest.Fragments(&fragment, i) - - fragmentJson := Fragment{} - fragmentJson.Files = make(map[string]File) - fragmentJson.Name = string(fragment.Name()) - fragmentJson.Bundles = make([]Bundle, fragment.BundlesLength()) for j := 0; j < fragment.BundlesLength(); j++ { bundle := AnkamaGames.Bundle{} fragment.Bundles(&bundle, j) @@ -79,7 +74,22 @@ func ParseManifest(data []byte) *Manifest { chunkJson.Size = chunk.Size() bundleJson.Chunks[k] = chunkJson } - fragmentJson.Bundles[j] = bundleJson + bundleLookup[bundleJson.Hash] = bundleJson + } + } + + for i := 0; i < flatbManifest.FragmentsLength(); i++ { + fragment := AnkamaGames.Fragment{} + flatbManifest.Fragments(&fragment, i) + + fragmentJson := Fragment{} + fragmentJson.Files = make(map[string]File) + fragmentJson.Name = string(fragment.Name()) + fragmentJson.Bundles = make([]Bundle, fragment.BundlesLength()) + for j := 0; j < fragment.BundlesLength(); j++ { + bundle := AnkamaGames.Bundle{} + fragment.Bundles(&bundle, j) + fragmentJson.Bundles[j] = bundleLookup[getHash(&bundle)] } for j := 0; j < fragment.FilesLength(); j++ { @@ -103,15 +113,32 @@ func ParseManifest(data []byte) *Manifest { if file.Symlink() != nil { fileJson.Symlink = string(file.Symlink()) } - fileJson.ReverseBundle = nil + bundles := NewSet[string]() for _, bundle := range fragmentJson.Bundles { for _, chunk := range bundle.Chunks { - if chunk.Hash == fileJson.Hash { - fileJson.ReverseBundle = &bundle - break + if len(fileJson.Chunks) == 0 { + if chunk.Hash == fileJson.Hash { + fileJson.ReverseBundles = []Bundle{bundle} + break + } + } else { + for _, fileChunk := range fileJson.Chunks { + if chunk.Hash == fileChunk.Hash { + bundles.Add(bundle.Hash) + } + } } } } + fileJson.ReverseBundles = make([]Bundle, bundles.Size()) + i := 0 + for _, hash := range bundles.Slice() { + fileJson.ReverseBundles[i] = bundleLookup[hash] + i++ + } + if len(fileJson.ReverseBundles) == 0 { + fileJson.ReverseBundles = nil + } fragmentJson.Files[fileJson.Name] = fileJson } manifest.Fragments[fragmentJson.Name] = fragmentJson @@ -120,17 +147,21 @@ func ParseManifest(data []byte) *Manifest { } func GetNeededBundles(files []File) []Bundle { - bundles := make(map[string]Bundle) + bundles := NewSet[string]() + bundleLookup := make(map[string]Bundle) for _, file := range files { - if file.ReverseBundle != nil { - bundles[file.ReverseBundle.Hash] = *file.ReverseBundle + if file.ReverseBundles != nil { + for _, bundle := range file.ReverseBundles { + bundles.Add(bundle.Hash) + bundleLookup[bundle.Hash] = bundle + } } } - result := make([]Bundle, len(bundles)) + res := make([]Bundle, bundles.Size()) i := 0 - for _, bundle := range bundles { - result[i] = bundle + for _, hash := range bundles.Slice() { + res[i] = bundleLookup[hash] i++ } - return result -} \ No newline at end of file + return res +} diff --git a/set.go b/set.go new file mode 100644 index 0000000..b4fd6bf --- /dev/null +++ b/set.go @@ -0,0 +1,62 @@ +package ankabuffer + +// based on string only https://gist.github.com/bgadrian/cb8b9344d9c66571ef331a14eb7a2e80 +// rewritten to be generic + +type Set[T comparable] struct { + list map[T]struct{} //empty structs occupy 0 memory +} + +func (s *Set[T]) Has(v T) bool { + _, ok := s.list[v] + return ok +} + +func (s *Set[T]) Add(v T) { + s.list[v] = struct{}{} +} + +func (s *Set[T]) Remove(v T) { + delete(s.list, v) +} + +func (s *Set[T]) Clear() { + s.list = make(map[T]struct{}) +} + +func (s *Set[T]) Size() int { + return len(s.list) +} + +func NewSet[T comparable]() *Set[T] { + s := &Set[T]{} + s.list = make(map[T]struct{}) + return s +} + +func (s *Set[T]) Slice() []T { + var res []T + for v := range s.list { + res = append(res, v) + } + return res +} + +func (s *Set[T]) AddMulti(list ...T) { + for _, v := range list { + s.Add(v) + } +} + +// fp + +func Map[T, U any](data []T, f func(T) U) []U { + + res := make([]U, 0, len(data)) + + for _, e := range data { + res = append(res, f(e)) + } + + return res +}