import { parentPort } from 'node:worker_threads'; import fs from 'node:fs'; import md5 from "./src/misc/md5.js"; import path from "path"; import defaultProcess from "./src/defaultProcess.js"; import npcInit from "./src/npcInit.js"; import skillDefinitions from "./src/skillDefinitions.js"; import wardrobeItems from "./src/wardrobeItems.js"; import wardrobeItemsTypes from "./src/wardrobeItemsTypes.js"; const thisFilesHash = md5(fs.readFileSync(__filename,{encoding: 'utf8'})); //https://stackoverflow.com/a/25221100/7200161 function baseFileName(fullpath){ return fullpath.split('\\').pop().split('/').pop(); } function convertFile(task){ const VERSION = task.VERSION; const filePath = task.filePath; const outPath = task.outPath; const generatedFilesPrefix = task.generatedFilesPrefix; const options = task.options; try{ const data = fs.readFileSync(filePath,{encoding: 'utf8'}); const startTime = (new Date()).getTime(); const baseFileNameStr = baseFileName(filePath); const outFilePath = path.join(outPath,generatedFilesPrefix,baseFileNameStr.split('.')[0]+'.tw'); const outFilePathTS = path.join(outPath,generatedFilesPrefix,baseFileNameStr.split('.')[0]+'.ts'); const qsp2twOptions = data.split('\n')?.[1]; if(qsp2twOptions.startsWith("!! SKIP_QSRC2TW")){ if(fs.existsSync(outFilePath)) fs.unlink(outFilePath,(err) => {if (err) throw err;}); if(fs.existsSync(outFilePathTS)) fs.unlink(outFilePathTS,(err) => {if (err) throw err;}); return [0,"SKIP"]; } //#region Skip File Output if outfile exists, is based on the same codebase (determined by hash) and has used the same compier-version const codeHash = md5(data); if (fs.existsSync(outFilePath)) { try{ const secondLineData = fs.readFileSync(outFilePath, "utf-8").split('\n')[1]; const qsrc2twResultMatch = secondLineData.match(//); if(qsrc2twResultMatch){ const qsrc2twResult = JSON.parse(qsrc2twResultMatch[1]); if((qsrc2twResult.code && codeHash == qsrc2twResult.code) && (qsrc2twResult.version && thisFilesHash == qsrc2twResult.version)){ return [0,"EXISTS"]; } } } catch(e){ //Something unexpected happens. No need to handle this, because we'll just run the default file-processing. } } //#endregion var convertMode = "default"; var convertModeOptions = {}; /*if(qsp2twOptions.startsWith("!! QSRC2TW_module")){ convertMode = qsp2twOptions.trim().split(" ").toReversed()[0]; }*/ //const modeLookupRegex = /\s*!!\s*QSRC2TW_module\s+(\w+)(\s+{[^}]+})?/; const modeLookupRegex = /\s*!!\s*QSRC2TW_module\s+(\w+)(\s+.+)?/; let modeLookupResult; try{ if(modeLookupResult = modeLookupRegex.exec(qsp2twOptions)){ convertMode = modeLookupResult[1]; if(modeLookupResult[2]) convertModeOptions = JSON.parse(modeLookupResult[2]); } } catch(e){ console.log(e.toString()); } /** * Return value is Array [TwineCode, TSCode]. TwineCode must not be null. */ var convertFunction = (code,options)=>[null,null]; switch (convertMode) { case "default": convertFunction = (code,options) => [defaultProcess(code),null]; break; case "npcInit": convertFunction = (code,options) => npcInit(code); break; case "stat_sklattrib_lvlset": convertFunction = (code,options) => skillDefinitions(code); break; case "wardrobeItems": convertFunction = (code,options) => wardrobeItems(code,options); break; case "wardrobeItemsTypes": convertFunction = (code,options) => wardrobeItemsTypes(code,options); break; default: console.warn("Unreckognized Convert Mode"); break; } try{ let twineCode = ""; let twineCodeRaw = undefined; let tsCodeRaw = undefined; const defaultConsole = console; if(!options.verboseErrors) console = {log:(...args)=>{}, debug: (...args)=>{},warn:(...args)=>{}, error: (...args)=>{}}; try{ [twineCodeRaw,tsCodeRaw] = convertFunction(data,convertModeOptions); } catch(e){ throw e; } finally{ console = defaultConsole; } if(!twineCodeRaw){ console.error("Twine Code must be generated by every convertMode"); return [2,"Invalid convertFunction"]; }else{ twineCode = twineCodeRaw.split('\n') .toSpliced(1,0,``) .join('\n'); fs.writeFile(outFilePath, twineCode, err => { if (err) { console.error(err); } else { } }); } if(!tsCodeRaw){ if(fs.existsSync(outFilePathTS)) fs.unlink(outFilePathTS,(err) => {if (err) throw err;}); }else{ fs.writeFile(outFilePathTS, tsCodeRaw, err => { if (err) { console.error(err); } else { } }); } const executionTime = (new Date()).getTime() - startTime; console.log(`${baseFileNameStr.padEnd(30,'.')} ${executionTime} ms`); return [0,"SUCCESS"]; }catch(e){ //console.error(`Error in "${baseFileNameStr}". No output was generated`); return [1,`Error in "${baseFileNameStr}". No output was generated`,e]; } } catch(e){ //console.error(); return [1,`Critical Error in "${filePath}". No output was generated`, e]; } } parentPort.on('message', (task) => { parentPort.postMessage(convertFile(task)); });