TFHres_db.js 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. const sqlite3 = require('sqlite3').verbose()
  2. let db = new sqlite3.Database('./test/resources_prod.tfhres')
  3. const fs = require('fs')
  4. // Every JSON file that contains dialogues is stored in ink_bytecode table in bytecode column so we query them
  5. // hiberlite_id is unique row id, duh
  6. sql = 'SELECT bytecode, hiberlite_id, shortname FROM ink_bytecode'
  7. db.all(sql, (err, rows) => {
  8. if (err) {
  9. throw err
  10. }
  11. if (process.argv[2] === 'decode') {
  12. output = decodeFile(rows);
  13. saveOutput('./Test_pixel_overworld_dialog.json', output);
  14. }
  15. else if (process.argv[2] === 'encode') {
  16. encodeFile(rows)
  17. }
  18. else if (process.argv[2] === 'questions') {
  19. json = require('./temp.json')
  20. jsonFileToQuestionMarks(json)
  21. saveOutput('./temp.json', json)
  22. }
  23. })
  24. // Save file
  25. saveOutput = (path, obj) => {
  26. fs.writeFile(path, JSON.stringify(obj, null, 4), 'utf8', (err) => {
  27. if (err) throw err; console.log('Saved!')
  28. })
  29. }
  30. ignoreSceneID = ['ari_outercave1-anutrainingsession_talktome_78', 'blanktest_start_1', 'prompt_test_doortdest1_119', 'prompt_test_door_test_120',
  31. 'prompt_test_dummyrock_123', 'prompt_test_othertrigger_113', 'prompt_test_testinteract1_117', 'prompt_test_walktrigger_111', 'prompt_test_walk_talk_test_106',
  32. 'testroomd_deer1_187', 'testroomd_defaultstart_168', 'testroomd_rockinteract1_169', 'testroomd_snake1_175', 'testroomd_snake2_186', 'testroomd_snakechest1_174',
  33. 'testroomd_wof1_202', 'testroome_blackness_destination_179', 'trade_test_defaultstart_28', 'trade_test_madison_73', 'trade_test_thinking_statue_2_61',
  34. 'trade_test_thinking_statue_3_62', 'trade_test_thinking_statue_56']
  35. // Main decode function
  36. function decodeFile(rows) {
  37. output = [];
  38. let skipped = 0;
  39. for (key in rows) {
  40. let sceneName = (rows[key].shortname)
  41. // database:/example.inkc
  42. // 'example.inkc'
  43. let start = /[^:\/]+$/
  44. // '.inkc'
  45. let end = /\.inkc/
  46. sceneName = sceneName.slice(sceneName.search(start), sceneName.search(end))
  47. if (ignoreSceneID.includes(sceneName)) {
  48. skipped++
  49. continue // continue to next key in rows
  50. }
  51. let dialogues = JSON.parse(rows[key].bytecode).root[2] // Root 2 contains dialogue related content
  52. output.push({ hiberlite_id: rows[key].hiberlite_id, scene: sceneName, text: {} }) // Creating header template so that decodeStuff has base to work with
  53. let elementNumber = parseInt(key) - skipped;
  54. decodeStuff(dialogues, output[elementNumber].text)
  55. }
  56. for (i = 0; i < output.length; i++) {
  57. if (Object.keys(output[i].text).length === 0) {
  58. output.splice(i, 1)
  59. i--
  60. }
  61. }
  62. return output;
  63. }
  64. ignoreKeys = ['on_create']
  65. // Every string starts with a '^' and is NOT followed by ':'
  66. var regExp = /^\^(?!:)/
  67. // Recursive function that iterates over object copying its hierarchy and saving text from it
  68. function decodeStuff(dialogues, outputText) {
  69. for (key in dialogues) {
  70. if (ignoreKeys.includes(key)) continue
  71. let val = dialogues[key]
  72. // Save string into output if we have one
  73. if (typeof val === 'string' && regExp.test(val)) {
  74. //Sometimes there are empty strings that only contain blank space so we skip them
  75. if (val != '^ ') outputText[key] = val.slice(1);
  76. }
  77. // Recursion time if we have something to iterate over
  78. else if (val && typeof val !== 'string') {
  79. outputText[key] = {};
  80. decodeStuff(dialogues[key], outputText[key])
  81. }
  82. }
  83. // Just clear junk and delete every empty branch of our output
  84. if (Object.keys(outputText) !== 0) {
  85. for (key of Object.keys(outputText)) {
  86. if (!outputText[key] || Object.keys(outputText[key]).length === 0) delete outputText[key]
  87. }
  88. }
  89. }
  90. // Main encode function
  91. function encodeFile(rows) {
  92. const temp = require('./pixel_overworld_dialog_rus.json'); // Encoding happens from a temp.json file
  93. const stmt = db.prepare('UPDATE ink_bytecode SET bytecode = ? WHERE hiberlite_id = ?'); // sql again
  94. var json
  95. rowsOrdered = {};
  96. for (j = 0; j < rows.length; j++) {
  97. key = rows[j].hiberlite_id
  98. rowsOrdered[key] = rows[j]
  99. }
  100. for (let i in temp) {
  101. rowsKey = temp[i].hiberlite_id
  102. if (!rowsOrdered[rowsKey]) {
  103. console.log('Row ' + temp[i].hiberlite_id + ' not found!')
  104. continue
  105. }
  106. json = JSON.parse(rowsOrdered[rowsKey].bytecode)
  107. encodeStuff(json.root[2], temp[i].text)
  108. stmt.run(JSON.stringify(json), temp[i].hiberlite_id); // Overrides json stored in db with our encoded json
  109. }
  110. console.log('In process... (pause means done)')
  111. }
  112. // Recursive function that iterates over extracted json replacing each string in packed db json
  113. // json is json to override, temp is our json
  114. function encodeStuff(json, temp, adress = []) {
  115. if (!temp) return // i don't remember why i added this, hope this is important
  116. for (let key in temp) {
  117. let val = temp[key]
  118. // If we find string use its index to override original json
  119. if (typeof val === 'string') {
  120. if (json[key] !== '^' + val) json[key] = '^' + val
  121. }
  122. // Recursion time
  123. else if (val && typeof val !== 'string') {
  124. encodeStuff(json[key], val)
  125. }
  126. }
  127. }
  128. // Function for testing purposes that changes decoded json to contain only question marks. Works properly only on decoded jsons!
  129. function jsonFileToQuestionMarks(json) {
  130. for (key in json) {
  131. let val = json[key]
  132. if (typeof val === 'string') {
  133. json[key] = val.replace(/\S/g, '?')
  134. }
  135. else if (val && typeof val !== 'string') {
  136. jsonFileToQuestionMarks(val)
  137. }
  138. }
  139. return json
  140. }