导出优化
This commit is contained in:
1 parent
72d8daa283
commit
79ce3165c1
17 files changed
+1559
-1291
No files matched your search
+10
-6
@@ -3,6 +3,7 @@ import { constants } from 'node:fs'
|
||||
import { homedir, platform } from 'node:os'
|
||||
import { join } from 'node:path'
|
||||
import { execFile } from 'node:child_process'
|
||||
import { createSpine38ImportOptions } from './spine38-project.mjs'
|
||||
|
||||
const SUPPORTED_VERSIONS = new Set(['3.8', '4.0', '4.1', '4.2', '4.3'])
|
||||
|
||||
@@ -42,9 +43,9 @@ export function normalizeSpineVersion(value) {
|
||||
return match[1]
|
||||
}
|
||||
|
||||
function run(executablePath, args, timeoutMs = 180000) {
|
||||
function run(executablePath, args, { cwd, timeoutMs = 180000 } = {}) {
|
||||
return new Promise((resolve, reject) => {
|
||||
execFile(executablePath, args, { timeout: timeoutMs, windowsHide: true, maxBuffer: 4 * 1024 * 1024 }, (error, stdout, stderr) => {
|
||||
execFile(executablePath, args, { cwd, timeout: timeoutMs, windowsHide: true, maxBuffer: 4 * 1024 * 1024 }, (error, stdout, stderr) => {
|
||||
if (error) {
|
||||
const details = [stdout, stderr, error.message]
|
||||
.filter(Boolean)
|
||||
@@ -59,15 +60,18 @@ function run(executablePath, args, timeoutMs = 180000) {
|
||||
})
|
||||
}
|
||||
|
||||
export async function importSpineProject({ executablePath, inputPath, outputPath, projectName, spineVersion }) {
|
||||
export async function importSpineProject({ executablePath, inputPath, outputPath, projectName, spineVersion, workspaceRoot }) {
|
||||
const version = normalizeSpineVersion(spineVersion)
|
||||
const editorVersion = `${version}.xx`
|
||||
const importOptions = version === '3.8'
|
||||
? createSpine38ImportOptions({ workspaceRoot, inputPath, outputPath })
|
||||
: { inputPath, outputPath }
|
||||
const result = await run(executablePath, [
|
||||
'--update', editorVersion,
|
||||
'--input', inputPath,
|
||||
'--output', outputPath,
|
||||
'--input', importOptions.inputPath,
|
||||
'--output', importOptions.outputPath,
|
||||
'--import', projectName,
|
||||
])
|
||||
], { cwd: importOptions.cwd })
|
||||
const output = await stat(outputPath).catch(() => null)
|
||||
if (!output?.isFile() || output.size === 0) throw new Error('Spine 未生成有效的工程文件')
|
||||
const detected = /Starting:\s+Spine\s+([0-9.]+)/i.exec(`${result.stdout}\n${result.stderr}`)?.[1] || editorVersion
|
||||
|
||||
@@ -105,6 +105,7 @@ const server = createServer(async (request, response) => {
|
||||
outputPath: workspace.outputPath,
|
||||
projectName: workspace.projectName,
|
||||
spineVersion,
|
||||
workspaceRoot: workspace.root,
|
||||
})
|
||||
const project = await workspace.readOutput()
|
||||
const projectFileName = `${safeProjectName(workspace.projectName)}.spine`
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { mkdir, mkdtemp, readFile, rm, writeFile } from 'node:fs/promises'
|
||||
import { tmpdir } from 'node:os'
|
||||
import { dirname, join, normalize, sep } from 'node:path'
|
||||
import { prepareSpine38SkeletonJson } from './spine38-project.mjs'
|
||||
|
||||
const MAX_JSON_BYTES = 64 * 1024 * 1024
|
||||
const MAX_IMAGE_BYTES = 32 * 1024 * 1024
|
||||
@@ -49,7 +50,11 @@ export async function createConversionWorkspace(payload) {
|
||||
const projectName = safeProjectName(payload.projectName)
|
||||
const inputPath = join(root, `${projectName}.json`)
|
||||
const outputPath = join(root, `${projectName}.spine`)
|
||||
await writeFile(inputPath, payload.skeletonJson, 'utf8')
|
||||
const importJson = spineVersion === '3.8'
|
||||
? prepareSpine38SkeletonJson(skeleton, imagesDirectory)
|
||||
: payload.skeletonJson
|
||||
await mkdir(join(root, imagesDirectory), { recursive: true })
|
||||
await writeFile(inputPath, importJson, 'utf8')
|
||||
let total = 0
|
||||
const archiveImages = []
|
||||
for (const image of Array.isArray(payload.images) ? payload.images : []) {
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
import { relative, sep } from 'node:path'
|
||||
|
||||
function relativeWorkspacePath(workspaceRoot, targetPath) {
|
||||
const path = relative(workspaceRoot, targetPath)
|
||||
if (!path || path === '..' || path.startsWith(`..${sep}`)) {
|
||||
throw new Error('Spine 3.8 工程文件必须位于连接器工作目录内')
|
||||
}
|
||||
return path
|
||||
}
|
||||
|
||||
export function normalizeSpine38ImagesPath(imagesDirectory) {
|
||||
const path = String(imagesDirectory || 'images')
|
||||
.replace(/\\/g, '/')
|
||||
.replace(/^\.\/+/, '')
|
||||
.replace(/\/+$/, '')
|
||||
return path || 'images'
|
||||
}
|
||||
|
||||
export function prepareSpine38SkeletonJson(skeleton, imagesDirectory) {
|
||||
const prepared = JSON.parse(JSON.stringify(skeleton))
|
||||
prepared.skeleton ||= {}
|
||||
// Spine 3.8 的命令行导入器对 "./images/" 的处理并不稳定,某些工程会
|
||||
// 将其固化为导入时的临时绝对路径。使用无前缀、无尾斜杠的工程内路径。
|
||||
prepared.skeleton.images = normalizeSpine38ImagesPath(imagesDirectory)
|
||||
return `${JSON.stringify(prepared, null, 2)}\n`
|
||||
}
|
||||
|
||||
export function createSpine38ImportOptions({ workspaceRoot, inputPath, outputPath }) {
|
||||
return {
|
||||
cwd: workspaceRoot,
|
||||
inputPath: relativeWorkspacePath(workspaceRoot, inputPath),
|
||||
outputPath: relativeWorkspacePath(workspaceRoot, outputPath),
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user