RepackingGbs.hx 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498
  1. package;
  2. import sys.FileSystem;
  3. import haxe.io.Path;
  4. import sys.io.File;
  5. import haxe.ds.ObjectMap;
  6. import format.gbs_otterui.GbsData;
  7. import format.gbs_otterui.GbsReader;
  8. import format.gbs_otterui.GbsWriter;
  9. import format.gbs_otterui.Tools;
  10. import haxe.io.Bytes;
  11. using format.gbs_otterui.Tools;
  12. class RepackingGbs {
  13. public function new() {}
  14. public function processingPixel() {
  15. // var location = "otterui-project/Import/Import-pixel-ui/BuckLobby.gbs";
  16. // gbsTestReadWrite(location);
  17. #if debug
  18. trace("Repacking gbs debug");
  19. #end
  20. //**PIXEL**/
  21. // Load export gbs
  22. var atlases_export_pixel = "otterui-project/OtterExport/Export-pixel-ui/Fonts";
  23. // путь с файлами до OtterExport - pixel-ui
  24. var fileList_export_pixel = recursiveDir("otterui-project/OtterExport/Export-pixel-ui");
  25. //
  26. // путь с файлами до Import - pixel-ui
  27. var fileList_import_pixel = recursiveDir("otterui-project/Import/Import-pixel-ui");
  28. //
  29. // путь до Merged - pixel-ui
  30. var path_merged_pixel = "otterui-project/Merged/pixel-ui-merged/";
  31. //
  32. // здесь проверяем массив сцен на наличие шрифтов
  33. fileList_import_pixel = arrayCheckFonts(fileList_import_pixel);
  34. if (fileList_export_pixel.length == 0 || fileList_import_pixel.length == 0) {
  35. trace('Warning! Export or Import pixel folder is empty.');
  36. return;
  37. }
  38. // Импортируемые игровые файлы
  39. var objectList_import_pixel = readGbsList(fileList_import_pixel);
  40. //***
  41. var objectList_export_pixel = readGbsList(fileList_export_pixel);
  42. fileList_export_pixel = [];
  43. var translatedFonts = fontsAllocate(objectList_export_pixel);
  44. objectList_export_pixel = [];
  45. var fromGameFonts = fontsComparingAllocate(translatedFonts, objectList_import_pixel);
  46. mergeFonts(fromGameFonts, translatedFonts);
  47. mapToObjects(fromGameFonts, objectList_import_pixel);
  48. calculateGbsLength(objectList_import_pixel);
  49. #if debug
  50. objectCheckOffsets(objectList_import_pixel, 0);
  51. objectCheckOffsets(objectList_import_pixel, 1);
  52. #end
  53. // write new gbs files
  54. writeMergedGbs(objectList_import_pixel, path_merged_pixel, fileList_import_pixel);
  55. fileList_import_pixel = [];
  56. renamingPng(atlases_export_pixel, path_merged_pixel, translatedFonts, fromGameFonts);
  57. fromGameFonts.clear();
  58. translatedFonts.clear();
  59. objectList_import_pixel = [];
  60. #if debug
  61. var location = "otterui-project/Merged/pixel-ui-merged/BuckLobby.gbs";
  62. if (Tools.fileExists(location)) {
  63. var gi = sys.io.File.read(location);
  64. trace('Start of gbs file reading: "$location"');
  65. var myGBS = new GbsReader(gi).read();
  66. gi.checkOffsets;
  67. gi.close();
  68. }
  69. #end
  70. // trace('test');
  71. }
  72. public function processingMain() {
  73. //**MAIN**/
  74. // Load export gbs
  75. var atlases_export_main = "otterui-project/OtterExport/Export-main-ui/Fonts";
  76. // путь с файлами до OtterExport - main-ui
  77. var fileList_export_main = recursiveDir("otterui-project/OtterExport/Export-main-ui");
  78. //
  79. // путь с файлами до Import - main-ui
  80. var fileList_import_main = recursiveDir("otterui-project/Import/Import-main-ui");
  81. //
  82. // путь до Merged - main-ui
  83. var path_merged_main = "otterui-project/Merged/main-ui-merged/";
  84. //
  85. // здесь проверяем массив сцен на наличие шрифтов
  86. fileList_import_main = arrayCheckFonts(fileList_import_main);
  87. if (fileList_export_main.length == 0 || fileList_import_main.length == 0) {
  88. trace('Warning! Export or Import main folder is empty.');
  89. return;
  90. }
  91. // Импортируемые игровые файлы
  92. var objectList_import_main = readGbsList(fileList_import_main);
  93. //***
  94. var objectList_export_main = readGbsList(fileList_export_main);
  95. fileList_export_main = [];
  96. var translatedFonts = fontsAllocate(objectList_export_main);
  97. objectList_export_main = [];
  98. var fromGameFonts = fontsComparingAllocate(translatedFonts, objectList_import_main);
  99. mergeFonts(fromGameFonts, translatedFonts);
  100. mapToObjects(fromGameFonts, objectList_import_main);
  101. calculateGbsLength(objectList_import_main);
  102. // write new gbs files
  103. writeMergedGbs(objectList_import_main, path_merged_main, fileList_import_main);
  104. fileList_import_main = [];
  105. renamingPng(atlases_export_main, path_merged_main, translatedFonts, fromGameFonts);
  106. fromGameFonts.clear();
  107. translatedFonts.clear();
  108. objectList_import_main = [];
  109. #if debug
  110. var location = "otterui-project/Merged/main-ui-merged/MainMenu.gbs";
  111. if (Tools.fileExists(location)) {
  112. var gi = sys.io.File.read(location);
  113. trace('Start of gbs file reading: "$location"');
  114. var myGBS = new GbsReader(gi).read();
  115. gi.checkOffsets;
  116. gi.close();
  117. }
  118. #end
  119. }
  120. function renamingPng(read_path:String, save_path:String, translated:Map<Int, GbsFont>, fromGame:Map<Int, GbsFont>) {
  121. // переименовать png файлы шрифтов под новое значение индексов
  122. // по количеству атласов в импорте и экспорте (импорт + экспорт + 1)
  123. var read_path = Path.addTrailingSlash(read_path);
  124. var save_path = Path.addTrailingSlash(save_path);
  125. for (key in translated.keys()) {
  126. var impFont = fromGame[key];
  127. var expFont = translated[key];
  128. if (expFont.atlasCount != 0) {
  129. var maxAtlasIndexImp = impFont.atlasCount - expFont.atlasCount - 1;
  130. for (i in 0...expFont.atlasCount) {
  131. var newIndex = maxAtlasIndexImp + i + 1;
  132. var name = expFont.fontName + '_${i}';
  133. // trace(i);
  134. // trace(newIndex);
  135. recursiveDir(read_path, name, save_path, newIndex);
  136. }
  137. }
  138. }
  139. }
  140. function writeMergedGbs(objectList:Array<GbsFile>, path:String, name:Array<String>) {
  141. var i = 0;
  142. while (i < objectList.length) {
  143. var save_location = path + name[i];
  144. if (FileSystem.exists(path)) {} else
  145. FileSystem.createDirectory(path);
  146. var go = sys.io.File.write(save_location);
  147. trace('Start of gbs file writing: "$save_location"');
  148. new GbsWriter(go).write(objectList[i]);
  149. go.close();
  150. i++;
  151. }
  152. }
  153. function calculateGbsLength(objectList:Array<GbsFile>) {
  154. for (gui in objectList) {
  155. // здесь суммируем длину всех шрифтов в объекте
  156. var allFontsLength = 0;
  157. var i = 0;
  158. while (i < gui.fontsBlock.length) {
  159. allFontsLength += gui.fontsBlock[i].fontLength;
  160. i++;
  161. }
  162. // calculating offsets
  163. var fileSize = gui.header.fileSize;
  164. var fontsOffset = gui.header.fontsOffset;
  165. var texturesOffset = gui.header.texturesOffset;
  166. var fontsToFileEnd = fileSize - (fontsOffset + 56);
  167. var texturesToFileEnd = fileSize - (texturesOffset + 56);
  168. var oldFontsLength = fontsToFileEnd - texturesToFileEnd;
  169. var currentOffset = allFontsLength - oldFontsLength;
  170. gui.header.texturesOffset = currentOffset + gui.header.texturesOffset;
  171. gui.header.soundsOffset = currentOffset + gui.header.soundsOffset;
  172. gui.header.viewsOffset = currentOffset + gui.header.viewsOffset;
  173. gui.header.messagesOffset = currentOffset + gui.header.messagesOffset;
  174. gui.header.fileSize = currentOffset + gui.header.fileSize;
  175. }
  176. }
  177. function mapToObjects(map:Map<Int, GbsFont>, objectList:Array<GbsFile>) {
  178. // objectList[0].fontsBlock[0].fontLength
  179. // objectList[0].fontsBlock[0].fontID
  180. // map[0].fontLength
  181. // map[0].fontID
  182. // fontID = key
  183. for (key in map.keys()) {
  184. var nGui = 0;
  185. while (nGui < objectList.length) {
  186. var nFont = 0;
  187. while (nFont < objectList[nGui].fontsBlock.length) {
  188. var id = objectList[nGui].fontsBlock[nFont].fontID;
  189. if (id == key) {
  190. var objectLength = objectList[nGui].fontsBlock[nFont].fontLength;
  191. var mapLength = map[key].fontLength;
  192. if (objectLength != mapLength) {
  193. objectList[nGui].fontsBlock[nFont] = map[key];
  194. }
  195. }
  196. nFont++;
  197. }
  198. nGui++;
  199. }
  200. }
  201. }
  202. function mergeFonts(importMap:Map<Int, GbsFont>, exportMap:Map<Int, GbsFont>) {
  203. for (key in importMap.keys()) {
  204. trace('merging font key: ${key}');
  205. var exportVal = exportMap[key];
  206. var importVal = importMap[key];
  207. // перебор по translated символам (exported)
  208. var nCharE = 0;
  209. while (nCharE < exportVal.charsBlock.length) {
  210. // перебор по fromGame символам (imported)
  211. var nCharI = 0;
  212. while (nCharI < importVal.charsBlock.length) {
  213. var charCodeExp = exportVal.charsBlock[nCharE].charCode;
  214. var charCodeImp = importVal.charsBlock[nCharI].charCode;
  215. #if utf16
  216. if ((charCodeExp == charCodeImp) || (charCodeExp == '?')) { // '?'
  217. #else
  218. if ((charCodeExp == charCodeImp) || (charCodeExp == '?\x00')) { // '?\x00'
  219. #end
  220. var charExpObj = exportVal.charsBlock[nCharE];
  221. exportVal.charsBlock.remove(charExpObj);
  222. // trace('indexI ${nCharI}');
  223. trace('removed character ${charExpObj.charCode} from array');
  224. if (nCharE == exportVal.charsBlock.length) {
  225. break;
  226. }
  227. nCharI = 0;
  228. // trace('length: ${exportVal.charsBlock.length}');
  229. // trace('indexE ${nCharE}');
  230. }
  231. nCharI++;
  232. }
  233. nCharE++;
  234. // var charCodeExp = exportVal.charsBlock[nCharE].charCode;
  235. // trace('character translated: ${charCodeExp}');
  236. }
  237. trace('characters in map has been filtrated');
  238. if (exportVal.charsCount > 0) {
  239. // скорректировать число атласов и индексы атласов у символов
  240. // здесь добавляем символы из exported в imported
  241. var impCount = importVal.charsCount - 1;
  242. var impIndex = importVal.charsBlock[impCount].charAtlasIndex;
  243. nCharE = 0;
  244. while (nCharE < exportVal.charsBlock.length) {
  245. var expIndex = exportVal.charsBlock[nCharE].charAtlasIndex;
  246. // trace(expIndex);
  247. var curIndex = impIndex + expIndex + 1;
  248. exportVal.charsBlock[nCharE].charAtlasIndex = curIndex;
  249. // trace('curIndex: ${curIndex} expIndex: ${expIndex}');
  250. nCharE++;
  251. }
  252. var expIndex = exportVal.charsBlock[0].charAtlasIndex;
  253. // trace(expIndex);
  254. // trace('nCharE: ${nCharE}');
  255. var atlasSum = exportVal.atlasCount + importVal.atlasCount;
  256. importVal.atlasCount = atlasSum;
  257. if (exportVal.maxTop > importVal.maxTop)
  258. importVal.maxTop = exportVal.maxTop;
  259. for (char in exportVal.charsBlock) {
  260. importVal.charsBlock.push(char);
  261. }
  262. exportVal.charsBlock = [];
  263. importVal.charsCount = importVal.charsBlock.length;
  264. importVal.fontLength = importVal.charsCount * 40 + 100;
  265. // trace(importVal.fontLength);
  266. } else
  267. exportVal.atlasCount = 0;
  268. }
  269. // сравнение по MaxTop
  270. // сравнение по длине шрифта
  271. // сравнение по количеству атласов
  272. // сравнение по количеству символов
  273. // сравнение символов по индексам
  274. // пересчитать длину шрифта
  275. // после добавления символов в шрифт, увеличивать длину шрифта на количество добавленных шрифтов
  276. // 1 структура символа 40 байт
  277. // заголовок шрифта 100 байт
  278. }
  279. function fontsAllocate(o:Array<GbsFile>) {
  280. var fontsMap:Map<Int, GbsFont> = [];
  281. var nScene = 0;
  282. while (nScene < o.length) {
  283. var nFont = 0;
  284. while (nFont < o[nScene].header.fontsCount) {
  285. var content = o[nScene].fontsBlock[nFont];
  286. var idFont = o[nScene].fontsBlock[nFont].fontID;
  287. // trace('scene number: ${nScene}');
  288. // trace('font number: ${nFont}');
  289. // trace('font id: ${idFont}');
  290. fontsMap.set(idFont, content);
  291. nFont++;
  292. }
  293. nScene++;
  294. }
  295. // var h = fontsMap.exists(55);
  296. // trace('exist id: ${h}');
  297. return fontsMap;
  298. }
  299. function fontsComparingAllocate(map:Map<Int, GbsFont>, o:Array<GbsFile>) {
  300. var objectsMap:Map<Int, GbsFont> = [];
  301. var nScene = 0;
  302. while (nScene < o.length) {
  303. var nFont = 0;
  304. while (nFont < o[nScene].header.fontsCount) {
  305. var idFont = o[nScene].fontsBlock[nFont].fontID;
  306. if (map.exists(idFont)) {
  307. // trace('scene number: ${nScene}');
  308. // trace('font number: ${nFont}');
  309. // trace('font id: ${idFont}');
  310. var content = o[nScene].fontsBlock[nFont];
  311. objectsMap.set(idFont, content);
  312. }
  313. nFont++;
  314. }
  315. nScene++;
  316. }
  317. return objectsMap;
  318. }
  319. function readGbsList(array:Array<String>) {
  320. var tmp = [];
  321. var i = 0;
  322. while (i < array.length) {
  323. var o = readGuiFile(array[i]);
  324. tmp.push(o);
  325. var path = haxe.io.Path.withoutDirectory(array[i]);
  326. array[i] = path;
  327. i++;
  328. }
  329. return tmp;
  330. }
  331. function readGuiFile(location:String) {
  332. var gi = sys.io.File.read(location);
  333. trace('Start of gbs file reading: "$location"');
  334. var gbs = new GbsReader(gi).read();
  335. gi.close();
  336. return gbs;
  337. }
  338. // Recursive loop through all directories / files
  339. function recursiveDir(directory:String, ?pngName:String, ?savePath:String, ?newIndex:Int) {
  340. var fs = sys.FileSystem;
  341. var paths = [];
  342. if (fs.exists(directory)) {
  343. trace("Reading directory: " + directory);
  344. for (file in fs.readDirectory(directory)) {
  345. var path = haxe.io.Path.join([directory, file]);
  346. if (!fs.isDirectory(path)) {
  347. var fileExt = new haxe.io.Path(path);
  348. if (fileExt.ext == "gbs" && Tools.fileExists(path) == true) {
  349. // trace('Gbs file found: $file');
  350. paths.push(path);
  351. }
  352. if (fileExt.ext == "png") {
  353. // здесь будет переименовывание файлов по индексам
  354. var fileName = fileExt.file;
  355. if (pngName == fileName) {
  356. var newName = fileExt.file.split('_');
  357. var dstPath = savePath + 'Fonts' + '/' + newName[0] + '_${newIndex}.' + fileExt.ext;
  358. // dstPath = Path.normalize(dstPath); //for unix-systems maybe
  359. if (fs.exists(savePath + 'Fonts')) {} else
  360. fs.createDirectory(savePath + 'Fonts');
  361. File.copy(path, dstPath);
  362. trace('${fileExt.file} has been copied');
  363. }
  364. }
  365. }
  366. }
  367. } else {
  368. trace('Unable to scan directory: "$directory"');
  369. fs.createDirectory(directory);
  370. }
  371. return paths;
  372. }
  373. function arrayCheckFonts(array:Array<String>) {
  374. var tmp = [];
  375. var i = 0;
  376. while (i < array.length) {
  377. if (Tools.checkFonts(array[i]) == true) {
  378. tmp.push(array[i]);
  379. }
  380. i++;
  381. }
  382. return array = tmp;
  383. }
  384. function objectCheckOffsets(array:Array<GbsFile>, n:Int) {
  385. var fileSize = array[n].header.fileSize;
  386. var fontsOffset = array[n].header.fontsOffset;
  387. var texturesOffset = array[n].header.texturesOffset;
  388. var soundsOffset = array[n].header.soundsOffset;
  389. var viewsOffset = array[n].header.viewsOffset;
  390. var messagesOffset = array[n].header.messagesOffset;
  391. var fontsToFileEnd = fileSize - (fontsOffset + 56);
  392. var texturesToFileEnd = fileSize - (texturesOffset + 56);
  393. var soundsToFileEnd = fileSize - (soundsOffset + 56);
  394. var viewsToFileEnd = fileSize - (viewsOffset + 56);
  395. var messagesToFileEnd = (fileSize - 56) - messagesOffset;
  396. var fBlockSize = fontsToFileEnd - texturesToFileEnd;
  397. var tBlockSize = texturesToFileEnd - soundsToFileEnd;
  398. var sBlockSize = soundsToFileEnd - viewsToFileEnd;
  399. var vBlockSize = viewsToFileEnd - messagesToFileEnd;
  400. var mBlockSize = messagesToFileEnd - 4;
  401. var eofCheck = fileSize - fBlockSize - tBlockSize - sBlockSize - vBlockSize - mBlockSize - 56 - 4;
  402. if (eofCheck == 0) {
  403. trace("Data offsets ok.");
  404. } else {
  405. trace("\n*****\nWARNING! Data offsets is range out end of file!\n*****\n");
  406. trace("Fonts to file end: " + fontsToFileEnd);
  407. trace("Textures to file end: " + texturesToFileEnd);
  408. trace("Sounds to file end: " + soundsToFileEnd);
  409. trace("Views to file end: " + viewsToFileEnd);
  410. trace("Messages to file end: " + messagesToFileEnd + '\n');
  411. trace("File Size: " + fileSize);
  412. trace("Fonts Size: " + fBlockSize);
  413. trace("Textures Size: " + tBlockSize);
  414. trace("Sounds Size: " + sBlockSize);
  415. trace("Views Size: " + vBlockSize);
  416. trace("Messages Size: " + mBlockSize);
  417. }
  418. trace('File has been checked.');
  419. }
  420. // Read/Write Test GBS
  421. function gbsTestReadWrite(location:String) {
  422. // GBS Read
  423. var gi = sys.io.File.read(location);
  424. trace('Start of gbs file reading: "$location"');
  425. var myGBS = new GbsReader(gi).read();
  426. gi.close();
  427. trace("Fonts count: " + myGBS.header.fontsCount);
  428. var fileInfo = Tools.fileExists(location);
  429. trace('$location:\nIs $fileInfo');
  430. // GBS Write
  431. var save_location = "test/TestLobby.gbs";
  432. //
  433. var go = sys.io.File.write(save_location);
  434. trace('Start of gbs file writing: "$save_location"');
  435. new GbsWriter(go).write(myGBS);
  436. go.close();
  437. // Checking written file
  438. var gi = sys.io.File.read(save_location);
  439. trace('Test start of gbs file reading: "$save_location"');
  440. var myGBS = new GbsReader(gi).read();
  441. gi.checkOffsets;
  442. gi.close();
  443. }
  444. }