Skip to content

Commit 56982f7

Browse files
committed
🐛 Fix tween_paused playing the animation after the tween
- Nothing read the pause tag, so tween_paused behaved exactly like tween - Tag is now added after tween, since tween's pause_all clears it - play and pause_all clear a pending pause so it can't leak into later animations
1 parent 44efa17 commit 56982f7

9 files changed

Lines changed: 565 additions & 194 deletions

File tree

‎TEXTURE_PALLETS.md‎

Whitespace-only changes.

‎src/systems/datapackCompiler/1.20.4/main.mcb‎

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,7 @@ IF (has_animations) {
199199

200200
data_manager prep read
201201

202+
tag @s remove <%TAGS.PAUSE_AFTER_TWEEN()%>
202203
tag @s add <%TAGS.ANIMATION_PLAYING(blueprint_id, animation.storage_name)%>
203204
scoreboard players set @s <%OBJECTIVES.FRAME(blueprint_id, animation.storage_name)%> 0
204205
tag @s add <%TAGS.TRANSFORMS_ONLY()%>
@@ -297,12 +298,13 @@ IF (has_animations) {
297298
}
298299

299300
function tween_paused {
300-
# Same as the tween function, except it does not play the animation afterwards
301+
# Same as the tween function, except the animation stays paused on to_frame once the tween finishes
301302
#ARGS: {duration: int, to_frame: int}
302303
debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%>
303304

304-
tag @s add <%TAGS.PAUSE_AFTER_TWEEN()%>
305305
$function ./tween {duration: $(duration), to_frame: $(to_frame)}
306+
# Added after tween, since tween clears it through pause_all
307+
tag @s add <%TAGS.PAUSE_AFTER_TWEEN()%>
306308
}
307309

308310
dir zzz {
@@ -312,6 +314,15 @@ IF (has_animations) {
312314
execute if score @s <%OBJECTIVES.TWEEN_DURATION()%> matches 1.. run return 1
313315
execute if score @s <%OBJECTIVES.TWEEN_DURATION()%> matches 0 on passengers run \
314316
data modify entity @s interpolation_duration set value <%interpolation_duration%>
317+
# Pause instead of playing once a tween started by tween_paused finishes
318+
execute \
319+
if score @s <%OBJECTIVES.TWEEN_DURATION()%> matches ..0 \
320+
if entity @s[tag=<%TAGS.PAUSE_AFTER_TWEEN()%>] \
321+
run return run block pause_after_tween {
322+
tag @s remove <%TAGS.PAUSE_AFTER_TWEEN()%>
323+
tag @s remove <%TAGS.ANIMATION_PLAYING(blueprint_id, animation.storage_name)%>
324+
}
325+
315326
# Animation logic
316327
IF (animation.loop_mode === 'loop' && animation.loop_delay === 0) {
317328
# Makes sure function keyframes in the last frame of the animation are activated.
@@ -663,6 +674,7 @@ IF (has_animations) {
663674
REPEAT (animations) as animation {
664675
tag @s remove <%TAGS.ANIMATION_PLAYING(blueprint_id, animation.storage_name)%>
665676
}
677+
tag @s remove <%TAGS.PAUSE_AFTER_TWEEN()%>
666678
}
667679
}
668680
}

‎src/systems/datapackCompiler/1.20.5/main.mcb‎

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,7 @@ IF (has_animations) {
201201

202202
data_manager prep read
203203

204+
tag @s remove <%TAGS.PAUSE_AFTER_TWEEN()%>
204205
tag @s add <%TAGS.ANIMATION_PLAYING(blueprint_id, animation.storage_name)%>
205206
scoreboard players set @s <%OBJECTIVES.FRAME(blueprint_id, animation.storage_name)%> 0
206207
tag @s add <%TAGS.TRANSFORMS_ONLY()%>
@@ -299,12 +300,13 @@ IF (has_animations) {
299300
}
300301

301302
function tween_paused {
302-
# Same as the tween function, except it does not play the animation afterwards
303+
# Same as the tween function, except the animation stays paused on to_frame once the tween finishes
303304
#ARGS: {duration: int, to_frame: int}
304305
debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%>
305306

306-
tag @s add <%TAGS.PAUSE_AFTER_TWEEN()%>
307307
$function ./tween {duration: $(duration), to_frame: $(to_frame)}
308+
# Added after tween, since tween clears it through pause_all
309+
tag @s add <%TAGS.PAUSE_AFTER_TWEEN()%>
308310
}
309311

310312
dir zzz {
@@ -314,6 +316,15 @@ IF (has_animations) {
314316
execute if score @s <%OBJECTIVES.TWEEN_DURATION()%> matches 1.. run return 1
315317
execute if score @s <%OBJECTIVES.TWEEN_DURATION()%> matches 0 on passengers run \
316318
data modify entity @s interpolation_duration set value <%interpolation_duration%>
319+
# Pause instead of playing once a tween started by tween_paused finishes
320+
execute \
321+
if score @s <%OBJECTIVES.TWEEN_DURATION()%> matches ..0 \
322+
if entity @s[tag=<%TAGS.PAUSE_AFTER_TWEEN()%>] \
323+
run return run block pause_after_tween {
324+
tag @s remove <%TAGS.PAUSE_AFTER_TWEEN()%>
325+
tag @s remove <%TAGS.ANIMATION_PLAYING(blueprint_id, animation.storage_name)%>
326+
}
327+
317328
# Animation logic
318329
IF (animation.loop_mode === 'loop' && animation.loop_delay === 0) {
319330
# Makes sure function keyframes in the last frame of the animation are activated.
@@ -665,6 +676,7 @@ IF (has_animations) {
665676
REPEAT (animations) as animation {
666677
tag @s remove <%TAGS.ANIMATION_PLAYING(blueprint_id, animation.storage_name)%>
667678
}
679+
tag @s remove <%TAGS.PAUSE_AFTER_TWEEN()%>
668680
}
669681
}
670682
}

‎src/systems/datapackCompiler/1.21.0/main.mcb‎

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,7 @@ IF (has_animations) {
201201

202202
data_manager prep read
203203

204+
tag @s remove <%TAGS.PAUSE_AFTER_TWEEN()%>
204205
tag @s add <%TAGS.ANIMATION_PLAYING(blueprint_id, animation.storage_name)%>
205206
scoreboard players set @s <%OBJECTIVES.FRAME(blueprint_id, animation.storage_name)%> 0
206207
tag @s add <%TAGS.TRANSFORMS_ONLY()%>
@@ -299,12 +300,13 @@ IF (has_animations) {
299300
}
300301

301302
function tween_paused {
302-
# Same as the tween function, except it does not play the animation afterwards
303+
# Same as the tween function, except the animation stays paused on to_frame once the tween finishes
303304
#ARGS: {duration: int, to_frame: int}
304305
debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%>
305306

306-
tag @s add <%TAGS.PAUSE_AFTER_TWEEN()%>
307307
$function ./tween {duration: $(duration), to_frame: $(to_frame)}
308+
# Added after tween, since tween clears it through pause_all
309+
tag @s add <%TAGS.PAUSE_AFTER_TWEEN()%>
308310
}
309311

310312
dir zzz {
@@ -314,6 +316,15 @@ IF (has_animations) {
314316
execute if score @s <%OBJECTIVES.TWEEN_DURATION()%> matches 1.. run return 1
315317
execute if score @s <%OBJECTIVES.TWEEN_DURATION()%> matches 0 on passengers run \
316318
data modify entity @s interpolation_duration set value <%interpolation_duration%>
319+
# Pause instead of playing once a tween started by tween_paused finishes
320+
execute \
321+
if score @s <%OBJECTIVES.TWEEN_DURATION()%> matches ..0 \
322+
if entity @s[tag=<%TAGS.PAUSE_AFTER_TWEEN()%>] \
323+
run return run block pause_after_tween {
324+
tag @s remove <%TAGS.PAUSE_AFTER_TWEEN()%>
325+
tag @s remove <%TAGS.ANIMATION_PLAYING(blueprint_id, animation.storage_name)%>
326+
}
327+
317328
# Animation logic
318329
IF (animation.loop_mode === 'loop' && animation.loop_delay === 0) {
319330
# Makes sure function keyframes in the last frame of the animation are activated.
@@ -665,6 +676,7 @@ IF (has_animations) {
665676
REPEAT (animations) as animation {
666677
tag @s remove <%TAGS.ANIMATION_PLAYING(blueprint_id, animation.storage_name)%>
667678
}
679+
tag @s remove <%TAGS.PAUSE_AFTER_TWEEN()%>
668680
}
669681
}
670682
}

‎src/systems/datapackCompiler/1.21.2/main.mcb‎

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,7 @@ IF (has_animations) {
202202

203203
data_manager prep read
204204

205+
tag @s remove <%TAGS.PAUSE_AFTER_TWEEN()%>
205206
tag @s add <%TAGS.ANIMATION_PLAYING(blueprint_id, animation.storage_name)%>
206207
scoreboard players set @s <%OBJECTIVES.FRAME(blueprint_id, animation.storage_name)%> 0
207208
tag @s add <%TAGS.TRANSFORMS_ONLY()%>
@@ -300,12 +301,13 @@ IF (has_animations) {
300301
}
301302

302303
function tween_paused {
303-
# Same as the tween function, except it does not play the animation afterwards
304+
# Same as the tween function, except the animation stays paused on to_frame once the tween finishes
304305
#ARGS: {duration: int, to_frame: int}
305306
debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%>
306307

307-
tag @s add <%TAGS.PAUSE_AFTER_TWEEN()%>
308308
$function ./tween {duration: $(duration), to_frame: $(to_frame)}
309+
# Added after tween, since tween clears it through pause_all
310+
tag @s add <%TAGS.PAUSE_AFTER_TWEEN()%>
309311
}
310312

311313
dir zzz {
@@ -315,6 +317,15 @@ IF (has_animations) {
315317
execute if score @s <%OBJECTIVES.TWEEN_DURATION()%> matches 1.. run return 1
316318
execute if score @s <%OBJECTIVES.TWEEN_DURATION()%> matches 0 on passengers run \
317319
data modify entity @s interpolation_duration set value <%interpolation_duration%>
320+
# Pause instead of playing once a tween started by tween_paused finishes
321+
execute \
322+
if score @s <%OBJECTIVES.TWEEN_DURATION()%> matches ..0 \
323+
if entity @s[tag=<%TAGS.PAUSE_AFTER_TWEEN()%>] \
324+
run return run block pause_after_tween {
325+
tag @s remove <%TAGS.PAUSE_AFTER_TWEEN()%>
326+
tag @s remove <%TAGS.ANIMATION_PLAYING(blueprint_id, animation.storage_name)%>
327+
}
328+
318329
# Animation logic
319330
IF (animation.loop_mode === 'loop' && animation.loop_delay === 0) {
320331
# Makes sure function keyframes in the last frame of the animation are activated.
@@ -666,6 +677,7 @@ IF (has_animations) {
666677
REPEAT (animations) as animation {
667678
tag @s remove <%TAGS.ANIMATION_PLAYING(blueprint_id, animation.storage_name)%>
668679
}
680+
tag @s remove <%TAGS.PAUSE_AFTER_TWEEN()%>
669681
}
670682
}
671683
}

‎src/systems/datapackCompiler/1.21.4/main.mcb‎

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,7 @@ IF (has_animations) {
250250

251251
data_manager prep read
252252

253+
tag @s remove <%TAGS.PAUSE_AFTER_TWEEN()%>
253254
tag @s add <%TAGS.ANIMATION_PLAYING(blueprint_id, animation.storage_name)%>
254255
scoreboard players set @s <%OBJECTIVES.FRAME(blueprint_id, animation.storage_name)%> 0
255256
tag @s add <%TAGS.TRANSFORMS_ONLY()%>
@@ -360,12 +361,13 @@ IF (has_animations) {
360361
}
361362

362363
function tween_paused {
363-
# Same as the tween function, except it does not play the animation afterwards
364+
# Same as the tween function, except the animation stays paused on to_frame once the tween finishes
364365
#ARGS: {duration: int, to_frame: int}
365366
debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%>
366367

367-
tag @s add <%TAGS.PAUSE_AFTER_TWEEN()%>
368368
$function ./tween {duration: $(duration), to_frame: $(to_frame)}
369+
# Added after tween, since tween clears it through pause_all
370+
tag @s add <%TAGS.PAUSE_AFTER_TWEEN()%>
369371
}
370372

371373
dir zzz {
@@ -385,6 +387,15 @@ IF (has_animations) {
385387
}
386388
}
387389

390+
# Pause instead of playing once a tween started by tween_paused finishes
391+
execute \
392+
if score @s <%OBJECTIVES.TWEEN_DURATION()%> matches ..0 \
393+
if entity @s[tag=<%TAGS.PAUSE_AFTER_TWEEN()%>] \
394+
run return run block pause_after_tween {
395+
tag @s remove <%TAGS.PAUSE_AFTER_TWEEN()%>
396+
tag @s remove <%TAGS.ANIMATION_PLAYING(blueprint_id, animation.storage_name)%>
397+
}
398+
388399
# Animation logic
389400
IF (animation.loop_mode === 'loop' && animation.loop_delay === 0) {
390401
# Makes sure function keyframes in the last frame of the animation are activated.
@@ -754,6 +765,7 @@ IF (has_animations) {
754765
REPEAT (animations) as animation {
755766
tag @s remove <%TAGS.ANIMATION_PLAYING(blueprint_id, animation.storage_name)%>
756767
}
768+
tag @s remove <%TAGS.PAUSE_AFTER_TWEEN()%>
757769
}
758770
}
759771
}

‎src/systems/datapackCompiler/1.21.5/main.mcb‎

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,7 @@ IF (has_animations) {
249249

250250
data_manager prep read
251251

252+
tag @s remove <%TAGS.PAUSE_AFTER_TWEEN()%>
252253
tag @s add <%TAGS.ANIMATION_PLAYING(blueprint_id, animation.storage_name)%>
253254
scoreboard players set @s <%OBJECTIVES.FRAME(blueprint_id, animation.storage_name)%> 0
254255
tag @s add <%TAGS.TRANSFORMS_ONLY()%>
@@ -359,12 +360,13 @@ IF (has_animations) {
359360
}
360361

361362
function tween_paused {
362-
# Same as the tween function, except it does not play the animation afterwards
363+
# Same as the tween function, except the animation stays paused on to_frame once the tween finishes
363364
#ARGS: {duration: int, to_frame: int}
364365
debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%>
365366

366-
tag @s add <%TAGS.PAUSE_AFTER_TWEEN()%>
367367
$function ./tween {duration: $(duration), to_frame: $(to_frame)}
368+
# Added after tween, since tween clears it through pause_all
369+
tag @s add <%TAGS.PAUSE_AFTER_TWEEN()%>
368370
}
369371

370372
dir zzz {
@@ -384,6 +386,15 @@ IF (has_animations) {
384386
}
385387
}
386388

389+
# Pause instead of playing once a tween started by tween_paused finishes
390+
execute \
391+
if score @s <%OBJECTIVES.TWEEN_DURATION()%> matches ..0 \
392+
if entity @s[tag=<%TAGS.PAUSE_AFTER_TWEEN()%>] \
393+
run return run block pause_after_tween {
394+
tag @s remove <%TAGS.PAUSE_AFTER_TWEEN()%>
395+
tag @s remove <%TAGS.ANIMATION_PLAYING(blueprint_id, animation.storage_name)%>
396+
}
397+
387398
# Animation logic
388399
IF (animation.loop_mode === 'loop' && animation.loop_delay === 0) {
389400
# Makes sure function keyframes in the last frame of the animation are activated.
@@ -753,6 +764,7 @@ IF (has_animations) {
753764
REPEAT (animations) as animation {
754765
tag @s remove <%TAGS.ANIMATION_PLAYING(blueprint_id, animation.storage_name)%>
755766
}
767+
tag @s remove <%TAGS.PAUSE_AFTER_TWEEN()%>
756768
}
757769
}
758770
}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
import { afterAll, beforeAll, describe, expect, it } from '@jest/globals'
2+
import * as fs from 'node:fs'
3+
import * as path from 'node:path'
4+
import { type ExportRun, relFiles, runFixtureExport } from './helpers/export'
5+
6+
/**
7+
* `tween_paused` runs `tween`, then tags the root with `aj.pause_after_tween`. The animation's
8+
* `zzz/on_tick` pauses it instead of playing once the tween finishes, and `play` / `pause_all`
9+
* clear the tag so a pending pause can't leak into a later animation.
10+
*/
11+
12+
const PAUSE_TAG = 'aj.pause_after_tween'
13+
14+
function readMatching(run: ExportRun, files: string[], match: (file: string) => boolean) {
15+
return files
16+
.filter(match)
17+
.map(f => fs.readFileSync(path.join(run.dataPackFolder, f), 'utf-8'))
18+
.join('\n')
19+
}
20+
21+
// 1.20.4 is the oldest main.mcb, 26.2 resolves to the newest.
22+
describe.each(['1.20.4', '26.2'])('tween_paused export (%s)', targetVersion => {
23+
let run: ExportRun
24+
let dpFiles: string[]
25+
const read = (match: (file: string) => boolean) => readMatching(run, dpFiles, match)
26+
27+
beforeAll(async () => {
28+
run = await runFixtureExport({
29+
fixture: 'test_blueprints/Dummy.ajblueprint',
30+
targetVersion,
31+
})
32+
dpFiles = relFiles(run.dataPackFolder)
33+
}, 180_000)
34+
35+
afterAll(() => run?.cleanup())
36+
37+
it('exports', () => {
38+
expect(run.ok).toBe(true)
39+
})
40+
41+
it('tags the root after tweening, so the tween does not clear the tag', () => {
42+
const tweenPaused = read(f => f.endsWith('/animations/floss/tween_paused.mcfunction'))
43+
const tweenCall = tweenPaused.indexOf('animations/floss/tween {')
44+
const tagAdd = tweenPaused.indexOf(`tag @s add ${PAUSE_TAG}`)
45+
expect(tweenCall).toBeGreaterThan(-1)
46+
expect(tagAdd).toBeGreaterThan(tweenCall)
47+
})
48+
49+
it('pauses the animation once a paused tween finishes', () => {
50+
const onTick = read(
51+
f =>
52+
f.includes('/animations/floss/zzz/on_tick') ||
53+
f.endsWith('/animations/floss/zzz/pause_after_tween.mcfunction')
54+
)
55+
expect(onTick).toMatch(/matches \.\.0/)
56+
expect(onTick).toContain(`if entity @s[tag=${PAUSE_TAG}]`)
57+
expect(onTick).toContain(`tag @s remove ${PAUSE_TAG}`)
58+
expect(onTick).toContain('tag @s remove aj_booth_rigs.dummy.animation.floss.playing')
59+
})
60+
61+
it('clears a pending pause when playing or pausing every animation', () => {
62+
expect(read(f => f.endsWith('/animations/floss/play.mcfunction'))).toContain(
63+
`tag @s remove ${PAUSE_TAG}`
64+
)
65+
expect(read(f => f.endsWith('/animations/pause_all.mcfunction'))).toContain(
66+
`tag @s remove ${PAUSE_TAG}`
67+
)
68+
})
69+
})

0 commit comments

Comments
 (0)