-
-
Notifications
You must be signed in to change notification settings - Fork 49
Expand file tree
/
Copy pathexporter.ts
More file actions
220 lines (196 loc) · 6.69 KB
/
exporter.ts
File metadata and controls
220 lines (196 loc) · 6.69 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
import { Stopwatch } from 'src/util/stopwatch'
import { projectTargetVersionIsAtLeast, saveBlueprint } from '../formats/blueprint'
import { blueprintSettingErrors } from '../formats/blueprint/settings'
import { openBlueprintSettingsDialog } from '../interface/dialog/blueprintSettings'
import { PROGRESS_DESCRIPTION, openExportProgressDialog } from '../interface/dialog/exportProgress'
import { openUnexpectedErrorDialog } from '../interface/dialog/unexpectedError'
import { resolvePath } from '../util/fileUtil'
import { isResourcePackPath } from '../util/minecraftUtil'
import { translate } from '../util/translation'
import { Variant } from '../variants'
import { hashAnimations, renderProjectAnimations } from './animationRenderer'
import { exportPluginBlueprint } from './pluginCompiler'
import compileDataPack from './datapackCompiler'
import { IntentionalExportError } from './errors'
import resourcepackCompiler from './resourcepackCompiler'
import { hashRig, renderRig } from './rigRenderer'
import { isCubeValid } from './util'
export function getExportPaths() {
const aj = Project!.animated_java
const resourcePackFolder = resolvePath(aj.resource_pack)
const dataPackFolder = resolvePath(aj.data_pack)
// These paths are all relative to the resource pack folder
const modelExportFolder = PathModule.join(
'assets/animated_java/models/blueprint/',
aj.export_namespace
)
const textureExportFolder = PathModule.join(
'assets/animated_java/textures/blueprint/',
aj.export_namespace
)
const displayItemPath = PathModule.join(
'assets/minecraft/models/item/',
aj.display_item.split(':').at(-1)! + '.json'
)
return {
resourcePackFolder,
dataPackFolder,
textureExportFolder,
modelExportFolder,
displayItemPath,
}
}
interface ExportProjectOptions {
forceSave?: boolean
debugMode?: boolean
}
async function actuallyExportProject({
forceSave = true,
debugMode = false,
}: ExportProjectOptions = {}): Promise<boolean> {
const aj = Project!.animated_java
const dialog = openExportProgressDialog()
// Wait for the dialog to open
await new Promise(resolve => requestAnimationFrame(resolve))
const selectedVariant = Variant.selected
Variant.getDefault().select()
const stopwatch = new Stopwatch('Project Export').start()
try {
// Verify that all variant texture maps are valid
for (const variant of Variant.all) {
variant.verifyTextureMap()
}
// Verify that all non-external textures have unique names
for (const texture of Texture.all) {
if (texture.path && isResourcePackPath(texture.path) && fs.existsSync(texture.path))
continue
if (Texture.all.some(t => t !== texture && t.name === texture.name)) {
throw new IntentionalExportError(
`Texture name "${texture.name}" is used more than once. Please make sure all textures have unique names.`
)
}
}
const {
resourcePackFolder,
dataPackFolder,
textureExportFolder,
modelExportFolder,
displayItemPath,
} = getExportPaths()
PROGRESS_DESCRIPTION.set('Rendering Rig...')
const rig = renderRig(modelExportFolder, textureExportFolder)
if (!rig.includes_custom_models && Texture.all.length !== 0) {
throw new IntentionalExportError(
translate('misc.failed_to_export.rig_has_textures_but_no_custom_models.message')
)
} else if (rig.includes_custom_models && Texture.all.length === 0) {
throw new IntentionalExportError(
translate('misc.failed_to_export.rig_has_custom_models_but_no_textures.message')
)
}
if (
Project!.animated_java.resource_pack_export_mode === 'none' &&
rig.includes_custom_models
) {
Blockbench.showMessageBox({
title: translate('misc.failed_to_export.title'),
message: translate('misc.failed_to_export.custom_models.message'),
buttons: [translate('misc.failed_to_export.button')],
})
dialog.close(0)
return false
}
const animations = await renderProjectAnimations(Project!, rig)
PROGRESS_DESCRIPTION.set('Hashing Rendered Objects...')
const rigHash = hashRig(rig)
const animationHash = hashAnimations(animations)
// TODO - Plugin mode should run without the resource pack compiler
// Always run the resource pack compiler because it calculates custom model data.
await resourcepackCompiler([aj.target_minecraft_version], {
rig,
displayItemPath,
resourcePackFolder,
textureExportFolder,
modelExportFolder,
debugMode,
})
if (!aj.enable_plugin_mode && aj.data_pack_export_mode !== 'none') {
await compileDataPack([aj.target_minecraft_version], {
rig,
animations,
dataPackFolder,
rigHash,
animationHash,
debugMode,
})
}
if (aj.enable_plugin_mode) {
PROGRESS_DESCRIPTION.set('Exporting Plugin JSON...')
exportPluginBlueprint({ rig, animations })
}
Project!.last_used_export_namespace = aj.export_namespace
if (forceSave) saveBlueprint()
Blockbench.showQuickMessage('Project exported successfully!', 2000)
return true
} catch (e: any) {
console.error(e)
if (e instanceof IntentionalExportError) {
Blockbench.showMessageBox(
{
title: translate('misc.failed_to_export.title'),
message: e.message,
buttons: [translate('misc.failed_to_export.button')],
...e.messageBoxOptions,
},
e.messageBoxCallback
)
return false
}
openUnexpectedErrorDialog(e as Error)
} finally {
selectedVariant?.select()
dialog.close(0)
stopwatch.debug()
}
return false
}
export async function exportProject(options?: ExportProjectOptions): Promise<boolean> {
if (!Project) return false // TODO: Handle this error better
if (Cube.all.some(cube => isCubeValid(cube) === 'invalid')) {
Blockbench.showMessageBox({
title: translate('misc.failed_to_export.title'),
message: translate(
projectTargetVersionIsAtLeast('1.21.6')
? 'misc.failed_to_export.invalid_rotation.message_post_1_21_6'
: 'misc.failed_to_export.invalid_rotation.message'
),
buttons: [translate('misc.failed_to_export.button')],
})
return false
}
blueprintSettingErrors.set({})
const settingsDialog = openBlueprintSettingsDialog()!
// Wait for the dialog to open
await new Promise(resolve => requestAnimationFrame(resolve))
console.log('Blueprint Setting Errors', blueprintSettingErrors.get())
if (Object.keys(blueprintSettingErrors.get()).length > 0) {
Blockbench.showMessageBox({
title: translate('misc.failed_to_export.title'),
message:
translate('misc.failed_to_export.blueprint_settings.message') +
'\n\n' +
Object.entries(blueprintSettingErrors.get())
.map(
v =>
translate('misc.failed_to_export.blueprint_settings.error_item', v[0]) +
'\n - ' +
v[1]
)
.join('\n\n'),
buttons: [translate('misc.failed_to_export.button')],
})
return false
}
settingsDialog.close(0)
return await actuallyExportProject(options)
}