import ArrayBufferSlice from "../../ArrayBufferSlice" ; import { readFileSync , writeFileSync , readdirSync , mkdirSync } from "fs" ; import * as BYML from "../../byml" ; import { assert , leftPad } from "../../util" ; function fetchDataSync ( path ) { const b = readFileSync ( path ) ; return new ArrayBufferSlice ( b . buffer , b . byteOffset , b . byteLength ) ; } const pathBaseIn = `../../../data/zelview_beta_raw` ; const pathBaseOut = `../../../data/zelview_beta` ; interface ZELVIEW0File { filename : string ; buffer : ArrayBufferSlice ; vStart : number ; } function pushFile ( files , basedir , filename , vStart = 0 , vEnd = null ) { const buffer = fetchDataSync ( `${ basedir }/${ filename }` ) ; if ( vEnd !== null ) assert ( vStart + buffer . byteLength === vEnd ) ; const file = { filename , buffer , vStart } ; files . push ( file ) ; return file ; } enum HeaderCommands { Spawns = 0x00 , Actors = 0x01 , Camera = 0x02 , Collision = 0x03 , Rooms = 0x04 , WindSettings = 0x05 , EntranceList = 0x06 , SpecialObjects = 0x07 , SpecialBehavior = 0x08 , Mesh = 0x0A , Objects = 0x0B , Waypoints = 0x0D , Transitions = 0x0E , Environment = 0x0F , Time = 0x10 , Skybox = 0x11 , End = 0x14 } function parseRoomTable ( files , buffer , basedir ) { const view = buffer . createDataView ( ) ; function readRooms ( nRooms , roomTableAddr ) { const rooms = [ ] ; assert ( ( roomTableAddr >>> 24 ) === 0x02 ) ; let roomTableIdx = roomTableAddr & 0x00FFFFFF ; for ( let i = 0 ; i < nRooms ; i ++ ) { const vStart = view . getUint32 ( roomTableIdx + 0x00 ) ; const vEnd = view . getUint32 ( roomTableIdx + 0x04 ) ; pushFile ( files , basedir , `room_${ i }.zmap` , vStart , vEnd ) ; roomTableIdx += 0x08 ; } } let offs = 0 ; while ( true ) { const cmd1 = view . getUint32 ( offs + 0x00 , false ) ; const cmd2 = view . getUint32 ( offs + 0x04 , false ) ; offs += 8 ; const cmdType = cmd1 >> 24 ; if ( cmdType === HeaderCommands . End ) break ; switch ( cmdType ) { case HeaderCommands . Rooms : const nRooms = ( cmd1 >> 16 ) & 0xFF ; return readRooms ( nRooms , cmd2 ) ; } } assert ( false ) ; } function main ( ) { const scenes = readdirSync ( `${ pathBaseIn }/scenes` ) ; scenes . sort ( ( a , b ) => { const ai = parseInt ( a , 10 ) ; const bi = parseInt ( b , 10 ) ; return ai - bi ; } ) ; let sceneDescStr = '' ; mkdirSync ( `${ pathBaseOut }` , { recursive : true } ) ; for ( let i = 0 ; i < scenes . length ; i ++ ) { const dirName = scenes [ i ] ; if ( ! dirName . includes ( ' - ' ) ) continue ; const sceneTableIndex = parseInt ( dirName , 10 ) ; const basedir = `${ pathBaseIn }/scenes/${ dirName }` ; const files = [ ] ; const sceneData = pushFile ( files , basedir , `scene.zscene` ) ; parseRoomTable ( files , sceneData . buffer , basedir ) ; const stream = new BYML . WritableStream ( ) ; stream . writeString ( 'ZELVIEW0' ) ; stream . writeUint32 ( files . length , true ) ; stream . writeUint32 ( 0 , true ) ; let offs = 0x10 + files . length * 0x40 ; for ( let i = 0 ; i < files . length ; i ++ ) { const { filename , buffer , vStart } = files [ i ] ; const size = buffer . byteLength ; stream . writeFixedString ( filename , 0x30 ) ; stream . writeUint32 ( vStart , true ) ; stream . writeUint32 ( vStart + size , true ) ; stream . writeUint32 ( offs , true ) ; stream . writeUint32 ( offs + size , true ) ; offs += size ; } for ( let i = 0 ; i < files . length ; i ++ ) stream . writeBufferSlice ( files [ i ] . buffer ) ; const zelview0Buffer = stream . finalize ( ) ; const outSceneId = `${ leftPad ( '' + sceneTableIndex , 2 ) }` ; writeFileSync ( `${ pathBaseOut }/${ outSceneId }.zelview0` , Buffer . from ( zelview0Buffer ) ) ; const sceneName = dirName . split ( ' - ' ) [ 1 ] ; sceneDescStr += `    new ZelviewSceneDesc('${ outSceneId }', "${ sceneName }", pathBase),\n` ; } writeFileSync ( `${ pathBaseOut }/_sceneDescs.txt` , sceneDescStr ) ; } main ( ) ;