Skip to content

Commit 92e4ae1

Browse files
committed
Progress fixes & possible locator rotation support
1 parent b3b28f1 commit 92e4ae1

File tree

7 files changed

+178
-56
lines changed

7 files changed

+178
-56
lines changed

exporters/datapackExporter/datapackExporter.ts

Lines changed: 57 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -726,6 +726,11 @@ export function loadExporter() {
726726
const bone = rig.nodeMap[
727727
node.uuid
728728
] as AnimatedJava.IRenderedNodes['Locator']
729+
const pos = node.pos
730+
const euler = new THREE.Euler().setFromQuaternion(node.rot, 'YZX')
731+
const rot = new THREE.Vector3(euler.x, euler.y, euler.z).multiplyScalar(
732+
180 / Math.PI
733+
)
729734
commands.push(
730735
`execute if entity @s[tag=${API.formatStr(tags.namedBoneEntity, [
731736
node.name,
@@ -735,11 +740,28 @@ export function loadExporter() {
735740
: `type=${bone.teleported_entity_type},`
736741
}tag=${API.formatStr(tags.locatorTag, [
737742
node.name,
738-
])},limit=1] ^${API.roundToN(node.pos.x, 10)} ^${API.roundToN(
739-
node.pos.y,
743+
])},limit=1] ^${API.roundToN(pos.x, 10)} ^${API.roundToN(
744+
pos.y - 1.62,
740745
10
741-
)} ^${API.roundToN(node.pos.z, 10)} ~ ~`
746+
)} ^${API.roundToN(pos.z, 10)} ~${API.roundToN(
747+
-rot.y + 180,
748+
10
749+
)} ~${API.roundToN(-rot.x, 10)}`
742750
)
751+
// commands.push(
752+
// `execute if entity @s[tag=${API.formatStr(tags.namedBoneEntity, [
753+
// node.name,
754+
// ])}] at @s run tp @e[${
755+
// bone.teleported_entity_type === ''
756+
// ? ''
757+
// : `type=${bone.teleported_entity_type},`
758+
// }tag=${API.formatStr(tags.locatorTag, [
759+
// node.name,
760+
// ])},limit=1] ^${API.roundToN(node.pos.x, 10)} ^${API.roundToN(
761+
// node.pos.y,
762+
// 10
763+
// )} ^${API.roundToN(node.pos.z, 10)} ~ ~`
764+
// )
743765
break
744766
}
745767
}
@@ -928,27 +950,33 @@ export function loadExporter() {
928950
datapack.childCount
929951
)
930952

931-
let content:
932-
| {
933-
projects: Record<
934-
string,
935-
{
936-
tick_functions: string[]
937-
load_functions: string[]
938-
file_list: string[]
939-
}
940-
>
941-
}
942-
| undefined
953+
interface IAJMeta {
954+
projects: Record<
955+
string,
956+
{
957+
tick_functions: string[]
958+
load_functions: string[]
959+
file_list: string[]
960+
}
961+
>
962+
}
943963

944-
const ajMetaPath = PathModule.join(EXPORT_FOLDER, 'animated_java.mcmeta')
945-
if (await fileExists(ajMetaPath)) {
946-
content = await fs.promises.readFile(ajMetaPath, 'utf-8').then(JSON.parse)
964+
let content: IAJMeta | undefined
965+
966+
const oldAJMetaPath = PathModule.join(EXPORT_FOLDER, 'animated_java.mcmeta')
967+
const ajMetaPath = PathModule.join(EXPORT_FOLDER, '.ajmeta')
968+
const existingMetaFile = (await fileExists(oldAJMetaPath))
969+
? oldAJMetaPath
970+
: (await fileExists(ajMetaPath))
971+
? ajMetaPath
972+
: undefined
973+
if (existingMetaFile !== undefined) {
974+
content = await fs.promises.readFile(existingMetaFile, 'utf-8').then(JSON.parse)
947975

948976
if (!content.projects) {
949977
const message = `Failed to read the animated_java.mcdata file. (Missing projects). Please delete the file and try again.`
950978
Blockbench.showMessageBox({
951-
title: 'Failed to read animated_java.mcmeta',
979+
title: 'Failed to read .ajmeta',
952980
message,
953981
})
954982
throw new AnimatedJava.API.ExpectedError(message)
@@ -965,7 +993,7 @@ export function loadExporter() {
965993
if (!project.file_list) {
966994
const message = `Failed to read the animated_java.mcdata file. (Missing project file_list). Please delete the file and try again.`
967995
Blockbench.showMessageBox({
968-
title: 'Failed to read animated_java.mcmeta',
996+
title: 'Failed to read .ajmeta',
969997
message,
970998
})
971999
throw new AnimatedJava.API.ExpectedError(message)
@@ -974,7 +1002,7 @@ export function loadExporter() {
9741002
if (!project.tick_functions) {
9751003
const message = `Failed to read the animated_java.mcdata file. (Missing project tick_functions). Please delete the file and try again.`
9761004
Blockbench.showMessageBox({
977-
title: 'Failed to read animated_java.mcmeta',
1005+
title: 'Failed to read .ajmeta',
9781006
message,
9791007
})
9801008
throw new AnimatedJava.API.ExpectedError(message)
@@ -983,20 +1011,21 @@ export function loadExporter() {
9831011
if (!project.load_functions) {
9841012
const message = `Failed to read the animated_java.mcdata file. (Missing project load_functions). Please delete the file and try again.`
9851013
Blockbench.showMessageBox({
986-
title: 'Failed to read animated_java.mcmeta',
1014+
title: 'Failed to read .ajmeta',
9871015
message,
9881016
})
9891017
throw new AnimatedJava.API.ExpectedError(message)
9901018
}
9911019

9921020
progress.total += project.file_list.length
9931021
const clock = new API.LimitClock(10)
994-
for (const path of project.file_list) {
1022+
for (let path of project.file_list) {
9951023
progress.add(1)
9961024
await clock.sync().then(b => b && progress.update())
9971025
if (path.endsWith('tick.json') || path.endsWith('load.json')) continue
998-
await fs.promises.unlink(PathModule.join(EXPORT_FOLDER, path)).catch(() => {})
999-
const dirPath = PathModule.join(EXPORT_FOLDER, PathModule.dirname(path))
1026+
path = PathModule.join(EXPORT_FOLDER, path)
1027+
await fs.promises.unlink(path).catch(() => {})
1028+
const dirPath = PathModule.dirname(path)
10001029
const contents = await fs.promises.readdir(dirPath).catch(() => {})
10011030
if (contents && contents.length === 0)
10021031
await fs.promises.rmdir(dirPath).catch(() => {})
@@ -1014,6 +1043,8 @@ export function loadExporter() {
10141043
a.values.push(...b.values)
10151044
return a
10161045
}
1046+
1047+
await fs.promises.rm(existingMetaFile)
10171048
} else {
10181049
content = {
10191050
projects: {
@@ -1025,7 +1056,7 @@ export function loadExporter() {
10251056
},
10261057
}
10271058
}
1028-
datapack.newFile('animated_java.mcmeta', content)
1059+
datapack.newFile('.ajmeta', content)
10291060
await Promise.all(
10301061
datapack.children.map(async child => await child.writeToDisk(EXPORT_FOLDER, progress))
10311062
)

src/exporter.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { projectSettingStructure } from './projectSettings'
55
import { IRenderedAnimation, renderAllAnimations } from './rendering/animationRenderer'
66
import { IRenderedRig, renderRig } from './rendering/modelRenderer'
77
import { animatedJavaSettings, IInfoPopup, Setting as AJSetting, Setting } from './settings'
8+
import { openAJExportInProgressDialog } from './ui/ajExportInProgress'
89
import { openAjFailedProjectExportReadinessDialog } from './ui/popups/failedProjectExportReadiness'
910
import { openUnexpectedErrorDialog } from './ui/popups/unexpectedError'
1011
import { consoleGroupCollapsed } from './util/console'
@@ -71,14 +72,17 @@ let activelyExporting = false
7172
export async function safeExportProject() {
7273
if (activelyExporting) return
7374
activelyExporting = true
75+
const dialog = openAJExportInProgressDialog()
7476
await exportProject().catch(e => {
7577
Blockbench.setProgress(0)
7678
Blockbench.setStatusBarText('')
7779
console.error(e)
80+
dialog.cancel()
7881
if (e instanceof ExpectedError) return
7982
openUnexpectedErrorDialog(e)
8083
})
8184
activelyExporting = false
85+
dialog.cancel()
8286
}
8387

8488
export const exportProject = consoleGroupCollapsed('exportProject', async () => {
@@ -88,7 +92,6 @@ export const exportProject = consoleGroupCollapsed('exportProject', async () =>
8892
// Pre-export
8993
const selectedVariant = Project.animated_java_variants!.selectedVariant!
9094
Project.animated_java_variants?.select()
91-
jQuery('#blackout').show()
9295

9396
const selectedExporterId = Project?.animated_java_settings?.exporter?.selected
9497
?.value as NamespacedString
@@ -161,7 +164,6 @@ export const exportProject = consoleGroupCollapsed('exportProject', async () =>
161164
Blockbench.showQuickMessage(translate('animated_java.quickmessage.exported_successfully'), 2000)
162165
// Post-export
163166
Project.animated_java_variants?.select(selectedVariant)
164-
jQuery('#blackout').hide()
165167
})
166168

167169
function verifySettings(structure: GUIStructure, settings: Array<Setting<any>>) {

src/exporter/resourcePackExporter.ts

Lines changed: 94 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
11
import { isValidResourcePackPath, safeFunctionName } from '../minecraft'
22
import { CustomModelData, IRenderedRig } from '../rendering/modelRenderer'
33
import { animatedJavaSettings } from '../settings'
4-
import { ExpectedError } from '../util/misc'
4+
import { ExpectedError, LimitClock } from '../util/misc'
55
import { ProgressBarController } from '../util/progress'
66
import { translate } from '../util/translation'
77
import { VirtualFolder } from '../util/virtualFileSystem'
88

9+
async function fileExists(path: string) {
10+
return !!(await fs.promises.stat(path).catch(() => false))
11+
}
12+
913
function showPredicateFileOverwriteConfirmation(path: string) {
1014
const result = confirm(
1115
translate('animated_java.popup.confirm_predicate_file_overwrite.body', {
@@ -27,7 +31,8 @@ export async function exportResources(
2731
) {
2832
const projectNamespace = projectSettings.project_namespace.value
2933
const resourcePackPath = PathModule.parse(projectSettings.resource_pack_mcmeta.value).dir
30-
const assetsPackFolder = new VirtualFolder('assets')
34+
const resourcePackFolder = new VirtualFolder('internal_resource_pack_folder')
35+
const assetsPackFolder = resourcePackFolder.newFolder('assets')
3136
const advancedResourcePackSettingsEnabled =
3237
projectSettings.enable_advanced_resource_pack_settings.value
3338

@@ -36,7 +41,6 @@ export async function exportResources(
3641
//------------------------------------
3742

3843
const [rigItemNamespace, rigItemName] = projectSettings.rig_item.value.split(':')
39-
4044
const minecraftFolder = assetsPackFolder.newFolder('minecraft').newFolder('models/item')
4145

4246
//------------------------------------
@@ -182,11 +186,95 @@ export async function exportResources(
182186
(a: any, b: any) => a.predicate.custom_model_data - b.predicate.custom_model_data
183187
)
184188

189+
interface IAJMeta {
190+
projects: Record<string, { file_list: string[] }>
191+
}
192+
193+
async function processAJMeta(filePaths: string[]) {
194+
const ajMetaPath = PathModule.join(resourcePackPath, '.ajmeta')
195+
let content: IAJMeta | undefined
196+
197+
// FIXME - This is an extremely hacky way to filter out the predicate item file from the file list
198+
filePaths = filePaths.filter(
199+
p =>
200+
p !==
201+
predicateItemFile.path
202+
.replace(resourcePackFolder.path + '/', '')
203+
.replaceAll('/', PathModule.sep)
204+
)
205+
206+
if (await fileExists(ajMetaPath)) {
207+
content = await fs.promises
208+
.readFile(ajMetaPath, 'utf8')
209+
.then(JSON.parse)
210+
.catch(() => {
211+
throw new Error('Failed to read .ajmeta file as JSON')
212+
})
213+
if (!content)
214+
throw new Error('Failed to read .ajmeta file as JSON. Content is undefined.')
215+
216+
if (!content.projects) {
217+
console.warn('Found existing .ajmeta file, but it is missing "projects" key.')
218+
content.projects = {}
219+
}
220+
221+
if (!content.projects[NAMESPACE]) {
222+
console.warn('Found existing .ajmeta file, but it is missing this project.')
223+
content.projects[NAMESPACE] = {
224+
file_list: [],
225+
}
226+
} else {
227+
const progress = new ProgressBarController(
228+
'Cleaning up old Resource Pack files...',
229+
content.projects[NAMESPACE].file_list.length
230+
)
231+
// Clean out old files from disk
232+
const clock = new LimitClock(10)
233+
for (let path of content.projects[NAMESPACE].file_list) {
234+
await clock.sync().then(b => b && progress.update())
235+
path = PathModule.join(resourcePackPath, path)
236+
await fs.promises.unlink(path).catch(() => undefined)
237+
const dirPath = PathModule.dirname(path)
238+
const contents = await fs.promises.readdir(dirPath).catch(() => undefined)
239+
if (contents && contents.length === 0)
240+
await fs.promises.rmdir(dirPath).catch(() => undefined)
241+
progress.add(1)
242+
}
243+
progress.finish()
244+
}
245+
246+
content.projects[NAMESPACE].file_list = filePaths
247+
}
248+
249+
if (!content) {
250+
console.warn('.ajmeta does not exist. Creating new .ajmeta file.')
251+
content = {
252+
projects: {
253+
[NAMESPACE]: {
254+
file_list: filePaths,
255+
},
256+
},
257+
}
258+
}
259+
260+
await fs.promises.writeFile(
261+
ajMetaPath,
262+
ajSettings.minify_output.value
263+
? JSON.stringify(content)
264+
: JSON.stringify(content, null, 4)
265+
)
266+
}
267+
185268
if (advancedResourcePackSettingsEnabled) {
186269
const progress = new ProgressBarController(
187270
'Writing Resource Pack to Disk',
188271
modelsFolder.childCount + texturesFolder.childCount + 1
189272
)
273+
274+
const filePaths = [...modelsFolder.getAllFilePaths(), ...texturesFolder.getAllFilePaths()]
275+
276+
await processAJMeta(filePaths)
277+
190278
await fs.promises.mkdir(rigExportFolder, { recursive: true })
191279
await modelsFolder.writeChildrenToDisk(rigExportFolder, progress)
192280

@@ -204,27 +292,12 @@ export async function exportResources(
204292
assetsPackFolder.childCount
205293
)
206294

207-
const rigFolderPath = PathModule.join(resourcePackPath, namespaceFolder.path)
208-
await fs.promises
209-
.access(rigFolderPath)
210-
.then(async () => {
211-
await fs.promises.rm(rigFolderPath, { recursive: true })
212-
})
213-
.catch(e => {
214-
console.warn(e)
215-
})
295+
const filePaths = resourcePackFolder.getAllFilePaths()
216296

217-
const textureFolderPath = PathModule.join(resourcePackPath, texturesFolder.path)
218-
await fs.promises
219-
.access(textureFolderPath)
220-
.then(async () => {
221-
await fs.promises.rm(textureFolderPath, { recursive: true })
222-
})
223-
.catch(e => {
224-
console.warn(e)
225-
})
297+
await processAJMeta(filePaths)
226298

227299
await assetsPackFolder.writeToDisk(resourcePackPath, progress)
300+
228301
progress.finish()
229302
}
230303
}

src/rendering/animationRenderer.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,8 +103,20 @@ export function getAnimationNodes(
103103
}
104104
break
105105
}
106-
case 'camera':
107106
case 'locator':
107+
matrix = getNodeMatrix(node.node, 1)
108+
if (node.parentNode) {
109+
const parentMatrix = getNodeMatrix(node.parentNode, 1)
110+
// Extract the rotation from the parent matrix and apply it to the child matrix
111+
const parentRotation = new THREE.Quaternion().setFromRotationMatrix(
112+
parentMatrix
113+
)
114+
const childRotation = new THREE.Quaternion().setFromRotationMatrix(matrix)
115+
childRotation.multiply(parentRotation)
116+
matrix.makeRotationFromQuaternion(childRotation)
117+
}
118+
break
119+
case 'camera':
108120
matrix = getNodeMatrix(node.node, 1)
109121
break
110122
}

0 commit comments

Comments
 (0)