Skip to content

Commit

Permalink
feat: show local games on landing page
Browse files Browse the repository at this point in the history
  • Loading branch information
joneugster committed Feb 25, 2025
1 parent 368b154 commit d5bfd46
Show file tree
Hide file tree
Showing 10 changed files with 86 additions and 40 deletions.
72 changes: 49 additions & 23 deletions client/src/components/landing_page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ import '@fontsource/roboto/700.css';
import '../css/landing_page.css'
import bgImage from '../assets/bg.jpg'

import { GameTile, useGetGameInfoQuery } from '../state/api'
import { GameTile } from '../state/api'
import path from 'path';

import ReactCountryFlag from 'react-country-flag';
// import ReactCountryFlag from 'react-country-flag';
import lean4gameConfig from '../config.json'
import i18next from 'i18next';
import { useContext } from 'react';
Expand Down Expand Up @@ -76,17 +76,58 @@ function LandingPage() {

const [usageCPU, setUsageCPU] = React.useState<number>()
const [usageMem, setUsageMem] = React.useState<number>()
const [gameTiles, setGameTiles] = React.useState<Array<JSX.Element>>([])

const { t, i18n } = useTranslation()
const { t } = useTranslation()

// Load the namespaces of all games
// TODO: should `allGames` contain game-ids starting with `g/`?
i18next.loadNamespaces(lean4gameConfig.allGames.map(id => `g/${id}`))

let allTiles = lean4gameConfig.allGames.map((gameId) => {
let q = useGetGameInfoQuery({game: `g/${gameId}`})
return q.data?.tile
})
const devMode = process.env.NODE_ENV == "development"

/**
*
*/
React.useEffect(() => {
let games = [...lean4gameConfig.allGames]
const fetchGameInfos = async () => {
try {
if (devMode) {
await fetch(`${window.location.origin}/data/local_games`)
.then(response => {if (response.ok) {return response.json()} else {throw ""}})
.then((localGames: string[]) => {
games = games.concat(localGames.map((game: string) => (`local/${game}`)))
games.push("test/Test")
})
}
const promises = games.map(async game => {
try {
const response = await fetch(`${window.location.origin}/data/g/${game}/Game.json`)
if (!response.ok) {return null}
let gameInfo = await response.json()
return [game, gameInfo.tile]
} catch (err) {
console.info(`game ${game} unavailable`)
console.debug(err)
return null
}
})
let response = await Promise.all(promises)
response = response.filter(tile => tile !== null)
let tiles = response.map(([id, tile]) => {
return <Tile
key={id}
gameId={`g/${id}`}
data={tile}
/>})
setGameTiles(tiles)
} catch (error) {
console.error("Error fetching data:", error)
}
}
fetchGameInfos()
}, [])

/** Parse `games/stats.csv` if present and display server capacity. */
React.useEffect(() => {
Expand Down Expand Up @@ -126,22 +167,7 @@ function LandingPage() {
</header>
<React.Suspense>
<div className="game-list">

{allTiles.filter(x => x != null).length == 0 ?
<p>
<Trans>
No Games loaded. Use <a>http://localhost:3000/#/g/local/FOLDER</a> to open a
game directly from a local folder.
</Trans>
</p>
: lean4gameConfig.allGames.map((id, i) => (
<Tile
key={id}
gameId={`g/${id}`}
data={allTiles[i]}
/>
))
}
{ gameTiles }
</div>
</React.Suspense>
{ // show server capacity from `games/stats.csv` if present
Expand Down
2 changes: 1 addition & 1 deletion client/src/components/popup/impressum.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export function ImpressumPopup () {
40225 Düsseldorf<br />
Germany<br />
+49 211 81-14690<br />
<a href="https://www.math.hhu.de/en/lehrstuehle-/-personen-/-ansprechpartner/innen/lehrstuehle-des-mathematischen-instituts/lehrstuhl-fuer-algebraische-geometrie/team">Contact Details</a>
<a href="https://www.math.hhu.de/lehrstuehle-/-personen-/-ansprechpartner/innen/lehrstuehle-des-mathematischen-instituts/lehrstuhl-fuer-algebraische-geometrie/team/prof-dr-marcus-zibrowius">Contact Details</a>
</p>
<p>
<strong>Legal form:</strong><br />
Expand Down
2 changes: 1 addition & 1 deletion client/src/components/popup/privacy.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ export function PrivacyPolicyPopup () {
40225 Düsseldorf<br />
Germany<br />
+49 211 81-14690<br />
<a href="https://www.math.hhu.de/en/lehrstuehle-/-personen-/-ansprechpartner/innen/lehrstuehle-des-mathematischen-instituts/lehrstuhl-fuer-algebraische-geometrie/team">Contact Details</a>
<a href="https://www.math.hhu.de/lehrstuehle-/-personen-/-ansprechpartner/innen/lehrstuehle-des-mathematischen-instituts/lehrstuhl-fuer-algebraische-geometrie/team/prof-dr-marcus-zibrowius">Contact Details</a>
</p>
</Trans>
}
Expand Down
2 changes: 1 addition & 1 deletion client/src/config.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"allGames": [
"leanprover-community/nng4",
"hhu-adam/Robo",
"hhu-adam/robo",
"djvelleman/stg4",
"trequetrum/lean4game-logic"
],
Expand Down
2 changes: 1 addition & 1 deletion doc/publish_game.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,4 @@ Now you can immediately play the game at `adam.math.hhu.de/#/g/{USER}/{REPOSITOR
Adding games to the main page happens manually by the server maintainers. Tell us if you want us
to add a tile for your game!

For example, you can [contact Jon on Zulip](https://leanprover.zulipchat.com/#narrow/dm/385895-Jon-Eugster). Or [via Email](https://www.math.hhu.de/en/lehrstuehle-/-personen-/-ansprechpartner/innen/lehrstuehle-des-mathematischen-instituts/lehrstuhl-fuer-algebraische-geometrie/team/jon-eugster).
For example, you can [contact Jon on Zulip](https://leanprover.zulipchat.com/#narrow/dm/385895-Jon-Eugster).
2 changes: 1 addition & 1 deletion index.html
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ <h1>Lean Game Server</h1>
40225 Düsseldorf<br />
Germany<br />
+49 211 81-14690<br />
<a href="https://www.math.hhu.de/en/lehrstuehle-/-personen-/-ansprechpartner/innen/lehrstuehle-des-mathematischen-instituts/lehrstuhl-fuer-algebraische-geometrie/team">Contact Details</a>
<a href="https://www.math.hhu.de/lehrstuehle-/-personen-/-ansprechpartner/innen/lehrstuehle-des-mathematischen-instituts/lehrstuhl-fuer-algebraische-geometrie/team/prof-dr-marcus-zibrowius">Contact Details</a>
</p>
<p>
<strong>Datenschutzerklärung:</strong><br />
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@
},
"scripts": {
"start": "concurrently -n server,client -c blue,green \"npm run start_server\" \"npm run start_client\"",
"start_server": "(cd server && lake build) && (cd relay && cross-env NODE_ENV=development nodemon -e mjs --exec \"node ./index.mjs\")",
"start_server": "(cd server && lake build && lake build TestGame) && (cd relay && cross-env NODE_ENV=development nodemon -e mjs --exec \"node ./index.mjs\")",
"start_client": "cross-env NODE_ENV=development vite --host",
"build": "npm run build_server && npm run build_client",
"preview": "vite preview",
Expand Down
23 changes: 19 additions & 4 deletions relay/index.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,20 @@ const server = app
req.url = filename
express.static(path.join(getGameDir(owner,repo),".i18n",lang))(req, res, next)
})
.use('/data/local_games', (req, res, next) => {
const directoryPath = path.join(__dirname, '..', '..')
console.error('here')
fs.readdir(directoryPath, (err, files) => {
if (err) {
return res.status(500).json({ error: "Unable to scan directory" })
}
let games = files
.map(file => path.join(directoryPath, file))
.filter(folderPath => fs.existsSync(path.join(folderPath, '.lake', 'gamedata')))
.map(folderPath => path.basename(folderPath))
res.json(games)
})
})
.use('/data/g/:owner/:repo/*', (req, res, next) => {
const owner = req.params.owner
const repo = req.params.repo
Expand Down Expand Up @@ -115,7 +129,7 @@ function getTag(owner, repo) {

function getGameDir(owner, repo) {
owner = owner.toLowerCase()
if (owner == 'local') {
if (owner == 'local' || owner == 'test' ) {
if(!isDevelopment) {
console.error(`No local games in production mode.`)
return ""
Expand All @@ -128,10 +142,11 @@ function getGameDir(owner, repo) {
}
}

let game_dir = (owner == 'local') ?
let game_dir =
// note: in the local case we need `repo` to be case sensitive
path.join(__dirname, '..', '..', repo) :
path.join(__dirname, '..', 'games', `${owner}`, `${repo.toLowerCase()}`)
(owner == 'local') ? path.join(__dirname, '..', '..', repo) :
(owner == 'test') ? path.join(__dirname, '..', 'server') :
path.join(__dirname, '..', 'games', `${owner}`, `${repo.toLowerCase()}`)

if(!fs.existsSync(game_dir)) {
console.error(`Game '${game_dir}' does not exist!`)
Expand Down
2 changes: 1 addition & 1 deletion server/GameServer/Command/LayerInfo.lean
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ elab "Languages" t:str* : command => do
modifyCurGame fun game => pure {game with
tile := {game.tile with languages := t.map (·.getString) |>.toList}}

/-- The Image of the game (optional). TODO: Not implemented -/
/-- The Image of the game (optional). The image should have ratio 500:200. -/
elab "CoverImage" t:str : command => do
let file := t.getString
if not <| ← System.FilePath.pathExists file then
Expand Down
17 changes: 11 additions & 6 deletions server/TestGame.lean
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import TestGame.Levels.DemoWorld1
import TestGame.Levels.DemoWorld2

-- Here's what we'll put on the title screen
Title "Hello World Game"
Title "Test Game"
Introduction
"
This text appears on the starting page where one selects the world/level to play.
Expand All @@ -19,11 +19,16 @@ Use markdown.
"

/-! Information to be displayed on the servers landing page. -/
Languages "English"
CaptionShort "Game Template"
CaptionLong "You should use this game as a template for your own game and add your own levels."
-- Prerequisites "" -- add this if your game depends on other games
-- CoverImage "images/cover.png"
Languages "en"
CaptionShort "This game is used for automated tests."
CaptionLong "It can be accessed at `localhost:3000/#/g/test/Test`."
Prerequisites "" -- add this if your game depends on other games

/-- warning: Make sure the cover image 'images/nonexistent.png' exists. -/
#guard_msgs in
CoverImage "images/nonexistent.png"

CoverImage "images/testGameCover.png"

/-! Build the game. Show's warnings if it found a problem with your game. -/

Expand Down

0 comments on commit d5bfd46

Please sign in to comment.