diff --git a/src/components/App.tsx b/src/components/App.tsx
index 9da8063..006bdd6 100644
--- a/src/components/App.tsx
+++ b/src/components/App.tsx
@@ -114,7 +114,9 @@ export function App() {
{selectedTab === 0 && }
{selectedTab === 1 && }
- {selectedTab === 2 && }
+
+
+
{selectedTab === 4 && }
diff --git a/src/components/Launcher.tsx b/src/components/Launcher.tsx
index d45a9f4..8130c0f 100644
--- a/src/components/Launcher.tsx
+++ b/src/components/Launcher.tsx
@@ -1,14 +1,10 @@
import {
Box,
Button,
- Checkbox,
Flex,
- FormControl,
- FormLabel,
Heading,
IconButton,
Image,
- Input,
List,
ListItem,
Modal,
@@ -18,234 +14,62 @@ import {
ModalFooter,
ModalHeader,
ModalOverlay,
- Select,
Spacer,
Spinner,
Text,
Tooltip,
useToken,
} from '@chakra-ui/react'
-import { AddIcon, EditIcon } from '@chakra-ui/icons'
-import { useQuery } from '@tanstack/react-query'
-import axios from 'axios'
-import React, { useEffect, useState } from 'react'
+import { AddIcon, EditIcon, ViewIcon } from '@chakra-ui/icons'
+import React, { useEffect, useRef, useState } from 'react'
import { v4 as uuidv4 } from 'uuid'
import {
- findVersionManifest,
GameInstall,
getGameInstallIsHacked,
getGameInstalModLoaderName,
+ LAUNCH_STATUS,
ModLoaderName,
- MojangVersionManifests,
- mojangVersionManifests,
- QUERY_KEYS,
- setGameInstallModLoaderName,
- toggleGameInstallModeUrl,
+ removeProperty,
} from '../constants'
-import { useCreateGameInstallMutation, useGameInstallsQuery } from '../hooks/useStore'
-import { mods } from '../utils/mods'
+import { useGameInstallsQuery } from '../hooks/useStore'
+import { NewGameInstall } from './NewGameInstall'
-const defaultVersion = '1.20.6'
-
-export const useMojangVersionManifestsQuery = () =>
- useQuery({
- queryKey: [QUERY_KEYS.useMojangVersionManifests],
- queryFn: async () => {
- const { data } = await axios.get(
- 'https://launchermeta.mojang.com/mc/game/version_manifest.json'
- )
- return mojangVersionManifests.parse(data)
- },
- refetchOnMount: false,
- refetchOnWindowFocus: false,
- refetchOnReconnect: false,
- })
-
-export function NewGameInstall(props: {
- existingInstall?: GameInstall
- isOpen: boolean
- onClose: () => void
-}) {
- const [yellow100] = useToken('colors', ['yellow.100'])
- const [newInstall, setNewInstall] = useState>(
- props.existingInstall ?? {
- name: '',
- path: '',
- versionManifest: undefined,
- }
- )
-
- const updateNewInstallVersionManifest = (version: string) => {
- const newVersionManifest = findVersionManifest(
- versionManifests.data,
- version
- )
- if (!newVersionManifest) return
- setNewInstall((prev) => ({
- ...prev,
- name:
- !prev.name || prev.name === prev.versionManifest?.id
- ? newVersionManifest.id
- : prev.name,
- versionManifest: newVersionManifest,
- }))
- }
-
- const versionManifests = useMojangVersionManifestsQuery()
- const createGameInstallMutation = useCreateGameInstallMutation({
- callback: props.onClose,
- })
-
- useEffect(() => {
- if (!newInstall.versionManifest?.id && versionManifests.isSuccess) {
- const defaultVersionManifest = findVersionManifest(
- versionManifests.data,
- defaultVersion
- )
- updateNewInstallVersionManifest(
- defaultVersionManifest
- ? defaultVersion
- : versionManifests.data.latest.release
- )
- }
- }, [
- newInstall.versionManifest?.id,
- versionManifests.isSuccess,
- versionManifests.data,
- ])
-
- return (
-
-
-
-
- {props.existingInstall ? 'Update' : 'New'} Install
-
-
- {versionManifests.isError ? (
-
- Error loading version manifests
- {versionManifests.error.message}
-
- ) : !versionManifests.isSuccess ||
- createGameInstallMutation.isPending ? (
-
-
-
- ) : (
-
-
- Version
-
-
-
- Name
-
- setNewInstall((prev) => ({
- ...prev,
- name: event.target.value,
- }))
- }
- />
-
-
- Mod loader
-
-
- {newInstall.fabricLoaderVersion && (
-
- {Object.entries(
- mods[`${newInstall?.versionManifest?.id}-fabric`] || {}
- ).map(([name, url]) => (
-
-
- setNewInstall((prev) =>
- toggleGameInstallModeUrl(
- prev,
- url,
- !!e.target.checked
- )
- )
- }
- >
- {name}
-
-
- ))}
-
- )}
-
- )}
-
- {versionManifests.isSuccess &&
- !createGameInstallMutation.isPending && (
-
- )}
-
-
-
- )
+interface RunningLaunch {
+ install: GameInstall
+ processId?: number
+ show: boolean
}
-export function LaunchGameInstall(props: {
+export function LaunchedGame(props: {
isOpen: boolean
launchId: string
install: GameInstall
onClose: () => void
+ onFinished: () => void
+ onProcessId: (processId: number) => void
}) {
+ const containerRef = useRef(null)
+ const textRef = useRef(null)
const [purple100] = useToken('colors', ['purple.100'])
+
useEffect(() => {
- if (!props.isOpen || !props.launchId) return
+ if (!props.launchId) return
const handle = window.api.launchGameInstall(
props.launchId,
props.install,
- (text) => {
- console.log(props.launchId, text)
+ (message) => {
+ if (message.message) {
+ if (textRef.current) textRef.current.textContent += message.message
+ if (containerRef.current)
+ containerRef.current.scrollTop = containerRef.current.scrollHeight
+ }
+ if (message.processId) props.onProcessId(message.processId)
+ if (message.status === LAUNCH_STATUS.finished) props.onFinished()
}
)
return () => window.api.removeListener(handle)
- }, [props.isOpen, props.launchId])
+ }, [props.launchId])
return (
@@ -255,6 +79,8 @@ export function LaunchGameInstall(props: {
bgImage="app-file://images/icons/obsidian.png"
bgSize={64}
border={`${purple100} 2px solid`}
+ minWidth="fit-content"
+ height="fit-content"
>
Launching {props.install.name}
@@ -262,6 +88,12 @@ export function LaunchGameInstall(props: {
+