Skip to content

Commit 31a311e

Browse files
committed
support old custom lean server games
1 parent e58ef17 commit 31a311e

File tree

4 files changed

+57
-21
lines changed

4 files changed

+57
-21
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@
8585
"build_server": "cd server && lake build",
8686
"build_client": "cross-env NODE_ENV=production vite build",
8787
"build_relay": "tsc -b ./relay",
88-
"production": "cross-env NODE_ENV=production node relay/index.mjs",
88+
"production": "cross-env NODE_ENV=production node relay/dist/src/index.js",
8989
"translate": "npx i18next-scanner --config client/i18next-scanner.config.cjs"
9090
},
9191
"eslintConfig": {

relay/scripts/bubblewrap.sh

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,15 @@ ELAN_HOME=$(lake env printenv ELAN_HOME)
55

66
# $1 : the game directory
77
# $2 : the lean4game folder
8-
# $3 : the gameserver executable
8+
# $3 : does the game use a custom Lean server?
9+
10+
if [ "$3" = "true" ]; then
11+
GAMESERVER_PATH="/game/.lake/packages/GameServer/server/.lake/build/bin/"
12+
GAMESERVER_CMD="./gameserver --server /game"
13+
else
14+
GAMESERVER_PATH="/game"
15+
GAMESERVER_CMD="lake serve --"
16+
fi
917

1018
(exec bwrap\
1119
--bind $2 /lean4game \
@@ -27,6 +35,6 @@ ELAN_HOME=$(lake env printenv ELAN_HOME)
2735
--unshare-uts \
2836
--unshare-cgroup \
2937
--die-with-parent \
30-
--chdir "/game/.lake/packages/GameServer/server/.lake/build/bin/" \
31-
./gameserver --server /game
38+
--chdir "$GAMESERVER_PATH" \
39+
$GAMESERVER_CMD
3240
)

relay/src/serverProcess.ts

Lines changed: 42 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,12 @@ import fs from 'fs';
66
import path from 'path';
77

88
type Tag = { owner: string; repo: string; };
9-
export type GameSession = { process: ChildProcess, game: string, gameDir: string}
9+
export type GameSession = {
10+
process: ChildProcess,
11+
game: string,
12+
gameDir: string,
13+
usesCustomLeanServer: boolean
14+
}
1015
const environment = process.env.NODE_ENV;
1116
const isDevelopment = environment === 'development';
1217

@@ -42,9 +47,10 @@ export class GameManager {
4247
const reResTag: Tag = { owner: reRes[1], repo: reRes[2] };
4348
const tag = this.getTagString(reResTag);
4449
const game = `${reResTag.owner}/${reResTag.repo}`
50+
const customLeanServer = this.getCustomLeanServer(reResTag.owner, reResTag.repo)
4551

4652
if (!this.queue[tag] || this.queue[tag].length == 0) {
47-
ps = this.createGameProcess(reResTag.owner, reResTag.repo);
53+
ps = this.createGameProcess(reResTag.owner, reResTag.repo, customLeanServer);
4854
// TODO (Matvey): extract further information from `req`, for example browser language.
4955
console.log(`[${new Date()}] Socket opened by ${ip} on ${game}`);
5056
} else {
@@ -60,29 +66,40 @@ export class GameManager {
6066

6167
const gameDir = this.getGameDir(reResTag.owner, reResTag.repo)
6268

63-
return {process: ps, game: game, gameDir: gameDir}
69+
return {process: ps, game: game, gameDir: gameDir, usesCustomLeanServer: customLeanServer !== null }
70+
}
71+
72+
getCustomLeanServer(owner, repo) : string | null {
73+
let gameDir = this.getGameDir(owner, repo);
74+
let binary = path.join(gameDir, ".lake", "packages", "GameServer", "server", ".lake", "build", "bin", "gameserver");
75+
if (fs.existsSync(binary)) {
76+
return binary
77+
} else {
78+
return null
79+
}
6480
}
6581

66-
createGameProcess(owner, repo) {
82+
createGameProcess(owner: string, repo: string, customLeanServer: string | null) {
6783
let game_dir = this.getGameDir(owner, repo);
6884
if (!game_dir) return;
6985

7086
let serverProcess: cp.ChildProcessWithoutNullStreams;
7187
if (isDevelopment) {
72-
let args = ["--server", game_dir];
73-
let binDir = path.join(game_dir, ".lake", "packages", "GameServer", "server", ".lake", "build", "bin");
74-
// Note: `cwd` is important to be the `bin` directory as `Watchdog` calls `./gameserver` again
75-
if (fs.existsSync(binDir)) {
76-
// Try to use the game's own copy of `gameserver`.
77-
serverProcess = cp.spawn("./gameserver", args, { cwd: binDir });
88+
if (customLeanServer) {
89+
// If the game still uses a custom Lean server, use it.
90+
// Note: `cwd` is important to be the `bin` directory as `Watchdog` calls `./gameserver` again
91+
serverProcess = cp.spawn(
92+
path.join(".", path.basename(customLeanServer)),
93+
["--server", game_dir],
94+
{ cwd: path.dirname(customLeanServer) }
95+
);
7896
} else {
79-
// If the game is built with `-Klean4game.local` there is no copy in the lake packages.
80-
serverProcess = cp.spawn("lake", ["serve", "--"],
81-
{ cwd: path.join(this.dir, "..", "..", "..", "..", "GameSkeleton") });
97+
serverProcess = cp.spawn("lake", ["serve", "--"], { cwd: game_dir });
8298
}
8399
} else {
100+
console.log(path.dirname(customLeanServer))
84101
serverProcess = cp.spawn("../../scripts/bubblewrap.sh",
85-
[game_dir, path.join(this.dir, '..')],
102+
[game_dir, path.join(this.dir, '..', '..', '..'), customLeanServer ? "true" : "false"],
86103
{ cwd: this.dir });
87104
}
88105

@@ -102,7 +119,10 @@ export class GameManager {
102119
const tagString = this.getTagString(tag);
103120
while (this.queue[tagString].length < this.queueLength[tagString]) {
104121
let serverProcess: cp.ChildProcessWithoutNullStreams;
105-
serverProcess = this.createGameProcess(tag.owner, tag.repo);
122+
serverProcess = this.createGameProcess(
123+
tag.owner, tag.repo,
124+
this.getCustomLeanServer(tag.owner, tag.repo)
125+
);
106126
if (serverProcess == null) {
107127
console.error('serverProcess was undefined/null');
108128
return;
@@ -114,7 +134,8 @@ export class GameManager {
114134
messageTranslation(
115135
socketConnection: jsonrpcserver.IConnection,
116136
serverConnection: jsonrpcserver.IConnection,
117-
gameDir: string
137+
gameDir: string,
138+
usesCustomLeanServer: boolean
118139
) {
119140

120141
let shiftLines = (p : any, offset : number) => {
@@ -146,6 +167,8 @@ export class GameManager {
146167

147168
if (isDevelopment) { console.log(`CLIENT: ${JSON.stringify(message)}`); }
148169

170+
if (usesCustomLeanServer) return message
171+
149172
if (message.method === "initialize") {
150173
difficulty = message.params.initializationOptions.difficulty
151174
inventory = message.params.initializationOptions.inventory
@@ -177,6 +200,9 @@ export class GameManager {
177200
});
178201
serverConnection.forward(socketConnection, message => {
179202
if (isDevelopment) { console.log(`SERVER: ${JSON.stringify(message)}`); }
203+
204+
if (usesCustomLeanServer) return message
205+
180206
return shiftLines(message, -PROOF_START_LINE);
181207
});
182208
}

relay/src/websocket.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,9 @@ export class GameSessionsObserver {
107107
});
108108
const serverConnection = jsonrpcserver.createProcessStreamConnection(this.players.get(ws).process);
109109

110-
this.gameManager.messageTranslation(socketConnection, serverConnection, gameDir)
110+
this.gameManager.messageTranslation(
111+
socketConnection, serverConnection, gameDir, gameSession.usesCustomLeanServer
112+
)
111113

112114
socketConnection.onClose(() => {
113115
serverConnection.dispose()

0 commit comments

Comments
 (0)