|
|
|
@ -40,6 +40,7 @@ import Markdown from './Markdown';
|
|
|
|
|
|
|
|
|
|
import Split from 'react-split'
|
|
|
|
|
import { Alert } from '@mui/material';
|
|
|
|
|
import { GameIdContext } from '../App';
|
|
|
|
|
|
|
|
|
|
export const MonacoEditorContext = React.createContext<monaco.editor.IStandaloneCodeEditor>(null as any);
|
|
|
|
|
|
|
|
|
@ -125,9 +126,9 @@ function PlayableLevel({worldId, levelId}) {
|
|
|
|
|
}]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const gameInfo = useGetGameInfoQuery()
|
|
|
|
|
|
|
|
|
|
const level = useLoadLevelQuery({world: worldId, level: levelId})
|
|
|
|
|
const gameId = React.useContext(GameIdContext)
|
|
|
|
|
const gameInfo = useGetGameInfoQuery({game: gameId})
|
|
|
|
|
const level = useLoadLevelQuery({game: gameId, world: worldId, level: levelId})
|
|
|
|
|
|
|
|
|
|
const dispatch = useAppDispatch()
|
|
|
|
|
|
|
|
|
@ -209,8 +210,8 @@ function PlayableLevel({worldId, levelId}) {
|
|
|
|
|
<Markdown>{level?.data?.conclusion}</Markdown>
|
|
|
|
|
</div>
|
|
|
|
|
{levelId >= gameInfo.data?.worldSize[worldId] ?
|
|
|
|
|
<Button to={`/`}><FontAwesomeIcon icon={faHome} /></Button> :
|
|
|
|
|
<Button to={`/world/${worldId}/level/${levelId + 1}`}>
|
|
|
|
|
<Button to={`/game/${gameId}`}><FontAwesomeIcon icon={faHome} /></Button> :
|
|
|
|
|
<Button to={`/game/${gameId}/world/${worldId}/level/${levelId + 1}`}>
|
|
|
|
|
Next <FontAwesomeIcon icon={faArrowRight} /></Button>}
|
|
|
|
|
|
|
|
|
|
</div>}
|
|
|
|
@ -230,7 +231,8 @@ function PlayableLevel({worldId, levelId}) {
|
|
|
|
|
export default Level
|
|
|
|
|
|
|
|
|
|
function Introduction({worldId}) {
|
|
|
|
|
const gameInfo = useGetGameInfoQuery()
|
|
|
|
|
const gameId = React.useContext(GameIdContext)
|
|
|
|
|
const gameInfo = useGetGameInfoQuery({game: gameId})
|
|
|
|
|
|
|
|
|
|
return <>
|
|
|
|
|
<div style={gameInfo.isLoading ? null : {display: "none"}} className="app-content loading"><CircularProgress /></div>
|
|
|
|
@ -245,8 +247,8 @@ function Introduction({worldId}) {
|
|
|
|
|
</div>
|
|
|
|
|
<div className="conclusion">
|
|
|
|
|
{0 == gameInfo.data?.worldSize[worldId] ?
|
|
|
|
|
<Button to={`/`}><FontAwesomeIcon icon={faHome} /></Button> :
|
|
|
|
|
<Button to={`/world/${worldId}/level/1`}>
|
|
|
|
|
<Button to={`/game/${gameId}`}><FontAwesomeIcon icon={faHome} /></Button> :
|
|
|
|
|
<Button to={`/game/${gameId}/world/${worldId}/level/1`}>
|
|
|
|
|
Start <FontAwesomeIcon icon={faArrowRight} />
|
|
|
|
|
</Button>}
|
|
|
|
|
</div>
|
|
|
|
@ -255,11 +257,12 @@ function Introduction({worldId}) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function LevelAppBar({isLoading, levelId, worldId, levelTitle}) {
|
|
|
|
|
const gameInfo = useGetGameInfoQuery()
|
|
|
|
|
const gameId = React.useContext(GameIdContext)
|
|
|
|
|
const gameInfo = useGetGameInfoQuery({game: gameId})
|
|
|
|
|
|
|
|
|
|
return <div className="app-bar" style={isLoading ? {display: "none"} : null} >
|
|
|
|
|
<div>
|
|
|
|
|
<Button to={`/`}><FontAwesomeIcon icon={faHome} /></Button>
|
|
|
|
|
<Button to={`/game/${gameId}`}><FontAwesomeIcon icon={faHome} /></Button>
|
|
|
|
|
<span className="app-bar-title">
|
|
|
|
|
{gameInfo.data?.worlds.nodes[worldId].title && `World: ${gameInfo.data?.worlds.nodes[worldId].title}`}
|
|
|
|
|
</span>
|
|
|
|
@ -269,10 +272,10 @@ function LevelAppBar({isLoading, levelId, worldId, levelTitle}) {
|
|
|
|
|
{levelTitle}
|
|
|
|
|
</span>
|
|
|
|
|
<Button disabled={levelId <= 0} inverted={true}
|
|
|
|
|
to={`/world/${worldId}/level/${levelId - 1}`}
|
|
|
|
|
to={`/game/${gameId}/world/${worldId}/level/${levelId - 1}`}
|
|
|
|
|
><FontAwesomeIcon icon={faArrowLeft} /> Previous</Button>
|
|
|
|
|
<Button disabled={levelId >= gameInfo.data?.worldSize[worldId]} inverted={true}
|
|
|
|
|
to={`/world/${worldId}/level/${levelId + 1}`}
|
|
|
|
|
to={`/game/${gameId}/world/${worldId}/level/${levelId + 1}`}
|
|
|
|
|
>Next <FontAwesomeIcon icon={faArrowRight} /></Button>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
@ -282,6 +285,7 @@ function LevelAppBar({isLoading, levelId, worldId, levelTitle}) {
|
|
|
|
|
function useLevelEditor(worldId: string, levelId: number, codeviewRef, initialCode, initialSelections, onDidChangeContent, onDidChangeSelection) {
|
|
|
|
|
|
|
|
|
|
const connection = React.useContext(ConnectionContext)
|
|
|
|
|
const gameId = React.useContext(GameIdContext)
|
|
|
|
|
|
|
|
|
|
const [editor, setEditor] = useState<monaco.editor.IStandaloneCodeEditor|null>(null)
|
|
|
|
|
const [infoProvider, setInfoProvider] = useState<null|InfoProvider>(null)
|
|
|
|
@ -308,7 +312,7 @@ function useLevelEditor(worldId: string, levelId: number, codeviewRef, initialCo
|
|
|
|
|
theme: 'vs-code-theme-converted'
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
const infoProvider = new InfoProvider(connection.getLeanClient())
|
|
|
|
|
const infoProvider = new InfoProvider(connection.getLeanClient(gameId))
|
|
|
|
|
|
|
|
|
|
const editorApi = infoProvider.getApi()
|
|
|
|
|
|
|
|
|
@ -358,7 +362,7 @@ function useLevelEditor(worldId: string, levelId: number, codeviewRef, initialCo
|
|
|
|
|
return () => { infoProvider.dispose(); editor.dispose() }
|
|
|
|
|
}, [])
|
|
|
|
|
|
|
|
|
|
const {leanClient, leanClientStarted} = useLeanClient()
|
|
|
|
|
const {leanClient, leanClientStarted} = useLeanClient(gameId)
|
|
|
|
|
|
|
|
|
|
// Create model when level changes
|
|
|
|
|
useEffect(() => {
|
|
|
|
@ -391,7 +395,8 @@ function useLevelEditor(worldId: string, levelId: number, codeviewRef, initialCo
|
|
|
|
|
|
|
|
|
|
/** Open all files in this world on the server so that they will load faster when accessed */
|
|
|
|
|
function useLoadWorldFiles(worldId) {
|
|
|
|
|
const gameInfo = useGetGameInfoQuery()
|
|
|
|
|
const gameId = React.useContext(GameIdContext)
|
|
|
|
|
const gameInfo = useGetGameInfoQuery({game: gameId})
|
|
|
|
|
const store = useStore()
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|