package diffService import ( "firefly-launcher/pkg/firefly" "firefly-launcher/pkg/firefly/pb" "firefly-launcher/pkg/hpatchz" "firefly-launcher/pkg/models" "fmt" "os" "path/filepath" "strings" "sync" "github.com/wailsapp/wails/v3/pkg/application" ) func (h *DiffService) LDiffPatchData(gamePath string) (bool, string) { entries, err := os.ReadDir(gamePath) if err != nil { return false, err.Error() } ldiffPath := filepath.Join(gamePath, "ldiff") for _, entry := range entries { if entry.IsDir() { continue } if !entry.Type().IsRegular() { continue } name := entry.Name() if strings.HasPrefix(name, "manifest") { manifestName := entry.Name() manifestPath := filepath.Join(gamePath, manifestName) manifest, err := firefly.LoadManifestProto(manifestPath) if err != nil { continue } ldiffEntries, err := os.ReadDir(ldiffPath) if err != nil { return false, err.Error() } application.Get().Event.Emit("diff:stage", map[string]string{"stage": "Processing LDiff"}) for i, ldiffEntry := range ldiffEntries { assetName := ldiffEntry.Name() var matchingAssets []struct { AssetName string AssetSize int64 Asset *pb.AssetManifest } application.Get().Event.Emit( "diff:progress", map[string]int{ "progress": i, "maxProgress": len(ldiffEntries), }) var wg sync.WaitGroup var mu sync.Mutex for _, assetGroup := range manifest.Assets { assetGroup := assetGroup wg.Go(func() { if data := assetGroup.AssetData; data != nil { for _, asset := range data.Assets { if asset.ChunkFileName == assetName { mu.Lock() matchingAssets = append(matchingAssets, struct { AssetName string AssetSize int64 Asset *pb.AssetManifest }{assetGroup.AssetName, assetGroup.AssetSize, asset}) mu.Unlock() } } } }) } wg.Wait() for _, ma := range matchingAssets { err := firefly.LDiffFile(ma.Asset, ma.AssetName, ma.AssetSize, ldiffPath, gamePath) if err != nil { continue } } } diffMapNames := make([]string, len(ldiffEntries)) for i, e := range ldiffEntries { diffMapNames[i] = e.Name() } diffMapList, err := MakeDiffMap(manifest, diffMapNames) if err != nil { return false, err.Error() } application.Get().Event.Emit("diff:stage", map[string]string{"stage": "Patching HDiff"}) for i, entry := range diffMapList { application.Get().Event.Emit( "diff:progress", map[string]int{ "progress": i, "maxProgress": len(diffMapList), }) sourceFile := filepath.Join(gamePath, entry.SourceFileName) patchFile := filepath.Join(gamePath, entry.PatchFileName) targetFile := filepath.Join(gamePath, entry.TargetFileName) if _, err := os.Stat(patchFile); os.IsNotExist(err) { continue } if entry.SourceFileName == "" { hpatchz.ApplyPatchEmpty(patchFile, targetFile) os.Remove(patchFile) continue } if _, err := os.Stat(sourceFile); os.IsNotExist(err) { continue } hpatchz.ApplyPatch(sourceFile, patchFile, targetFile) if entry.SourceFileName != entry.TargetFileName { os.Remove(sourceFile) } os.Remove(patchFile) } } } os.RemoveAll(ldiffPath) return true, "patching completed" } func MakeDiffMap(manifest *pb.ManifestProto, chunkNames []string) ([]*models.HDiffData, error) { var hdiffFiles []*models.HDiffData for _, asset := range manifest.Assets { assetName := asset.AssetName assetSize := asset.AssetSize if asset.AssetData != nil { for _, chunk := range asset.AssetData.Assets { matched := false for _, name := range chunkNames { if name == chunk.ChunkFileName { matched = true break } } if !matched { continue } if chunk.OriginalFileSize != 0 || chunk.HdiffFileSize != assetSize { hdiffFiles = append(hdiffFiles, &models.HDiffData{ SourceFileName: chunk.OriginalFilePath, TargetFileName: assetName, PatchFileName: fmt.Sprintf("%s.hdiff", assetName), }) } } } } return hdiffFiles, nil }