diff --git a/src/App.vue b/src/App.vue index 172ee34..b19f2cc 100644 --- a/src/App.vue +++ b/src/App.vue @@ -873,14 +873,10 @@ import { CodeEditor } from 'monaco-editor-vue3'; export default { name: 'BlueprintEditor', - components: { - CodeEditor - }, + components: { CodeEditor }, setup() { - // 文件输入引用 + // 引用和状态定义 const fileInput = ref(null); - - // 状态 const uploadedFiles = ref([]); const statusMessages = ref([]); const progress = ref(0); @@ -895,94 +891,13 @@ export default { const isParsed = ref(false); const isDataSyncing = ref(false); const hasJsonChanges = ref(false); - - // JSON编辑器内容缓存 const jsonEditorContent = ref(''); const lastValidJson = ref(''); - // 默认的 sbpcfg 十六进制数据 - const defaultSbpcfgHex = '04000000e5ffffff5300610074006900730066006100630074006f00720079002000dd84fe56167f918f6856d89ea48b73006200700063006600670000000e0300000000803f0000803f0000803f0000803f300000002f47616d652f466163746f727947616d652f2d5368617265642f426c75657072696e742f49636f6e4c696272617279000c00000049636f6e4c69627261727900010000000000000000000000000000000000000000'; - - // 编辑器选项 - const editorOptions = ref({ - automaticLayout: true, - minimap: { enabled: false }, - scrollBeyondLastLine: false, - fontSize: 14, - lineNumbers: 'on', - folding: true, - tabSize: 2, - scrollbar: { - verticalScrollbarSize: 8, - horizontalScrollbarSize: 8 - } - }); - - const smallEditorOptions = ref({ - ...editorOptions.value, - fontSize: 12, - automaticLayout: true, - minimap: { enabled: false }, - tabSize: 2, - }); - - // 蓝图数据对象 - 统一管理所有数据 - const blueprintData = ref({ - name: '', - compressionInfo: { - chunkHeaderVersion: 0, - packageFileTag: 0, - maxUncompressedChunkContentSize: 0, - compressionAlgorithm: 0 - }, - header: { - headerVersion: 0, - saveVersion: 0, - buildVersion: 0, - designerDimension: { - x: 0, - y: 0, - z: 0 - }, - recipeReferences: [], - itemCosts: [] - }, - config: { - configVersion: 0, - description: '', - color: { - r: 0, - g: 0, - b: 0, - a: 1 - }, - iconID: 0, - referencedIconLibrary: '', - iconLibraryType: '', - lastEditedBy: [{ - accountId: "", - displayName: "", - platformName: "" - }] - }, - objects: [] // 统一管理所有对象数据 - }); - - // 使用轻量级对象存储文件信息 - const fileInfo = ref({ - blueprintName: '', - mainFileName: '', - configFileName: '' - }); - - // 实体编辑器状态 + // 实体编辑器状态(保留进阶编辑功能) const selectedEntityIndex = ref(null); const activeTab = ref('raw'); - const newProperty = ref({ - name: '', - type: 'FloatProperty', - value: 0 - }); + const newProperty = ref({ name: '', type: 'FloatProperty', value: 0 }); const tabs = ref([ { id: 'raw', label: '原始JSON' }, { id: 'position', label: '位置' }, @@ -992,32 +907,45 @@ export default { ]); const objectProperties = ref({}); const attachedComponentJson = ref([]); + + // 默认配置和编辑器选项 + const defaultSbpcfgHex = '04000000e5ffffff5300610074006900730066006100630074006f00720079002000dd84fe56167f918f6856d89ea48b73006200700063006600670000000e0300000000803f0000803f0000803f0000803f300000002f47616d652f466163746f727947616d652f2d5368617265642f426c75657072696e742f49636f6e4c696272617279000c00000049636f6e4c69627261727900010000000000000000000000000000000000000000'; + const editorOptions = { + automaticLayout: true, + minimap: { enabled: false }, + scrollBeyondLastLine: false, + fontSize: 14, + lineNumbers: 'on', + folding: true, + tabSize: 2, + scrollbar: { verticalScrollbarSize: 8, horizontalScrollbarSize: 8 } + }; + + const smallEditorOptions = { ...editorOptions, fontSize: 12 }; + + // 主数据对象 + const blueprintData = ref(createEmptyBlueprintData()); + const fileInfo = ref({ blueprintName: '', mainFileName: '', configFileName: '' }); + // 计算属性 - const canParse = computed(() => { - return fileInfo.value.mainFileName; - }); - + const canParse = computed(() => fileInfo.value.mainFileName); const mainFileName = computed(() => fileInfo.value.mainFileName); const configFileName = computed(() => fileInfo.value.configFileName); const blueprintName = computed(() => fileInfo.value.blueprintName); - - // 计算属性:根据开关状态决定显示的JSON内容 + const displayedJson = computed({ get: () => { if (!isParsed.value) return ''; - // 如果有JSON验证错误,显示当前编辑器内容 if (jsonValidationError.value && jsonEditorContent.value) { return jsonEditorContent.value; } - // 如果有未保存的JSON编辑器内容,优先使用 if (jsonEditorContent.value && hasJsonChanges.value) { return jsonEditorContent.value; } - // 否则使用当前数据生成JSON const jsonObj = { ...blueprintData.value, objects: showObjects.value ? blueprintData.value.objects : undefined @@ -1027,201 +955,87 @@ export default { lastValidJson.value = currentJson; return currentJson; }, - set: (value) => { - jsonEditorContent.value = value; - } + set: (value) => jsonEditorContent.value = value }); - - // 实体编辑器计算属性 - const filteredEntities = computed(() => { - return blueprintData.value.objects.filter(entity => - entity && entity.type === 'SaveEntity' - ); - }); - - const selectedEntity = computed(() => { - if (selectedEntityIndex.value === null) return null; - return filteredEntities.value[selectedEntityIndex.value] || null; - }); - + + // 实体编辑器计算属性(保留进阶编辑功能) + const filteredEntities = computed(() => + blueprintData.value.objects.filter(entity => entity?.type === 'SaveEntity') + ); + + const selectedEntity = computed(() => + selectedEntityIndex.value !== null ? filteredEntities.value[selectedEntityIndex.value] : null + ); + const entityJson = computed({ - get: () => { - return selectedEntity.value - ? JSON.stringify(selectedEntity.value, null, 2) - : ''; - }, - set: (value) => { - // 将在更新按钮点击时处理 - } + get: () => selectedEntity.value ? JSON.stringify(selectedEntity.value, null, 2) : '', + set: (value) => {} // 将在更新按钮点击时处理 }); - + const componentsJson = computed({ - get: () => { - return selectedEntity.value && selectedEntity.value.components - ? JSON.stringify(selectedEntity.value.components, null, 2) - : ''; - }, - set: (value) => { - // 将在更新按钮点击时处理 - } + get: () => selectedEntity.value?.components ? JSON.stringify(selectedEntity.value.components, null, 2) : '', + set: (value) => {} // 将在更新按钮点击时处理 }); - - const attachedComponents = computed(() => { - if (!selectedEntity.value) return []; - - return blueprintData.value.objects.filter(e => - e && e.type === 'SaveComponent' && - e.parentEntityName === selectedEntity.value.instanceName - ); - }); - + + const attachedComponents = computed(() => + blueprintData.value.objects.filter(e => + e?.type === 'SaveComponent' && e.parentEntityName === selectedEntity.value?.instanceName + ) + ); + // 辅助函数 - const isComplexValue = (value) => { - if (value === null || value === undefined) return false; - return typeof value === 'object' && !(value instanceof Array); - }; + const isComplexValue = (value) => value && typeof value === 'object' && !Array.isArray(value); const getPropertyDisplayValue = (property) => { if (!property) return ''; - - if (isComplexValue(property.value)) { - return JSON.stringify(property.value, null, 2); - } - - // 处理嵌套的value对象(如ByteProperty的情况) - if (property.value && typeof property.value === 'object' && 'value' in property.value) { - return property.value.value; - } - + if (isComplexValue(property.value)) return JSON.stringify(property.value, null, 2); + if (property.value?.value !== undefined) return property.value.value; return property.value; }; - + const setPropertyValue = (property, newValue) => { if (!property) return; - try { - // 如果是复杂对象,尝试解析JSON if (typeof newValue === 'string' && newValue.trim().startsWith('{')) { property.value = JSON.parse(newValue); - } else if (property.value && typeof property.value === 'object' && 'value' in property.value) { - // 处理嵌套value对象的情况(如ByteProperty) + } else if (property.value?.value !== undefined) { property.value.value = newValue; } else { property.value = newValue; } } catch (e) { - console.warn('JSON解析失败,保持原值:', e); + console.warn('JSON解析失败:', e); } }; - - const getDisplayName = (instanceName) => { - if (!instanceName) return ''; - return instanceName.replace(/^Persistent_Level:PersistentLevel\./, ''); - }; - - const getTypeName = (typePath) => { - if (!typePath) return ''; - return typePath.split('/').pop() || typePath; - }; - - // JSON验证函数 + + const getDisplayName = (instanceName) => instanceName?.replace(/^Persistent_Level:PersistentLevel\./, '') || ''; + const getTypeName = (typePath) => typePath?.split('/').pop() || typePath || ''; + + // 核心方法 const validateJson = (jsonString) => { - if (!jsonString || jsonString.trim() === '') { - return { isValid: true }; - } - + if (!jsonString?.trim()) return { isValid: true }; try { - // 尝试解析JSON - const parsed = JSON.parse(jsonString); - return { isValid: true, data: parsed }; + return { isValid: true, data: JSON.parse(jsonString) }; } catch (error) { return { isValid: false, error: error.message }; } }; - - // JSON编辑器变化处理 - const onJsonEditorChange = (value) => { - jsonEditorContent.value = value; - - // 验证JSON格式 - const validationResult = validateJson(value); - if (validationResult.isValid) { - jsonValidationError.value = ''; - hasJsonChanges.value = true; - jsonEditStatus.value = 'JSON已修改,点击"更新数据"保存更改'; - } else { - jsonValidationError.value = validationResult.error; - jsonEditStatus.value = 'JSON格式错误,请修复后再更新'; - } - }; - - // 数据同步方法 - const syncJsonDisplay = () => { - // 在下一次DOM更新后刷新JSON显示 - nextTick(() => { - jsonEditorContent.value = ''; // 清空缓存,强制使用最新数据 - }); - }; - - const onBasicDataChange = () => { - syncJsonDisplay(); - jsonEditStatus.value = '数据已修改,JSON将自动更新'; - }; - - const onEntityDataChange = () => { - syncJsonDisplay(); - jsonEditStatus.value = '实体数据已修改,JSON将自动更新'; - }; - - const onEntityJsonChange = () => { - syncJsonDisplay(); - jsonEditStatus.value = '实体JSON已修改,JSON将自动更新'; - }; - - const onObjectPropertyChange = (key, value) => { - if (selectedEntity.value && selectedEntity.value.properties && selectedEntity.value.properties[key]) { - try { - selectedEntity.value.properties[key].value = JSON.parse(value); - syncJsonDisplay(); - jsonEditStatus.value = '属性已修改,JSON将自动更新'; - } catch (e) { - console.error('JSON解析错误:', e); - } - } - }; - - const onComponentsJsonChange = () => { - syncJsonDisplay(); - jsonEditStatus.value = '组件已修改,JSON将自动更新'; - }; - - const onAttachedComponentChange = (index, value) => { - attachedComponentJson.value[index] = value; - syncJsonDisplay(); - jsonEditStatus.value = '附属组件已修改,JSON将自动更新'; - }; - + + const syncJsonDisplay = () => nextTick(() => { jsonEditorContent.value = ''; }); + // 文件操作方法 - const triggerFileInput = () => { - fileInput.value.click(); - }; + const triggerFileInput = () => fileInput.value.click(); - const handleFileChange = (e) => { - const files = Array.from(e.target.files); - processFiles(files); - }; + const handleFileChange = (e) => processFiles(Array.from(e.target.files)); const handleDrop = (e) => { e.preventDefault(); - const files = Array.from(e.dataTransfer.files); - processFiles(files); + processFiles(Array.from(e.dataTransfer.files)); }; const processFiles = (files) => { error.value = ''; - const validFiles = files.filter(file => - file.name.endsWith('.sbp') || file.name.endsWith('.sbpcfg') - ); + const validFiles = files.filter(f => f.name.endsWith('.sbp') || f.name.endsWith('.sbpcfg')); if (validFiles.length === 0) { error.value = '请上传有效的蓝图文件 (.sbp 或 .sbpcfg)'; @@ -1236,105 +1050,120 @@ export default { mainFileName: sbpFile.name, configFileName: sbpcfgFile ? sbpcfgFile.name : '' }; - uploadedFiles.value = validFiles; }; const resetFiles = () => { uploadedFiles.value = []; - fileInfo.value = { - blueprintName: '', - mainFileName: '', - configFileName: '' - }; + fileInfo.value = { blueprintName: '', mainFileName: '', configFileName: '' }; + statusMessages.value = []; + progress.value = 0; + error.value = exportStatus.value = jsonEditStatus.value = jsonValidationError.value = ''; + isParsing.value = isExporting.value = isDataSyncing.value = hasJsonChanges.value = false; + showObjects.value = isParsed.value = false; + selectedEntityIndex.value = null; + activeTab.value = 'raw'; + jsonEditorContent.value = lastValidJson.value = ''; + blueprintData.value = createEmptyBlueprintData(); + }; + + // 解析相关方法 + const initParsingState = () => { + isParsing.value = true; statusMessages.value = []; progress.value = 0; error.value = ''; - exportStatus.value = ''; jsonEditStatus.value = ''; jsonValidationError.value = ''; - isParsing.value = false; - isExporting.value = false; - isDataSyncing.value = false; - hasJsonChanges.value = false; - showObjects.value = false; - activeVisualTab.value = 'basic'; - isParsed.value = false; selectedEntityIndex.value = null; activeTab.value = 'raw'; jsonEditorContent.value = ''; - lastValidJson.value = ''; - - // 重置蓝图数据 - blueprintData.value = { - name: '', - compressionInfo: { - chunkHeaderVersion: 0, - packageFileTag: 0, - maxUncompressedChunkContentSize: 0, - compressionAlgorithm: 0 - }, - header: { - headerVersion: 0, - saveVersion: 0, - buildVersion: 0, - designerDimension: { - x: 0, - y: 0, - z: 0 - }, - recipeReferences: [], - itemCosts: [] - }, - config: { - configVersion: 0, - description: '', - color: { - r: 0, - g: 0, - b: 0, - a: 1 - }, - iconID: 0, - referencedIconLibrary: '', - iconLibraryType: '', - lastEditedBy: [{ - accountId: "", - displayName: "", - platformName: "" - }] - }, - objects: [] - }; + hasJsonChanges.value = false; }; - + + const readFileAsArrayBuffer = (file) => { + return new Promise((resolve, reject) => { + const reader = new FileReader(); + reader.onload = () => resolve(reader.result); + reader.onerror = reject; + reader.readAsArrayBuffer(file); + }); + }; + + const handleProgress = (p, msg) => { + progress.value = p * 100; + statusMessages.value.push(`进度: ${Math.round(p * 100)}% - ${msg}`); + }; + + const normalizeBlueprintData = (blueprint) => ({ + name: blueprint.name || '', + compressionInfo: { + chunkHeaderVersion: blueprint.compressionInfo?.chunkHeaderVersion || 0, + packageFileTag: blueprint.compressionInfo?.packageFileTag || 0, + maxUncompressedChunkContentSize: blueprint.compressionInfo?.maxUncompressedChunkContentSize || 0, + compressionAlgorithm: blueprint.compressionInfo?.compressionAlgorithm || 0 + }, + header: { + headerVersion: blueprint.header?.headerVersion || 0, + saveVersion: blueprint.header?.saveVersion || 0, + buildVersion: blueprint.header?.buildVersion || 0, + designerDimension: { + x: blueprint.header?.designerDimension?.x || 0, + y: blueprint.header?.designerDimension?.y || 0, + z: blueprint.header?.designerDimension?.z || 0 + }, + recipeReferences: blueprint.header?.recipeReferences || [], + itemCosts: blueprint.header?.itemCosts || [] + }, + config: { + configVersion: blueprint.config?.configVersion || 0, + description: blueprint.config?.description || '', + color: { + r: blueprint.config?.color?.r || 0, + g: blueprint.config?.color?.g || 0, + b: blueprint.config?.color?.b || 0, + a: blueprint.config?.color?.a || 1 + }, + iconID: blueprint.config?.iconID || 0, + referencedIconLibrary: blueprint.config?.referencedIconLibrary || '', + iconLibraryType: blueprint.config?.iconLibraryType || '', + lastEditedBy: blueprint.config?.lastEditedBy || [{ + accountId: "", + displayName: "", + platformName: "" + }] + }, + objects: blueprint.objects || [] + }); + + const handleParseSuccess = () => { + statusMessages.value.push('蓝图文件解析完成!'); + isParsed.value = true; + progress.value = 100; + jsonEditStatus.value = '数据解析完成,可以开始编辑'; + + const jsonObj = { + ...blueprintData.value, + objects: showObjects.value ? blueprintData.value.objects : undefined + }; + lastValidJson.value = JSON.stringify(jsonObj, null, 2); + }; + + const handleParseError = (err) => { + console.error('解析错误:', err); + error.value = `解析错误: ${err.message}`; + statusMessages.value.push('解析失败!'); + jsonEditStatus.value = '解析失败,请检查文件格式'; + }; + const parseBlueprint = async () => { if (!canParse.value || isParsing.value) return; try { - isParsing.value = true; - statusMessages.value = []; - progress.value = 0; - error.value = ''; - jsonEditStatus.value = ''; - jsonValidationError.value = ''; - selectedEntityIndex.value = null; - activeTab.value = 'raw'; - jsonEditorContent.value = ''; - hasJsonChanges.value = false; - + initParsingState(); const sbpFile = uploadedFiles.value.find(f => f.name.endsWith('.sbp')); const sbpcfgFile = uploadedFiles.value.find(f => f.name.endsWith('.sbpcfg')); - const readFileAsArrayBuffer = (file) => { - return new Promise((resolve, reject) => { - const reader = new FileReader(); - reader.onload = () => resolve(reader.result); - reader.onerror = reject; - reader.readAsArrayBuffer(file); - }); - }; - const sbpBuffer = await readFileAsArrayBuffer(sbpFile); let sbpcfgBuffer = null; @@ -1358,80 +1187,66 @@ export default { fileInfo.value.blueprintName, sbpBuffer, sbpcfgBuffer, - { - onProgressCallback: (p, msg) => { - progress.value = p * 100; - statusMessages.value.push(`进度: ${Math.round(p * 100)}% - ${msg}`); - } - } + { onProgressCallback: handleProgress } ); - // 统一设置所有数据到主蓝图数据对象 - blueprintData.value = { - name: blueprint.name || '', - compressionInfo: { - chunkHeaderVersion: blueprint.compressionInfo?.chunkHeaderVersion || 0, - packageFileTag: blueprint.compressionInfo?.packageFileTag || 0, - maxUncompressedChunkContentSize: blueprint.compressionInfo?.maxUncompressedChunkContentSize || 0, - compressionAlgorithm: blueprint.compressionInfo?.compressionAlgorithm || 0 - }, - header: { - headerVersion: blueprint.header?.headerVersion || 0, - saveVersion: blueprint.header?.saveVersion || 0, - buildVersion: blueprint.header?.buildVersion || 0, - designerDimension: { - x: blueprint.header?.designerDimension?.x || 0, - y: blueprint.header?.designerDimension?.y || 0, - z: blueprint.header?.designerDimension?.z || 0 - }, - recipeReferences: blueprint.header?.recipeReferences || [], - itemCosts: blueprint.header?.itemCosts || [] - }, - config: { - configVersion: blueprint.config?.configVersion || 0, - description: blueprint.config?.description || '', - color: { - r: blueprint.config?.color?.r || 0, - g: blueprint.config?.color?.g || 0, - b: blueprint.config?.color?.b || 0, - a: blueprint.config?.color?.a || 1 - }, - iconID: blueprint.config?.iconID || 0, - referencedIconLibrary: blueprint.config?.referencedIconLibrary || '', - iconLibraryType: blueprint.config?.iconLibraryType || '', - lastEditedBy: blueprint.config?.lastEditedBy || [{ - accountId: "", - displayName: "", - platformName: "" - }] - }, - objects: blueprint.objects || [] // 统一管理对象数据 - }; - - statusMessages.value.push('蓝图文件解析完成!'); - isParsed.value = true; - progress.value = 100; - jsonEditStatus.value = '数据解析完成,可以开始编辑'; - - // 初始化lastValidJson - const jsonObj = { - ...blueprintData.value, - objects: showObjects.value ? blueprintData.value.objects : undefined - }; - lastValidJson.value = JSON.stringify(jsonObj, null, 2); - + blueprintData.value = normalizeBlueprintData(blueprint); + handleParseSuccess(); } catch (err) { - console.error('解析错误:', err); - error.value = `解析错误: ${err.message}`; - statusMessages.value.push('解析失败!'); - jsonEditStatus.value = '解析失败,请检查文件格式'; + handleParseError(err); } finally { - setTimeout(() => { - isParsing.value = false; - }, 1000); + setTimeout(() => { isParsing.value = false; }, 1000); } }; - + + // 导出相关方法 + const prepareExportData = () => { + const exportData = JSON.parse(JSON.stringify(blueprintData.value)); + const timestamp = Date.now().toString(); + + if (!exportData.config.lastEditedBy) { + exportData.config.lastEditedBy = []; + } + + exportData.config.lastEditedBy.push({ + accountId: timestamp, + displayName: "LinXingLuo", + platformName: "Satisfactory-edit" + }); + + return exportData; + }; + + const generateFiles = async (exportData) => { + let mainFileHeader = null; + const mainFileBodyChunks = []; + + const summary = await Parser.WriteBlueprintFiles( + exportData, + header => { mainFileHeader = header; }, + chunk => { mainFileBodyChunks.push(chunk); } + ); + + const mainFileData = new Uint8Array([ + ...mainFileHeader, + ...mainFileBodyChunks.flatMap(chunk => [...chunk]) + ]); + + return { mainFileData, configFileBinary: summary.configFileBinary }; + }; + + const downloadFile = (data, filename) => { + const blob = new Blob([data], { type: 'application/octet-stream' }); + const url = URL.createObjectURL(blob); + const a = document.createElement('a'); + a.href = url; + a.download = filename; + document.body.appendChild(a); + a.click(); + document.body.removeChild(a); + URL.revokeObjectURL(url); + }; + const exportBlueprint = async () => { if (!isParsed.value || isExporting.value) return; @@ -1439,59 +1254,13 @@ export default { isExporting.value = true; exportStatus.value = '开始导出蓝图文件...'; - // 创建当前时间戳 - const timestamp = Date.now().toString(); + const exportData = prepareExportData(); + const { mainFileData, configFileBinary } = await generateFiles(exportData); - // 准备导出的数据 - const exportData = JSON.parse(JSON.stringify(blueprintData.value)); - - // 确保 lastEditedBy 数组存在 - if (!exportData.config.lastEditedBy) { - exportData.config.lastEditedBy = []; - } - - // 在数组尾部添加新的编辑者信息 - exportData.config.lastEditedBy.push({ - accountId: timestamp, - displayName: "LinXingLuo", - platformName: "Satisfactory-edit" - }); - - let mainFileHeader = null; - const mainFileBodyChunks = []; - - const summary = await Parser.WriteBlueprintFiles( - exportData, - header => { - mainFileHeader = header; - }, - chunk => { - mainFileBodyChunks.push(chunk); - } - ); - - const mainFileData = new Uint8Array([ - ...mainFileHeader, - ...mainFileBodyChunks.flatMap(chunk => [...chunk]) - ]); - - const downloadFile = (data, filename, type) => { - const blob = new Blob([data], { type }); - const url = URL.createObjectURL(blob); - const a = document.createElement('a'); - a.href = url; - a.download = filename; - document.body.appendChild(a); - a.click(); - document.body.removeChild(a); - URL.revokeObjectURL(url); - }; - - downloadFile(mainFileData, `${blueprintName.value}.sbp`, 'application/octet-stream'); - downloadFile(summary.configFileBinary, `${blueprintName.value}.sbpcfg`, 'application/octet-stream'); + downloadFile(mainFileData, `${blueprintName.value}.sbp`); + downloadFile(configFileBinary, `${blueprintName.value}.sbpcfg`); exportStatus.value = '蓝图文件导出成功!'; - } catch (err) { console.error('导出错误:', err); exportStatus.value = `导出错误: ${err.message}`; @@ -1499,121 +1268,132 @@ export default { isExporting.value = false; } }; - - const formatJson = () => { - try { - if (!jsonEditorContent.value) { - jsonEditStatus.value = '没有内容可格式化'; - return; - } - - const validationResult = validateJson(jsonEditorContent.value); - if (!validationResult.isValid) { - jsonValidationError.value = validationResult.error; - jsonEditStatus.value = 'JSON格式错误,无法格式化'; - return; - } - - const obj = validationResult.data; - const formattedJson = JSON.stringify(obj, null, 2); - jsonEditorContent.value = formattedJson; - jsonEditStatus.value = 'JSON已格式化'; - - } catch (e) { - error.value = 'JSON格式错误,无法格式化'; - jsonEditStatus.value = '格式化失败:JSON格式错误'; - } - }; - - const refreshJson = () => { - // 只有有更改时才提示刷新 - if (hasJsonChanges.value) { - if (confirm('刷新将丢失当前的更改,是否继续?')) { - forceRefreshJson(); - } + + // JSON操作方法 + const onJsonEditorChange = (value) => { + jsonEditorContent.value = value; + const validation = validateJson(value); + if (validation.isValid) { + jsonValidationError.value = ''; + hasJsonChanges.value = true; + jsonEditStatus.value = 'JSON已修改,点击"更新数据"保存更改'; } else { - forceRefreshJson(); + jsonValidationError.value = validation.error; + jsonEditStatus.value = 'JSON格式错误,请修复后再更新'; } }; - + + const formatJson = () => { + if (!jsonEditorContent.value) { + jsonEditStatus.value = '没有内容可格式化'; + return; + } + + const validation = validateJson(jsonEditorContent.value); + if (!validation.isValid) { + jsonValidationError.value = validation.error; + jsonEditStatus.value = 'JSON格式错误,无法格式化'; + return; + } + + jsonEditorContent.value = JSON.stringify(validation.data, null, 2); + jsonEditStatus.value = 'JSON已格式化'; + }; + const forceRefreshJson = () => { - // 清空缓存,强制使用最新数据 jsonEditorContent.value = ''; jsonValidationError.value = ''; hasJsonChanges.value = false; jsonEditStatus.value = 'JSON已刷新到最新数据'; }; - - const updateDataFromJson = () => { - if (!jsonEditorContent.value || !hasJsonChanges.value) { - jsonEditStatus.value = '没有要更新的内容或内容无变化'; - return; - } - - // 首先验证JSON - const validationResult = validateJson(jsonEditorContent.value); - if (!validationResult.isValid) { - jsonValidationError.value = validationResult.error; - jsonEditStatus.value = 'JSON格式错误,无法更新数据'; - return; - } - + + const refreshJson = () => { + hasJsonChanges.value ? + (confirm('刷新将丢失当前的更改,是否继续?') && forceRefreshJson()) : + forceRefreshJson(); + }; + + const updateBlueprintData = (editedObj) => { try { isDataSyncing.value = true; jsonEditStatus.value = '正在更新数据...'; - const editedObj = validationResult.data; - - // 更新所有数据到主蓝图数据对象 Object.keys(editedObj).forEach(key => { if (key === 'objects') { - // 特殊处理objects字段 if (editedObj.objects !== undefined) { blueprintData.value.objects = editedObj.objects; } } else { - // 简单赋值 blueprintData.value[key] = editedObj[key]; } }); - // 确保objects字段始终存在 if (!blueprintData.value.objects) { blueprintData.value.objects = []; } - // 保存当前状态为有效状态 lastValidJson.value = jsonEditorContent.value; hasJsonChanges.value = false; statusMessages.value.push('数据更新成功!'); jsonEditStatus.value = '数据更新成功!'; - // 如果当前有选中的实体,重新初始化相关数据 if (selectedEntityIndex.value !== null) { initObjectProperties(); initAttachedComponentJson(); } - } catch (e) { console.error('JSON更新错误:', e); error.value = '更新数据失败:' + e.message; jsonEditStatus.value = '更新失败:' + e.message; } finally { - setTimeout(() => { - isDataSyncing.value = false; - }, 500); + setTimeout(() => { isDataSyncing.value = false; }, 500); } }; - - // 实体编辑器方法 + + const updateDataFromJson = () => { + if (!jsonEditorContent.value || !hasJsonChanges.value) { + jsonEditStatus.value = '没有要更新的内容或内容无变化'; + return; + } + + const validation = validateJson(jsonEditorContent.value); + if (!validation.isValid) { + jsonValidationError.value = validation.error; + jsonEditStatus.value = 'JSON格式错误,无法更新数据'; + return; + } + + updateBlueprintData(validation.data); + }; + + // 实体编辑器方法(保留进阶编辑功能) const selectEntity = (index) => { selectedEntityIndex.value = index; activeTab.value = 'raw'; initObjectProperties(); initAttachedComponentJson(); }; - + + const initObjectProperties = () => { + if (!selectedEntity.value || !selectedEntity.value.properties) return; + + objectProperties.value = {}; + for (const key in selectedEntity.value.properties) { + const prop = selectedEntity.value.properties[key]; + if (isComplexValue(prop.value)) { + objectProperties.value[key] = JSON.stringify(prop.value, null, 2); + } + } + }; + + const initAttachedComponentJson = () => { + attachedComponentJson.value = []; + attachedComponents.value.forEach(comp => { + attachedComponentJson.value.push(JSON.stringify(comp, null, 2)); + }); + }; + const updateEntityFromJson = () => { try { const updatedEntity = JSON.parse(entityJson.value); @@ -1632,7 +1412,7 @@ export default { jsonEditStatus.value = '实体更新失败:' + error.message; } }; - + const updateComponents = () => { try { const updatedComponents = JSON.parse(componentsJson.value); @@ -1646,7 +1426,7 @@ export default { jsonEditStatus.value = '组件更新失败:' + error.message; } }; - + const updateAttachedComponent = (index) => { try { const updatedComponent = JSON.parse(attachedComponentJson.value[index]); @@ -1665,7 +1445,7 @@ export default { jsonEditStatus.value = '附属组件更新失败:' + error.message; } }; - + const deleteProperty = (key) => { if (selectedEntity.value && selectedEntity.value.properties && selectedEntity.value.properties[key]) { delete selectedEntity.value.properties[key]; @@ -1674,7 +1454,7 @@ export default { jsonEditStatus.value = '属性已删除,JSON已同步'; } }; - + const addProperty = () => { if (!newProperty.value.name || !selectedEntity.value) return; @@ -1693,163 +1473,155 @@ export default { objectProperties.value[newProperty.value.name] = JSON.stringify(newProperty.value.value, null, 2); } - newProperty.value = { - name: '', - type: 'FloatProperty', - value: 0 - }; - + newProperty.value = { name: '', type: 'FloatProperty', value: 0 }; syncJsonDisplay(); jsonEditStatus.value = '属性已添加,JSON已同步'; }; - - const initObjectProperties = () => { - if (!selectedEntity.value || !selectedEntity.value.properties) return; - - objectProperties.value = {}; - for (const key in selectedEntity.value.properties) { - const prop = selectedEntity.value.properties[key]; - if (isComplexValue(prop.value)) { - objectProperties.value[key] = JSON.stringify(prop.value, null, 2); - } - } - }; - - const initAttachedComponentJson = () => { - attachedComponentJson.value = []; - attachedComponents.value.forEach(comp => { - attachedComponentJson.value.push(JSON.stringify(comp, null, 2)); - }); - }; - + // 图形化编辑器方法 const addRecipe = () => { - blueprintData.value.header.recipeReferences.push({ - pathName: "" - }); + blueprintData.value.header.recipeReferences.push({ pathName: "" }); syncJsonDisplay(); jsonEditStatus.value = '配方已添加,JSON已同步'; }; - + const removeRecipe = (index) => { blueprintData.value.header.recipeReferences.splice(index, 1); syncJsonDisplay(); jsonEditStatus.value = '配方已删除,JSON已同步'; }; - + const addItemCost = () => { - blueprintData.value.header.itemCosts.push([ - { pathName: "" }, - 0 - ]); + blueprintData.value.header.itemCosts.push([{ pathName: "" }, 0]); syncJsonDisplay(); jsonEditStatus.value = '物品成本已添加,JSON已同步'; }; - + const removeItemCost = (index) => { blueprintData.value.header.itemCosts.splice(index, 1); syncJsonDisplay(); jsonEditStatus.value = '物品成本已删除,JSON已同步'; }; - - // 监听对象变化 - watch(() => blueprintData.value.objects, () => { - if (selectedEntity.value) { - initAttachedComponentJson(); + + // 数据同步方法 + const onBasicDataChange = () => { + syncJsonDisplay(); + jsonEditStatus.value = '数据已修改,JSON将自动更新'; + }; + + const onEntityDataChange = () => { + syncJsonDisplay(); + jsonEditStatus.value = '实体数据已修改,JSON将自动更新'; + }; + + const onEntityJsonChange = () => { + syncJsonDisplay(); + jsonEditStatus.value = '实体JSON已修改,JSON将自动更新'; + }; + + const onObjectPropertyChange = (key, value) => { + if (selectedEntity.value && selectedEntity.value.properties && selectedEntity.value.properties[key]) { + try { + selectedEntity.value.properties[key].value = JSON.parse(value); + syncJsonDisplay(); + jsonEditStatus.value = '属性已修改,JSON将自动更新'; + } catch (e) { + console.error('JSON解析错误:', e); + } } + }; + + const onComponentsJsonChange = () => { + syncJsonDisplay(); + jsonEditStatus.value = '组件已修改,JSON将自动更新'; + }; + + const onAttachedComponentChange = (index, value) => { + attachedComponentJson.value[index] = value; + syncJsonDisplay(); + jsonEditStatus.value = '附属组件已修改,JSON将自动更新'; + }; + + // 监听器 + watch(() => blueprintData.value.objects, () => { + if (selectedEntity.value) initAttachedComponentJson(); }, { deep: true }); - - // 监听showObjects变化,确保JSON显示同步 + watch(showObjects, (newVal) => { - // 当切换Objects段显示时,如果有未保存的更改,提示用户 if (hasJsonChanges.value) { jsonEditStatus.value = `Objects段显示${newVal ? '开启' : '关闭'} - 注意:有未保存的更改`; } else { jsonEditStatus.value = `Objects段显示${newVal ? '开启' : '关闭'}`; } - - // 刷新JSON显示,但不标记为有更改 jsonEditorContent.value = ''; }); - + return { - // 文件操作相关 - fileInput, - uploadedFiles, - blueprintName, - displayedJson, - statusMessages, - progress, - error, - exportStatus, - jsonEditStatus, - jsonValidationError, - isParsing, - isExporting, - isDataSyncing, - hasJsonChanges, - showObjects, - activeVisualTab, - blueprintData, - canParse, - mainFileName, - configFileName, - isParsed, - editorOptions, - smallEditorOptions, + // 状态和引用 + fileInput, uploadedFiles, blueprintName, displayedJson, statusMessages, progress, error, + exportStatus, jsonEditStatus, jsonValidationError, isParsing, isExporting, isDataSyncing, + hasJsonChanges, showObjects, activeVisualTab, blueprintData, canParse, mainFileName, + configFileName, isParsed, editorOptions: ref(editorOptions), smallEditorOptions: ref(smallEditorOptions), - // 实体编辑器相关 - filteredEntities, - selectedEntityIndex, - activeTab, - newProperty, - tabs, - objectProperties, - attachedComponentJson, - selectedEntity, - entityJson, - componentsJson, - attachedComponents, + // 实体编辑器(保留进阶编辑功能) + filteredEntities, selectedEntityIndex, activeTab, newProperty, tabs, objectProperties, + attachedComponentJson, selectedEntity, entityJson, componentsJson, attachedComponents, // 辅助函数 - isComplexValue, - getPropertyDisplayValue, - setPropertyValue, + isComplexValue, getPropertyDisplayValue, setPropertyValue, getDisplayName, getTypeName, - // 方法 - triggerFileInput, - handleFileChange, - handleDrop, - resetFiles, - parseBlueprint, - exportBlueprint, - formatJson, - refreshJson, - updateDataFromJson, - addRecipe, - removeRecipe, - addItemCost, - removeItemCost, - getDisplayName, - getTypeName, + // 文件操作方法 + triggerFileInput, handleFileChange, handleDrop, resetFiles, parseBlueprint, exportBlueprint, + + // JSON操作方法 + onJsonEditorChange, formatJson, refreshJson, updateDataFromJson, // 实体编辑器方法 - selectEntity, - updateEntityFromJson, - updateComponents, - updateAttachedComponent, - deleteProperty, - addProperty, + selectEntity, updateEntityFromJson, updateComponents, updateAttachedComponent, + deleteProperty, addProperty, + + // 图形化编辑器方法 + addRecipe, removeRecipe, addItemCost, removeItemCost, // 数据同步方法 - onJsonEditorChange, - onBasicDataChange, - onEntityDataChange, - onEntityJsonChange, - onObjectPropertyChange, - onComponentsJsonChange, - onAttachedComponentChange + onBasicDataChange, onEntityDataChange, onEntityJsonChange, + onObjectPropertyChange, onComponentsJsonChange, onAttachedComponentChange }; } +}; + +// 辅助函数定义 +function createEmptyBlueprintData() { + return { + name: '', + compressionInfo: { + chunkHeaderVersion: 0, + packageFileTag: 0, + maxUncompressedChunkContentSize: 0, + compressionAlgorithm: 0 + }, + header: { + headerVersion: 0, + saveVersion: 0, + buildVersion: 0, + designerDimension: { x: 0, y: 0, z: 0 }, + recipeReferences: [], + itemCosts: [] + }, + config: { + configVersion: 0, + description: '', + color: { r: 0, g: 0, b: 0, a: 1 }, + iconID: 0, + referencedIconLibrary: '', + iconLibraryType: '', + lastEditedBy: [{ + accountId: "", + displayName: "", + platformName: "" + }] + }, + objects: [] + }; } \ No newline at end of file