feat: launch, download info

This commit is contained in:
Artemy 2023-06-20 16:19:36 +03:00
parent 771520dcbd
commit 63c9bbf2e6
13 changed files with 183 additions and 16 deletions

2
.gitignore vendored
View file

@ -126,3 +126,5 @@ dist
.yarn/build-state.yml .yarn/build-state.yml
.yarn/install-state.gz .yarn/install-state.gz
.pnp.* .pnp.*
.pimi

View file

@ -15,7 +15,7 @@ module.exports = async (context) => {
return return
} }
const appId = 'com.electron.app' const appId = 'com.pimi-launcher.app'
const { appOutDir } = context const { appOutDir } = context

View file

@ -1,4 +1,4 @@
appId: com.electron.app appId: com.pimi-launcher.app
productName: pimi-launcher productName: pimi-launcher
directories: directories:
buildResources: build buildResources: build

View file

@ -18,7 +18,7 @@ import { defineConfig, externalizeDepsPlugin } from 'electron-vite'
import react from '@vitejs/plugin-react' import react from '@vitejs/plugin-react'
import commonjsExternals from 'vite-plugin-commonjs-externals' import commonjsExternals from 'vite-plugin-commonjs-externals'
const externals = ['pimi-launcher-core'] const externals = ['pimi-launcher-core', 'path']
export default defineConfig({ export default defineConfig({
main: { main: {

57
package-lock.json generated
View file

@ -20,6 +20,7 @@
"devDependencies": { "devDependencies": {
"@electron/notarize": "^1.2.3", "@electron/notarize": "^1.2.3",
"@vitejs/plugin-react": "^4.0.0", "@vitejs/plugin-react": "^4.0.0",
"autoprefixer": "^10.4.14",
"electron": "^24.4.1", "electron": "^24.4.1",
"electron-builder": "^24.4.0", "electron-builder": "^24.4.0",
"electron-vite": "^1.0.23", "electron-vite": "^1.0.23",
@ -27,6 +28,7 @@
"eslint-config-prettier": "^8.8.0", "eslint-config-prettier": "^8.8.0",
"eslint-plugin-prettier": "^4.2.1", "eslint-plugin-prettier": "^4.2.1",
"eslint-plugin-react": "^7.32.2", "eslint-plugin-react": "^7.32.2",
"postcss": "^8.4.24",
"prettier": "^2.8.8", "prettier": "^2.8.8",
"react": "^18.2.0", "react": "^18.2.0",
"react-dom": "^18.2.0", "react-dom": "^18.2.0",
@ -2062,6 +2064,39 @@
"node": ">= 4.0.0" "node": ">= 4.0.0"
} }
}, },
"node_modules/autoprefixer": {
"version": "10.4.14",
"resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.14.tgz",
"integrity": "sha512-FQzyfOsTlwVzjHxKEqRIAdJx9niO6VCBCoEwax/VLSoQF29ggECcPuBqUMZ+u8jCZOPSy8b8/8KnuFbp0SaFZQ==",
"dev": true,
"funding": [
{
"type": "opencollective",
"url": "https://opencollective.com/postcss/"
},
{
"type": "tidelift",
"url": "https://tidelift.com/funding/github/npm/autoprefixer"
}
],
"dependencies": {
"browserslist": "^4.21.5",
"caniuse-lite": "^1.0.30001464",
"fraction.js": "^4.2.0",
"normalize-range": "^0.1.2",
"picocolors": "^1.0.0",
"postcss-value-parser": "^4.2.0"
},
"bin": {
"autoprefixer": "bin/autoprefixer"
},
"engines": {
"node": "^10 || ^12 || >=14"
},
"peerDependencies": {
"postcss": "^8.1.0"
}
},
"node_modules/available-typed-arrays": { "node_modules/available-typed-arrays": {
"version": "1.0.5", "version": "1.0.5",
"resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz",
@ -4306,6 +4341,19 @@
"node": ">= 6" "node": ">= 6"
} }
}, },
"node_modules/fraction.js": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.2.0.tgz",
"integrity": "sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA==",
"dev": true,
"engines": {
"node": "*"
},
"funding": {
"type": "patreon",
"url": "https://www.patreon.com/infusion"
}
},
"node_modules/fs-extra": { "node_modules/fs-extra": {
"version": "9.1.0", "version": "9.1.0",
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz",
@ -6327,6 +6375,15 @@
"node": ">=0.10.0" "node": ">=0.10.0"
} }
}, },
"node_modules/normalize-range": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz",
"integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==",
"dev": true,
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/normalize-url": { "node_modules/normalize-url": {
"version": "6.1.0", "version": "6.1.0",
"resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz", "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz",

