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 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({
main: {

14
package-lock.json generated
View file

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

View file

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

View file

@ -5,3 +5,7 @@
.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;
}
::-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'
async function launch(version, setProgress, setDownload, setGameStarted, setStarted) {
async function launch(
version,
setProgress,
setDownload,
setGameStarted,
setStarted,
setTerminalLines
) {
const launcher = new Client()
let terminalLines = []
let opts = {
authorization: Authenticator.getAuth(
@ -23,13 +30,20 @@ async function launch(version, setProgress, setDownload, setGameStarted, setStar
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('debug', (e) => {
terminalLines = terminalLines.concat(e)
setTerminalLines(terminalLines)
})
launcher.on('data', (e) => {
terminalLines = terminalLines.concat(e)
setTerminalLines(terminalLines)
})
launcher.on('arguments', () => setGameStarted(true))
launcher.on('close', () => {
setGameStarted(false)
setStarted(false)
setTerminalLines([])
})
}

View file

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