@@ -21,16 +21,12 @@ import { install } from './npm';
2121import { downloadGithubRepo } from './download-github-folder' ;
2222import { startMobileDebugServer } from './mobile-debug-server' ;
2323import { getLanIp } from './network' ;
24- import { getAbgen , killAbgen , startAbgenForPreview , type AbgenInstance } from './abgen' ;
2524
26- export type Preview = {
27- child : Child ;
28- url : string ;
29- opts : PreviewOptions ;
30- abgen ?: AbgenInstance | null ;
31- } ;
25+ export type Preview = { child : Child ; url : string ; opts : PreviewOptions } ;
3226
33- // Explorer deeplink params for locally generated asset bundles (abgen)
27+ // Explorer deeplink params for locally generated asset bundles. sdk-commands owns the
28+ // abgen sidecar (--asset-bundles) and injects both params into the deeplink it fires;
29+ // the hub only flips them when preview options change mid-session.
3430const LOCAL_AB_PARAM = 'local-ab' ;
3531const OPTIMIZED_ASSETS_URL_PARAM = 'optimized-assets-url' ;
3632
@@ -73,7 +69,6 @@ export async function killPreview(path: string) {
7369 const preview = previewCache . get ( path ) ;
7470 const promise = preview ?. child . kill ( ) . catch ( ( ) => { } ) ;
7571 previewCache . delete ( path ) ;
76- await killAbgen ( path ) ;
7772 await promise ;
7873}
7974
@@ -211,11 +206,7 @@ export async function getMobilePreview(path: string): Promise<{ url: string; qr:
211206
212207// This fn is for already created deep-link. Just to add or remove values to a generated deep-link
213208// decentraland://position=80,80&skip-auth-screen=true etc
214- function updateDeepLinkWithOpts (
215- params : string ,
216- newOpts : PreviewOptions ,
217- abgenUrl ?: string | null ,
218- ) : string {
209+ function updateDeepLinkWithOpts ( params : string , newOpts : PreviewOptions ) : string {
219210 try {
220211 const urlParams = new URLSearchParams ( params ) ;
221212
@@ -238,10 +229,15 @@ function updateDeepLinkWithOpts(
238229 setOrDeleteParam ( PREVIEW_OPTIONS_MAP . enableLandscapeTerrains , newOpts . enableLandscapeTerrains ) ;
239230 setOrDeleteParam ( PREVIEW_OPTIONS_MAP . multiInstance , newOpts . multiInstance ) ;
240231
241- // Locally generated asset bundles: only when the toggle is on AND abgen is running
242- const useLocalAb = ! ! ( newOpts . optimizedAssets && abgenUrl ) ;
243- setOrDeleteParam ( LOCAL_AB_PARAM , useLocalAb ) ;
244- setOrDeleteParam ( OPTIMIZED_ASSETS_URL_PARAM , useLocalAb ? abgenUrl : false ) ;
232+ // Locally generated asset bundles: toggling off strips both params (back to raw
233+ // GLTFs immediately); toggling on sets local-ab and keeps whatever sidecar url the
234+ // captured deeplink carries — if the preview was started without --asset-bundles
235+ // there is no sidecar, the manifest fetch fails, and the scene stays raw until the
236+ // preview is restarted with the toggle on.
237+ setOrDeleteParam ( LOCAL_AB_PARAM , newOpts . optimizedAssets ) ;
238+ if ( ! newOpts . optimizedAssets ) {
239+ setOrDeleteParam ( OPTIMIZED_ASSETS_URL_PARAM , false ) ;
240+ }
245241
246242 // this param is different from what we recieved from the CLI that the one that the launcher uses.
247243 setOrDeleteParam ( 'open-deeplink-in-new-instance' , newOpts . openNewInstance ) ;
@@ -283,6 +279,21 @@ function selfBinPath(): string {
283279 }
284280}
285281
282+ // Feature-detect the opt-in sidecar flag in the scene's installed sdk-commands
283+ // (same pattern as shouldRunLegacyDeploy). The quote-delimited match avoids false
284+ // positives on the older opt-out flag --no-asset-bundles.
285+ async function supportsAssetBundles ( path : string ) : Promise < boolean > {
286+ try {
287+ const file = await fs . readFile (
288+ join ( path , 'node_modules' , '@dcl/sdk-commands/dist/commands/start/index.js' ) ,
289+ 'utf-8' ,
290+ ) ;
291+ return / [ " ' ] - - a s s e t - b u n d l e s [ " ' ] / . test ( file ) ;
292+ } catch {
293+ return false ;
294+ }
295+ }
296+
286297export async function start (
287298 path : string ,
288299 opts : PreviewOptions & { retry ?: boolean } ,
@@ -298,14 +309,8 @@ export async function start(
298309
299310 // If we have a preview running for this path open it
300311 if ( isPreviewRunning ( preview ) ) {
301- // Toggled on mid-session: start abgen against the already-running preview server
302- if ( opts . optimizedAssets && ! getAbgen ( path ) ?. alive ( ) ) {
303- const serverUrl = getPreviewServerUrl ( preview . url ) ;
304- preview . abgen = serverUrl ? await startAbgenForPreview ( path , serverUrl ) : null ;
305- }
306-
307312 // Check if options have changed and update the URL accordingly
308- const updatedUrl = updateDeepLinkWithOpts ( preview . url , opts , getAbgen ( path ) ?. url ) ;
313+ const updatedUrl = updateDeepLinkWithOpts ( preview . url , opts ) ;
309314 await dclDeepLink ( updatedUrl ) ;
310315
311316 return path ;
@@ -315,14 +320,18 @@ export async function start(
315320
316321 try {
317322 const extraArgs : string [ ] = [ ] ;
318- let abgen : AbgenInstance | null = null ;
319- let previewPort : number | null = null ;
320323
324+ // sdk-commands owns the asset-bundle sidecar: --asset-bundles boots it and injects
325+ // local-ab + optimized-assets-url into the deeplink it fires. Missing binary or a
326+ // sidecar that never comes up degrades to raw GLTFs inside sdk-commands itself.
321327 if ( opts . optimizedAssets ) {
322- // Pre-pick the preview server port so abgen can point at it before sdk-commands boots
323- previewPort = await getAvailablePort ( ) ;
324- extraArgs . push ( '--port' , previewPort . toString ( ) ) ;
325- abgen = await startAbgenForPreview ( path , `http://127.0.0.1:${ previewPort } ` ) ;
328+ if ( await supportsAssetBundles ( path ) ) {
329+ extraArgs . push ( '--asset-bundles' ) ;
330+ } else {
331+ log . warn (
332+ '[CLI] Installed @dcl/sdk-commands does not support --asset-bundles; previewing with raw GLTFs' ,
333+ ) ;
334+ }
326335 }
327336
328337 const process = run ( '@dcl/sdk-commands' , 'sdk-commands' , {
@@ -342,29 +351,7 @@ export async function start(
342351
343352 const url = resultLogs . match ( dclLauncherURL ) ?. [ 1 ] ?? '' ;
344353
345- // If sdk-commands ended up on a different port (e.g. the pre-picked one raced),
346- // abgen points at a dead content server: kill it so the preview degrades to raw GLTFs.
347- if ( abgen && previewPort !== null ) {
348- const realmUrl = getPreviewServerUrl ( url ) ;
349- if ( realmUrl && new URL ( realmUrl ) . port !== previewPort . toString ( ) ) {
350- log . warn (
351- `[ABGen] Preview server bound to ${ realmUrl } instead of port ${ previewPort } ; disabling local asset bundles` ,
352- ) ;
353- await killAbgen ( path ) ;
354- abgen = null ;
355- }
356- }
357-
358- const preview : Preview = { child : process , url, opts, abgen } ;
359- previewCache . set ( path , preview ) ;
360-
361- // sdk-commands already opened the client with its own deeplink (it knows nothing about
362- // abgen). Re-fire it augmented with the local asset-bundle params so the running client
363- // picks them up — same mechanism used when options change on a later Preview press.
364- if ( abgen ) {
365- await dclDeepLink ( updateDeepLinkWithOpts ( url , opts , abgen . url ) ) ;
366- }
367-
354+ previewCache . set ( path , { child : process , url, opts } ) ;
368355 return path ;
369356 } catch ( error ) {
370357 killPreview ( path ) ;
0 commit comments