UPDATE: update new language patch
This commit is contained in:
@@ -2,145 +2,174 @@ package internal
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
assetMeta "firefly-launcher/pkg/language-patch/asset-meta"
|
||||
excelLanguage "firefly-launcher/pkg/language-patch/excel-language"
|
||||
"firefly-launcher/pkg/models"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"slices"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type LanguageService struct{}
|
||||
|
||||
func isValidLang(lang string) bool {
|
||||
valid := []string{"en", "jp", "cn", "kr"}
|
||||
for _, v := range valid {
|
||||
if lang == v {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
return slices.Contains(valid, lang)
|
||||
}
|
||||
|
||||
func (l *LanguageService) GetLanguage(path string) (string, string, error) {
|
||||
files, err := os.ReadDir(path)
|
||||
func (l *LanguageService) GetLanguage(path string) (bool, string, string, string) {
|
||||
currentVersionGame, err := models.ParseBinaryVersion(filepath.Join(path, "BinaryVersion.bytes"))
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
return false, "", "", err.Error()
|
||||
}
|
||||
|
||||
for _, file := range files {
|
||||
filePath := filepath.Join(path, file.Name())
|
||||
|
||||
content, err := os.ReadFile(filePath)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
patternToFind := []byte("SpriteOutput/UI/Fonts/RPG_CN.ttf")
|
||||
idx := bytes.Index(content, patternToFind)
|
||||
if idx == -1 {
|
||||
continue
|
||||
}
|
||||
|
||||
pattern := []byte("Korean")
|
||||
idx = bytes.Index(content, pattern)
|
||||
if idx == -1 {
|
||||
continue
|
||||
}
|
||||
|
||||
// Move to os text language
|
||||
idx += 10
|
||||
idx += 4
|
||||
osText := string(content[idx : idx+2])
|
||||
idx += 3 * 4
|
||||
|
||||
// Move to cn voice language
|
||||
idx += 1
|
||||
idx += 5
|
||||
cnVoice := string(content[idx : idx+2])
|
||||
idx += 3 * 2 // skip 2 entries
|
||||
|
||||
// Move to os voice language
|
||||
idx += 1
|
||||
idx += 5
|
||||
osVoice := string(content[idx : idx+2])
|
||||
idx += 3 * 5 // skip 5 entries
|
||||
|
||||
// Move to cn text language
|
||||
idx += 1
|
||||
idx += 4
|
||||
cnText := string(content[idx : idx+2])
|
||||
|
||||
textLang := osText
|
||||
voiceLang := osVoice
|
||||
if !isValidLang(textLang) {
|
||||
textLang = cnText
|
||||
}
|
||||
if !isValidLang(voiceLang) {
|
||||
voiceLang = cnVoice
|
||||
}
|
||||
|
||||
return textLang, voiceLang, nil
|
||||
typeVersionGame := "os"
|
||||
if strings.Contains(currentVersionGame.Name, "CN") {
|
||||
typeVersionGame = "cn"
|
||||
}
|
||||
|
||||
return "", "", fmt.Errorf("couldn't find file to read language from")
|
||||
}
|
||||
assetPath := filepath.Join(path, "DesignData\\Windows")
|
||||
|
||||
func replaceBytes(content []byte, idx int, choice string, param int) int {
|
||||
for i := 0; i < param; i++ {
|
||||
copy(content[idx:idx+2], []byte(choice))
|
||||
idx += 3
|
||||
}
|
||||
return idx
|
||||
}
|
||||
|
||||
func (l *LanguageService) SetLanguage(path string, text, voice string) (bool, error) {
|
||||
files, err := os.ReadDir(path)
|
||||
indexHash, err := assetMeta.GetIndexHash(assetPath)
|
||||
if err != nil {
|
||||
return false, err
|
||||
return false, "", "", err.Error()
|
||||
}
|
||||
|
||||
for _, file := range files {
|
||||
filePath := filepath.Join(path, file.Name())
|
||||
|
||||
content, err := os.ReadFile(filePath)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
patternToFind := []byte("SpriteOutput/UI/Fonts/RPG_CN.ttf")
|
||||
idx := bytes.Index(content, patternToFind)
|
||||
if idx == -1 {
|
||||
continue
|
||||
}
|
||||
|
||||
pattern := []byte("Korean")
|
||||
idx = bytes.Index(content, pattern)
|
||||
if idx == -1 {
|
||||
continue
|
||||
}
|
||||
|
||||
idx += 10
|
||||
idx += 4
|
||||
idx = replaceBytes(content, idx, text, 4)
|
||||
idx += 1
|
||||
|
||||
idx += 5
|
||||
idx = replaceBytes(content, idx, voice, 2)
|
||||
idx += 1
|
||||
|
||||
idx += 5
|
||||
idx = replaceBytes(content, idx, voice, 5)
|
||||
|
||||
idx += 1
|
||||
|
||||
idx += 4
|
||||
_ = replaceBytes(content, idx, text, 2)
|
||||
|
||||
err = os.WriteFile(filePath, content, 0644)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return true, nil
|
||||
DesignIndex, err := assetMeta.DesignIndexFromBytes(assetPath, indexHash)
|
||||
if err != nil {
|
||||
return false, "", "", err.Error()
|
||||
}
|
||||
dataEntry, fileEntry, err := DesignIndex.FindDataAndFileByTarget(-515329346)
|
||||
if err != nil {
|
||||
return false, "", "", err.Error()
|
||||
}
|
||||
allowedLanguage := excelLanguage.NewExcelLanguage(assetPath, &dataEntry, &fileEntry)
|
||||
languageRows, err := allowedLanguage.Parse()
|
||||
if err != nil {
|
||||
return false, "", "", err.Error()
|
||||
}
|
||||
|
||||
return false, fmt.Errorf("couldn't find file to patch. Make sure this file is placed in the correct folder")
|
||||
currentTextLang := ""
|
||||
currentVoiceLang := ""
|
||||
|
||||
pairs := []struct {
|
||||
area string
|
||||
typ *uint8
|
||||
}{
|
||||
{"os", nil},
|
||||
{"cn", func() *uint8 { v := uint8(1); return &v }()},
|
||||
{"os", func() *uint8 { v := uint8(1); return &v }()},
|
||||
{"cn", nil},
|
||||
}
|
||||
|
||||
for _, p := range pairs {
|
||||
var found *excelLanguage.LanguageRow
|
||||
for i := range languageRows {
|
||||
if languageRows[i].Area != nil && *languageRows[i].Area == p.area {
|
||||
if (languageRows[i].Type == nil && p.typ == nil) ||
|
||||
(languageRows[i].Type != nil && p.typ != nil && *languageRows[i].Type == *p.typ) {
|
||||
found = &languageRows[i]
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if found == nil {
|
||||
continue
|
||||
}
|
||||
if found.DefaultLanguage != nil && found.Area != nil && *found.Area == typeVersionGame && found.Type == nil {
|
||||
currentTextLang = *found.DefaultLanguage
|
||||
}
|
||||
if found.DefaultLanguage != nil && found.Area != nil && *found.Area == typeVersionGame && found.Type != nil {
|
||||
currentVoiceLang = *found.DefaultLanguage
|
||||
}
|
||||
}
|
||||
|
||||
if currentTextLang == "" || currentVoiceLang == "" || !isValidLang(currentTextLang) || !isValidLang(currentVoiceLang) {
|
||||
return false, "", "", "not found language"
|
||||
}
|
||||
|
||||
return true, currentTextLang, currentVoiceLang, ""
|
||||
}
|
||||
|
||||
|
||||
|
||||
func (l *LanguageService) SetLanguage(path string, text, voice string) (bool, string) {
|
||||
indexHash, err := assetMeta.GetIndexHash(path)
|
||||
if err != nil {
|
||||
return false, err.Error()
|
||||
}
|
||||
|
||||
DesignIndex, err := assetMeta.DesignIndexFromBytes(path, indexHash)
|
||||
if err != nil {
|
||||
return false, err.Error()
|
||||
}
|
||||
dataEntry, fileEntry, err := DesignIndex.FindDataAndFileByTarget(-515329346)
|
||||
if err != nil {
|
||||
return false, err.Error()
|
||||
}
|
||||
allowedLanguage := excelLanguage.NewExcelLanguage(path, &dataEntry, &fileEntry)
|
||||
languageRows, err := allowedLanguage.Parse()
|
||||
if err != nil {
|
||||
return false, err.Error()
|
||||
}
|
||||
|
||||
pairs := []struct {
|
||||
area string
|
||||
typ *uint8
|
||||
lang string
|
||||
}{
|
||||
{"os", nil, text},
|
||||
{"cn", func() *uint8 { v := uint8(1); return &v }(), voice},
|
||||
{"os", func() *uint8 { v := uint8(1); return &v }(), voice},
|
||||
{"cn", nil, text},
|
||||
}
|
||||
|
||||
for _, p := range pairs {
|
||||
var found *excelLanguage.LanguageRow
|
||||
for i := range languageRows {
|
||||
if languageRows[i].Area != nil && *languageRows[i].Area == p.area {
|
||||
if (languageRows[i].Type == nil && p.typ == nil) ||
|
||||
(languageRows[i].Type != nil && p.typ != nil && *languageRows[i].Type == *p.typ) {
|
||||
found = &languageRows[i]
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if found == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
found.DefaultLanguage = &p.lang
|
||||
found.LanguageList = []string{p.lang}
|
||||
}
|
||||
|
||||
data, err := allowedLanguage.Unmarshal(languageRows)
|
||||
if err != nil {
|
||||
return false, err.Error()
|
||||
}
|
||||
|
||||
filePath := filepath.Join(path, fileEntry.FileByteName+".bytes")
|
||||
|
||||
f, err := os.OpenFile(filePath, os.O_RDWR, 0644)
|
||||
if err != nil {
|
||||
return false, err.Error()
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
if _, err := f.Seek(int64(dataEntry.Offset), 0); err != nil {
|
||||
return false, err.Error()
|
||||
}
|
||||
if _, err := f.Write(data); err != nil {
|
||||
return false, err.Error()
|
||||
}
|
||||
|
||||
if len(data) < int(dataEntry.Size) {
|
||||
remaining := int(dataEntry.Size) - len(data)
|
||||
zeros := bytes.Repeat([]byte{0}, remaining)
|
||||
if _, err := f.Write(zeros); err != nil {
|
||||
return false, err.Error()
|
||||
}
|
||||
}
|
||||
return true, "success"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user