Compare commits

...

7 Commits
v1.7.0 ... main

Author SHA1 Message Date
Thoronium
0ef50b889b Merge pull request #251 from navidmafi/main
fix(web): standardize utils/game.ts for cross-platform (needs windows test)
2025-11-27 00:33:36 -07:00
Thoronium
d9b820c842 Return proper value from getGameExecutable
getGameExecutable returns the executable name only.
basename can remove filetype instead of splitting.
2025-11-27 00:31:12 -07:00
NotThorny
986259d96b Bump version 2025-11-15 00:41:10 -07:00
NotThorny
97454de75e Fix default config not generating
Fixes #262
2025-11-15 00:35:51 -07:00
NotThorny
f61f4eed51 Bump version 2025-11-14 15:24:14 -07:00
NotThorny
99b45ddf52 Fix reading profile path 2025-11-14 15:24:14 -07:00
Navid Mafi
0370576c11 fix(web): cross-platform game and data paths on 2025-02-17 23:40:30 +03:30
19 changed files with 58 additions and 134 deletions

View File

@@ -1,6 +1,6 @@
{
"name": "cultivation",
"version": "1.7.0",
"version": "1.7.2",
"private": true,
"dependencies": {
"@tauri-apps/api": "^1.0.0-rc.5",

View File

@@ -1,7 +1,7 @@
{
"lang_name": "简体中文",
"main": {
"title": "Cultivation: Thorny Edition",
"title": "Cultivation",
"launch_button": "启动",
"gc_enable": "以 Grasscutter 模式连接",
"https_enable": "使用 HTTPS",

View File

@@ -1,7 +1,7 @@
{
"lang_name": "繁體中文",
"main": {
"title": "Cultivation: Thorny Edition",
"title": "Cultivation",
"launch_button": "啟動",
"gc_enable": "以Grasscutter模式連接",
"https_enable": "使用 HTTPS",

View File

@@ -1,7 +1,7 @@
{
"lang_name": "Deutsch",
"main": {
"title": "Cultivation: Thorny Edition",
"title": "Cultivation",
"launch_button": "Starten",
"gc_enable": "Mit Grasscutter verbinden",
"https_enable": "HTTPS verwenden",

View File

@@ -1,7 +1,7 @@
{
"lang_name": "English",
"main": {
"title": "Cultivation: Thorny Edition",
"title": "Cultivation",
"launch_button": "Launch",
"gc_enable": "Connect to Grasscutter",
"https_enable": "Use HTTPS",

View File

@@ -1,7 +1,7 @@
{
"lang_name": "Español",
"main": {
"title": "Cultivation: Thorny Edition",
"title": "Cultivation",
"launch_button": "Launch",
"gc_enable": "Conectar Via Grasscutter",
"https_enable": "Usar HTTPS",

View File

@@ -1,7 +1,7 @@
{
"lang_name": "Francais",
"main": {
"title": "Cultivation: Thorny Edition",
"title": "Cultivation",
"launch_button": "Lancer",
"gc_enable": "Se connecter avec Grasscutter",
"https_enable": "Utiliser HTTPS",

View File

@@ -1,7 +1,7 @@
{
"lang_name": "Indonesia",
"main": {
"title": "Cultivation: Thorny Edition",
"title": "Cultivation",
"launch_button": "Luncurkan",
"gc_enable": "Terhubung Melalui GrassCutter",
"ip_placeholder": "Alamat Server...",

View File

@@ -1,7 +1,7 @@
{
"lang_name": "日本語",
"main": {
"title": "Cultivation: Thorny Edition",
"title": "Cultivation",
"launch_button": "起動",
"gc_enable": "Grasscutterに接続",
"https_enable": "HTTPS接続を使用",

View File

@@ -1,7 +1,7 @@
{
"lang_name": "한국어",
"main": {
"title": "Cultivation: Thorny Edition",
"title": "Cultivation",
"launch_button": "게임 시작",
"gc_enable": "Grasscutter 연결",
"https_enable": "HTTPS 사용",

View File

@@ -1,7 +1,7 @@
{
"lang_name": "Latviešu",
"main": {
"title": "Cultivation: Thorny Edition",
"title": "Cultivation",
"launch_button": "Palaist",
"gc_enable": "Savienot ar Grasscutter",
"https_enable": "Izm. HTTPS",

View File

@@ -1,7 +1,7 @@
{
"lang_name": "Nederlands",
"main": {
"title": "Cultivation: Thorny Edition",
"title": "Cultivation",
"launch_button": "Start",
"gc_enable": "Verbind Met Grasscutter",
"https_enable": "Gebruik HTTPS",

View File

@@ -1,7 +1,7 @@
{
"lang_name": "Русский",
"main": {
"title": "Cultivation: Thorny Edition",
"title": "Cultivation",
"launch_button": "Запустить",
"gc_enable": "Подключиться с Grasscutter",
"https_enable": "Исп. HTTPS",

View File

@@ -1,7 +1,7 @@
{
"lang_name": "Tiếng Việt",
"main": {
"title": "Cultivation: Thorny Edition",
"title": "Cultivation",
"launch_button": "Khởi Chạy",
"gc_enable": "Kết nối qua Grasscutter",
"https_enable": "Dùng HTTPS",

View File

@@ -40,22 +40,22 @@ pub fn config_path(profile: String) -> PathBuf {
if profile.as_str() == "default" {
path.push("configuration.json");
} else {
path.push("profile");
path.push(profile);
path.push("profiles");
path.push(profile + ".json");
}
path
}
pub fn get_config(profile_name: String) -> Configuration {
let path = config_path(profile_name);
let path = config_path(profile_name.clone());
let config = std::fs::read_to_string(path).unwrap_or("{}".to_string());
let config: Configuration = serde_json::from_str(&config).unwrap_or_default();
let default = String::from("default");
let prof = config.profile.as_ref().unwrap_or(&default);
if *prof != String::from("default") {
get_config(prof.clone());
//let default = String::from("default");
let prof = config.profile.clone().unwrap_or_default();
if prof != String::from("default") && prof != profile_name.clone() {
return get_config(prof.clone());
}
config

View File

@@ -7,7 +7,7 @@
},
"package": {
"productName": "Cultivation",
"version": "1.7.0"
"version": "1.7.2"
},
"tauri": {
"allowlist": {

View File

@@ -143,7 +143,7 @@ export default class NewsSection extends React.Component<IProps, IState> {
<tr>
<td>
Work in progress area! These numbers may be outdated, so please do not use them as reference. Latest
version: Grasscutter 1.7.4 (4.0) / Forks (6.1) - Cultivation 1.7.0
version: Grasscutter 1.7.4 (4.0) / Forks (6.1) - Cultivation 1.7.2
</td>
</tr>
)

View File

@@ -177,6 +177,19 @@ async function readConfigFile() {
configFilePath = local + 'cultivation/configuration.json'
}
const dataFiles = await fs.readDir(local + 'cultivation')
// Ensure config exists
if (!dataFiles.find((fileOrDir) => fileOrDir?.name === 'configuration.json')) {
// Create config file
const file: fs.FsTextFileOption = {
path: configFilePath,
contents: JSON.stringify(defaultConfig),
}
await fs.writeFile(file)
}
// Read existing config to get profile name
const raw = await fs.readTextFile(configFilePath)
const cfg = <Configuration>JSON.parse(raw)
@@ -206,19 +219,6 @@ async function readConfigFile() {
await fs.createDir(local + 'cultivation/grasscutter').catch((e) => console.log(e))
}
const dataFiles = await fs.readDir(local + 'cultivation')
// Ensure config exists
if (!dataFiles.find((fileOrDir) => fileOrDir?.name === 'configuration.json')) {
// Create config file
const file: fs.FsTextFileOption = {
path: configFilePath,
contents: JSON.stringify(defaultConfig),
}
await fs.writeFile(file)
}
// Finally, read the file
return await fs.readTextFile(configFilePath)
}

View File

@@ -1,110 +1,34 @@
import { invoke } from '@tauri-apps/api'
import { getConfig } from './configuration'
import { basename, dirname, join } from '@tauri-apps/api/path'
import { getConfigOption } from './configuration'
export const getGrasscutterJar = () => getConfigOption('grasscutter_path')
export async function getGameExecutable() {
const config = await getConfig()
if (!config.game_install_path) {
return null
}
const pathArr = config.game_install_path.replace(/\\/g, '/').split('/')
return pathArr[pathArr.length - 1]
}
export async function getGrasscutterJar() {
const config = await getConfig()
if (!config.grasscutter_path) {
return null
}
const pathArr = config.grasscutter_path.replace(/\\/g, '/').split('/')
return pathArr[pathArr.length - 1]
}
export async function getGameFolder() {
const config = await getConfig()
if (!config.game_install_path) {
return null
}
const pathArr = config.game_install_path.replace(/\\/g, '/').split('/')
pathArr.pop()
const path = pathArr.join('/')
return path
}
export async function getGameDataFolder() {
const gameExec = await getGameExecutable()
if (!gameExec) {
return null
}
return (await getGameFolder()) + '\\' + gameExec.replace('.exe', '_Data')
}
const exe_path = await getConfigOption('game_install_path')
return await basename(exe_path)
}
export async function getGameVersion() {
const GameData = await getGameDataFolder()
const platform = await invoke('get_platform')
if (!GameData) {
return null
}
let hasAsb = await invoke('dir_exists', {
path: GameData + '\\StreamingAssets\\asb_settings.json',
})
if (platform != 'windows') {
hasAsb = await invoke('dir_exists', {
path: GameData + '/StreamingAssets/asb_settings.json',
})
}
const execPath = await getConfigOption('game_install_path')
const rootPath = await dirname(execPath)
const baseName = (await basename(execPath, ".exe"))
const datapath = await join(rootPath, `${baseName}_Data`)
const asbPath = await join(datapath, 'StreamingAssets', 'asb_settings.json')
const hasAsb = await invoke<boolean>('dir_exists', { path: asbPath })
if (!hasAsb) {
// For games that cannot determine game version
let otherGameVer: string = await invoke('read_file', {
path: GameData + '\\StreamingAssets\\BinaryVersion.bytes',
})
const versionFile = await join(datapath, 'StreamingAssets', 'BinaryVersion.bytes')
const rawVersion = await invoke<string>('read_file', { path: versionFile })
if (!rawVersion) return null
if (platform != 'windows') {
otherGameVer = await invoke('read_file', {
path: GameData + '/StreamingAssets/BinaryVersion.bytes',
})
}
const versionRaw = otherGameVer.split('.')
const version = {
major: parseInt(versionRaw[0]),
minor: parseInt(versionRaw[1]),
// This will probably never matter, just use major/minor. If needed, full version values are near EOF
release: 0,
}
if (otherGameVer == null || otherGameVer.length < 1) {
return null
}
return version
const [major, minor] = rawVersion.split('.').map(Number)
return { major, minor, release: 0 }
}
const settings = JSON.parse(
await invoke('read_file', {
path: GameData + '\\StreamingAssets\\asb_settings.json',
})
)
const settings = JSON.parse(await invoke<string>('read_file', { path: asbPath }))
const [major, minorRelease] = settings.variance.split('.')
const [minor, release] = minorRelease.split('_').map(Number)
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
return { major: parseInt(major), minor, release }
}