import { requireLocal } from '../require' ; import * as nodefs from 'fs' ; import * as nodepath from 'path' ; const fs = requireLocal ( 'fs' ) ; const path = requireLocal ( 'path' ) ; import { saveFile as save } from './saveFile' ; const mods = [ ] ; let packagesCache ; async function listAllFiles ( dir , filelist , ending , root ? ) { if ( root === undefined ) { root = dir ; } const files = await tryReadDir ( dir ) ; const promises = [ ] ; for ( const file of files ) { promises . push ( searchFile ( file , dir , filelist , ending , root ) ) ; } await Promise . all ( promises ) ; return filelist ; } async function tryReadDir ( dir ) { try { return await fs . promises . readdir ( dir ) ; } catch { return [ ] ; } } param file param dir param filelist param ending param root async function searchFile ( file , dir , filelist , ending , root ? ) { const stat = await fs . promises . stat ( path . resolve ( dir , file ) ) ; if ( stat . isDirectory ( ) ) { await listAllFiles ( path . resolve ( dir , file ) , filelist , ending , root ) ; } else if ( ! ending || file . toLowerCase ( ) . endsWith ( ending . toLowerCase ( ) ) ) { const normalized = path . resolve ( dir , file ) . split ( path . normalize ( root ) ) [ 1 ] . replace ( /\\/g , '/' ) ; const result = normalized . startsWith ( '/' ) ? normalized . substr ( 1 ) : normalized ; if ( ! filelist . includes ( result ) ) { filelist . push ( result ) ; } } } param dir param file async function searchSubFolder ( dir , file ) { const result = [ ] ; const files = await tryReadDir ( dir ) ; for ( const folder of files ) { try { const stat = await fs . promises . stat ( path . join ( dir , folder , file ) ) ; if ( stat . isFile ( ) ) { result . push ( path . join ( dir , folder , file ) ) ; } } catch ( e ) { console . error ( e ) ; } } return result ; } function selectMod ( name , packages , result ) { const pkg = packages . get ( name ) ; if ( ! pkg ) { return ; } result . push ( pkg . folderName ) ; if ( ! pkg . ccmodDependencies ) { return ; } for ( const depName of Object . keys ( pkg . ccmodDependencies ) ) { selectMod ( depName , packages , result ) ; } } async function getAsync ( file ) { try { const stat = await fs . promises . stat ( file ) ; if ( stat . isFile ( ) ) { return fs . promises . readFile ( file ) ; } } catch ( e ) { console . error ( e ) ; } return null ; } async function resolveAsync ( file ) { try { const stat = await fs . promises . stat ( file ) ; if ( stat . isFile ( ) ) { return file ; } } catch ( e ) { console . error ( e ) ; } return null ; } async function readMods ( dir ) { if ( packagesCache ) { return packagesCache ; } const modFolder = path . join ( dir , 'mods/' ) ; const files = await searchSubFolder ( modFolder , 'package.json' ) ; const promises = [ ] ; for ( const file of files ) { promises . push ( ( async ( ) : Promise < [ string , Buffer ] > => [ path . basename ( path . dirname ( file ) ) , await fs . promises . readFile ( file ) ] ) ( ) ) ; } const rawPackages = await Promise . all ( promises ) ; const packages = new Map < string , { folderName : string ; ccmodDependencies ? : Map < string , string > ; } > ( ) ; for ( const [ name , pkg ] of rawPackages ) { const parsed = JSON . parse ( pkg as unknown as string ) ; parsed . folderName = name ; packages . set ( parsed . name , parsed ) ; } packagesCache = packages ; return packages ; } export async function getAllFiles ( dir ) { const images = await listAllFiles ( path . resolve ( dir , 'media/' ) , [ ] , 'png' , path . resolve ( dir ) ) ; const data = await listAllFiles ( path . resolve ( dir , 'data/' ) , [ ] , 'json' , path . resolve ( dir ) ) ; for ( const mod of mods ) { const modDir = path . join ( dir , 'mods' , mod , 'assets' ) ; await listAllFiles ( path . resolve ( modDir , 'media/' ) , images , 'png' , path . resolve ( modDir ) ) ; await listAllFiles ( path . resolve ( modDir , 'data/' ) , data , 'json' , path . resolve ( modDir ) ) ; } images . sort ( ) ; data . sort ( ) ; return { images , data } ; } export async function getAllTilesets ( dir ) { const result = await listAllFiles ( path . resolve ( dir , 'media/map/' ) , [ ] , 'png' , path . resolve ( dir ) ) ; for ( const mod of mods ) { const modDir = path . join ( dir , 'mods' , mod , 'assets' ) ; await listAllFiles ( path . resolve ( modDir , 'media/map/' ) , result , 'png' , path . resolve ( modDir ) ) ; } return result . sort ( ) ; } export async function getAllMaps ( dir ) { const paths = [ ] ; if ( mods . length === 0 ) { await listAllFiles ( path . resolve ( dir , 'data/maps/' ) , paths , 'json' , path . resolve ( dir ) ) ; } else { const modDir = path . join ( dir , 'mods' , mods [ 0 ] , 'assets' ) ; await listAllFiles ( path . resolve ( modDir , 'data/maps/' ) , paths , 'json' , path . resolve ( modDir ) ) ; } return paths . sort ( ) . map ( p => p . substring ( 'data/maps/' . length , p . length - '.json' . length ) ) . map ( p => p . replace ( /\//g , '.' ) . replace ( /\\/g , '.' ) ) ; } export async function getAllMods ( dir ) { const packages = await readMods ( dir ) ; return Array . from ( packages . keys ( ) ) . sort ( ) ; } export async function selectedMod ( dir , modName ) { const packages = await readMods ( dir ) ; mods . splice ( 0 ) ; selectMod ( modName , packages , mods ) ; } export async function get < T > ( dir , file ) { const promises = [ ] ; for ( const mod of mods ) { const modFile = path . join ( dir , 'mods' , mod , 'assets' , file ) ; promises . push ( getAsync ( modFile ) ) ; } promises . push ( getAsync ( path . join ( dir , file ) ) ) ; const results = await Promise . all ( promises ) ; for ( const result of results ) { if ( result ) { return JSON . parse ( result as unknown as string ) ; } } throw new Error ( 'File not found: ' + file ) ; } export async function resolve ( dir , file ) { const promises = [ ] ; for ( const mod of mods ) { const modFile = path . join ( dir , 'mods' , mod , 'assets' , file ) ; promises . push ( resolveAsync ( modFile ) ) ; } promises . push ( resolveAsync ( path . join ( dir , file ) ) ) ; const results = await Promise . all ( promises ) ; for ( const result of results ) { if ( result ) { return path . relative ( dir , result ) ; } } throw new Error ( 'File not found: ' + file ) ; } export async function saveFile ( assetsPath , file ) { if ( mods . length === 0 ) { return save ( assetsPath , file ) ; } else { return save ( path . join ( assetsPath , 'mods' , mods [ 0 ] , 'assets' ) , file ) ; } }