11import { spawn , type ChildProcess } from "node:child_process" ;
22import path from "node:path" ;
3- import { mkdtemp , rename , writeFile } from "node:fs/promises" ;
3+ import { chmod , copyFile , mkdtemp , rename , writeFile } from "node:fs/promises" ;
44import { createInterface , type Interface } from "node:readline" ;
55import AdmZip from "adm-zip" ;
66import { resolveDirectBedrockDownloadUrl } from "./bedrock-downloads.js" ;
@@ -13,6 +13,7 @@ import { resolveProjectRelativePath } from "./environment.js";
1313import {
1414 copyDirectory ,
1515 ensureDirectory ,
16+ ensureParentDirectory ,
1617 exists ,
1718 readJson ,
1819 readText ,
@@ -34,7 +35,10 @@ import {
3435 resolveConfiguredWorldSourcePath ,
3536 resolveProjectWorldSourceDirectory ,
3637} from "./world.js" ;
37- import { resolveProjectServerStatePath } from "./server-state.js" ;
38+ import {
39+ PROJECT_SERVER_STATE_ROOT ,
40+ resolveProjectServerStatePath ,
41+ } from "./server-state.js" ;
3842
3943type AllowlistEntry = {
4044 xuid : string ;
@@ -63,6 +67,8 @@ export type ResolvedBdsState = {
6367 worldSourceDirectory : string ;
6468 executablePath : string ;
6569 zipPath : string ;
70+ customExecutableSourcePath ?: string ;
71+ customExecutableInjected : boolean ;
6672} ;
6773
6874function resolveBdsPlatform (
@@ -120,9 +126,48 @@ export function resolveBdsRuntimeState(
120126 ? `bedrock-server-preview-${ version } -${ platform } .zip`
121127 : `bedrock-server-${ version } -${ platform } .zip` ,
122128 ) ,
129+ customExecutableInjected : false ,
123130 } ;
124131}
125132
133+ function resolveProjectCustomExecutablePath (
134+ projectRoot : string ,
135+ state : ResolvedBdsState ,
136+ ) : string {
137+ return path . join (
138+ projectRoot ,
139+ PROJECT_SERVER_STATE_ROOT ,
140+ path . basename ( state . executablePath ) ,
141+ ) ;
142+ }
143+
144+ async function applyCustomExecutableOverride (
145+ projectRoot : string ,
146+ state : ResolvedBdsState ,
147+ debug ?: DebugLogger ,
148+ ) : Promise < void > {
149+ const customExecutableSourcePath = resolveProjectCustomExecutablePath (
150+ projectRoot ,
151+ state ,
152+ ) ;
153+ if ( ! ( await exists ( customExecutableSourcePath ) ) ) {
154+ return ;
155+ }
156+
157+ await ensureParentDirectory ( state . executablePath ) ;
158+ await copyFile ( customExecutableSourcePath , state . executablePath ) ;
159+ if ( state . platform === "linux" ) {
160+ await chmod ( state . executablePath , 0o755 ) ;
161+ }
162+
163+ state . customExecutableSourcePath = customExecutableSourcePath ;
164+ state . customExecutableInjected = true ;
165+ debug ?. log ( "bds" , "applied custom BDS executable override" , {
166+ sourcePath : customExecutableSourcePath ,
167+ executablePath : state . executablePath ,
168+ } ) ;
169+ }
170+
126171async function downloadIfMissing (
127172 state : ResolvedBdsState ,
128173 debug ?: DebugLogger ,
@@ -363,6 +408,7 @@ async function extractIfMissing(
363408 await readProjectPermissions ( projectRoot , config ) ,
364409 ) ;
365410 await ensureModulePermissions ( state . serverDirectory ) ;
411+ await applyCustomExecutableOverride ( projectRoot , state , debug ) ;
366412 return ;
367413 }
368414
@@ -418,6 +464,7 @@ async function extractIfMissing(
418464 await readProjectPermissions ( projectRoot , config ) ,
419465 ) ;
420466 await ensureModulePermissions ( state . serverDirectory ) ;
467+ await applyCustomExecutableOverride ( projectRoot , state , debug ) ;
421468}
422469
423470async function copyBuiltArtifacts (
@@ -889,6 +936,21 @@ export class BdsServerController {
889936 return ;
890937 }
891938
939+ if ( state . customExecutableInjected ) {
940+ const sourceLabel = state . customExecutableSourcePath
941+ ? path . relative (
942+ this . projectRoot ,
943+ state . customExecutableSourcePath ,
944+ )
945+ : path . join (
946+ PROJECT_SERVER_STATE_ROOT ,
947+ path . basename ( state . executablePath ) ,
948+ ) ;
949+ console . log (
950+ `[dev] Notice: using custom local-server executable override from ${ sourceLabel } .` ,
951+ ) ;
952+ }
953+
892954 this . options . debug ?. log ( "bds" , "starting managed server" , {
893955 executablePath : state . executablePath ,
894956 cwd : state . serverDirectory ,
0 commit comments