texture-reader.js 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. // 图片文件读取模块
  2. // 负责处理所有图片文件相关的逻辑
  3. const fs = require('fs');
  4. const path = require('path');
  5. class TextureReader {
  6. constructor(serverDir) {
  7. this.serverDir = serverDir;
  8. this.sequencesPath = path.join(serverDir, 'disk_data');
  9. }
  10. /**
  11. * 获取可用的文件夹列表
  12. * @returns {Promise<string[]>} 文件夹名称数组
  13. */
  14. async getAvailableFolders() {
  15. return new Promise((resolve, reject) => {
  16. fs.readdir(this.sequencesPath, { withFileTypes: true }, (err, files) => {
  17. if (err) {
  18. reject(err);
  19. return;
  20. }
  21. const folders = files
  22. .filter(dirent => dirent.isDirectory() && dirent.name.startsWith('player_'))
  23. .map(dirent => dirent.name)
  24. .sort();
  25. resolve(folders);
  26. });
  27. });
  28. }
  29. /**
  30. * 获取指定文件夹中的帧文件列表
  31. * @param {string} folderName - 文件夹名称
  32. * @returns {Promise<{frames: number[], maxFrame: number}>} 帧文件信息
  33. */
  34. async getFrameFiles(folderName) {
  35. return new Promise((resolve, reject) => {
  36. const folderPath = path.join(this.sequencesPath, folderName);
  37. console.log(`[TextureReader] 请求帧列表: folderName=${folderName}, folderPath=${folderPath}`);
  38. fs.readdir(folderPath, (err, files) => {
  39. if (err) {
  40. console.error(`[TextureReader] 读取文件夹失败: ${err.message}, folderPath=${folderPath}`);
  41. reject(err);
  42. return;
  43. }
  44. // 过滤出 PNG 文件,并按数字排序
  45. // 支持两种格式:1) 纯数字.png (如 00.png) 2) 任意名称+数字.png (如 动画00.png)
  46. const pngFiles = files
  47. .filter(file => file.toLowerCase().endsWith('.png'))
  48. .map(file => {
  49. let frameNum = null;
  50. // 先尝试匹配纯数字格式:00.png, 01.png
  51. let match = /^(\d+)\.png$/i.exec(file);
  52. if (match) {
  53. frameNum = parseInt(match[1], 10);
  54. } else {
  55. // 再尝试匹配文件名末尾的数字格式:动画00.png, 生成白色背景长矛刺击动画00.png
  56. match = /(\d+)\.png$/i.exec(file);
  57. if (match) {
  58. frameNum = parseInt(match[1], 10);
  59. }
  60. }
  61. if (frameNum !== null) {
  62. return {
  63. frameNum: frameNum,
  64. fileName: file
  65. };
  66. }
  67. return null;
  68. })
  69. .filter(item => item !== null)
  70. .sort((a, b) => a.frameNum - b.frameNum);
  71. const result = {
  72. frames: pngFiles.map(item => item.frameNum),
  73. fileNames: pngFiles.map(item => item.fileName),
  74. maxFrame: pngFiles.length > 0 ? Math.max(...pngFiles.map(item => item.frameNum)) : 0
  75. };
  76. resolve(result);
  77. });
  78. });
  79. }
  80. /**
  81. * 处理获取文件夹列表的 API 请求
  82. * @param {http.ServerResponse} res - HTTP 响应对象
  83. */
  84. handleGetFolders(res) {
  85. this.getAvailableFolders()
  86. .then(folders => {
  87. res.writeHead(200, { 'Content-Type': 'application/json' });
  88. res.end(JSON.stringify(folders));
  89. })
  90. .catch(err => {
  91. res.writeHead(500, { 'Content-Type': 'application/json' });
  92. res.end(JSON.stringify({ error: 'Failed to read sequences directory', details: err.message }));
  93. });
  94. }
  95. /**
  96. * 处理获取帧文件列表的 API 请求
  97. * @param {string} folderName - 文件夹名称
  98. * @param {http.ServerResponse} res - HTTP 响应对象
  99. */
  100. handleGetFrames(folderName, res) {
  101. this.getFrameFiles(folderName)
  102. .then(result => {
  103. // 检查是否有图片
  104. if (!result.frames || result.frames.length === 0) {
  105. res.writeHead(400, { 'Content-Type': 'application/json' });
  106. res.end(JSON.stringify({
  107. error: '该文件夹中没有图片',
  108. frames: []
  109. }));
  110. return;
  111. }
  112. res.writeHead(200, { 'Content-Type': 'application/json' });
  113. res.end(JSON.stringify(result));
  114. })
  115. .catch(err => {
  116. res.writeHead(404, { 'Content-Type': 'application/json' });
  117. res.end(JSON.stringify({ error: 'Folder not found', details: err.message }));
  118. });
  119. }
  120. }
  121. module.exports = TextureReader;