View file

@ -3,8 +3,8 @@
"version": "1.0.0", "version": "1.0.0",
"description": "An Electron application with React", "description": "An Electron application with React",
"main": "./out/main/index.js", "main": "./out/main/index.js",
"author": "example.com", "author": "artegoser",
"homepage": "https://www.electronjs.org", "homepage": "https://github.com/artegoser/pimi-launcher",
"scripts": { "scripts": {
"format": "prettier --write .", "format": "prettier --write .",
"lint": "eslint . --ext .js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix", "lint": "eslint . --ext .js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix",
@ -28,6 +28,7 @@
"devDependencies": { "devDependencies": {
"@electron/notarize": "^1.2.3", "@electron/notarize": "^1.2.3",
"@vitejs/plugin-react": "^4.0.0", "@vitejs/plugin-react": "^4.0.0",
"autoprefixer": "^10.4.14",
"electron": "^24.4.1", "electron": "^24.4.1",
"electron-builder": "^24.4.0", "electron-builder": "^24.4.0",
"electron-vite": "^1.0.23", "electron-vite": "^1.0.23",
@ -35,6 +36,7 @@
"eslint-config-prettier": "^8.8.0", "eslint-config-prettier": "^8.8.0",
"eslint-plugin-prettier": "^4.2.1", "eslint-plugin-prettier": "^4.2.1",
"eslint-plugin-react": "^7.32.2", "eslint-plugin-react": "^7.32.2",
"postcss": "^8.4.24",
"prettier": "^2.8.8", "prettier": "^2.8.8",
"react": "^18.2.0", "react": "^18.2.0",
"react-dom": "^18.2.0", "react-dom": "^18.2.0",

6
postcss.config.js Normal file
View file

@ -0,0 +1,6 @@
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {}
}
}

View file

@ -57,7 +57,7 @@ function createWindow() {
// Some APIs can only be used after this event occurs. // Some APIs can only be used after this event occurs.
app.whenReady().then(() => { app.whenReady().then(() => {
// Set app user model id for windows // Set app user model id for windows
electronApp.setAppUserModelId('com.electron') electronApp.setAppUserModelId('com.pimi-launcher')
// Default open or close DevTools by F12 in development // Default open or close DevTools by F12 in development
// and ignore CommandOrControl + R in production. // and ignore CommandOrControl + R in production.

View file

@ -13,7 +13,7 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
import { contextBridge } from 'electron' import { contextBridge, nativeImage } from 'electron'
import { electronAPI } from '@electron-toolkit/preload' import { electronAPI } from '@electron-toolkit/preload'
// Custom APIs for renderer // Custom APIs for renderer
@ -24,6 +24,7 @@ const api = {}
// just add to the DOM global. // just add to the DOM global.
if (process.contextIsolated) { if (process.contextIsolated) {
try { try {
contextBridge.exposeInMainWorld('nativeImage', nativeImage)
contextBridge.exposeInMainWorld('electron', electronAPI) contextBridge.exposeInMainWorld('electron', electronAPI)
contextBridge.exposeInMainWorld('api', api) contextBridge.exposeInMainWorld('api', api)
} catch (error) { } catch (error) {
@ -32,4 +33,5 @@ if (process.contextIsolated) {
} else { } else {
window.electron = electronAPI window.electron = electronAPI
window.api = api window.api = api
window.nativeImage = nativeImage
} }

View file

@ -1,3 +1,7 @@
@tailwind base; @tailwind base;
@tailwind components; @tailwind components;
@tailwind utilities; @tailwind utilities;
.inputs {
@apply bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500;
}

View file

@ -0,0 +1,36 @@
import { Client, Authenticator } from 'pimi-launcher-core'
async function launch(version, setProgress, setDownload, setGameStarted, setStarted) {
console.log(version)
const launcher = new Client()
let opts = {
authorization: Authenticator.getAuth(
localStorage.getItem('name') || 'Steve',
localStorage.getItem('password') || ''
),
root: './.pimi',
version: {
number: version.id,
type: version.type
},
memory: {
max: '6G',
min: '4G'
}
}
launcher.on('progress', (e) => setProgress(e))
launcher.on('download', (e) => setDownload(e))
launcher.on('debug', (e) => console.log(e))
launcher.on('data', (e) => console.log(e))
launcher.on('arguments', () => setGameStarted(true))
launcher.on('close', () => {
setGameStarted(false)
setStarted(false)
})
await launcher.launch(opts)
}
export { launch }

View file

@ -15,22 +15,80 @@
import { useState } from 'react' import { useState } from 'react'
import { utils } from 'pimi-launcher-core' import { utils } from 'pimi-launcher-core'
import { launch } from '../components/utils'
function Main() { function Main() {
const [versions, setVersions] = useState(false) const [versions, setVersions] = useState(false)
const [version, setVersion] = useState(false)
const [download, setDownload] = useState(false)
const [progress, setProgress] = useState(false)
const [started, setStarted] = useState(false)
const [gameStarted, setGameStarted] = useState(false)
utils.getVersions().then((data) => { utils.getVersions().then((data) => {
setVersions(data) setVersions(data)
setVersion(data[0])
}) })
if (versions) return (
return versions.map((version) => { versions && (
return ( <div className="grid grid-cols-3 gap-4 m-5">
<div key={version.id} className="text-3xl font-bold"> <div>
{version.id} <input
type="text"
id="name"
className="inputs"
placeholder="Your name"
defaultValue={localStorage.getItem('name') || 'Steve'}
onChange={(e) => {
localStorage.setItem('name', e.target.value)
}}
/>
</div> </div>
) <div>
}) <select
else return <></> name="pets"
id="pet-select"
className="inputs"
onChange={(e) => setVersion(e.target.value)}
>
{versions.map((version) => {
return (
<option key={version.id} value={version} className="text-1xl font-bold underline">
{version.id}
</option>
)
})}
</select>
</div>
<div>
<input
type="button"
value="Start"
className="inputs"
onClick={() => {
launch(version, setProgress, setDownload, setGameStarted, setStarted)
setStarted(true)
}}
/>
</div>
{started && gameStarted && (
<>
<div>Minecraft launches...</div>
</>
)}
{started && !gameStarted && (
<>
<div>Downloading{'.'.repeat(progress.task % 3)}</div>
<div>
{download || 'please wait'} {`(${progress.type})` || ''}
</div>
<div>{((progress.task / progress.total) * 100 || 0).toFixed(2)}%</div>
</>
)}
</div>
)
)
} }
export default Main export default Main

View file

@ -15,7 +15,7 @@
/** @type {import('tailwindcss').Config} */ /** @type {import('tailwindcss').Config} */
module.exports = { module.exports = {
content: ['./src/**/*.{js,jsx,ts,tsx}'], content: ['./src/renderer/src/**/*.{js,jsx,ts,tsx}'],
theme: { theme: {
extend: {} extend: {}
}, },