@@ -9,6 +9,20 @@ import { isElectronEnvironment, getSpawnEnv, findNpxCliJs, getNpxBin } from './u
99const HAMMURABI_PACKAGE = '@dcl/hammurabi-server'
1010const HAMMURABI_VERSION = 'next'
1111
12+ const BEVY_PACKAGE = '@dcl/bevy-headless-server'
13+ const BEVY_VERSION = 'next'
14+
15+ // The bevy server exits with this when it can never run here (unsupported platform,
16+ // missing binary, bad arguments), which is our cue to fall back to hammurabi.
17+ const EXIT_UNAVAILABLE = 78
18+
19+ type ServerEngine = 'bevy' | 'hammurabi'
20+
21+ function selectedEngine ( ) : ServerEngine {
22+ const requested = process . env . DCL_SERVER_ENGINE
23+ return requested === 'bevy' || requested === 'hammurabi' ? requested : 'hammurabi'
24+ }
25+
1226/**
1327 * Registers cleanup handlers on the global process object
1428 * Returns a function to remove the handlers
@@ -31,14 +45,17 @@ function registerProcessCleanup(cleanup: () => void): () => void {
3145export function startHammurabiServer (
3246 components : Pick < CliComponents , 'logger' > ,
3347 workingDir : string ,
34- realm : string
48+ realm : string ,
49+ engine : ServerEngine = 'hammurabi'
3550) : ChildProcess {
51+ const pkg = engine === 'bevy' ? `${ BEVY_PACKAGE } @${ BEVY_VERSION } ` : `${ HAMMURABI_PACKAGE } @${ HAMMURABI_VERSION } `
52+
3653 printProgressInfo (
3754 components . logger ,
38- `Starting ${ colors . bold ( 'Multiplayer Server' ) } with realm: ${ colors . bold ( realm ) } `
55+ `Starting ${ colors . bold ( 'Multiplayer Server' ) } ( ${ engine } ) with realm: ${ colors . bold ( realm ) } `
3956 )
4057
41- const npxArgs = [ '--yes' , ` ${ HAMMURABI_PACKAGE } @ ${ HAMMURABI_VERSION } ` , `--realm=${ realm } ` ]
58+ const npxArgs = [ '--yes' , pkg , `--realm=${ realm } ` ]
4259 const npxCliJs = findNpxCliJs ( )
4360
4461 // In Electron, override npm_config_prefix because npm derives its prefix from process.execPath,
@@ -80,18 +97,31 @@ export function startHammurabiServer(
8097 * In the auth-server SDK, all scenes are authoritative multiplayer.
8198 * Uses npx to handle installation and execution in a single step (works in Electron).
8299 *
100+ * Which implementation runs is chosen by DCL_SERVER_ENGINE (bevy | hammurabi). When bevy
101+ * reports itself unavailable on this machine, hammurabi is started instead.
102+ *
83103 * @param components - Preview components including logger
84104 * @param project - The project to start the multiplayer server for
85- * @param realm - The realm URL to pass to the hammurabi server
105+ * @param realm - The realm URL to pass to the server
86106 * @returns The ChildProcess if started, undefined otherwise
87107 */
88108export function spawnAuthServer (
89109 components : PreviewComponents ,
90110 project : ProjectUnion ,
91111 realm : string
92112) : ChildProcess | undefined {
113+ const engine = selectedEngine ( )
93114 try {
94- return startHammurabiServer ( components , project . workingDirectory , realm )
115+ const child = startHammurabiServer ( components , project . workingDirectory , realm , engine )
116+ if ( engine === 'bevy' ) {
117+ child . on ( 'close' , ( code ) => {
118+ if ( code === EXIT_UNAVAILABLE ) {
119+ printWarning ( components . logger , 'Bevy multiplayer server unavailable here — falling back to hammurabi' )
120+ startHammurabiServer ( components , project . workingDirectory , realm , 'hammurabi' )
121+ }
122+ } )
123+ }
124+ return child
95125 } catch ( error : any ) {
96126 printWarning ( components . logger , `Failed to start Multiplayer Server: ${ error . message } ` )
97127 return undefined
0 commit comments