mirror of
https://github.com/Grasscutters/Cultivation.git
synced 2025-12-14 16:14:48 +01:00
Merge pull request #83 from 4Benj/main
Fix some filesystem related bugs
This commit is contained in:
@@ -63,7 +63,7 @@ pub fn copy_file(path: String, new_path: String) -> bool {
|
|||||||
let path_buf = std::path::PathBuf::from(&path);
|
let path_buf = std::path::PathBuf::from(&path);
|
||||||
|
|
||||||
// If the new path doesn't exist, create it.
|
// If the new path doesn't exist, create it.
|
||||||
if !dir_exists(new_path_buf.pop().to_string().as_str()) {
|
if !dir_exists(std::path::PathBuf::from(&new_path).pop().to_string().as_str()) {
|
||||||
std::fs::create_dir_all(&new_path).unwrap();
|
std::fs::create_dir_all(&new_path).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -85,7 +85,7 @@ pub fn copy_file_with_new_name(path: String, new_path: String, new_name: String)
|
|||||||
let path_buf = std::path::PathBuf::from(&path);
|
let path_buf = std::path::PathBuf::from(&path);
|
||||||
|
|
||||||
// If the new path doesn't exist, create it.
|
// If the new path doesn't exist, create it.
|
||||||
if !dir_exists(new_path_buf.pop().to_string().as_str()) {
|
if !dir_exists(std::path::PathBuf::from(&new_path).pop().to_string().as_str()) {
|
||||||
match std::fs::create_dir_all(&new_path) {
|
match std::fs::create_dir_all(&new_path) {
|
||||||
Ok(_) => {}
|
Ok(_) => {}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
@@ -95,8 +95,10 @@ pub fn copy_file_with_new_name(path: String, new_path: String, new_name: String)
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
new_path_buf.push(new_name);
|
||||||
|
|
||||||
// Copy old to new
|
// Copy old to new
|
||||||
match std::fs::copy(&path_buf, format!("{}/{}", new_path, new_name)) {
|
match std::fs::copy(&path_buf, &new_path_buf) {
|
||||||
Ok(_) => true,
|
Ok(_) => true,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
println!("Failed to copy file: {}", e);
|
println!("Failed to copy file: {}", e);
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use std::fs::File;
|
use std::{fs, path::Path, fs::File, fs::OpenOptions, io::Read, io::Write};
|
||||||
use std::fs::OpenOptions;
|
|
||||||
use std::io::Read;
|
|
||||||
use std::io::Write;
|
|
||||||
|
|
||||||
// For these two functions, a non-zero return value indicates failure.
|
// For these two functions, a non-zero return value indicates failure.
|
||||||
extern "C" {
|
extern "C" {
|
||||||
@@ -13,6 +10,12 @@ extern "C" {
|
|||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub fn patch_metadata(metadata_folder: &str) -> bool {
|
pub fn patch_metadata(metadata_folder: &str) -> bool {
|
||||||
let metadata_file = &(metadata_folder.to_owned() + "\\global-metadata-unpatched.dat");
|
let metadata_file = &(metadata_folder.to_owned() + "\\global-metadata-unpatched.dat");
|
||||||
|
// check if metadata_file exists
|
||||||
|
if !Path::new(metadata_file).exists() {
|
||||||
|
println!("Metadata file not found");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
println!("Patching metadata file: {}", metadata_file);
|
println!("Patching metadata file: {}", metadata_file);
|
||||||
let decrypted = decrypt_metadata(metadata_file);
|
let decrypted = decrypt_metadata(metadata_file);
|
||||||
if do_vecs_match(&decrypted, &Vec::new()) {
|
if do_vecs_match(&decrypted, &Vec::new()) {
|
||||||
@@ -111,20 +114,17 @@ fn replace_keys(data: &[u8]) -> Vec<u8> {
|
|||||||
fn replace_rsa_key(old_data: &str, to_replace: &str, file_name: &str) -> String {
|
fn replace_rsa_key(old_data: &str, to_replace: &str, file_name: &str) -> String {
|
||||||
// Read dispatch key file
|
// Read dispatch key file
|
||||||
unsafe {
|
unsafe {
|
||||||
// Get key folder from exe path
|
// Get key path from current directory
|
||||||
let mut exe_path = std::env::current_exe().unwrap();
|
let key_file_path = std::env::current_dir().unwrap().join("keys").join(file_name);
|
||||||
exe_path.pop();
|
|
||||||
|
|
||||||
let key_folder = exe_path.to_str().unwrap().to_string();
|
let key_data = match fs::read(&key_file_path) {
|
||||||
let mut new_key_file = match File::open(format!("{}/keys/{}", key_folder, file_name)) {
|
|
||||||
Ok(file) => file,
|
Ok(file) => file,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
println!("Failed to open keys/{}: {}", file_name, e);
|
println!("Failed to open {}: {}", key_file_path.to_str().unwrap(), e);
|
||||||
return String::new();
|
return String::new();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let mut key_data = Vec::new();
|
|
||||||
new_key_file.read_to_end(&mut key_data).unwrap();
|
|
||||||
let new_key = String::from_utf8_unchecked(key_data.to_vec());
|
let new_key = String::from_utf8_unchecked(key_data.to_vec());
|
||||||
|
|
||||||
// Replace old key with new key
|
// Replace old key with new key
|
||||||
@@ -134,6 +134,7 @@ fn replace_rsa_key(old_data: &str, to_replace: &str, file_name: &str) -> String
|
|||||||
|
|
||||||
fn encrypt_metadata(old_data: &[u8]) -> Vec<u8> {
|
fn encrypt_metadata(old_data: &[u8]) -> Vec<u8> {
|
||||||
let mut data = old_data.to_vec();
|
let mut data = old_data.to_vec();
|
||||||
|
|
||||||
let success = unsafe { encrypt_global_metadata(data.as_mut_ptr(), data.len()) } == 0;
|
let success = unsafe { encrypt_global_metadata(data.as_mut_ptr(), data.len()) } == 0;
|
||||||
if success {
|
if success {
|
||||||
println!("Successfully encrypted global-metadata");
|
println!("Successfully encrypted global-metadata");
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import Plus from '../../resources/icons/plus.svg'
|
|||||||
|
|
||||||
import './ServerLaunchSection.css'
|
import './ServerLaunchSection.css'
|
||||||
import { dataDir } from '@tauri-apps/api/path'
|
import { dataDir } from '@tauri-apps/api/path'
|
||||||
import { getGameExecutable } from '../../utils/game'
|
import { getGameExecutable, getGameVersion } from '../../utils/game'
|
||||||
import { patchGame, unpatchGame } from '../../utils/metadata'
|
import { patchGame, unpatchGame } from '../../utils/metadata'
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
@@ -110,6 +110,24 @@ export default class ServerLaunchSection extends React.Component<IProps, IState>
|
|||||||
// Connect to proxy
|
// Connect to proxy
|
||||||
if (config.toggle_grasscutter) {
|
if (config.toggle_grasscutter) {
|
||||||
if (config.patch_metadata) {
|
if (config.patch_metadata) {
|
||||||
|
const gameVersion = await getGameVersion()
|
||||||
|
console.log(gameVersion)
|
||||||
|
|
||||||
|
if(gameVersion == null) {
|
||||||
|
alert('Game version could not be determined. Please make sure you have the game correctly selected and try again.')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if(gameVersion?.major == 2 && gameVersion?.minor < 8) {
|
||||||
|
alert('Game version is too old for metadata patching. Please disable metadata patching in the settings and try again.')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if(gameVersion?.major == 3 && gameVersion?.minor >= 1) {
|
||||||
|
alert('Game version is too new for metadata patching. Please disable metadata patching in the settings to launch the game.\nNOTE: You will require a UA patch to play the game.')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
const patched = await patchGame()
|
const patched = await patchGame()
|
||||||
|
|
||||||
if (!patched) {
|
if (!patched) {
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { invoke } from '@tauri-apps/api'
|
||||||
import { getConfig } from './configuration'
|
import { getConfig } from './configuration'
|
||||||
|
|
||||||
export async function getGameExecutable() {
|
export async function getGameExecutable() {
|
||||||
@@ -25,3 +26,34 @@ export async function getGameFolder() {
|
|||||||
|
|
||||||
return path
|
return path
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function getGameDataFolder() {
|
||||||
|
const gameExec = await getGameExecutable()
|
||||||
|
|
||||||
|
if (!gameExec) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
return (await getGameFolder()) + '\\' + gameExec.replace('.exe', '_Data')
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getGameVersion() {
|
||||||
|
const GameData = await getGameDataFolder();
|
||||||
|
|
||||||
|
if (!GameData) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
const settings = JSON.parse(await invoke('read_file', {
|
||||||
|
path: GameData + '\\StreamingAssets\\asb_settings.json',
|
||||||
|
}))
|
||||||
|
|
||||||
|
const versionRaw = settings.variance.split('.');
|
||||||
|
const version = {
|
||||||
|
major: parseInt(versionRaw[0]),
|
||||||
|
minor: parseInt(versionRaw[1].split('_')[0]),
|
||||||
|
release: parseInt(versionRaw[1].split('_')[1]),
|
||||||
|
}
|
||||||
|
|
||||||
|
return version;
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { invoke } from '@tauri-apps/api'
|
import { invoke } from '@tauri-apps/api'
|
||||||
import { dataDir } from '@tauri-apps/api/path'
|
import { dataDir } from '@tauri-apps/api/path'
|
||||||
import DownloadHandler from './download'
|
import DownloadHandler from './download'
|
||||||
import { getGameExecutable, getGameFolder } from './game'
|
import { getGameDataFolder, getGameExecutable, getGameFolder, getGameVersion } from './game'
|
||||||
|
|
||||||
export async function patchMetadata() {
|
export async function patchMetadata() {
|
||||||
const metadataExists = await invoke('dir_exists', {
|
const metadataExists = await invoke('dir_exists', {
|
||||||
@@ -171,13 +171,13 @@ export async function unpatchGame() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function getGameMetadataPath() {
|
export async function getGameMetadataPath() {
|
||||||
const gameExec = await getGameExecutable()
|
const gameData = await getGameDataFolder()
|
||||||
|
|
||||||
if (!gameExec) {
|
if (!gameData) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
return ((await getGameFolder()) + '\\' + gameExec.replace('.exe', '_Data') + '\\Managed\\Metadata').replace(
|
return (gameData + '\\Managed\\Metadata').replace(
|
||||||
/\\/g,
|
/\\/g,
|
||||||
'/'
|
'/'
|
||||||
)
|
)
|
||||||
@@ -188,6 +188,7 @@ export async function getBackupMetadataPath() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function globalMetadataLink() {
|
export async function globalMetadataLink() {
|
||||||
|
// TODO: Get metadata based on current game version.
|
||||||
const versionAPIUrl =
|
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'
|
'https://sdk-os-static.mihoyo.com/hk4e_global/mdk/launcher/api/resource?channel_id=1&key=gcStgarh&launcher_id=10&sub_channel_id=0'
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user