mirror of
https://github.com/Grasscutters/Cultivation.git
synced 2025-12-13 15:44:35 +01:00
Compare commits
9 Commits
v1.0.3-alp
...
resource_c
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b0c545d032 | ||
|
|
88dd7b854f | ||
|
|
e159bc2cdb | ||
|
|
cc4600ec77 | ||
|
|
f37e44a88c | ||
|
|
4f806efc93 | ||
|
|
083de896b3 | ||
|
|
9c64c1f282 | ||
|
|
aa10a908ad |
@@ -14,6 +14,8 @@
|
|||||||
"enabled": "Enabled",
|
"enabled": "Enabled",
|
||||||
"disabled": "Disabled",
|
"disabled": "Disabled",
|
||||||
"game_exec": "Set Game Executable",
|
"game_exec": "Set Game Executable",
|
||||||
|
"game_version": "Set Game Version",
|
||||||
|
"emergency_metadata": "Emergency Metadata Restore",
|
||||||
"grasscutter_jar": "Set Grasscutter JAR",
|
"grasscutter_jar": "Set Grasscutter JAR",
|
||||||
"toggle_encryption": "Toggle Encryption",
|
"toggle_encryption": "Toggle Encryption",
|
||||||
"java_path": "Set Custom Java Path",
|
"java_path": "Set Custom Java Path",
|
||||||
|
|||||||
@@ -49,7 +49,8 @@ fn main() {
|
|||||||
downloader::stop_download,
|
downloader::stop_download,
|
||||||
lang::get_lang,
|
lang::get_lang,
|
||||||
lang::get_languages,
|
lang::get_languages,
|
||||||
web::valid_url
|
web::valid_url,
|
||||||
|
web::web_get
|
||||||
])
|
])
|
||||||
.run(tauri::generate_context!())
|
.run(tauri::generate_context!())
|
||||||
.expect("error while running tauri application");
|
.expect("error while running tauri application");
|
||||||
|
|||||||
@@ -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();
|
let response = client.get(url).header(USER_AGENT, "cultivation").send().await.unwrap();
|
||||||
|
|
||||||
response.status().as_str() == "200"
|
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
|
||||||
}
|
}
|
||||||
@@ -115,9 +115,9 @@ export default class TopBar extends React.Component<IProps, IState> {
|
|||||||
<div id="downloadsBtn" className='TopButton' onClick={this.props.downFunc}>
|
<div id="downloadsBtn" className='TopButton' onClick={this.props.downFunc}>
|
||||||
<img src={downBtn} alt="downloads" />
|
<img src={downBtn} alt="downloads" />
|
||||||
</div>
|
</div>
|
||||||
{/* <div id="gameBtn" className="TopButton" onClick={this.props.gameFunc}>
|
<div id="gameBtn" className="TopButton" onClick={this.props.gameFunc}>
|
||||||
<img src={gameBtn} alt="game" />
|
<img src={gameBtn} alt="game" />
|
||||||
</div> */}
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -12,12 +12,7 @@ import { getConfigOption, setConfigOption } from '../../../utils/configuration'
|
|||||||
import { invoke } from '@tauri-apps/api'
|
import { invoke } from '@tauri-apps/api'
|
||||||
import { listen } from '@tauri-apps/api/event'
|
import { listen } from '@tauri-apps/api/event'
|
||||||
import HelpButton from '../common/HelpButton'
|
import HelpButton from '../common/HelpButton'
|
||||||
|
import { getVersionCache, VersionData } from '../../../utils/resources'
|
||||||
const STABLE_REPO_DOWNLOAD = 'https://github.com/Grasscutters/Grasscutter/archive/refs/heads/stable.zip'
|
|
||||||
const DEV_REPO_DOWNLOAD = 'https://github.com/Grasscutters/Grasscutter/archive/refs/heads/development.zip'
|
|
||||||
const STABLE_DOWNLOAD = 'https://nightly.link/Grasscutters/Grasscutter/workflows/build/stable/Grasscutter.zip'
|
|
||||||
const DEV_DOWNLOAD = 'https://nightly.link/Grasscutters/Grasscutter/workflows/build/development/Grasscutter.zip'
|
|
||||||
const RESOURCES_DOWNLOAD = 'https://github.com/Koko-boya/Grasscutter_Resources/archive/refs/heads/main.zip'
|
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
closeFn: () => void;
|
closeFn: () => void;
|
||||||
@@ -30,6 +25,7 @@ interface IState {
|
|||||||
repo_downloading: boolean
|
repo_downloading: boolean
|
||||||
grasscutter_set: boolean
|
grasscutter_set: boolean
|
||||||
resources_exist: boolean
|
resources_exist: boolean
|
||||||
|
version_data: VersionData | null
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class Downloads extends React.Component<IProps, IState> {
|
export default class Downloads extends React.Component<IProps, IState> {
|
||||||
@@ -41,7 +37,8 @@ export default class Downloads extends React.Component<IProps, IState> {
|
|||||||
resources_downloading: this.props.downloadManager.downloadingResources(),
|
resources_downloading: this.props.downloadManager.downloadingResources(),
|
||||||
repo_downloading: this.props.downloadManager.downloadingRepo(),
|
repo_downloading: this.props.downloadManager.downloadingRepo(),
|
||||||
grasscutter_set: false,
|
grasscutter_set: false,
|
||||||
resources_exist: false
|
resources_exist: false,
|
||||||
|
version_data: null
|
||||||
}
|
}
|
||||||
|
|
||||||
this.getGrasscutterFolder = this.getGrasscutterFolder.bind(this)
|
this.getGrasscutterFolder = this.getGrasscutterFolder.bind(this)
|
||||||
@@ -55,6 +52,11 @@ export default class Downloads extends React.Component<IProps, IState> {
|
|||||||
|
|
||||||
async componentDidMount() {
|
async componentDidMount() {
|
||||||
const gc_path = await getConfigOption('grasscutter_path')
|
const gc_path = await getConfigOption('grasscutter_path')
|
||||||
|
const versionData = await getVersionCache()
|
||||||
|
|
||||||
|
this.setState({
|
||||||
|
version_data: versionData,
|
||||||
|
})
|
||||||
|
|
||||||
listen('jar_extracted', () => {
|
listen('jar_extracted', () => {
|
||||||
this.setState({ grasscutter_set: true }, this.forceUpdate)
|
this.setState({ grasscutter_set: true }, this.forceUpdate)
|
||||||
@@ -109,7 +111,7 @@ export default class Downloads extends React.Component<IProps, IState> {
|
|||||||
|
|
||||||
async downloadGrasscutterStableRepo() {
|
async downloadGrasscutterStableRepo() {
|
||||||
const folder = await this.getGrasscutterFolder()
|
const folder = await this.getGrasscutterFolder()
|
||||||
this.props.downloadManager.addDownload(STABLE_REPO_DOWNLOAD, folder + '\\grasscutter_repo.zip', () =>{
|
this.props.downloadManager.addDownload(this.state.version_data?.stable, folder + '\\grasscutter_repo.zip', () =>{
|
||||||
unzip(folder + '\\grasscutter_repo.zip', folder + '\\', this.toggleButtons)
|
unzip(folder + '\\grasscutter_repo.zip', folder + '\\', this.toggleButtons)
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -118,7 +120,7 @@ export default class Downloads extends React.Component<IProps, IState> {
|
|||||||
|
|
||||||
async downloadGrasscutterDevRepo() {
|
async downloadGrasscutterDevRepo() {
|
||||||
const folder = await this.getGrasscutterFolder()
|
const folder = await this.getGrasscutterFolder()
|
||||||
this.props.downloadManager.addDownload(DEV_REPO_DOWNLOAD, folder + '\\grasscutter_repo.zip', () =>{
|
this.props.downloadManager.addDownload(this.state.version_data?.dev, folder + '\\grasscutter_repo.zip', () =>{
|
||||||
unzip(folder + '\\grasscutter_repo.zip', folder + '\\', this.toggleButtons)
|
unzip(folder + '\\grasscutter_repo.zip', folder + '\\', this.toggleButtons)
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -127,7 +129,7 @@ export default class Downloads extends React.Component<IProps, IState> {
|
|||||||
|
|
||||||
async downloadGrasscutterStable() {
|
async downloadGrasscutterStable() {
|
||||||
const folder = await this.getGrasscutterFolder()
|
const folder = await this.getGrasscutterFolder()
|
||||||
this.props.downloadManager.addDownload(STABLE_DOWNLOAD, folder + '\\grasscutter.zip', () =>{
|
this.props.downloadManager.addDownload(this.state.version_data?.stableJar, folder + '\\grasscutter.zip', () =>{
|
||||||
unzip(folder + '\\grasscutter.zip', folder + '\\', this.toggleButtons)
|
unzip(folder + '\\grasscutter.zip', folder + '\\', this.toggleButtons)
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -139,7 +141,7 @@ export default class Downloads extends React.Component<IProps, IState> {
|
|||||||
|
|
||||||
async downloadGrasscutterLatest() {
|
async downloadGrasscutterLatest() {
|
||||||
const folder = await this.getGrasscutterFolder()
|
const folder = await this.getGrasscutterFolder()
|
||||||
this.props.downloadManager.addDownload(DEV_DOWNLOAD, folder + '\\grasscutter.zip', () =>{
|
this.props.downloadManager.addDownload(this.state.version_data?.devJar, folder + '\\grasscutter.zip', () =>{
|
||||||
unzip(folder + '\\grasscutter.zip', folder + '\\', this.toggleButtons)
|
unzip(folder + '\\grasscutter.zip', folder + '\\', this.toggleButtons)
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -151,7 +153,7 @@ export default class Downloads extends React.Component<IProps, IState> {
|
|||||||
|
|
||||||
async downloadResources() {
|
async downloadResources() {
|
||||||
const folder = await this.getGrasscutterFolder()
|
const folder = await this.getGrasscutterFolder()
|
||||||
this.props.downloadManager.addDownload(RESOURCES_DOWNLOAD, folder + '\\resources.zip', async () => {
|
this.props.downloadManager.addDownload(this.state.version_data?.resources, folder + '\\resources.zip', async () => {
|
||||||
// Delete the existing folder if it exists
|
// Delete the existing folder if it exists
|
||||||
if (await invoke('dir_exists', {
|
if (await invoke('dir_exists', {
|
||||||
path: folder + '\\resources'
|
path: folder + '\\resources'
|
||||||
@@ -200,7 +202,7 @@ export default class Downloads extends React.Component<IProps, IState> {
|
|||||||
</HelpButton>
|
</HelpButton>
|
||||||
</div>
|
</div>
|
||||||
<div className='DownloadValue' id="downloadMenuButtonGCStable">
|
<div className='DownloadValue' id="downloadMenuButtonGCStable">
|
||||||
<BigButton disabled={this.state.grasscutter_downloading} onClick={this.downloadGrasscutterStable} id="grasscutterStableBtn" >
|
<BigButton disabled={this.state.grasscutter_downloading || !this.state.version_data?.stableJar} onClick={this.downloadGrasscutterStable} id="grasscutterStableBtn" >
|
||||||
<Tr text="components.download" />
|
<Tr text="components.download" />
|
||||||
</BigButton>
|
</BigButton>
|
||||||
</div>
|
</div>
|
||||||
@@ -215,7 +217,7 @@ export default class Downloads extends React.Component<IProps, IState> {
|
|||||||
</HelpButton>
|
</HelpButton>
|
||||||
</div>
|
</div>
|
||||||
<div className='DownloadValue' id="downloadMenuButtonGCDev">
|
<div className='DownloadValue' id="downloadMenuButtonGCDev">
|
||||||
<BigButton disabled={this.state.grasscutter_downloading} onClick={this.downloadGrasscutterLatest} id="grasscutterLatestBtn" >
|
<BigButton disabled={this.state.grasscutter_downloading || !this.state.version_data?.devJar} onClick={this.downloadGrasscutterLatest} id="grasscutterLatestBtn" >
|
||||||
<Tr text="components.download" />
|
<Tr text="components.download" />
|
||||||
</BigButton>
|
</BigButton>
|
||||||
</div>
|
</div>
|
||||||
@@ -233,7 +235,7 @@ export default class Downloads extends React.Component<IProps, IState> {
|
|||||||
</HelpButton>
|
</HelpButton>
|
||||||
</div>
|
</div>
|
||||||
<div className='DownloadValue' id="downloadMenuButtonGCStableData">
|
<div className='DownloadValue' id="downloadMenuButtonGCStableData">
|
||||||
<BigButton disabled={this.state.repo_downloading} onClick={this.downloadGrasscutterStableRepo} id="grasscutterStableRepo" >
|
<BigButton disabled={this.state.repo_downloading || !this.state.version_data?.stable} onClick={this.downloadGrasscutterStableRepo} id="grasscutterStableRepo" >
|
||||||
<Tr text="components.download" />
|
<Tr text="components.download" />
|
||||||
</BigButton>
|
</BigButton>
|
||||||
</div>
|
</div>
|
||||||
@@ -248,7 +250,7 @@ export default class Downloads extends React.Component<IProps, IState> {
|
|||||||
</HelpButton>
|
</HelpButton>
|
||||||
</div>
|
</div>
|
||||||
<div className='DownloadValue' id="downloadMenuButtonGCDevData">
|
<div className='DownloadValue' id="downloadMenuButtonGCDevData">
|
||||||
<BigButton disabled={this.state.repo_downloading} onClick={this.downloadGrasscutterStableRepo} id="grasscutterDevRepo" >
|
<BigButton disabled={this.state.repo_downloading || !this.state.version_data?.dev} onClick={this.downloadGrasscutterStableRepo} id="grasscutterDevRepo" >
|
||||||
<Tr text="components.download" />
|
<Tr text="components.download" />
|
||||||
</BigButton>
|
</BigButton>
|
||||||
</div>
|
</div>
|
||||||
@@ -264,7 +266,11 @@ export default class Downloads extends React.Component<IProps, IState> {
|
|||||||
</HelpButton>
|
</HelpButton>
|
||||||
</div>
|
</div>
|
||||||
<div className='DownloadValue' id="downloadMenuButtonResources">
|
<div className='DownloadValue' id="downloadMenuButtonResources">
|
||||||
<BigButton disabled={this.state.resources_downloading || !this.state.grasscutter_set || this.state.resources_exist} onClick={this.downloadResources} id="resourcesBtn" >
|
<BigButton disabled={
|
||||||
|
this.state.resources_downloading
|
||||||
|
|| !this.state.grasscutter_set
|
||||||
|
|| this.state.resources_exist
|
||||||
|
|| !this.state.version_data?.resources} onClick={this.downloadResources} id="resourcesBtn" >
|
||||||
<Tr text="components.download" />
|
<Tr text="components.download" />
|
||||||
</BigButton>
|
</BigButton>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -8,8 +8,7 @@ import DirInput from '../common/DirInput'
|
|||||||
import BigButton from '../common/BigButton'
|
import BigButton from '../common/BigButton'
|
||||||
import HelpButton from '../common/HelpButton'
|
import HelpButton from '../common/HelpButton'
|
||||||
import { unzip } from '../../../utils/zipUtils'
|
import { unzip } from '../../../utils/zipUtils'
|
||||||
|
import { getVersionCache } from '../../../utils/resources'
|
||||||
const GAME_DOWNLOAD = ''
|
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
closeFn: () => void;
|
closeFn: () => void;
|
||||||
@@ -20,6 +19,7 @@ interface IState {
|
|||||||
gameDownloading: boolean;
|
gameDownloading: boolean;
|
||||||
gameDownloadFolder: string;
|
gameDownloadFolder: string;
|
||||||
dirPlaceholder: string;
|
dirPlaceholder: string;
|
||||||
|
clientDownloadLink: string | null | undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class Downloads extends React.Component<IProps, IState> {
|
export default class Downloads extends React.Component<IProps, IState> {
|
||||||
@@ -29,23 +29,25 @@ export default class Downloads extends React.Component<IProps, IState> {
|
|||||||
this.state = {
|
this.state = {
|
||||||
gameDownloading: false,
|
gameDownloading: false,
|
||||||
gameDownloadFolder: '',
|
gameDownloadFolder: '',
|
||||||
dirPlaceholder: ''
|
dirPlaceholder: '',
|
||||||
|
clientDownloadLink: ''
|
||||||
}
|
}
|
||||||
|
|
||||||
this.downloadGame = this.downloadGame.bind(this)
|
this.downloadGame = this.downloadGame.bind(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
async componentDidMount() {
|
async componentDidMount() {
|
||||||
this.setState({
|
const versionCache = await getVersionCache()
|
||||||
dirPlaceholder: await translate('components.select_folder')
|
|
||||||
})
|
|
||||||
|
|
||||||
console.log(this.state)
|
this.setState({
|
||||||
|
dirPlaceholder: await translate('components.select_folder'),
|
||||||
|
clientDownloadLink: versionCache?.client_download_link
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async downloadGame() {
|
async downloadGame() {
|
||||||
const folder = this.state.gameDownloadFolder
|
const folder = this.state.gameDownloadFolder
|
||||||
this.props.downloadManager.addDownload(GAME_DOWNLOAD, folder + '\\game.zip', () =>{
|
this.props.downloadManager.addDownload(this.state.clientDownloadLink, folder + '\\game.zip', () =>{
|
||||||
unzip(folder + '\\game.zip', folder + '\\', () => {
|
unzip(folder + '\\game.zip', folder + '\\', () => {
|
||||||
this.setState({
|
this.setState({
|
||||||
gameDownloading: false
|
gameDownloading: false
|
||||||
@@ -63,7 +65,7 @@ export default class Downloads extends React.Component<IProps, IState> {
|
|||||||
<Menu heading='Download Game' closeFn={this.props.closeFn} className="GameDownloadMenu">
|
<Menu heading='Download Game' closeFn={this.props.closeFn} className="GameDownloadMenu">
|
||||||
<div className="GameDownload">
|
<div className="GameDownload">
|
||||||
{
|
{
|
||||||
this.state.gameDownloadFolder !== '' && !this.state.gameDownloading ?
|
this.state.gameDownloadFolder !== '' && !this.state.gameDownloading && this.state.clientDownloadLink ?
|
||||||
<BigButton id="downloadGameBtn" onClick={this.downloadGame}>Download Game</BigButton>
|
<BigButton id="downloadGameBtn" onClick={this.downloadGame}>Download Game</BigButton>
|
||||||
: <BigButton id="disabledGameBtn" onClick={() => null} disabled>Download Game</BigButton>
|
: <BigButton id="disabledGameBtn" onClick={() => null} disabled>Download Game</BigButton>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import * as server from '../../../utils/server'
|
|||||||
|
|
||||||
import './Options.css'
|
import './Options.css'
|
||||||
import BigButton from '../common/BigButton'
|
import BigButton from '../common/BigButton'
|
||||||
|
import { cacheLauncherResources, getVersionCache, getVersions } from '../../../utils/resources'
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
closeFn: () => void;
|
closeFn: () => void;
|
||||||
@@ -20,6 +21,8 @@ interface IProps {
|
|||||||
interface IState {
|
interface IState {
|
||||||
game_install_path: string
|
game_install_path: string
|
||||||
grasscutter_path: string
|
grasscutter_path: string
|
||||||
|
client_version: string
|
||||||
|
meta_download: string | null | undefined
|
||||||
java_path: string
|
java_path: string
|
||||||
grasscutter_with_game: boolean
|
grasscutter_with_game: boolean
|
||||||
language_options: { [key: string]: string }[],
|
language_options: { [key: string]: string }[],
|
||||||
@@ -41,6 +44,8 @@ export default class Options extends React.Component<IProps, IState> {
|
|||||||
this.state = {
|
this.state = {
|
||||||
game_install_path: '',
|
game_install_path: '',
|
||||||
grasscutter_path: '',
|
grasscutter_path: '',
|
||||||
|
client_version: '',
|
||||||
|
meta_download: '',
|
||||||
java_path: '',
|
java_path: '',
|
||||||
grasscutter_with_game: false,
|
grasscutter_with_game: false,
|
||||||
language_options: [],
|
language_options: [],
|
||||||
@@ -58,6 +63,7 @@ export default class Options extends React.Component<IProps, IState> {
|
|||||||
this.setGameExec = this.setGameExec.bind(this)
|
this.setGameExec = this.setGameExec.bind(this)
|
||||||
this.setGrasscutterJar = this.setGrasscutterJar.bind(this)
|
this.setGrasscutterJar = this.setGrasscutterJar.bind(this)
|
||||||
this.setJavaPath = this.setJavaPath.bind(this)
|
this.setJavaPath = this.setJavaPath.bind(this)
|
||||||
|
this.setClientVersion = this.setClientVersion.bind(this)
|
||||||
this.setAkebi = this.setAkebi.bind(this)
|
this.setAkebi = this.setAkebi.bind(this)
|
||||||
this.toggleGrasscutterWithGame = this.toggleGrasscutterWithGame.bind(this)
|
this.toggleGrasscutterWithGame = this.toggleGrasscutterWithGame.bind(this)
|
||||||
this.setCustomBackground = this.setCustomBackground.bind(this)
|
this.setCustomBackground = this.setCustomBackground.bind(this)
|
||||||
@@ -77,6 +83,8 @@ export default class Options extends React.Component<IProps, IState> {
|
|||||||
game_install_path: config.game_install_path || '',
|
game_install_path: config.game_install_path || '',
|
||||||
grasscutter_path: config.grasscutter_path || '',
|
grasscutter_path: config.grasscutter_path || '',
|
||||||
java_path: config.java_path || '',
|
java_path: config.java_path || '',
|
||||||
|
client_version: config.client_version || '',
|
||||||
|
meta_download: (await getVersionCache())?.metadata_backup_link || '',
|
||||||
grasscutter_with_game: config.grasscutter_with_game || false,
|
grasscutter_with_game: config.grasscutter_with_game || false,
|
||||||
language_options: languages,
|
language_options: languages,
|
||||||
current_language: config.language || 'en',
|
current_language: config.language || 'en',
|
||||||
@@ -101,6 +109,17 @@ export default class Options extends React.Component<IProps, IState> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async setClientVersion(value: string) {
|
||||||
|
await setConfigOption('client_version', value)
|
||||||
|
|
||||||
|
const newCache = await cacheLauncherResources()
|
||||||
|
|
||||||
|
this.setState({
|
||||||
|
client_version: value,
|
||||||
|
meta_download: newCache?.metadata_backup_link
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
setGrasscutterJar(value: string) {
|
setGrasscutterJar(value: string) {
|
||||||
setConfigOption('grasscutter_path', value)
|
setConfigOption('grasscutter_path', value)
|
||||||
|
|
||||||
@@ -199,16 +218,49 @@ export default class Options extends React.Component<IProps, IState> {
|
|||||||
<DirInput onChange={this.setGameExec} value={this.state?.game_install_path} extensions={['exe']} />
|
<DirInput onChange={this.setGameExec} value={this.state?.game_install_path} extensions={['exe']} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div className='OptionSection' id="menuOptionsContainerClientVersion">
|
||||||
|
<div className='OptionLabel' id="menuOptionsLabelClientVersion">
|
||||||
|
<Tr text="options.game_version" />
|
||||||
|
</div>
|
||||||
|
<div className='OptionValue' id="menuOptionsDirClientVersion">
|
||||||
|
<select value={this.state.client_version} id="menuOptionsSelectMenuThemes" onChange={(event) => {
|
||||||
|
this.setClientVersion(event.target.value)
|
||||||
|
}}>
|
||||||
|
{getVersions().map(t => (
|
||||||
|
<option
|
||||||
|
key={t}
|
||||||
|
value={t}>
|
||||||
|
|
||||||
|
{t}
|
||||||
|
</option>
|
||||||
|
))}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className='OptionSection' id="menuOptionsContainerMetadataDownload">
|
||||||
|
<div className='OptionLabel' id="menuOptionsLabelMetadataDownload">
|
||||||
|
<Tr text="options.emergency_metadata" />
|
||||||
|
</div>
|
||||||
|
<div className='OptionValue' id="menuOptionsButtonMetadataDownload">
|
||||||
|
<BigButton disabled={this.state.meta_download === ''} onClick={this.toggleEncryption} id="toggleEnc">
|
||||||
|
<Tr text='components.download' />
|
||||||
|
</BigButton>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
{
|
{
|
||||||
this.state.swag && (
|
this.state.swag && (
|
||||||
<div className='OptionSection' id="menuOptionsContainerAkebi">
|
<>
|
||||||
<div className='OptionLabel' id="menuOptionsLabelAkebi">
|
<Divider />
|
||||||
<Tr text="swag.akebi" />
|
<div className='OptionSection' id="menuOptionsContainerAkebi">
|
||||||
|
<div className='OptionLabel' id="menuOptionsLabelAkebi">
|
||||||
|
<Tr text="swag.akebi" />
|
||||||
|
</div>
|
||||||
|
<div className='OptionValue' id="menuOptionsDirAkebi">
|
||||||
|
<DirInput onChange={this.setAkebi} value={this.state?.akebi_path} extensions={['exe']} />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className='OptionValue' id="menuOptionsDirAkebi">
|
<Divider />
|
||||||
<DirInput onChange={this.setAkebi} value={this.state?.akebi_path} extensions={['exe']} />
|
</>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
<div className='OptionSection' id="menuOptionsContainerGCJar">
|
<div className='OptionSection' id="menuOptionsContainerGCJar">
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { fs } from '@tauri-apps/api'
|
import { fs } from '@tauri-apps/api'
|
||||||
import { dataDir } from '@tauri-apps/api/path'
|
import { dataDir } from '@tauri-apps/api/path'
|
||||||
|
import { cacheLauncherResources } from './resources'
|
||||||
|
|
||||||
let configFilePath: string
|
let configFilePath: string
|
||||||
let defaultConfig: Configuration
|
let defaultConfig: Configuration
|
||||||
@@ -17,6 +18,7 @@ let defaultConfig: Configuration
|
|||||||
last_port: '443',
|
last_port: '443',
|
||||||
language: 'en',
|
language: 'en',
|
||||||
customBackground: '',
|
customBackground: '',
|
||||||
|
client_version: '2.7.0',
|
||||||
cert_generated: false,
|
cert_generated: false,
|
||||||
theme: 'default',
|
theme: 'default',
|
||||||
https_enabled: false,
|
https_enabled: false,
|
||||||
@@ -39,6 +41,7 @@ export interface Configuration {
|
|||||||
last_port: string
|
last_port: string
|
||||||
language: string
|
language: string
|
||||||
customBackground: string
|
customBackground: string
|
||||||
|
client_version: string
|
||||||
cert_generated: boolean
|
cert_generated: boolean
|
||||||
theme: string
|
theme: string
|
||||||
https_enabled: boolean
|
https_enabled: boolean
|
||||||
@@ -116,6 +119,12 @@ async function readConfigFile() {
|
|||||||
contents: JSON.stringify(defaultConfig)
|
contents: JSON.stringify(defaultConfig)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Also just shoe-horning this in, cache resources on first launch
|
||||||
|
const versionData = await cacheLauncherResources()
|
||||||
|
|
||||||
|
defaultConfig.client_version = versionData?.game || ''
|
||||||
|
|
||||||
|
// Write config
|
||||||
await fs.writeFile(file)
|
await fs.writeFile(file)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -107,7 +107,9 @@ export default class DownloadHandler {
|
|||||||
return this.downloads.some(d => d.path.includes('grasscutter_repo.zip'))
|
return this.downloads.some(d => d.path.includes('grasscutter_repo.zip'))
|
||||||
}
|
}
|
||||||
|
|
||||||
addDownload(url: string, path: string, onFinish?: () => void) {
|
addDownload(url: string | null | undefined, path: string, onFinish?: () => void) {
|
||||||
|
if (!url) return
|
||||||
|
|
||||||
// Begin download from rust backend, don't add if the download addition fails
|
// Begin download from rust backend, don't add if the download addition fails
|
||||||
invoke('download_file', { url, path })
|
invoke('download_file', { url, path })
|
||||||
const obj = {
|
const obj = {
|
||||||
|
|||||||
106
src/utils/resources.ts
Normal file
106
src/utils/resources.ts
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
import { fs, invoke } from '@tauri-apps/api'
|
||||||
|
import { dataDir } from '@tauri-apps/api/path'
|
||||||
|
import { getConfig } from './configuration'
|
||||||
|
|
||||||
|
export interface VersionData {
|
||||||
|
game: string
|
||||||
|
metadata: string | null
|
||||||
|
metadata_backup_link: string | null
|
||||||
|
client_download_link: string | null
|
||||||
|
resources: string
|
||||||
|
stableJar: string | null
|
||||||
|
devJar: string | null
|
||||||
|
stable: string | null
|
||||||
|
dev: string | null
|
||||||
|
}
|
||||||
|
|
||||||
|
const globals: {
|
||||||
|
[key: string]: VersionData
|
||||||
|
} = {
|
||||||
|
'2.8.0': {
|
||||||
|
game: '2.8.0',
|
||||||
|
metadata: '2.8.0',
|
||||||
|
metadata_backup_link: null,
|
||||||
|
client_download_link: null,
|
||||||
|
resources: 'https://gitlab.com/yukiz/GrasscutterResources/-/archive/2.8/GrasscutterResources-2.8.zip',
|
||||||
|
stableJar: null,
|
||||||
|
devJar: 'https://nightly.link/Grasscutters/Grasscutter/actions/runs/2661955213/Grasscutter.zip',
|
||||||
|
stable: null,
|
||||||
|
dev: 'https://github.com/Grasscutters/Grasscutter/archive/refs/heads/2.8.zip'
|
||||||
|
},
|
||||||
|
'2.7.0': {
|
||||||
|
game: '2.7.0',
|
||||||
|
metadata: null,
|
||||||
|
metadata_backup_link: null,
|
||||||
|
client_download_link: null,
|
||||||
|
resources: 'https://github.com/Koko-boya/Grasscutter_Resources/archive/refs/heads/main.zip',
|
||||||
|
stableJar: 'https://nightly.link/Grasscutters/Grasscutter/workflows/build/stable/Grasscutter.zip',
|
||||||
|
devJar: 'https://nightly.link/Grasscutters/Grasscutter/workflows/build/development/Grasscutter.zip',
|
||||||
|
stable: 'https://github.com/Grasscutters/Grasscutter/archive/refs/heads/stable.zip',
|
||||||
|
dev: 'https://github.com/Grasscutters/Grasscutter/archive/refs/heads/development.zip'
|
||||||
|
},
|
||||||
|
'2.6.0': {
|
||||||
|
game: '2.6.0',
|
||||||
|
metadata: null,
|
||||||
|
metadata_backup_link: null,
|
||||||
|
client_download_link: null,
|
||||||
|
resources: 'https://github.com/Koko-boya/Grasscutter_Resources/archive/0e99a59218a346c2d56c54953f99077882de4a6d.zip',
|
||||||
|
stableJar: 'https://github.com/Grasscutters/Grasscutter/releases/download/v1.1.0/grasscutter-1.1.0.jar',
|
||||||
|
devJar: null,
|
||||||
|
stable: 'https://github.com/Grasscutters/Grasscutter/archive/refs/heads/2.6.zip',
|
||||||
|
dev: null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function cacheLauncherResources() {
|
||||||
|
const config = await getConfig()
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
const selectedVersion = config.client_version || versions.data.game.latest.version
|
||||||
|
const selectedVersionData = globals[selectedVersion]
|
||||||
|
|
||||||
|
if (!selectedVersionData) {
|
||||||
|
console.log('Failed to get version for selected version')
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
const latest = versions.data.game.latest
|
||||||
|
const latestData = globals[latest.version]
|
||||||
|
|
||||||
|
if (latestData) {
|
||||||
|
latestData.metadata_backup_link = latest.decompressed_path + '/GenshinImpact_Data/Managed/Metadata/global-metadata.dat'
|
||||||
|
latestData.client_download_link = latest.path
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write
|
||||||
|
fs.writeFile({
|
||||||
|
path: await dataDir() + 'cultivation/resources.json',
|
||||||
|
contents: JSON.stringify(selectedVersionData)
|
||||||
|
})
|
||||||
|
|
||||||
|
// In case we want to get it right away too
|
||||||
|
return selectedVersionData
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getVersionCache() {
|
||||||
|
const raw = await fs.readTextFile(await dataDir() + 'cultivation/resources.json').catch(e => {
|
||||||
|
console.log(e)
|
||||||
|
return null
|
||||||
|
})
|
||||||
|
|
||||||
|
return raw ? JSON.parse(raw) as VersionData : null
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getVersions() {
|
||||||
|
return Object.keys(globals)
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user