mirror of
https://github.com/Grasscutters/Cultivation.git
synced 2025-12-13 23:54:48 +01:00
232 lines
6.3 KiB
TypeScript
232 lines
6.3 KiB
TypeScript
import { invoke } from '@tauri-apps/api'
|
|
import { dataDir } from '@tauri-apps/api/path'
|
|
import { getConfig } from './configuration'
|
|
import DownloadHandler from './download'
|
|
import { getGameExecutable, getGameFolder } from './game'
|
|
|
|
export async function patchMetadata() {
|
|
const metadataExists = await invoke('dir_exists', {
|
|
path: await getGameMetadataPath() + '\\global-metadata.dat'
|
|
})
|
|
|
|
console.log(await getGameMetadataPath())
|
|
|
|
if (!metadataExists) {
|
|
return false
|
|
}
|
|
|
|
console.log('Copying unpatched metadata to backup location')
|
|
|
|
// Copy unpatched metadata to backup location
|
|
const copiedMeta = await invoke('copy_file_with_new_name', {
|
|
path: await getGameMetadataPath() + '\\global-metadata.dat',
|
|
newPath: await getBackupMetadataPath(),
|
|
newName: 'global-metadata-unpatched.dat'
|
|
})
|
|
|
|
if (!copiedMeta) {
|
|
console.log(await getBackupMetadataPath())
|
|
return false
|
|
}
|
|
|
|
// backup was successful! Time to patch
|
|
|
|
console.log('Patching backedup metadata')
|
|
|
|
const patchedMeta = await invoke('patch_metadata', {
|
|
metadataFolder: await getBackupMetadataPath(),
|
|
})
|
|
|
|
if (!patchedMeta) {
|
|
return false
|
|
}
|
|
|
|
// Patch also worked! Time to replace
|
|
console.log('Replacing unpatched game metadata with patched metadata')
|
|
|
|
const replacedMeta = await invoke('copy_file_with_new_name', {
|
|
path: await getBackupMetadataPath() + '\\global-metadata-patched.dat',
|
|
newPath: await getGameMetadataPath(),
|
|
newName: 'global-metadata.dat'
|
|
})
|
|
|
|
if (!replacedMeta) {
|
|
return false
|
|
}
|
|
|
|
console.log('Replacement successful!')
|
|
|
|
return true
|
|
}
|
|
|
|
export async function patchGame() {
|
|
const backupExists = await invoke('dir_exists', {
|
|
path: await getBackupMetadataPath() + '\\global-metadata-unpatched.dat'
|
|
})
|
|
|
|
if (!backupExists) {
|
|
// No backup found? Patching creates one
|
|
const patched = await patchMetadata()
|
|
|
|
if (!patched) {
|
|
return false
|
|
}
|
|
}
|
|
|
|
// Are we already patched? If so, that's fine, just continue as normal
|
|
const gameIsPatched = await invoke('are_files_identical', {
|
|
path1: await getBackupMetadataPath() + '\\global-metadata-patched.dat',
|
|
path2: await getGameMetadataPath() + '\\global-metadata.dat'
|
|
})
|
|
|
|
if (gameIsPatched) {
|
|
return true
|
|
}
|
|
|
|
// Is the current backup the same as the games current metadata?
|
|
const backupIsCurrent = await invoke('are_files_identical', {
|
|
path1: await getBackupMetadataPath() + '\\global-metadata-unpatched.dat',
|
|
path2: await getGameMetadataPath() + '\\global-metadata.dat'
|
|
})
|
|
|
|
// Game has probably been updated. We need to repatch the game...
|
|
if (!backupIsCurrent) {
|
|
const deletedOldBackup = await invoke('delete_file', {
|
|
path: await getBackupMetadataPath() + '\\global-metadata-unpatched.dat'
|
|
})
|
|
const deletedOldPatched = await invoke('delete_file', {
|
|
path: await getBackupMetadataPath() + '\\global-metadata-patched.dat'
|
|
})
|
|
|
|
// It's fine if these deletes fail. The game will be replaced anyway.
|
|
if (!deletedOldBackup) {
|
|
console.log('Warning: Failed to delete old backup!')
|
|
}
|
|
|
|
if (!deletedOldPatched) {
|
|
console.log('Warning: Failed to delete old patched metadata!')
|
|
}
|
|
|
|
console.log('Patching Metadata')
|
|
|
|
const patched = await patchMetadata()
|
|
|
|
if (!patched) {
|
|
return false
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
console.log('Metadata is not patched')
|
|
console.log('Replacing unpatched metadata')
|
|
|
|
// Finally, replace the unpatched metadata with the patched one
|
|
const replaced = await invoke('copy_file_with_new_name', {
|
|
path: await getBackupMetadataPath() + '\\global-metadata-patched.dat',
|
|
newPath: await getGameMetadataPath(),
|
|
newName: 'global-metadata.dat'
|
|
})
|
|
|
|
if (!replaced) {
|
|
return false
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
export async function unpatchGame() {
|
|
const backupExists = await invoke('dir_exists', {
|
|
path: await getBackupMetadataPath() + '\\global-metadata-unpatched.dat'
|
|
})
|
|
|
|
if (!backupExists) {
|
|
// Let's just hope the game isn't on a patched metadata since we don't have a backup...
|
|
return true
|
|
}
|
|
|
|
const metaPatched = await invoke('are_files_identical', {
|
|
path1: await getBackupMetadataPath() + '\\global-metadata-patched.dat',
|
|
path2: await getGameMetadataPath() + '\\global-metadata.dat'
|
|
})
|
|
|
|
const metaExists = await invoke('dir_exists', {
|
|
path: await getGameMetadataPath() + '\\global-metadata.dat'
|
|
})
|
|
|
|
if (!metaPatched && metaExists) {
|
|
// Game isn't patched
|
|
return true
|
|
}
|
|
|
|
console.log('Replacing patched game metadata with unpatched metadata')
|
|
|
|
const replaced = await invoke('copy_file_with_new_name', {
|
|
path: await getBackupMetadataPath() + '\\global-metadata-unpatched.dat',
|
|
newPath: await getGameMetadataPath(),
|
|
newName: 'global-metadata.dat'
|
|
})
|
|
|
|
return replaced
|
|
}
|
|
|
|
export async function getGameMetadataPath() {
|
|
const gameExec = await getGameExecutable()
|
|
|
|
if (!gameExec) {
|
|
return null
|
|
}
|
|
|
|
return (await getGameFolder() + '\\' + gameExec.replace('.exe', '_Data') + '\\Managed\\Metadata').replace(/\\/g, '/')
|
|
}
|
|
|
|
export async function getBackupMetadataPath() {
|
|
return await dataDir() + 'cultivation\\metadata'
|
|
}
|
|
|
|
export async function globalMetadataLink() {
|
|
const versionAPIUrl = 'https://sdk-os-static.mihoyo.com/hk4e_global/mdk/launcher/api/resource?channel_id=1&key=gcStgarh&launcher_id=10&sub_channel_id=0'
|
|
|
|
// Get versions from API
|
|
const versions = JSON.parse(await invoke('web_get', {
|
|
url: versionAPIUrl
|
|
}))
|
|
|
|
if (!versions || versions.retcode !== 0) {
|
|
console.log('Failed to get versions from API')
|
|
return null
|
|
}
|
|
|
|
// Get latest version
|
|
const latest = versions.data.game.latest
|
|
|
|
return latest.decompressed_path as string + '/GenshinImpact_Data/Managed/Metadata/global-metadata.dat'
|
|
}
|
|
|
|
export async function restoreMetadata(manager: DownloadHandler) {
|
|
const backupExists = await invoke('dir_exists', {
|
|
path: await getBackupMetadataPath() + '\\global-metadata-unpatched.dat'
|
|
})
|
|
|
|
if (!backupExists) {
|
|
console.log('No backup found! Replacing with global metadata link')
|
|
|
|
const metaLink = await globalMetadataLink()
|
|
|
|
if (!metaLink) {
|
|
console.log('Coudl not get global metadata link!')
|
|
return false
|
|
}
|
|
|
|
// Download the file
|
|
manager.addDownload(metaLink, await getBackupMetadataPath() + '\\global-metadata-unpatched.dat', () => {
|
|
unpatchGame()
|
|
})
|
|
}
|
|
|
|
console.log('Restoring backedup metadata')
|
|
|
|
await unpatchGame()
|
|
|
|
return true
|
|
} |