Files
2025-09-09 08:47:16 +07:00

260 lines
7.6 KiB
Go

package diffService
import (
"bufio"
"encoding/json"
"firefly-launcher/pkg/constant"
"firefly-launcher/pkg/hpatchz"
"firefly-launcher/pkg/models"
"firefly-launcher/pkg/sevenzip"
"firefly-launcher/pkg/verifier"
"fmt"
"os"
"path/filepath"
"strings"
"github.com/wailsapp/wails/v3/pkg/application"
)
type DiffService struct{}
func (h *DiffService) CheckTypeHDiff(patchPath string) (bool, string, string) {
if ok, err := sevenzip.IsFileIn7z(patchPath, "hdifffiles.txt"); err == nil && ok {
return true, "hdifffiles.txt", ""
}
if ok, err := sevenzip.IsFileIn7z(patchPath, "hdifffiles.txt"); err == nil && ok {
return true, "hdifffiles.json", ""
}
if ok, err := sevenzip.IsFileIn7z(patchPath, "hdiffmap.json"); err == nil && ok {
return true, "hdiffmap.json", ""
}
if ok, err := sevenzip.IsFileIn7z(patchPath, "manifest"); err == nil && ok {
return true, "manifest", ""
}
return false, "", "not found hdifffiles.txt or hdiffmap.json"
}
func (h *DiffService) VersionValidate(gamePath, patchPath string) (bool, string) {
oldBinPath := filepath.Join(gamePath, "StarRail_Data\\StreamingAssets\\BinaryVersion.bytes")
if _, err := os.Stat(oldBinPath); err != nil {
return false, err.Error()
}
if _, err := os.Stat(patchPath); err != nil {
return false, err.Error()
}
if _, err := os.Stat(constant.TempUrl); os.IsNotExist(err) {
if err := os.MkdirAll(constant.TempUrl, os.ModePerm); err != nil {
return false, err.Error()
}
}
okFull, errFull := sevenzip.IsFileIn7z(patchPath, "StarRail_Data\\StreamingAssets\\BinaryVersion.bytes")
okDiff, errDiff := sevenzip.IsFileIn7z(patchPath, "StarRail_Data\\StreamingAssets\\BinaryVersion.bytes.hdiff")
if (errFull != nil && errDiff != nil) || (!okFull && !okDiff) {
return false, "BinaryVersion file not found in patch"
}
var tempBinFile string
if okFull {
if err := sevenzip.ExtractAFileFromZip(patchPath, "StarRail_Data\\StreamingAssets\\BinaryVersion.bytes", constant.TempUrl); err != nil {
return false, err.Error()
}
tempBinFile = filepath.Join(constant.TempUrl, "BinaryVersion.bytes")
} else {
if err := sevenzip.ExtractAFileFromZip(patchPath, "StarRail_Data\\StreamingAssets\\BinaryVersion.bytes.hdiff", constant.TempUrl); err != nil {
return false, err.Error()
}
patchBinFile := filepath.Join(constant.TempUrl, "BinaryVersion.bytes.hdiff")
sourceBinFile := oldBinPath
tempBinFile = filepath.Join(constant.TempUrl, "BinaryVersion.bytes")
if err := hpatchz.ApplyPatch(sourceBinFile, patchBinFile, tempBinFile); err != nil {
os.Remove(patchBinFile)
return false, err.Error()
}
os.Remove(patchBinFile)
}
okFullPkg, err1 := sevenzip.IsFileIn7z(patchPath, "pkg_version")
okDiffPkg, err2 := sevenzip.IsFileIn7z(patchPath, "pkg_version.hdiff")
if err1 != nil && err2 != nil {
return false, err1.Error()
}
if okFullPkg {
if err := sevenzip.ExtractAFileFromZip(patchPath, "pkg_version", constant.TempUrl); err != nil {
return false, err.Error()
}
}
if okDiffPkg {
if err := sevenzip.ExtractAFileFromZip(patchPath, "pkg_version.hdiff", constant.TempUrl); err != nil {
return false, err.Error()
}
patchPkgFile := filepath.Join(constant.TempUrl, "pkg_version.hdiff")
sourcePkgFile := filepath.Join(gamePath, "pkg_version")
tempPkgFile := filepath.Join(constant.TempUrl, "pkg_version")
if err := hpatchz.ApplyPatch(sourcePkgFile, patchPkgFile, tempPkgFile); err != nil {
os.Remove(patchPkgFile)
os.Remove(tempPkgFile)
return false, err.Error()
}
os.Remove(patchPkgFile)
}
tempPkgFile := filepath.Join(constant.TempUrl, "pkg_version")
pkgDataList, err := models.LoadPkgVersion(tempPkgFile)
if err != nil {
os.Remove(tempPkgFile)
return false, err.Error()
}
os.Remove(tempPkgFile)
// MD5 check BinaryVersion
flags := false
for _, pkgData := range pkgDataList {
if filepath.ToSlash(pkgData.RemoteFile) == "StarRail_Data/StreamingAssets/BinaryVersion.bytes" {
flags = true
md5, err := verifier.FileMD5(tempBinFile)
if err != nil {
os.Remove(tempBinFile)
return false, err.Error()
}
if md5 != pkgData.MD5 {
os.Remove(tempBinFile)
return false, fmt.Sprintf("md5 mismatch for %s: expected %s, got %s",
tempBinFile, pkgData.MD5, md5)
}
break
}
}
if !flags {
os.Remove(tempBinFile)
return false, "BinaryVersion file not found in patch"
}
_, err = models.ParseBinaryVersion(tempBinFile)
if err != nil {
os.Remove(tempBinFile)
return false, err.Error()
}
os.Remove(tempBinFile)
return true, "validated"
}
func (h *DiffService) HDiffPatchData(gamePath string) (bool, string) {
hdiffMapPath := filepath.Join(gamePath, "hdiffmap.json")
hdiffFilesPath := filepath.Join(gamePath, "hdifffiles.txt")
hdifffilesJsonPath := filepath.Join(gamePath, "hdifffiles.json")
var jsonData struct {
DiffMap []*models.HDiffData `json:"diff_map"`
}
if _, err := os.Stat(hdiffMapPath); err == nil {
data, err := os.ReadFile(hdiffMapPath)
if err != nil {
return false, err.Error()
}
var jsonDataDiffMap struct {
DiffMap []*models.DiffMapType `json:"diff_map"`
}
if err := json.Unmarshal(data, &jsonDataDiffMap); err != nil {
return false, err.Error()
}
for _, entry := range jsonDataDiffMap.DiffMap {
jsonData.DiffMap = append(jsonData.DiffMap, entry.ToHDiffData())
}
} else if _, err := os.Stat(hdifffilesJsonPath); err == nil {
data, err := os.ReadFile(hdifffilesJsonPath)
if err != nil {
return false, err.Error()
}
if err := json.Unmarshal(data, &jsonData); err != nil {
return false, err.Error()
}
} else if _, err := os.Stat(hdiffFilesPath); err == nil {
files, err := models.LoadHDiffFiles(hdiffFilesPath)
if err != nil {
return false, err.Error()
}
for _, entry := range files {
jsonData.DiffMap = append(jsonData.DiffMap, entry.ToHDiffData())
}
} else {
return false, "no hdiff entries map exist"
}
application.Get().Event.Emit("diff:stage", map[string]string{"stage": "Patching HDiff"})
for i, entry := range jsonData.DiffMap {
application.Get().Event.Emit(
"diff:progress", map[string]int{
"progress": i,
"maxProgress": len(jsonData.DiffMap),
})
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.Remove(filepath.Join(gamePath, "hdiffmap.json"))
os.Remove(filepath.Join(gamePath, "hdifffiles.txt"))
os.Remove(filepath.Join(gamePath, "hdifffiles.json"))
return true, "patching completed"
}
func (h *DiffService) DeleteFiles(gamePath string) (bool, string) {
var deleteFiles []string
file, err := os.Open(filepath.Join(gamePath, "deletefiles.txt"))
if err != nil {
return false, ""
}
defer file.Close()
scanner := bufio.NewScanner(file)
for scanner.Scan() {
line := strings.TrimSpace(scanner.Text())
if line != "" {
deleteFiles = append(deleteFiles, line)
}
}
if err := scanner.Err(); err != nil {
file.Close()
return false, "no delete files exist"
}
file.Close()
for i, file := range deleteFiles {
os.Remove(filepath.Join(gamePath, file))
application.Get().Event.Emit("diff:progress", map[string]int{"progress": i, "maxProgress": len(deleteFiles)})
}
os.Remove(filepath.Join(gamePath, "deletefiles.txt"))
return true, ""
}