|
| 1 | +// @ts-ignore |
| 2 | +import en from './lang/en.yaml' |
| 3 | +// TODO - Remake this exporter, it's a bit of a mess. |
| 4 | +interface ISerealizedAnimationNode { |
| 5 | + type: 'bone' | 'camera' | 'locator' |
| 6 | + name: string |
| 7 | + uuid: string |
| 8 | + node: undefined |
| 9 | + matrix: number[] |
| 10 | + pos: [number, number, number] |
| 11 | + rot: [number, number, number, number] |
| 12 | + scale: [number, number, number] |
| 13 | + interpolation?: 'instant' | 'default' |
| 14 | +} |
| 15 | + |
| 16 | +function serializeFrame(frame: AnimatedJava.IRenderedFrame) { |
| 17 | + return { |
| 18 | + time: frame.time, |
| 19 | + nodes: frame.nodes.map(serializeAnimationNode), |
| 20 | + variant: frame.variant, |
| 21 | + commands: frame.commands, |
| 22 | + animationState: frame.animationState, |
| 23 | + } |
| 24 | +} |
| 25 | + |
| 26 | +function serializeOutlinerNode(node: AnimatedJava.AnyRenderedNode) { |
| 27 | + switch (node.type) { |
| 28 | + case 'bone': { |
| 29 | + const { |
| 30 | + type, |
| 31 | + name, |
| 32 | + parent, |
| 33 | + customModelData, |
| 34 | + resourceLocation, |
| 35 | + scale, |
| 36 | + modelPath, |
| 37 | + node: outlinerNode, |
| 38 | + } = node |
| 39 | + return { |
| 40 | + type, |
| 41 | + parent, |
| 42 | + name, |
| 43 | + uuid: outlinerNode.uuid, |
| 44 | + customModelData, |
| 45 | + resourceLocation, |
| 46 | + scale, |
| 47 | + modelPath, |
| 48 | + } |
| 49 | + } |
| 50 | + case 'camera': { |
| 51 | + const { type, name, parent, teleported_entity_type, node: outlinerNode } = node |
| 52 | + return { |
| 53 | + type, |
| 54 | + parent, |
| 55 | + name, |
| 56 | + uuid: outlinerNode.uuid, |
| 57 | + teleported_entity_type, |
| 58 | + } |
| 59 | + } |
| 60 | + case 'locator': { |
| 61 | + const { type, name, parent, teleported_entity_type, node: outlinerNode } = node |
| 62 | + return { |
| 63 | + type, |
| 64 | + parent, |
| 65 | + name, |
| 66 | + uuid: outlinerNode.uuid, |
| 67 | + teleported_entity_type, |
| 68 | + } |
| 69 | + } |
| 70 | + } |
| 71 | +} |
| 72 | + |
| 73 | +function serializeAnimationNode(node: AnimatedJava.IAnimationNode): ISerealizedAnimationNode { |
| 74 | + const { type, name, uuid, matrix, pos, rot, scale, interpolation } = node |
| 75 | + return { |
| 76 | + type, |
| 77 | + name, |
| 78 | + uuid, |
| 79 | + node: undefined, |
| 80 | + matrix: matrix.toArray(), |
| 81 | + pos: [pos.x, pos.y, pos.z], |
| 82 | + rot: [rot.x, rot.y, rot.z, rot.w], |
| 83 | + scale: [scale.x, scale.y, scale.z], |
| 84 | + interpolation, |
| 85 | + } |
| 86 | +} |
| 87 | + |
| 88 | +interface ISerealizedAnimation { |
| 89 | + frames: ISerealizedAnimationNode[] |
| 90 | + duration: number |
| 91 | + loopMode: 'loop' | 'once' | 'hold' |
| 92 | +} |
| 93 | + |
| 94 | +function serializeAnimation(animation: AnimatedJava.IRenderedAnimation): any { |
| 95 | + return { |
| 96 | + ...animation, |
| 97 | + frames: animation.frames.map(serializeFrame), |
| 98 | + } |
| 99 | +} |
| 100 | + |
| 101 | +interface RawExportData { |
| 102 | + project_settings: Record<string, any> |
| 103 | + exporter_settings: Record<string, any> |
| 104 | + rig: { |
| 105 | + default_pose: ISerealizedAnimationNode[] |
| 106 | + node_structure: AnimatedJava.INodeStructure |
| 107 | + node_map: any |
| 108 | + } |
| 109 | + animations: Record<string, ISerealizedAnimation> |
| 110 | +} |
| 111 | + |
| 112 | +export function loadExporter() { |
| 113 | + const API = AnimatedJava.API |
| 114 | + |
| 115 | + API.addTranslations('en', en as Record<string, string>) |
| 116 | + |
| 117 | + const TRANSLATIONS = { |
| 118 | + output_file: { |
| 119 | + error: { |
| 120 | + empty: API.translate( |
| 121 | + 'animated_java.exporters.json_exporter.settings.output_file.error.empty' |
| 122 | + ), |
| 123 | + }, |
| 124 | + }, |
| 125 | + } |
| 126 | + |
| 127 | + new API.Exporter({ |
| 128 | + id: 'animated_java:json_exporter', |
| 129 | + name: API.translate('animated_java.exporters.json_exporter.name'), |
| 130 | + description: API.translate('animated_java.exporters.json_exporter.description'), |
| 131 | + getSettings() { |
| 132 | + return { |
| 133 | + output_file: new API.Settings.FileSetting( |
| 134 | + { |
| 135 | + id: 'animated_java:json_exporter/output_file', |
| 136 | + displayName: API.translate( |
| 137 | + 'animated_java.exporters.json_exporter.settings.output_file' |
| 138 | + ), |
| 139 | + description: API.translate( |
| 140 | + 'animated_java.exporters.json_exporter.settings.output_file.description' |
| 141 | + ).split('\n'), |
| 142 | + defaultValue: '', |
| 143 | + }, |
| 144 | + function onUpdate(setting) { |
| 145 | + if (!setting.value) { |
| 146 | + setting.infoPopup = API.createInfo( |
| 147 | + 'error', |
| 148 | + TRANSLATIONS.output_file.error.empty |
| 149 | + ) |
| 150 | + } |
| 151 | + } |
| 152 | + ), |
| 153 | + } |
| 154 | + }, |
| 155 | + settingsStructure: [ |
| 156 | + { |
| 157 | + type: 'setting', |
| 158 | + settingId: 'animated_java:json_exporter/output_file', |
| 159 | + }, |
| 160 | + ], |
| 161 | + async export(exportOptions) { |
| 162 | + console.log('Export Options:', exportOptions) |
| 163 | + |
| 164 | + const data: RawExportData = { |
| 165 | + project_settings: {}, |
| 166 | + exporter_settings: {}, |
| 167 | + rig: { |
| 168 | + default_pose: exportOptions.rig.defaultPose.map(serializeAnimationNode), |
| 169 | + node_structure: exportOptions.rig.nodeStructure, |
| 170 | + node_map: {}, |
| 171 | + }, |
| 172 | + animations: {}, |
| 173 | + } |
| 174 | + |
| 175 | + for (const [key, setting] of Object.entries(exportOptions.projectSettings)) { |
| 176 | + data.project_settings[key] = setting._save() |
| 177 | + } |
| 178 | + |
| 179 | + for (const [key, setting] of Object.entries(exportOptions.exporterSettings)) { |
| 180 | + data.exporter_settings[key] = setting._save() |
| 181 | + } |
| 182 | + |
| 183 | + for (const [uuid, node] of Object.entries(exportOptions.rig.nodeMap)) { |
| 184 | + if (!node.node.export) continue |
| 185 | + data.rig.node_map[uuid] = serializeOutlinerNode(node) |
| 186 | + } |
| 187 | + |
| 188 | + for (const animation of exportOptions.renderedAnimations) { |
| 189 | + data.animations[animation.name] = serializeAnimation(animation) |
| 190 | + } |
| 191 | + |
| 192 | + console.log('Exported data:', data) |
| 193 | + |
| 194 | + await fs.promises.writeFile( |
| 195 | + exportOptions.exporterSettings.output_file.value, |
| 196 | + exportOptions.ajSettings.minify_output.value |
| 197 | + ? JSON.stringify(data) |
| 198 | + : JSON.stringify(data, null, '\t') |
| 199 | + ) |
| 200 | + }, |
| 201 | + }) |
| 202 | +} |
0 commit comments