emergency metadata recovery

This commit is contained in:
SpikeHD 2022-07-15 19:35:57 -07:00
parent a1b0fec871
commit bd54a78e4b
7 changed files with 88 additions and 2 deletions

View File

@ -15,6 +15,7 @@
"disabled": "Disabled",
"game_path": "Set Game Install Path",
"game_executable": "Set Game Executable",
"recover_metadata": "Emergency Metadata Recovery",
"grasscutter_jar": "Set Grasscutter JAR",
"toggle_encryption": "Toggle Encryption",
"java_path": "Set Custom Java Path",

View File

@ -66,7 +66,13 @@ pub fn copy_file_with_new_name(path: String, new_path: String, new_name: String)
// If the new path doesn't exist, create it.
if !dir_exists(new_path_buf.pop().to_string().as_str()) {
std::fs::create_dir_all(&new_path).unwrap();
match std::fs::create_dir_all(&new_path) {
Ok(_) => {}
Err(e) => {
println!("Failed to create directory: {}", e);
return false;
}
};
}
// Copy old to new

View File

@ -54,6 +54,7 @@ fn main() {
lang::get_lang,
lang::get_languages,
web::valid_url,
web::web_get,
metadata_patcher::patch_metadata
])
.run(tauri::generate_context!())

View File

@ -15,4 +15,10 @@ pub(crate) async fn valid_url(url: String) -> bool {
let response = client.get(url).header(USER_AGENT, "cultivation").send().await.unwrap();
response.status().as_str() == "200"
}
#[tauri::command]
pub async fn web_get(url: String) -> String {
// Send a GET request to the specified URL and send the response body back to the client.
query(&url).await
}

View File

@ -206,6 +206,7 @@ class App extends React.Component<IProps, IState> {
// Options menu
this.state.optionsOpen ? (
<Options
downloadManager={downloadHandler}
closeFn={() => this.setState({ optionsOpen: !this.state.optionsOpen })}
/>
) : null

View File

@ -12,9 +12,12 @@ import * as server from '../../../utils/server'
import './Options.css'
import BigButton from '../common/BigButton'
import DownloadHandler from '../../../utils/download'
import * as meta from '../../../utils/metadata'
interface IProps {
closeFn: () => void;
downloadManager: DownloadHandler;
}
interface IState {
@ -62,6 +65,7 @@ export default class Options extends React.Component<IProps, IState> {
this.toggleGrasscutterWithGame = this.toggleGrasscutterWithGame.bind(this)
this.setCustomBackground = this.setCustomBackground.bind(this)
this.toggleEncryption = this.toggleEncryption.bind(this)
this.restoreMetadata = this.restoreMetadata.bind(this)
}
async componentDidMount() {
@ -190,6 +194,11 @@ export default class Options extends React.Component<IProps, IState> {
})
}
async restoreMetadata() {
console.log(this.props)
await meta.restoreMetadata(this.props.downloadManager)
}
render() {
return (
<Menu closeFn={this.props.closeFn} className="Options" heading="Options">
@ -201,6 +210,16 @@ export default class Options extends React.Component<IProps, IState> {
<DirInput onChange={this.setGameExecutable} value={this.state?.game_install_path} extensions={['exe']} />
</div>
</div>
<div className="OptionSection" id="menuOptionsContainermetaDownload">
<div className="OptionLabel" id="menuOptionsLabelmetaDownload">
<Tr text="options.recover_metadata" />
</div>
<div className="OptionValue" id="menuOptionsButtonmetaDownload">
<BigButton onClick={this.restoreMetadata} id="metaDownload">
<Tr text='components.download' />
</BigButton>
</div>
</div>
{
this.state.swag && (
<div className='OptionSection' id="menuOptionsContainerAkebi">

View File

@ -1,6 +1,7 @@
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() {
@ -149,7 +150,11 @@ export async function unpatchGame() {
path2: await getGameMetadataPath() + '\\global-metadata.dat'
})
if (!metaPatched) {
const metaExists = await invoke('dir_exists', {
path: await getGameMetadataPath() + '\\global-metadata.dat'
})
if (!metaPatched && metaExists) {
// Game isn't patched
return true
}
@ -177,4 +182,51 @@ export async function getGameMetadataPath() {
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
}