mirror of
https://github.com/Grasscutters/Cultivation.git
synced 2025-12-12 23:24:35 +01:00
Add profiles
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "cultivation",
|
"name": "cultivation",
|
||||||
"version": "1.6.3",
|
"version": "1.7.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@tauri-apps/api": "^1.0.0-rc.5",
|
"@tauri-apps/api": "^1.0.0-rc.5",
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"lang_name": "English",
|
"lang_name": "English",
|
||||||
"main": {
|
"main": {
|
||||||
"title": "Cultivation",
|
"title": "Cultivation: Thorny Edition",
|
||||||
"launch_button": "Launch",
|
"launch_button": "Launch",
|
||||||
"gc_enable": "Connect to Grasscutter",
|
"gc_enable": "Connect to Grasscutter",
|
||||||
"https_enable": "Use HTTPS",
|
"https_enable": "Use HTTPS",
|
||||||
@@ -39,7 +39,9 @@
|
|||||||
"web_cache": "Delete webCaches folder",
|
"web_cache": "Delete webCaches folder",
|
||||||
"launch_args": "Launch Args",
|
"launch_args": "Launch Args",
|
||||||
"offline_mode": "Offline Mode",
|
"offline_mode": "Offline Mode",
|
||||||
"fix_res": "Fix Login Timeout"
|
"fix_res": "Fix Login Timeout",
|
||||||
|
"show_version": "Show game version in buttons",
|
||||||
|
"save_profile": "Save profile"
|
||||||
},
|
},
|
||||||
"downloads": {
|
"downloads": {
|
||||||
"grasscutter_fullbuild": "Download Grasscutter 4.0 All-in-One",
|
"grasscutter_fullbuild": "Download Grasscutter 4.0 All-in-One",
|
||||||
|
|||||||
@@ -30,20 +30,33 @@ pub struct Configuration {
|
|||||||
pub redirect_more: Option<bool>,
|
pub redirect_more: Option<bool>,
|
||||||
pub launch_args: Option<String>,
|
pub launch_args: Option<String>,
|
||||||
pub offline_mode: Option<bool>,
|
pub offline_mode: Option<bool>,
|
||||||
|
pub show_version: Option<bool>,
|
||||||
|
pub profile: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn config_path() -> PathBuf {
|
pub fn config_path(profile: String) -> PathBuf {
|
||||||
let mut path = tauri::api::path::data_dir().unwrap();
|
let mut path = tauri::api::path::data_dir().unwrap();
|
||||||
path.push("cultivation");
|
path.push("cultivation");
|
||||||
path.push("configuration.json");
|
if profile.as_str() == "default" {
|
||||||
|
path.push("configuration.json");
|
||||||
|
} else {
|
||||||
|
path.push("profile");
|
||||||
|
path.push(profile);
|
||||||
|
}
|
||||||
|
|
||||||
path
|
path
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_config() -> Configuration {
|
pub fn get_config(profile_name: String) -> Configuration {
|
||||||
let path = config_path();
|
let path = config_path(profile_name);
|
||||||
let config = std::fs::read_to_string(path).unwrap_or("{}".to_string());
|
let config = std::fs::read_to_string(path).unwrap_or("{}".to_string());
|
||||||
let config: Configuration = serde_json::from_str(&config).unwrap_or_default();
|
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());
|
||||||
|
}
|
||||||
|
|
||||||
config
|
config
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -101,7 +101,7 @@ async fn parse_args(inp: &Vec<String>) -> Result<Args, ArgsError> {
|
|||||||
|
|
||||||
args.parse(inp).unwrap();
|
args.parse(inp).unwrap();
|
||||||
|
|
||||||
let config = config::get_config();
|
let config = config::get_config(String::from("default"));
|
||||||
|
|
||||||
if args.value_of("help")? {
|
if args.value_of("help")? {
|
||||||
println!("{}", args.full_usage());
|
println!("{}", args.full_usage());
|
||||||
@@ -207,6 +207,7 @@ fn main() -> Result<(), ArgsError> {
|
|||||||
is_grasscutter_running,
|
is_grasscutter_running,
|
||||||
restart_grasscutter,
|
restart_grasscutter,
|
||||||
get_theme_list,
|
get_theme_list,
|
||||||
|
get_profile_list,
|
||||||
system_helpers::run_command,
|
system_helpers::run_command,
|
||||||
system_helpers::run_program,
|
system_helpers::run_program,
|
||||||
system_helpers::run_program_args,
|
system_helpers::run_program_args,
|
||||||
@@ -536,3 +537,20 @@ async fn get_theme_list(data_dir: String) -> Vec<HashMap<String, String>> {
|
|||||||
|
|
||||||
themes
|
themes
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tauri::command]
|
||||||
|
async fn get_profile_list(data_dir: String) -> Vec<String> {
|
||||||
|
let profile_loc = format!("{}/profiles", data_dir);
|
||||||
|
|
||||||
|
// Ensure folder exists
|
||||||
|
if !std::path::Path::new(&profile_loc).exists() {
|
||||||
|
std::fs::create_dir_all(&profile_loc).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut p_list = Vec::new();
|
||||||
|
for entry in std::fs::read_dir(&profile_loc).unwrap() {
|
||||||
|
p_list.push(entry.unwrap().file_name().into_string().unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
p_list
|
||||||
|
}
|
||||||
|
|||||||
@@ -349,7 +349,7 @@ pub async fn unpatch_game() -> bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_game_rsa_path() -> Option<String> {
|
pub async fn get_game_rsa_path() -> Option<String> {
|
||||||
let config = config::get_config();
|
let config = config::get_config(String::from("default"));
|
||||||
|
|
||||||
config.game_install_path.as_ref()?;
|
config.game_install_path.as_ref()?;
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
},
|
},
|
||||||
"package": {
|
"package": {
|
||||||
"productName": "Cultivation",
|
"productName": "Cultivation",
|
||||||
"version": "1.6.3"
|
"version": "1.7.0"
|
||||||
},
|
},
|
||||||
"tauri": {
|
"tauri": {
|
||||||
"allowlist": {
|
"allowlist": {
|
||||||
|
|||||||
@@ -170,6 +170,8 @@ export class Main extends React.Component<IProps, IState> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Ensure old configs are updated to use RSA
|
// Ensure old configs are updated to use RSA
|
||||||
|
const updatedProfile = await getConfigOption('profile')
|
||||||
|
await setConfigOption('profile', updatedProfile)
|
||||||
const updatedConfig = await getConfigOption('patch_rsa')
|
const updatedConfig = await getConfigOption('patch_rsa')
|
||||||
await setConfigOption('patch_rsa', updatedConfig)
|
await setConfigOption('patch_rsa', updatedConfig)
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
#playButton > div {
|
#playButton > div {
|
||||||
margin-bottom: 6px;
|
margin-bottom: 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#playButton .BigButton {
|
#playButton .BigButton {
|
||||||
@@ -26,10 +26,27 @@
|
|||||||
|
|
||||||
#serverControls {
|
#serverControls {
|
||||||
color: white;
|
color: white;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
flex-direction: row;
|
||||||
text-shadow: 1px 1px 8px black;
|
text-shadow: 1px 1px 8px black;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#menuOptionsContainerProfiles {
|
||||||
|
justify-self: right;
|
||||||
|
align-self: right;
|
||||||
|
padding-left: 8px;
|
||||||
|
width: min-content;
|
||||||
|
}
|
||||||
|
|
||||||
|
#serverControls select {
|
||||||
|
width: 150px;
|
||||||
|
height: 30px;
|
||||||
|
border: none;
|
||||||
|
border-bottom: 2px solid #cecece;
|
||||||
|
border-radius: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
.BottomSection .CheckboxDisplay {
|
.BottomSection .CheckboxDisplay {
|
||||||
border-color: #c5c5c5;
|
border-color: #c5c5c5;
|
||||||
background: #fff;
|
background: #fff;
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import Checkbox from './common/Checkbox'
|
|||||||
import BigButton from './common/BigButton'
|
import BigButton from './common/BigButton'
|
||||||
import TextInput from './common/TextInput'
|
import TextInput from './common/TextInput'
|
||||||
import HelpButton from './common/HelpButton'
|
import HelpButton from './common/HelpButton'
|
||||||
import { getConfig, saveConfig, setConfigOption } from '../../utils/configuration'
|
import { getConfig, saveConfig, setConfigOption, setProfileOption } from '../../utils/configuration'
|
||||||
import { translate } from '../../utils/language'
|
import { translate } from '../../utils/language'
|
||||||
import { invoke } from '@tauri-apps/api/tauri'
|
import { invoke } from '@tauri-apps/api/tauri'
|
||||||
|
|
||||||
@@ -43,6 +43,8 @@ interface IState {
|
|||||||
migotoSet: boolean
|
migotoSet: boolean
|
||||||
|
|
||||||
unElevated: boolean
|
unElevated: boolean
|
||||||
|
profile: string
|
||||||
|
profiles: string[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class ServerLaunchSection extends React.Component<IProps, IState> {
|
export default class ServerLaunchSection extends React.Component<IProps, IState> {
|
||||||
@@ -66,6 +68,8 @@ export default class ServerLaunchSection extends React.Component<IProps, IState>
|
|||||||
akebiSet: false,
|
akebiSet: false,
|
||||||
migotoSet: false,
|
migotoSet: false,
|
||||||
unElevated: false,
|
unElevated: false,
|
||||||
|
profile: 'default',
|
||||||
|
profiles: ['default'],
|
||||||
}
|
}
|
||||||
|
|
||||||
this.toggleGrasscutter = this.toggleGrasscutter.bind(this)
|
this.toggleGrasscutter = this.toggleGrasscutter.bind(this)
|
||||||
@@ -75,6 +79,7 @@ export default class ServerLaunchSection extends React.Component<IProps, IState>
|
|||||||
this.toggleHttps = this.toggleHttps.bind(this)
|
this.toggleHttps = this.toggleHttps.bind(this)
|
||||||
this.launchServer = this.launchServer.bind(this)
|
this.launchServer = this.launchServer.bind(this)
|
||||||
this.setButtonLabel = this.setButtonLabel.bind(this)
|
this.setButtonLabel = this.setButtonLabel.bind(this)
|
||||||
|
this.setProfile = this.setProfile.bind(this)
|
||||||
|
|
||||||
listen('start_grasscutter', async () => {
|
listen('start_grasscutter', async () => {
|
||||||
this.launchServer()
|
this.launchServer()
|
||||||
@@ -102,6 +107,8 @@ export default class ServerLaunchSection extends React.Component<IProps, IState>
|
|||||||
akebiSet: config.akebi_path !== '',
|
akebiSet: config.akebi_path !== '',
|
||||||
migotoSet: config.migoto_path !== '',
|
migotoSet: config.migoto_path !== '',
|
||||||
unElevated: config.un_elevated || false,
|
unElevated: config.un_elevated || false,
|
||||||
|
profile: config.profile || 'default',
|
||||||
|
profiles: (await this.getProfileList()).map((t) => t),
|
||||||
})
|
})
|
||||||
|
|
||||||
this.setButtonLabel()
|
this.setButtonLabel()
|
||||||
@@ -393,6 +400,25 @@ export default class ServerLaunchSection extends React.Component<IProps, IState>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async setProfile(value: string) {
|
||||||
|
this.setState({ profile: value })
|
||||||
|
await setProfileOption('profile', value)
|
||||||
|
window.location.reload()
|
||||||
|
}
|
||||||
|
|
||||||
|
async getProfileList() {
|
||||||
|
const profiles: string[] = await invoke('get_profile_list', {
|
||||||
|
dataDir: `${await dataDir()}/cultivation`,
|
||||||
|
})
|
||||||
|
const list = ['default']
|
||||||
|
|
||||||
|
profiles.forEach((t) => {
|
||||||
|
list.push(t.split('.json')[0])
|
||||||
|
})
|
||||||
|
|
||||||
|
return list
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<div id="playButton">
|
<div id="playButton">
|
||||||
@@ -403,6 +429,23 @@ export default class ServerLaunchSection extends React.Component<IProps, IState>
|
|||||||
onChange={this.toggleGrasscutter}
|
onChange={this.toggleGrasscutter}
|
||||||
checked={this.state.grasscutterEnabled}
|
checked={this.state.grasscutterEnabled}
|
||||||
/>
|
/>
|
||||||
|
<div className="OptionSection" id="menuOptionsContainerProfiles">
|
||||||
|
<div className="OptionValue" id="menuOptionsSelectProfiles">
|
||||||
|
<select
|
||||||
|
value={this.state.profile}
|
||||||
|
id="menuOptionsSelectMenuProfiles"
|
||||||
|
onChange={(event) => {
|
||||||
|
this.setProfile(event.target.value)
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{this.state.profiles.map((t) => (
|
||||||
|
<option key={t} value={t}>
|
||||||
|
{t}
|
||||||
|
</option>
|
||||||
|
))}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{this.state.grasscutterEnabled && (
|
{this.state.grasscutterEnabled && (
|
||||||
|
|||||||
@@ -20,3 +20,8 @@
|
|||||||
.OptionSection .HelpButton img {
|
.OptionSection .HelpButton img {
|
||||||
filter: invert(0%) sepia(91%) saturate(7464%) hue-rotate(101deg) brightness(0%) contrast(107%);
|
filter: invert(0%) sepia(91%) saturate(7464%) hue-rotate(101deg) brightness(0%) contrast(107%);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
input#profile_name {
|
||||||
|
height: 25px;
|
||||||
|
border-radius: 6px;
|
||||||
|
}
|
||||||
|
|||||||
@@ -4,7 +4,14 @@ import { dataDir } from '@tauri-apps/api/path'
|
|||||||
import DirInput from '../common/DirInput'
|
import DirInput from '../common/DirInput'
|
||||||
import Menu from './Menu'
|
import Menu from './Menu'
|
||||||
import Tr, { getLanguages } from '../../../utils/language'
|
import Tr, { getLanguages } from '../../../utils/language'
|
||||||
import { setConfigOption, getConfig, getConfigOption, Configuration } from '../../../utils/configuration'
|
import {
|
||||||
|
setConfigOption,
|
||||||
|
getConfig,
|
||||||
|
getConfigOption,
|
||||||
|
Configuration,
|
||||||
|
saveNewProfileConfig,
|
||||||
|
setProfileOption,
|
||||||
|
} from '../../../utils/configuration'
|
||||||
import Checkbox from '../common/Checkbox'
|
import Checkbox from '../common/Checkbox'
|
||||||
import Divider from './Divider'
|
import Divider from './Divider'
|
||||||
import { getThemeList } from '../../../utils/themes'
|
import { getThemeList } from '../../../utils/themes'
|
||||||
@@ -57,6 +64,8 @@ interface IState {
|
|||||||
launch_args: string
|
launch_args: string
|
||||||
offline_mode: boolean
|
offline_mode: boolean
|
||||||
newer_game: boolean
|
newer_game: boolean
|
||||||
|
show_version: boolean
|
||||||
|
profile_name: string
|
||||||
|
|
||||||
// Linux stuff
|
// Linux stuff
|
||||||
grasscutter_elevation: string
|
grasscutter_elevation: string
|
||||||
@@ -95,6 +104,8 @@ export default class Options extends React.Component<IProps, IState> {
|
|||||||
launch_args: '',
|
launch_args: '',
|
||||||
offline_mode: false,
|
offline_mode: false,
|
||||||
newer_game: false,
|
newer_game: false,
|
||||||
|
show_version: true,
|
||||||
|
profile_name: '',
|
||||||
|
|
||||||
// Linux stuff
|
// Linux stuff
|
||||||
grasscutter_elevation: GrasscutterElevation.None,
|
grasscutter_elevation: GrasscutterElevation.None,
|
||||||
@@ -118,6 +129,9 @@ export default class Options extends React.Component<IProps, IState> {
|
|||||||
this.addMigotoDelay = this.addMigotoDelay.bind(this)
|
this.addMigotoDelay = this.addMigotoDelay.bind(this)
|
||||||
this.toggleUnElevatedGame = this.toggleUnElevatedGame.bind(this)
|
this.toggleUnElevatedGame = this.toggleUnElevatedGame.bind(this)
|
||||||
this.setLaunchArgs = this.setLaunchArgs.bind(this)
|
this.setLaunchArgs = this.setLaunchArgs.bind(this)
|
||||||
|
this.toggleShowVersion = this.toggleShowVersion.bind(this)
|
||||||
|
this.setProfileName = this.setProfileName.bind(this)
|
||||||
|
this.saveProfile = this.saveProfile.bind(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
async componentDidMount() {
|
async componentDidMount() {
|
||||||
@@ -156,6 +170,7 @@ export default class Options extends React.Component<IProps, IState> {
|
|||||||
launch_args: config.launch_args,
|
launch_args: config.launch_args,
|
||||||
offline_mode: config.offline_mode || false,
|
offline_mode: config.offline_mode || false,
|
||||||
newer_game: config.newer_game || false,
|
newer_game: config.newer_game || false,
|
||||||
|
show_version: config.show_version || false,
|
||||||
|
|
||||||
// Linux stuff
|
// Linux stuff
|
||||||
grasscutter_elevation: config.grasscutter_elevation || GrasscutterElevation.None,
|
grasscutter_elevation: config.grasscutter_elevation || GrasscutterElevation.None,
|
||||||
@@ -350,6 +365,17 @@ export default class Options extends React.Component<IProps, IState> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async toggleShowVersion() {
|
||||||
|
const changedVal = !(await getConfigOption('show_version'))
|
||||||
|
await setConfigOption('show_version', changedVal)
|
||||||
|
|
||||||
|
this.setState({
|
||||||
|
show_version: changedVal,
|
||||||
|
})
|
||||||
|
|
||||||
|
emit('set_config', { show_version: changedVal })
|
||||||
|
}
|
||||||
|
|
||||||
async setGCElevation(value: string) {
|
async setGCElevation(value: string) {
|
||||||
setConfigOption('grasscutter_elevation', value)
|
setConfigOption('grasscutter_elevation', value)
|
||||||
|
|
||||||
@@ -487,6 +513,28 @@ export default class Options extends React.Component<IProps, IState> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setProfileName(text: string) {
|
||||||
|
this.setState({
|
||||||
|
profile_name: text,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async saveProfile() {
|
||||||
|
if (this.state.profile_name == '') {
|
||||||
|
alert('No name set')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const config = await getConfig()
|
||||||
|
await saveNewProfileConfig(config, this.state.profile_name)
|
||||||
|
await setProfileOption('profile', this.state.profile_name)
|
||||||
|
this.setState({
|
||||||
|
profile_name: '',
|
||||||
|
})
|
||||||
|
|
||||||
|
window.location.reload()
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<Menu closeFn={this.props.closeFn} className="Options" heading="Options">
|
<Menu closeFn={this.props.closeFn} className="Options" heading="Options">
|
||||||
@@ -659,6 +707,24 @@ export default class Options extends React.Component<IProps, IState> {
|
|||||||
|
|
||||||
<Divider />
|
<Divider />
|
||||||
|
|
||||||
|
<div className="OptionSection" id="profileConfigContainer">
|
||||||
|
<div className="OptionLabel" id="menuOptionsLabelProfile">
|
||||||
|
<Tr text="options.save_profile" />
|
||||||
|
</div>
|
||||||
|
<TextInput
|
||||||
|
id="profile_name"
|
||||||
|
key="profile_name"
|
||||||
|
placeholder={'Profile name...'}
|
||||||
|
onChange={this.setProfileName}
|
||||||
|
initalValue={''}
|
||||||
|
/>
|
||||||
|
<BigButton onClick={this.saveProfile} id="saveProfile">
|
||||||
|
{'Save'}
|
||||||
|
</BigButton>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Divider />
|
||||||
|
|
||||||
<div className="OptionSection" id="menuOptionsContainerGCWGame">
|
<div className="OptionSection" id="menuOptionsContainerGCWGame">
|
||||||
<div className="OptionLabel" id="menuOptionsLabelGCWDame">
|
<div className="OptionLabel" id="menuOptionsLabelGCWDame">
|
||||||
<Tr text="options.grasscutter_with_game" />
|
<Tr text="options.grasscutter_with_game" />
|
||||||
@@ -711,19 +777,14 @@ export default class Options extends React.Component<IProps, IState> {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div className="OptionSection" id="menuOptionsContainerShowVer">
|
||||||
{/* <div className="OptionSection" id="menuOptionsContainerNewerGame">
|
<div className="OptionLabel" id="menuOptionsLabelShowVer">
|
||||||
<div className="OptionLabel" id="menuOptionsLabelNewerGame">
|
<Tr text="options.show_version" />
|
||||||
<Tr text="Patch Mihoyonet" />
|
|
||||||
</div>
|
</div>
|
||||||
<div className="OptionValue" id="menuOptionsCheckboxNewerGame">
|
<div className="OptionValue" id="menuOptionsButtonShowVer">
|
||||||
<Checkbox
|
<Checkbox onChange={() => this.toggleShowVersion()} checked={this.state.show_version} id="showVer" />
|
||||||
onChange={() => this.toggleOption('newer_game')}
|
|
||||||
checked={this.state?.newer_game}
|
|
||||||
id="newerGame"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</div> */}
|
</div>
|
||||||
|
|
||||||
<Divider />
|
<Divider />
|
||||||
|
|
||||||
|
|||||||
@@ -143,7 +143,7 @@ export default class NewsSection extends React.Component<IProps, IState> {
|
|||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td>
|
||||||
Work in progress area! These numbers may be outdated, so please do not use them as reference. Latest
|
Work in progress area! These numbers may be outdated, so please do not use them as reference. Latest
|
||||||
version: Grasscutter 1.7.4 - Cultivation 1.6.3
|
version: Grasscutter 1.7.4 (4.0) / Forks (6.1) - Cultivation 1.7.0
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -31,6 +31,8 @@ let defaultConfig: Configuration
|
|||||||
launch_args: '',
|
launch_args: '',
|
||||||
offline_mode: false,
|
offline_mode: false,
|
||||||
newer_game: false,
|
newer_game: false,
|
||||||
|
show_version: true,
|
||||||
|
profile: 'default',
|
||||||
|
|
||||||
// Linux stuff
|
// Linux stuff
|
||||||
grasscutter_elevation: 'None',
|
grasscutter_elevation: 'None',
|
||||||
@@ -68,6 +70,8 @@ export interface Configuration {
|
|||||||
launch_args: string
|
launch_args: string
|
||||||
offline_mode: boolean
|
offline_mode: boolean
|
||||||
newer_game: boolean
|
newer_game: boolean
|
||||||
|
show_version: boolean
|
||||||
|
profile: string
|
||||||
|
|
||||||
// Linux stuff
|
// Linux stuff
|
||||||
grasscutter_elevation: string
|
grasscutter_elevation: string
|
||||||
@@ -90,6 +94,15 @@ export async function setConfigOption<K extends keyof Configuration>(key: K, val
|
|||||||
await saveConfig(<Configuration>config)
|
await saveConfig(<Configuration>config)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function setProfileOption<K extends keyof Configuration>(key: K, value: Configuration[K]): Promise<void> {
|
||||||
|
const config = await getConfig()
|
||||||
|
config[key] = value
|
||||||
|
const defaultConfig = await getDefaultConfig()
|
||||||
|
defaultConfig[key] = value
|
||||||
|
|
||||||
|
await saveProfileConfig(<Configuration>defaultConfig)
|
||||||
|
}
|
||||||
|
|
||||||
export async function getConfigOption<K extends keyof Configuration>(key: K): Promise<Configuration[K]> {
|
export async function getConfigOption<K extends keyof Configuration>(key: K): Promise<Configuration[K]> {
|
||||||
const config = await getConfig()
|
const config = await getConfig()
|
||||||
const defaults = defaultConfig
|
const defaults = defaultConfig
|
||||||
@@ -113,16 +126,69 @@ export async function getConfig() {
|
|||||||
return parsed
|
return parsed
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function getDefaultConfig() {
|
||||||
|
const raw = await readDefaultConfigFile()
|
||||||
|
let parsed: Configuration = defaultConfig
|
||||||
|
|
||||||
|
try {
|
||||||
|
parsed = <Configuration>JSON.parse(raw)
|
||||||
|
} catch (e) {
|
||||||
|
// We could not open the file
|
||||||
|
console.log(e)
|
||||||
|
}
|
||||||
|
|
||||||
|
return parsed
|
||||||
|
}
|
||||||
|
|
||||||
export async function saveConfig(obj: Configuration) {
|
export async function saveConfig(obj: Configuration) {
|
||||||
const raw = JSON.stringify(obj)
|
const raw = JSON.stringify(obj)
|
||||||
|
|
||||||
await writeConfigFile(raw)
|
await writeConfigFile(raw)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function saveProfileConfig(obj: Configuration) {
|
||||||
|
const local = await dataDir()
|
||||||
|
const raw = JSON.stringify(obj)
|
||||||
|
const prevPath = configFilePath
|
||||||
|
configFilePath = local + 'cultivation/configuration.json'
|
||||||
|
await writeConfigFile(raw)
|
||||||
|
|
||||||
|
configFilePath = prevPath
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function saveNewProfileConfig(obj: Configuration, prof: string) {
|
||||||
|
obj['profile'] = prof
|
||||||
|
const local = await dataDir()
|
||||||
|
const raw = JSON.stringify(obj)
|
||||||
|
configFilePath = local + 'cultivation/profiles/' + obj['profile'] + '.json'
|
||||||
|
|
||||||
|
const file: fs.FsTextFileOption = {
|
||||||
|
path: configFilePath,
|
||||||
|
contents: raw,
|
||||||
|
}
|
||||||
|
|
||||||
|
await fs.writeFile(file)
|
||||||
|
}
|
||||||
|
|
||||||
async function readConfigFile() {
|
async function readConfigFile() {
|
||||||
const local = await dataDir()
|
const local = await dataDir()
|
||||||
|
|
||||||
if (!configFilePath) configFilePath = local + 'cultivation/configuration.json'
|
if (!configFilePath) {
|
||||||
|
configFilePath = local + 'cultivation/configuration.json'
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read existing config to get profile name
|
||||||
|
const raw = await fs.readTextFile(configFilePath)
|
||||||
|
const cfg = <Configuration>JSON.parse(raw)
|
||||||
|
// Switch file to config-specified profile
|
||||||
|
let pf = cfg['profile']
|
||||||
|
if (pf != 'default') {
|
||||||
|
const pff = pf
|
||||||
|
pf = 'profiles/' + pff + '.json'
|
||||||
|
} else {
|
||||||
|
pf = 'configuration.json'
|
||||||
|
}
|
||||||
|
configFilePath = local + 'cultivation/' + pf
|
||||||
|
|
||||||
// Ensure Cultivation dir exists
|
// Ensure Cultivation dir exists
|
||||||
const dirs = await fs.readDir(local)
|
const dirs = await fs.readDir(local)
|
||||||
@@ -157,6 +223,12 @@ async function readConfigFile() {
|
|||||||
return await fs.readTextFile(configFilePath)
|
return await fs.readTextFile(configFilePath)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function readDefaultConfigFile() {
|
||||||
|
const local = await dataDir()
|
||||||
|
configFilePath = local + 'cultivation/configuration.json'
|
||||||
|
return await fs.readTextFile(configFilePath)
|
||||||
|
}
|
||||||
|
|
||||||
async function writeConfigFile(raw: string) {
|
async function writeConfigFile(raw: string) {
|
||||||
// All external config functions call readConfigFile, which ensure files exists
|
// All external config functions call readConfigFile, which ensure files exists
|
||||||
await fs.writeFile({
|
await fs.writeFile({
|
||||||
|
|||||||
Reference in New Issue
Block a user