task_processor.js 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. import { parentPort } from 'node:worker_threads';
  2. import fs from 'node:fs';
  3. import md5 from "./src/misc/md5.js";
  4. import path from "path";
  5. import defaultProcess from "./src/defaultProcess.js";
  6. import npcInit from "./src/npcInit.js";
  7. import skillDefinitions from "./src/skillDefinitions.js";
  8. import wardrobeItems from "./src/wardrobeItems.js";
  9. import wardrobeItemsTypes from "./src/wardrobeItemsTypes.js";
  10. const thisFilesHash = md5(fs.readFileSync(__filename,{encoding: 'utf8'}));
  11. //https://stackoverflow.com/a/25221100/7200161
  12. function baseFileName(fullpath){
  13. return fullpath.split('\\').pop().split('/').pop();
  14. }
  15. function convertFile(task){
  16. const VERSION = task.VERSION;
  17. const filePath = task.filePath;
  18. const outPath = task.outPath;
  19. const generatedFilesPrefix = task.generatedFilesPrefix;
  20. const options = task.options;
  21. try{
  22. const data = fs.readFileSync(filePath,{encoding: 'utf8'});
  23. const startTime = (new Date()).getTime();
  24. const baseFileNameStr = baseFileName(filePath);
  25. const outFilePath = path.join(outPath,generatedFilesPrefix,baseFileNameStr.split('.')[0]+'.tw');
  26. const outFilePathTS = path.join(outPath,generatedFilesPrefix,baseFileNameStr.split('.')[0]+'.ts');
  27. const qsp2twOptions = data.split('\n')?.[1];
  28. if(qsp2twOptions.startsWith("!! SKIP_QSRC2TW")){
  29. if(fs.existsSync(outFilePath))
  30. fs.unlink(outFilePath,(err) => {if (err) throw err;});
  31. if(fs.existsSync(outFilePathTS))
  32. fs.unlink(outFilePathTS,(err) => {if (err) throw err;});
  33. return [0,"SKIP"];
  34. }
  35. //#region Skip File Output if outfile exists, is based on the same codebase (determined by hash) and has used the same compier-version
  36. const codeHash = md5(data);
  37. if (fs.existsSync(outFilePath)) {
  38. try{
  39. const secondLineData = fs.readFileSync(outFilePath, "utf-8").split('\n')[1];
  40. const qsrc2twResultMatch = secondLineData.match(/<!--\s*qsrc2twResult=({.*})\s*-->/);
  41. if(qsrc2twResultMatch){
  42. const qsrc2twResult = JSON.parse(qsrc2twResultMatch[1]);
  43. if((qsrc2twResult.code && codeHash == qsrc2twResult.code) &&
  44. (qsrc2twResult.version && thisFilesHash == qsrc2twResult.version)){
  45. return [0,"EXISTS"];
  46. }
  47. }
  48. }
  49. catch(e){
  50. //Something unexpected happens. No need to handle this, because we'll just run the default file-processing.
  51. }
  52. }
  53. //#endregion
  54. var convertMode = "default";
  55. var convertModeOptions = {};
  56. /*if(qsp2twOptions.startsWith("!! QSRC2TW_module")){
  57. convertMode = qsp2twOptions.trim().split(" ").toReversed()[0];
  58. }*/
  59. //const modeLookupRegex = /\s*!!\s*QSRC2TW_module\s+(\w+)(\s+{[^}]+})?/;
  60. const modeLookupRegex = /\s*!!\s*QSRC2TW_module\s+(\w+)(\s+.+)?/;
  61. let modeLookupResult;
  62. try{
  63. if(modeLookupResult = modeLookupRegex.exec(qsp2twOptions)){
  64. convertMode = modeLookupResult[1];
  65. if(modeLookupResult[2])
  66. convertModeOptions = JSON.parse(modeLookupResult[2]);
  67. }
  68. }
  69. catch(e){
  70. console.log(e.toString());
  71. }
  72. /**
  73. * Return value is Array [TwineCode, TSCode]. TwineCode must not be null.
  74. */
  75. var convertFunction = (code,options)=>[null,null];
  76. switch (convertMode) {
  77. case "default": convertFunction = (code,options) => [defaultProcess(code),null]; break;
  78. case "npcInit": convertFunction = (code,options) => npcInit(code); break;
  79. case "stat_sklattrib_lvlset": convertFunction = (code,options) => skillDefinitions(code); break;
  80. case "wardrobeItems": convertFunction = (code,options) => wardrobeItems(code,options); break;
  81. case "wardrobeItemsTypes": convertFunction = (code,options) => wardrobeItemsTypes(code,options); break;
  82. default:
  83. console.warn("Unreckognized Convert Mode");
  84. break;
  85. }
  86. try{
  87. let twineCode = "";
  88. let twineCodeRaw = undefined;
  89. let tsCodeRaw = undefined;
  90. const defaultConsole = console;
  91. if(!options.verboseErrors)
  92. console = {log:(...args)=>{}, debug: (...args)=>{},warn:(...args)=>{}, error: (...args)=>{}};
  93. try{
  94. [twineCodeRaw,tsCodeRaw] = convertFunction(data,convertModeOptions);
  95. }
  96. catch(e){
  97. throw e;
  98. }
  99. finally{
  100. console = defaultConsole;
  101. }
  102. if(!twineCodeRaw){
  103. console.error("Twine Code must be generated by every convertMode");
  104. return [2,"Invalid convertFunction"];
  105. }else{
  106. twineCode = twineCodeRaw.split('\n')
  107. .toSpliced(1,0,`<!--qsrc2twResult={"version":"${thisFilesHash}","code":"${codeHash}","time":"${(new Date().toISOString())}"}-->`)
  108. .join('\n');
  109. fs.writeFile(outFilePath, twineCode, err => {
  110. if (err) {
  111. console.error(err);
  112. } else {
  113. }
  114. });
  115. }
  116. if(!tsCodeRaw){
  117. if(fs.existsSync(outFilePathTS))
  118. fs.unlink(outFilePathTS,(err) => {if (err) throw err;});
  119. }else{
  120. fs.writeFile(outFilePathTS, tsCodeRaw, err => {
  121. if (err) {
  122. console.error(err);
  123. } else {
  124. }
  125. });
  126. }
  127. const executionTime = (new Date()).getTime() - startTime;
  128. console.log(`${baseFileNameStr.padEnd(30,'.')} ${executionTime} ms`);
  129. return [0,"SUCCESS"];
  130. }catch(e){
  131. //console.error(`Error in "${baseFileNameStr}". No output was generated`);
  132. return [1,`Error in "${baseFileNameStr}". No output was generated`,e];
  133. }
  134. }
  135. catch(e){
  136. //console.error();
  137. return [1,`Critical Error in "${filePath}". No output was generated`, e];
  138. }
  139. }
  140. parentPort.on('message', (task) => {
  141. parentPort.postMessage(convertFile(task));
  142. });