feat: terminal

This commit is contained in:
Artemy 2023-06-21 14:51:56 +03:00
parent bff72b3ff8
commit 4b332b8aa2
7 changed files with 136 additions and 77 deletions

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', 'path', 'process', 'fs'] const externals = ['pimi-launcher-core', 'path', 'process', 'fs', 'console']
export default defineConfig({ export default defineConfig({
main: { main: {

14
package-lock.json generated
View file

@ -1,12 +1,12 @@
{ {
"name": "pimi-launcher", "name": "pimi-launcher",
"version": "1.1.0-alpha", "version": "1.2.0-alpha",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "pimi-launcher", "name": "pimi-launcher",
"version": "1.1.0-alpha", "version": "1.2.0-alpha",
"hasInstallScript": true, "hasInstallScript": true,
"dependencies": { "dependencies": {
"@electron-toolkit/preload": "^2.0.0", "@electron-toolkit/preload": "^2.0.0",
@ -16,6 +16,7 @@
"pimi-launcher-core": "^1.1.1", "pimi-launcher-core": "^1.1.1",
"react-router-dom": "^6.13.0", "react-router-dom": "^6.13.0",
"react-select": "^5.7.3", "react-select": "^5.7.3",
"react-terminal-ui": "^1.0.5",
"vite-plugin-commonjs-externals": "^0.1.3" "vite-plugin-commonjs-externals": "^0.1.3"
}, },
"devDependencies": { "devDependencies": {
@ -7530,6 +7531,15 @@
"react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0"
} }
}, },
"node_modules/react-terminal-ui": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/react-terminal-ui/-/react-terminal-ui-1.0.5.tgz",
"integrity": "sha512-yR19ej58dwU3koLiTR0m0nLbqJZoOyeThGWg1B3VrwUs+PLraqjP2C4AkRgiGNUwWMn4u6T0djY5DZXq0Zlvjg==",
"peerDependencies": {
"react": ">16.13.0",
"react-dom": ">16.13.0"
}
},
"node_modules/react-transition-group": { "node_modules/react-transition-group": {
"version": "4.4.5", "version": "4.4.5",
"resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz", "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz",

View file

@ -1,6 +1,6 @@
{ {
"name": "pimi-launcher", "name": "pimi-launcher",
"version": "1.1.1-alpha", "version": "1.2.0-alpha",
"description": "Modern Minecraft Launcher", "description": "Modern Minecraft Launcher",
"main": "./out/main/index.js", "main": "./out/main/index.js",
"author": "artegoser", "author": "artegoser",
@ -27,6 +27,7 @@
"pimi-launcher-core": "^1.1.1", "pimi-launcher-core": "^1.1.1",
"react-router-dom": "^6.13.0", "react-router-dom": "^6.13.0",
"react-select": "^5.7.3", "react-select": "^5.7.3",
"react-terminal-ui": "^1.0.5",
"vite-plugin-commonjs-externals": "^0.1.3" "vite-plugin-commonjs-externals": "^0.1.3"
}, },
"devDependencies": { "devDependencies": {

View file

@ -5,3 +5,7 @@
.inputs { .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; @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;
} }
::-webkit-scrollbar {
width: 0;
}

View file

@ -0,0 +1,21 @@
import Terminal, { ColorMode, TerminalOutput } from 'react-terminal-ui'
import PropTypes from 'prop-types'
function MinecraftTerminal({ lines, height = '300px' }) {
const terminalLineData = lines.map((line, index) => (
<TerminalOutput key={index}>{line}</TerminalOutput>
))
return (
<Terminal name="Minecraft Console" height={height} colorMode={ColorMode.Light}>
{terminalLineData}
</Terminal>
)
}
MinecraftTerminal.propTypes = {
lines: PropTypes.arrayOf(PropTypes.string),
height: PropTypes.string
}
export default MinecraftTerminal

View file

@ -1,7 +1,14 @@
import { Client, Authenticator } from 'pimi-launcher-core' import { Client, Authenticator } from 'pimi-launcher-core'
async function launch(
async function launch(version, setProgress, setDownload, setGameStarted, setStarted) { version,
setProgress,
setDownload,
setGameStarted,
setStarted,
setTerminalLines
) {
const launcher = new Client() const launcher = new Client()
let terminalLines = []
let opts = { let opts = {
authorization: Authenticator.getAuth( authorization: Authenticator.getAuth(
@ -23,13 +30,20 @@ async function launch(version, setProgress, setDownload, setGameStarted, setStar
launcher.on('progress', (e) => setProgress(e)) launcher.on('progress', (e) => setProgress(e))
launcher.on('download', (e) => setDownload(e)) launcher.on('download', (e) => setDownload(e))
launcher.on('debug', (e) => console.log(e)) launcher.on('debug', (e) => {
launcher.on('data', (e) => console.log(e)) terminalLines = terminalLines.concat(e)
setTerminalLines(terminalLines)
})
launcher.on('data', (e) => {
terminalLines = terminalLines.concat(e)
setTerminalLines(terminalLines)
})
launcher.on('arguments', () => setGameStarted(true)) launcher.on('arguments', () => setGameStarted(true))
launcher.on('close', () => { launcher.on('close', () => {
setGameStarted(false) setGameStarted(false)
setStarted(false) setStarted(false)
setTerminalLines([])
}) })
} }

View file

@ -19,6 +19,7 @@ import { launch } from '../components/utils'
import Select from 'react-select' import Select from 'react-select'
import path from 'path' import path from 'path'
import fs from 'fs' import fs from 'fs'
import MinecraftTerminal from '../components/MinecraftTerminal'
function Main() { function Main() {
const [versions, setVersions] = useState(false) const [versions, setVersions] = useState(false)
const [version, setVersion] = useState(false) const [version, setVersion] = useState(false)
@ -27,6 +28,7 @@ function Main() {
const [started, setStarted] = useState(false) const [started, setStarted] = useState(false)
const [gameStarted, setGameStarted] = useState(false) const [gameStarted, setGameStarted] = useState(false)
const [installed_versions, setInstalledVersions] = useState(false) const [installed_versions, setInstalledVersions] = useState(false)
const [terminalLines, setTerminalLines] = useState([])
useEffect(() => { useEffect(() => {
if (!versions) { if (!versions) {
@ -38,79 +40,86 @@ function Main() {
} }
}) })
console.log('hi')
return ( return (
versions && ( versions && (
<div className="grid grid-cols-3 gap-4 m-5"> <>
<div> <div className="grid grid-cols-3 gap-4 m-5">
<input <div>
type="text" <input
id="name" type="text"
className="inputs" id="name"
placeholder="Your name" className="inputs"
defaultValue={localStorage.getItem('name') || 'Steve'} placeholder="Your name"
onChange={(e) => { defaultValue={localStorage.getItem('name') || 'Steve'}
localStorage.setItem('name', e.target.value) onChange={(e) => {
}} localStorage.setItem('name', e.target.value)
/> }}
</div> />
<div> </div>
<Select <div>
onChange={(e) => { <Select
setVersion(versions[e.value]) onChange={(e) => {
}} setVersion(versions[e.value])
defaultValue={{ value: versions[0], label: versions[0].id }} }}
options={versions.map((version, index) => { defaultValue={{ value: versions[0], label: versions[0].id }}
return { options={versions.map((version, index) => {
value: index, return {
label: version.id, value: index,
type: version.type, label: version.id,
installed: installed_versions?.includes(version.id) type: version.type,
} installed: installed_versions?.includes(version.id)
})} }
styles={{ })}
control: (styles) => ({ styles={{
...styles, control: (styles) => ({
backgroundColor: 'white' ...styles,
}), backgroundColor: 'white'
option: (styles, { data, isFocused }) => ({ }),
...styles, option: (styles, { data, isFocused }) => ({
backgroundColor: isFocused ? '#c9d2e7' : data.installed ? '#cccccc' : 'white' ...styles,
}) backgroundColor: isFocused ? '#c9d2e7' : data.installed ? '#cccccc' : 'white'
}} })
/> }}
</div> />
<div> </div>
<input <div>
type="button" <input
value="Start" type="button"
className="inputs" value="Start"
onClick={() => { className="inputs"
launch(version, setProgress, setDownload, setGameStarted, setStarted) onClick={() => {
setStarted(true) launch(
}} version,
disabled={started} setProgress,
/> setDownload,
</div> setGameStarted,
setStarted,
setTerminalLines
)
setStarted(true)
}}
disabled={started}
/>
</div>
{started && gameStarted && ( {started && !gameStarted && (
<> <>
<div className="text-2xl font-bold">Minecraft launches...</div> <div className="text-2xl font-bold">Downloading{'.'.repeat(progress.task % 3)}</div>
</> <div className="break-words text-2xl font-bold">
{download || 'please wait'} {`(${progress.type})` || ''}
</div>
<div className="text-2xl font-bold">
{((progress.task / progress.total) * 100 || 0).toFixed(2)}%
</div>
</>
)}
</div>
{started && (
<div className="m-5">
<MinecraftTerminal lines={terminalLines} />
</div>
)} )}
{started && !gameStarted && ( </>
<>
<div className="text-2xl font-bold">Downloading{'.'.repeat(progress.task % 3)}</div>
<div className="break-words text-2xl font-bold">
{download || 'please wait'} {`(${progress.type})` || ''}
</div>
<div className="text-2xl font-bold">
{((progress.task / progress.total) * 100 || 0).toFixed(2)}%
</div>
</>
)}
</div>
) )
) )
} }