From 858d8edf7aba344539317754e0e3e7dbefacb4e0 Mon Sep 17 00:00:00 2001 From: Jenny Crowe Date: Tue, 27 Feb 2024 23:29:40 -0700 Subject: [PATCH 01/23] Cam tweening working! UI buggy af. To fix. --- source/funkin/play/PlayState.hx | 46 ++++++++++++- .../funkin/play/event/FocusCameraSongEvent.hx | 67 +++++++++++++++++++ 2 files changed, 111 insertions(+), 2 deletions(-) diff --git a/source/funkin/play/PlayState.hx b/source/funkin/play/PlayState.hx index 5bbf83e17..a745be6cd 100644 --- a/source/funkin/play/PlayState.hx +++ b/source/funkin/play/PlayState.hx @@ -219,6 +219,12 @@ class PlayState extends MusicBeatSubState */ public var cameraFollowPoint:FlxObject; + /** + * An FlxTween that tweens the camera to the follow point. + * Only used when tweening the camera manually, rather than tweening via follow. + */ + public var cameraFollowTween:FlxTween; + /** * The camera follow point from the last stage. * Used to persist the position of the `cameraFollowPosition` between levels. @@ -2847,15 +2853,51 @@ class PlayState extends MusicBeatSubState /** * Resets the camera's zoom level and focus point. */ - public function resetCamera():Void + public function resetCamera(?resetZoom:Bool = true, ?cancelFollowTween:Bool = true):Void { + // Cancel the follow tween if it's active. + if (cancelFollowTween && cameraFollowTween != null) + { + cameraFollowTween.cancel(); + } + FlxG.camera.follow(cameraFollowPoint, LOCKON, 0.04); FlxG.camera.targetOffset.set(); - FlxG.camera.zoom = defaultCameraZoom; + + if (resetZoom) + { + FlxG.camera.zoom = defaultCameraZoom; + } + // Snap the camera to the follow point immediately. FlxG.camera.focusOn(cameraFollowPoint.getPosition()); } + /** + * Disables camera following and tweens the camera to the follow point manually. + */ + public function tweenCamera(?duration:Float, ?ease:NullFloat>):Void + { + // Cancel the current tween if it's active. + if (cameraFollowTween != null) + { + cameraFollowTween.cancel(); + } + + // Disable camera following for the duration of the tween. + FlxG.camera.target = null; + + // Follow tween! Caching it so we can cancel it later if needed. + var followPos:FlxPoint = cameraFollowPoint.getPosition() - FlxPoint.weak(FlxG.camera.width * 0.5, FlxG.camera.height * 0.5); + cameraFollowTween = FlxTween.tween(FlxG.camera.scroll, {x: followPos.x, y: followPos.y}, duration, + { + ease: ease, + onComplete: function(_) { + resetCamera(false, false); // Re-enable camera following when the tween is complete. + } + }); + } + #if (debug || FORCE_DEBUG_VERSION) /** * Jumps forward or backward a number of sections in the song. diff --git a/source/funkin/play/event/FocusCameraSongEvent.hx b/source/funkin/play/event/FocusCameraSongEvent.hx index 847df4a60..28a629f1a 100644 --- a/source/funkin/play/event/FocusCameraSongEvent.hx +++ b/source/funkin/play/event/FocusCameraSongEvent.hx @@ -1,5 +1,6 @@ package funkin.play.event; +import flixel.tweens.FlxEase; // Data from the chart import funkin.data.song.SongData; import funkin.data.song.SongData.SongEventData; @@ -66,6 +67,13 @@ class FocusCameraSongEvent extends SongEvent if (char == null) char = cast data.value; + var useTween:Null = data.getBool('useTween'); + if (useTween == null) useTween = false; + var duration:Null = data.getFloat('duration'); + if (duration == null) duration = 4.0; + var ease:Null = data.getString('ease'); + if (ease == null) ease = 'linear'; + switch (char) { case -1: // Position @@ -114,6 +122,20 @@ class FocusCameraSongEvent extends SongEvent default: trace('Unknown camera focus: ' + data); } + + if (useTween) // always ends up false?? + { + var durSeconds = Conductor.instance.stepLengthMs * duration / 1000; + + var easeFunction:NullFloat> = Reflect.field(FlxEase, ease); + if (easeFunction == null) + { + trace('Invalid ease function: $ease'); + return; + } + + PlayState.instance.tweenCamera(durSeconds, easeFunction); + } } public override function getTitle():String @@ -155,6 +177,51 @@ class FocusCameraSongEvent extends SongEvent step: 10.0, type: SongEventFieldType.FLOAT, units: "px" + }, + { + name: 'useTween', + title: 'Use Tween', + type: SongEventFieldType.BOOL, + defaultValue: false + }, + { + name: 'duration', + title: 'Duration', + defaultValue: 4.0, + step: 0.5, + type: SongEventFieldType.FLOAT, + units: 'steps' + }, + { + name: 'ease', + title: 'Easing Type', + defaultValue: 'linear', + type: SongEventFieldType.ENUM, + keys: [ + 'Linear' => 'linear', + 'Instant' => 'INSTANT', + 'Quad In' => 'quadIn', + 'Quad Out' => 'quadOut', + 'Quad In/Out' => 'quadInOut', + 'Cube In' => 'cubeIn', + 'Cube Out' => 'cubeOut', + 'Cube In/Out' => 'cubeInOut', + 'Quart In' => 'quartIn', + 'Quart Out' => 'quartOut', + 'Quart In/Out' => 'quartInOut', + 'Quint In' => 'quintIn', + 'Quint Out' => 'quintOut', + 'Quint In/Out' => 'quintInOut', + 'Smooth Step In' => 'smoothStepIn', + 'Smooth Step Out' => 'smoothStepOut', + 'Smooth Step In/Out' => 'smoothStepInOut', + 'Sine In' => 'sineIn', + 'Sine Out' => 'sineOut', + 'Sine In/Out' => 'sineInOut', + 'Elastic In' => 'elasticIn', + 'Elastic Out' => 'elasticOut', + 'Elastic In/Out' => 'elasticInOut', + ] } ]); } From d9cf097e460de497a7a6754c85eade23b39b9aa3 Mon Sep 17 00:00:00 2001 From: Jenny Crowe Date: Mon, 4 Mar 2024 20:57:21 -0700 Subject: [PATCH 02/23] Fixed bools and associated checkboxes not updating properly. --- source/funkin/play/event/FocusCameraSongEvent.hx | 2 +- .../debug/charting/toolboxes/ChartEditorEventDataToolbox.hx | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/source/funkin/play/event/FocusCameraSongEvent.hx b/source/funkin/play/event/FocusCameraSongEvent.hx index 28a629f1a..979b1ad7b 100644 --- a/source/funkin/play/event/FocusCameraSongEvent.hx +++ b/source/funkin/play/event/FocusCameraSongEvent.hx @@ -123,7 +123,7 @@ class FocusCameraSongEvent extends SongEvent trace('Unknown camera focus: ' + data); } - if (useTween) // always ends up false?? + if (useTween) { var durSeconds = Conductor.instance.stepLengthMs * duration / 1000; diff --git a/source/funkin/ui/debug/charting/toolboxes/ChartEditorEventDataToolbox.hx b/source/funkin/ui/debug/charting/toolboxes/ChartEditorEventDataToolbox.hx index ec46e1f85..50b341272 100644 --- a/source/funkin/ui/debug/charting/toolboxes/ChartEditorEventDataToolbox.hx +++ b/source/funkin/ui/debug/charting/toolboxes/ChartEditorEventDataToolbox.hx @@ -237,6 +237,11 @@ class ChartEditorEventDataToolbox extends ChartEditorBaseToolbox { value = event.target.value.value; } + else if (field.type == BOOL) + { + var chk:CheckBox = cast event.target; + value = cast(chk.selected, Null); // Need to cast to nullable bool or the compiler will get mad. + } trace('ChartEditorToolboxHandler.buildEventDataFormFromSchema() - ${event.target.id} = ${value}'); From 21b895ab9735ca1c121026326ab5ab2a0c4c2e24 Mon Sep 17 00:00:00 2001 From: Jenny Crowe Date: Fri, 8 Mar 2024 14:50:26 -0700 Subject: [PATCH 03/23] Assets submod update --- assets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets b/assets index 55c602f2a..49c409b4c 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit 55c602f2adbbd84de541ea86e5e646c4d2a1df0b +Subproject commit 49c409b4c8321d8cd317787a78c479aaa64cb517 From d495420938ab4a4efad2c2c3d265352c165fe488 Mon Sep 17 00:00:00 2001 From: Cameron Taylor Date: Sun, 10 Mar 2024 15:24:43 -0400 Subject: [PATCH 04/23] fixes capitalization in checkstyle settings --- .vscode/settings.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 87ed06aed..ea93651ed 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -85,7 +85,7 @@ }, "projectManager.git.baseFolders": ["./"], - "haxecheckstyle.sourceFolders": ["src", "Source"], + "haxecheckstyle.sourceFolders": ["src", "source"], "haxecheckstyle.externalSourceRoots": [], "haxecheckstyle.configurationFile": "checkstyle.json", "haxecheckstyle.codeSimilarityBufferSize": 100, From 6b8fb7dc77a9c11ecc5afa541e05d004c64aaca2 Mon Sep 17 00:00:00 2001 From: Jenny Crowe Date: Sun, 10 Mar 2024 16:35:41 -0700 Subject: [PATCH 05/23] Standardized camera zoom tweening to match camera follow tweening. Implemented methods to cancel tweens in necessary places. Start of pausing tweens when pausing the game (WIP). (CHANGES NOT TESTED EXPECT SOMETHING TO BREAK) --- source/funkin/play/GameOverSubState.hx | 9 +- source/funkin/play/PlayState.hx | 124 +++++++++++++++--- .../funkin/play/event/FocusCameraSongEvent.hx | 22 ++-- .../funkin/play/event/ZoomCameraSongEvent.hx | 8 +- .../ui/debug/stage/StageOffsetSubState.hx | 11 +- 5 files changed, 136 insertions(+), 38 deletions(-) diff --git a/source/funkin/play/GameOverSubState.hx b/source/funkin/play/GameOverSubState.hx index 95304d762..b3e815a41 100644 --- a/source/funkin/play/GameOverSubState.hx +++ b/source/funkin/play/GameOverSubState.hx @@ -119,6 +119,8 @@ class GameOverSubState extends MusicBeatSubState // Set up the visuals // + var playState = PlayState.instance; + // Add a black background to the screen. var bg = new FunkinSprite().makeSolidColor(FlxG.width * 2, FlxG.height * 2, FlxColor.BLACK); // We make this transparent so that we can see the stage underneath during debugging, @@ -130,13 +132,16 @@ class GameOverSubState extends MusicBeatSubState // Pluck Boyfriend from the PlayState and place him (in the same position) in the GameOverSubState. // We can then play the character's `firstDeath` animation. - boyfriend = PlayState.instance.currentStage.getBoyfriend(true); + boyfriend = playState.currentStage.getBoyfriend(true); boyfriend.isDead = true; add(boyfriend); boyfriend.resetCharacter(); + // Cancel camera tweening if it's currently active. + playState.cancelAllCameraTweens(); + // Assign a camera follow point to the boyfriend's position. - cameraFollowPoint = new FlxObject(PlayState.instance.cameraFollowPoint.x, PlayState.instance.cameraFollowPoint.y, 1, 1); + cameraFollowPoint = new FlxObject(playState.cameraFollowPoint.x, playState.cameraFollowPoint.y, 1, 1); cameraFollowPoint.x = boyfriend.getGraphicMidpoint().x; cameraFollowPoint.y = boyfriend.getGraphicMidpoint().y; var offsets:Array = boyfriend.getDeathCameraOffsets(); diff --git a/source/funkin/play/PlayState.hx b/source/funkin/play/PlayState.hx index 3ce1f4948..0bd731bc6 100644 --- a/source/funkin/play/PlayState.hx +++ b/source/funkin/play/PlayState.hx @@ -242,6 +242,11 @@ class PlayState extends MusicBeatSubState */ public var cameraFollowTween:FlxTween; + /** + * An FlxTween that zooms the camera to the desired amount. + */ + public var cameraZoomTween:FlxTween; + /** * The camera follow point from the last stage. * Used to persist the position of the `cameraFollowPosition` between levels. @@ -402,10 +407,12 @@ class PlayState extends MusicBeatSubState var startingSong:Bool = false; /** - * False if `FlxG.sound.music` + * Track if we currently have the music paused for a Pause substate, so we can unpause it when we return. */ var musicPausedBySubState:Bool = false; + var cameraFollowTweenPausedBySubState:Bool = false; // Idea FOR LATER: Store paused tweens in an array, so we know which ones to unpause when leaving the Pause substate. + /** * False until `create()` has completed. */ @@ -1126,14 +1133,24 @@ class PlayState extends MusicBeatSubState // Pause the music. if (FlxG.sound.music != null) { - musicPausedBySubState = FlxG.sound.music.playing; - if (musicPausedBySubState) + if (FlxG.sound.music.playing) { FlxG.sound.music.pause(); + musicPausedBySubState = true; } + + // Pause vocals. + // Not tracking that we've done this via a bool because vocal re-syncing involves pausing the vocals anyway. if (vocals != null) vocals.pause(); } + // Pause camera tweening. + if (cameraFollowTween != null && cameraFollowTween.active) + { + cameraFollowTween.active = false; + cameraFollowTweenPausedBySubState = true; + } + // Pause the countdown. Countdown.pauseCountdown(); } @@ -1155,10 +1172,18 @@ class PlayState extends MusicBeatSubState if (event.eventCanceled) return; - // Resume + // Resume music if we paused it. if (musicPausedBySubState) { FlxG.sound.music.play(); + musicPausedBySubState = false; + } + + // Resume camera tweening if we paused it. + if (cameraFollowTweenPausedBySubState) + { + cameraFollowTween.active = true; + cameraFollowTweenPausedBySubState = false; } if (currentConversation != null) @@ -1166,6 +1191,7 @@ class PlayState extends MusicBeatSubState currentConversation.resumeMusic(); } + // Re-sync vocals. if (FlxG.sound.music != null && !startingSong && !isInCutscene) resyncVocals(); // Resume the countdown. @@ -2852,6 +2878,9 @@ class PlayState extends MusicBeatSubState */ function performCleanup():Void { + // If the camera is being tweened, stop it. + cancelAllCameraTweens(); + if (currentConversation != null) { remove(currentConversation); @@ -2910,6 +2939,9 @@ class PlayState extends MusicBeatSubState // Stop camera zooming on beat. cameraZoomRate = 0; + // Cancel camera tweening if it's active. + cancelAllCameraTweens(); + // If the opponent is GF, zoom in on the opponent. // Else, if there is no GF, zoom in on BF. // Else, zoom in on GF. @@ -2996,12 +3028,12 @@ class PlayState extends MusicBeatSubState /** * Resets the camera's zoom level and focus point. */ - public function resetCamera(?resetZoom:Bool = true, ?cancelFollowTween:Bool = true):Void + public function resetCamera(?resetZoom:Bool = true, ?cancelTweens:Bool = true):Void { - // Cancel the follow tween if it's active. - if (cancelFollowTween && cameraFollowTween != null) + // Cancel camera tweens if any are active. + if (cancelTweens) { - cameraFollowTween.cancel(); + cancelAllCameraTweens(); } FlxG.camera.follow(cameraFollowPoint, LOCKON, 0.04); @@ -3019,26 +3051,78 @@ class PlayState extends MusicBeatSubState /** * Disables camera following and tweens the camera to the follow point manually. */ - public function tweenCamera(?duration:Float, ?ease:NullFloat>):Void + public function tweenCameraToFollowPoint(?duration:Float, ?ease:NullFloat>):Void { // Cancel the current tween if it's active. + cancelCameraFollowTween(); + + if (duration == 0) + { + // Instant movement. Just reset the camera to force it to the follow point. + resetCamera(false, false); + } + else + { + // Disable camera following for the duration of the tween. + FlxG.camera.target = null; + + // Follow tween! Caching it so we can cancel/pause it later if needed. + var followPos:FlxPoint = cameraFollowPoint.getPosition() - FlxPoint.weak(FlxG.camera.width * 0.5, FlxG.camera.height * 0.5); + cameraFollowTween = FlxTween.tween(FlxG.camera.scroll, {x: followPos.x, y: followPos.y}, duration, + { + ease: ease, + onComplete: function(_) { + resetCamera(false, false); // Re-enable camera following when the tween is complete. + } + }); + } + } + + public function cancelCameraFollowTween() + { if (cameraFollowTween != null) { cameraFollowTween.cancel(); } + } - // Disable camera following for the duration of the tween. - FlxG.camera.target = null; + /** + * Tweens the camera zoom to the desired amount. Tweens defaultCameraZoom to avoid breaking camera bops. + */ + public function tweenCameraZoom(?zoom:Float, ?duration:Float, ?ease:NullFloat>):Void + { + // Cancel the current tween if it's active. + cancelCameraZoomTween(); - // Follow tween! Caching it so we can cancel it later if needed. - var followPos:FlxPoint = cameraFollowPoint.getPosition() - FlxPoint.weak(FlxG.camera.width * 0.5, FlxG.camera.height * 0.5); - cameraFollowTween = FlxTween.tween(FlxG.camera.scroll, {x: followPos.x, y: followPos.y}, duration, - { - ease: ease, - onComplete: function(_) { - resetCamera(false, false); // Re-enable camera following when the tween is complete. - } - }); + var targetZoom = zoom * FlxCamera.defaultZoom; + + if (duration == 0) + { + // Instant zoom. No tween needed. + defaultCameraZoom = targetZoom; + } + else + { + // Zoom tween! Caching it so we can cancel/pause it later if needed. + cameraZoomTween = FlxTween.tween(this, {defaultCameraZoom: targetZoom}, duration, {ease: ease}); + } + } + + public function cancelCameraZoomTween() + { + if (cameraZoomTween != null) + { + cameraZoomTween.cancel(); + } + } + + /** + * Cancel all active camera tweens simultaneously. + */ + public function cancelAllCameraTweens() + { + cancelCameraFollowTween(); + cancelCameraZoomTween(); } #if (debug || FORCE_DEBUG_VERSION) diff --git a/source/funkin/play/event/FocusCameraSongEvent.hx b/source/funkin/play/event/FocusCameraSongEvent.hx index 979b1ad7b..cd4366dd2 100644 --- a/source/funkin/play/event/FocusCameraSongEvent.hx +++ b/source/funkin/play/event/FocusCameraSongEvent.hx @@ -125,16 +125,22 @@ class FocusCameraSongEvent extends SongEvent if (useTween) { - var durSeconds = Conductor.instance.stepLengthMs * duration / 1000; - - var easeFunction:NullFloat> = Reflect.field(FlxEase, ease); - if (easeFunction == null) + switch (ease) { - trace('Invalid ease function: $ease'); - return; - } + case 'INSTANT': + PlayState.instance.tweenCameraToFollowPoint(0); + default: + var durSeconds = Conductor.instance.stepLengthMs * duration / 1000; - PlayState.instance.tweenCamera(durSeconds, easeFunction); + var easeFunction:NullFloat> = Reflect.field(FlxEase, ease); + if (easeFunction == null) + { + trace('Invalid ease function: $ease'); + return; + } + + PlayState.instance.tweenCameraToFollowPoint(durSeconds, easeFunction); + } } } diff --git a/source/funkin/play/event/ZoomCameraSongEvent.hx b/source/funkin/play/event/ZoomCameraSongEvent.hx index 809130499..187664e97 100644 --- a/source/funkin/play/event/ZoomCameraSongEvent.hx +++ b/source/funkin/play/event/ZoomCameraSongEvent.hx @@ -69,9 +69,10 @@ class ZoomCameraSongEvent extends SongEvent switch (ease) { case 'INSTANT': - // Set the zoom. Use defaultCameraZoom to prevent breaking camera bops. - PlayState.instance.defaultCameraZoom = zoom * FlxCamera.defaultZoom; + PlayState.instance.tweenCameraZoom(zoom, 0); default: + var durSeconds = Conductor.instance.stepLengthMs * duration / 1000; + var easeFunction:NullFloat> = Reflect.field(FlxEase, ease); if (easeFunction == null) { @@ -79,8 +80,7 @@ class ZoomCameraSongEvent extends SongEvent return; } - FlxTween.tween(PlayState.instance, {defaultCameraZoom: zoom * FlxCamera.defaultZoom}, (Conductor.instance.stepLengthMs * duration / 1000), - {ease: easeFunction}); + PlayState.instance.tweenCameraZoom(zoom, durSeconds, easeFunction); } } diff --git a/source/funkin/ui/debug/stage/StageOffsetSubState.hx b/source/funkin/ui/debug/stage/StageOffsetSubState.hx index e8a5d0a23..fa5056220 100644 --- a/source/funkin/ui/debug/stage/StageOffsetSubState.hx +++ b/source/funkin/ui/debug/stage/StageOffsetSubState.hx @@ -49,8 +49,11 @@ class StageOffsetSubState extends HaxeUISubState { super.create(); + var playState = PlayState.instance; + FlxG.mouse.visible = true; - PlayState.instance.pauseMusic(); + playState.pauseMusic(); + playState.cancelAllCameraTweens(); FlxG.camera.target = null; setupUIListeners(); @@ -63,8 +66,8 @@ class StageOffsetSubState extends HaxeUISubState // add(uiStuff); - PlayState.instance.persistentUpdate = true; - component.cameras = [PlayState.instance.camHUD]; + playState.persistentUpdate = true; + component.cameras = [playState.camHUD]; // uiStuff.cameras = [PlayState.instance.camHUD]; // btn.cameras = [PlayState.instance.camHUD]; @@ -72,7 +75,7 @@ class StageOffsetSubState extends HaxeUISubState var layerList:ListView = findComponent("prop-layers"); - for (thing in PlayState.instance.currentStage) + for (thing in playState.currentStage) { var prop:StageProp = cast thing; if (prop != null && prop.name != null) From 3aada18a5998f18c745034910db16eb8c4aa816d Mon Sep 17 00:00:00 2001 From: Cameron Taylor Date: Thu, 14 Mar 2024 04:03:33 -0700 Subject: [PATCH 06/23] title screen volume fix --- source/funkin/ui/title/TitleState.hx | 1 + 1 file changed, 1 insertion(+) diff --git a/source/funkin/ui/title/TitleState.hx b/source/funkin/ui/title/TitleState.hx index 1c194d80d..9dca759be 100644 --- a/source/funkin/ui/title/TitleState.hx +++ b/source/funkin/ui/title/TitleState.hx @@ -223,6 +223,7 @@ class TitleState extends MusicBeatState var shouldFadeIn = (FlxG.sound.music == null); // Load music. Includes logic to handle BPM changes. FunkinSound.playMusic('freakyMenu', false, true); + FlxG.sound.music.volume = 0; // Fade from 0.0 to 0.7 over 4 seconds if (shouldFadeIn) FlxG.sound.music.fadeIn(4, 0, 0.7); } From e3b09bc8396f23754a8f6fa3e191825a6b77e755 Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Thu, 14 Mar 2024 20:41:31 -0400 Subject: [PATCH 07/23] Clean up the classic MILF script --- assets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets b/assets index 0e2c5bf21..fff87b632 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit 0e2c5bf2134c7e517b70cf74afd58abe5c7b5e50 +Subproject commit fff87b6320a1fe2b46538bb77abe06b5b20376e0 From 82383018f66147df8374212abd8b54d9cc8145cc Mon Sep 17 00:00:00 2001 From: Cameron Taylor Date: Thu, 14 Mar 2024 19:27:07 -0700 Subject: [PATCH 08/23] funkin soundtray --- assets | 2 +- source/Main.hx | 9 +- source/funkin/ui/options/FunkinSoundTray.hx | 138 ++++++++++++++++++++ 3 files changed, 147 insertions(+), 2 deletions(-) create mode 100644 source/funkin/ui/options/FunkinSoundTray.hx diff --git a/assets b/assets index 0e2c5bf21..223722892 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit 0e2c5bf2134c7e517b70cf74afd58abe5c7b5e50 +Subproject commit 2237228923c6bd35df1e68e3b2a13dfffd1c243d diff --git a/source/Main.hx b/source/Main.hx index a40fda29d..758edcc65 100644 --- a/source/Main.hx +++ b/source/Main.hx @@ -100,8 +100,15 @@ class Main extends Sprite // George recommends binding the save before FlxGame is created. Save.load(); + var game:FlxGame = new FlxGame(gameWidth, gameHeight, initialState, framerate, framerate, skipSplash, startFullscreen); - addChild(new FlxGame(gameWidth, gameHeight, initialState, framerate, framerate, skipSplash, startFullscreen)); + // FlxG.game._customSoundTray wants just the class, it calls new from + // create() in there, which gets called when it's added to stage + // which is why it needs to be added before addChild(game) here + @:privateAccess + game._customSoundTray = funkin.ui.options.FunkinSoundTray; + + addChild(game); #if hxcpp_debug_server trace('hxcpp_debug_server is enabled! You can now connect to the game with a debugger.'); diff --git a/source/funkin/ui/options/FunkinSoundTray.hx b/source/funkin/ui/options/FunkinSoundTray.hx new file mode 100644 index 000000000..31c38286d --- /dev/null +++ b/source/funkin/ui/options/FunkinSoundTray.hx @@ -0,0 +1,138 @@ +package funkin.ui.options; + +import flixel.system.ui.FlxSoundTray; +import flixel.tweens.FlxTween; +import flixel.system.FlxAssets; +import flixel.tweens.FlxEase; +import openfl.display.Bitmap; +import openfl.display.BitmapData; +import openfl.utils.Assets; +import funkin.util.MathUtil; + +/** + * Extends the default flixel soundtray, but with some art + * and lil polish! + * + * Gets added to the game in Main.hx, right after FlxGame is new'd + * since it's a Sprite rather than Flixel related object + */ +class FunkinSoundTray extends FlxSoundTray +{ + var graphicScale:Float = 0.30; + var lerpYPos:Float = 0; + + var volumeMaxSound:String; + + public function new() + { + // calls super, then removes all children to add our own + // graphics + super(); + removeChildren(); + + var bg:Bitmap = new Bitmap(Assets.getBitmapData(Paths.image("soundtray/volumebox"))); + bg.scaleX = graphicScale; + bg.scaleY = graphicScale; + addChild(bg); + + y = -height; + visible = false; + + // clear the bars array entirely, it was initialized + // in the super class + _bars = []; + + // 1...11 due to how block named the assets, + // we are trying to get assets bars_1-10 + for (i in 1...11) + { + var bar:Bitmap = new Bitmap(Assets.getBitmapData(Paths.image("soundtray/bars_" + i))); + bar.x = 10; + bar.y = 5; + bar.scaleX = graphicScale; + bar.scaleY = graphicScale; + addChild(bar); + _bars.push(bar); + } + + y = -height; + screenCenter(); + + volumeUpSound = Paths.sound("soundtray/Volup"); + volumeDownSound = Paths.sound("soundtray/Voldown"); + volumeMaxSound = Paths.sound("soundtray/VolMAX"); + + trace("Custom tray added!"); + } + + override public function update(MS:Float):Void + { + y = MathUtil.coolLerp(y, lerpYPos, 0.1); + + // Animate sound tray thing + if (_timer > 0) + { + _timer -= (MS / 1000); + } + else if (y > -height) + { + lerpYPos = -height; + + if (y <= -height) + { + visible = false; + active = false; + + #if FLX_SAVE + // Save sound preferences + if (FlxG.save.isBound) + { + FlxG.save.data.mute = FlxG.sound.muted; + FlxG.save.data.volume = FlxG.sound.volume; + FlxG.save.flush(); + } + #end + } + } + } + + /** + * Makes the little volume tray slide out. + * + * @param up Whether the volume is increasing. + */ + override public function show(up:Bool = false):Void + { + _timer = 1; + lerpYPos = 0; + visible = true; + active = true; + var globalVolume:Int = Math.round(FlxG.sound.volume * 10); + + if (FlxG.sound.muted) + { + globalVolume = 0; + } + + if (!silent) + { + var sound = up ? volumeUpSound : volumeDownSound; + + if (globalVolume == 10) sound = volumeMaxSound; + + if (sound != null) FlxG.sound.load(sound).play(); + } + + for (i in 0..._bars.length) + { + if (i < globalVolume) + { + _bars[i].visible = true; + } + else + { + _bars[i].visible = false; + } + } + } +} From d68ea0eb465c0405f20cde6e75b8a2667d756bb3 Mon Sep 17 00:00:00 2001 From: Cameron Taylor Date: Thu, 14 Mar 2024 19:40:07 -0700 Subject: [PATCH 09/23] lil polish --- source/funkin/ui/options/FunkinSoundTray.hx | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/source/funkin/ui/options/FunkinSoundTray.hx b/source/funkin/ui/options/FunkinSoundTray.hx index 31c38286d..4af94569b 100644 --- a/source/funkin/ui/options/FunkinSoundTray.hx +++ b/source/funkin/ui/options/FunkinSoundTray.hx @@ -38,6 +38,15 @@ class FunkinSoundTray extends FlxSoundTray y = -height; visible = false; + // makes an alpha'd version of all the bars (bar_10.png) + var backingBar:Bitmap = new Bitmap(Assets.getBitmapData(Paths.image("soundtray/bars_10"))); + backingBar.x = 10; + backingBar.y = 5; + backingBar.scaleX = graphicScale; + backingBar.scaleY = graphicScale; + addChild(backingBar); + backingBar.alpha = 0.4; + // clear the bars array entirely, it was initialized // in the super class _bars = []; @@ -76,7 +85,7 @@ class FunkinSoundTray extends FlxSoundTray } else if (y > -height) { - lerpYPos = -height; + lerpYPos = -height - 10; if (y <= -height) { @@ -104,7 +113,7 @@ class FunkinSoundTray extends FlxSoundTray override public function show(up:Bool = false):Void { _timer = 1; - lerpYPos = 0; + lerpYPos = 10; visible = true; active = true; var globalVolume:Int = Math.round(FlxG.sound.volume * 10); From 4866667e1c463bda8f6c5849985182c1b27b524d Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Fri, 15 Mar 2024 02:25:34 -0400 Subject: [PATCH 10/23] ANNIHILATE M.I.L.F. custom gameplay --- assets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets b/assets index fff87b632..6fef3c78e 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit fff87b6320a1fe2b46538bb77abe06b5b20376e0 +Subproject commit 6fef3c78e7c2ec16746337081c91af4095602634 From 1541f0aa68478d0651c8ba2fccc181e75883e964 Mon Sep 17 00:00:00 2001 From: Jenny Crowe Date: Fri, 15 Mar 2024 01:52:22 -0700 Subject: [PATCH 11/23] Camera tween pausing/unpausing additions --- assets | 2 +- source/funkin/play/PlayState.hx | 23 ++++++++++++++++------- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/assets b/assets index 0e2c5bf21..223722892 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit 0e2c5bf2134c7e517b70cf74afd58abe5c7b5e50 +Subproject commit 2237228923c6bd35df1e68e3b2a13dfffd1c243d diff --git a/source/funkin/play/PlayState.hx b/source/funkin/play/PlayState.hx index 7c0ed64b3..d6cb5bd47 100644 --- a/source/funkin/play/PlayState.hx +++ b/source/funkin/play/PlayState.hx @@ -412,7 +412,10 @@ class PlayState extends MusicBeatSubState */ var musicPausedBySubState:Bool = false; - var cameraFollowTweenPausedBySubState:Bool = false; // Idea FOR LATER: Store paused tweens in an array, so we know which ones to unpause when leaving the Pause substate. + /** + * Track any camera tweens we've paused for a Pause substate, so we can unpause them when we return. + */ + var cameraTweensPausedBySubState:List = new List(); /** * False until `create()` has completed. @@ -1145,11 +1148,17 @@ class PlayState extends MusicBeatSubState if (vocals != null) vocals.pause(); } - // Pause camera tweening. + // Pause camera tweening, and keep track of which tweens we pause. if (cameraFollowTween != null && cameraFollowTween.active) { cameraFollowTween.active = false; - cameraFollowTweenPausedBySubState = true; + cameraTweensPausedBySubState.add(cameraFollowTween); + } + + if (cameraZoomTween != null && cameraZoomTween.active) + { + cameraZoomTween.active = false; + cameraTweensPausedBySubState.add(cameraZoomTween); } // Pause the countdown. @@ -1180,12 +1189,12 @@ class PlayState extends MusicBeatSubState musicPausedBySubState = false; } - // Resume camera tweening if we paused it. - if (cameraFollowTweenPausedBySubState) + // Resume camera tweens if we paused any. + for (camTween in cameraTweensPausedBySubState) { - cameraFollowTween.active = true; - cameraFollowTweenPausedBySubState = false; + camTween.active = true; } + cameraTweensPausedBySubState.clear(); if (currentConversation != null) { From f31634351bb1443c4858b690204ecd813869fc28 Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Fri, 15 Mar 2024 16:45:18 -0400 Subject: [PATCH 12/23] Fix an issue where stage character scale was overriding base character scale. --- source/funkin/play/character/BaseCharacter.hx | 9 +++- source/funkin/play/stage/Stage.hx | 54 ++++++++++--------- .../util/plugins/ReloadAssetsDebugPlugin.hx | 4 ++ 3 files changed, 40 insertions(+), 27 deletions(-) diff --git a/source/funkin/play/character/BaseCharacter.hx b/source/funkin/play/character/BaseCharacter.hx index d39f19b76..2796f8123 100644 --- a/source/funkin/play/character/BaseCharacter.hx +++ b/source/funkin/play/character/BaseCharacter.hx @@ -193,6 +193,11 @@ class BaseCharacter extends Bopper return _data.death?.cameraOffsets ?? [0.0, 0.0]; } + public function getBaseScale():Float + { + return _data.scale; + } + public function getDeathCameraZoom():Float { return _data.death?.cameraZoom ?? 1.0; @@ -260,8 +265,8 @@ class BaseCharacter extends Bopper } /** - * Set the sprite scale to the appropriate value. - * @param scale + * Set the character's sprite scale to the appropriate value. + * @param scale The desired scale. */ public function setScale(scale:Null):Void { diff --git a/source/funkin/play/stage/Stage.hx b/source/funkin/play/stage/Stage.hx index 56026469a..db42b0dd3 100644 --- a/source/funkin/play/stage/Stage.hx +++ b/source/funkin/play/stage/Stage.hx @@ -109,10 +109,11 @@ class Stage extends FlxSpriteGroup implements IPlayStateScriptedClass implements { getBoyfriend().resetCharacter(true); // Reapply the camera offsets. - var charData = _data.characters.bf; - getBoyfriend().scale.set(charData.scale, charData.scale); - getBoyfriend().cameraFocusPoint.x += charData.cameraOffsets[0]; - getBoyfriend().cameraFocusPoint.y += charData.cameraOffsets[1]; + var stageCharData:StageDataCharacter = _data.characters.bf; + var finalScale:Float = getBoyfriend().getBaseScale() * stageCharData.scale; + getBoyfriend().setScale(finalScale); + getBoyfriend().cameraFocusPoint.x += stageCharData.cameraOffsets[0]; + getBoyfriend().cameraFocusPoint.y += stageCharData.cameraOffsets[1]; } else { @@ -122,19 +123,21 @@ class Stage extends FlxSpriteGroup implements IPlayStateScriptedClass implements { getGirlfriend().resetCharacter(true); // Reapply the camera offsets. - var charData = _data.characters.gf; - getGirlfriend().scale.set(charData.scale, charData.scale); - getGirlfriend().cameraFocusPoint.x += charData.cameraOffsets[0]; - getGirlfriend().cameraFocusPoint.y += charData.cameraOffsets[1]; + var stageCharData:StageDataCharacter = _data.characters.gf; + var finalScale:Float = getBoyfriend().getBaseScale() * stageCharData.scale; + getGirlfriend().setScale(finalScale); + getGirlfriend().cameraFocusPoint.x += stageCharData.cameraOffsets[0]; + getGirlfriend().cameraFocusPoint.y += stageCharData.cameraOffsets[1]; } if (getDad() != null) { getDad().resetCharacter(true); // Reapply the camera offsets. - var charData = _data.characters.dad; - getDad().scale.set(charData.scale, charData.scale); - getDad().cameraFocusPoint.x += charData.cameraOffsets[0]; - getDad().cameraFocusPoint.y += charData.cameraOffsets[1]; + var stageCharData:StageDataCharacter = _data.characters.dad; + var finalScale:Float = getBoyfriend().getBaseScale() * stageCharData.scale; + getDad().setScale(finalScale); + getDad().cameraFocusPoint.x += stageCharData.cameraOffsets[0]; + getDad().cameraFocusPoint.y += stageCharData.cameraOffsets[1]; } // Reset positions of named props. @@ -393,23 +396,23 @@ class Stage extends FlxSpriteGroup implements IPlayStateScriptedClass implements #end // Apply position and z-index. - var charData:StageDataCharacter = null; + var stageCharData:StageDataCharacter = null; switch (charType) { case BF: this.characters.set('bf', character); - charData = _data.characters.bf; + stageCharData = _data.characters.bf; character.flipX = !character.getDataFlipX(); character.name = 'bf'; character.initHealthIcon(false); case GF: this.characters.set('gf', character); - charData = _data.characters.gf; + stageCharData = _data.characters.gf; character.flipX = character.getDataFlipX(); character.name = 'gf'; case DAD: this.characters.set('dad', character); - charData = _data.characters.dad; + stageCharData = _data.characters.dad; character.flipX = character.getDataFlipX(); character.name = 'dad'; character.initHealthIcon(true); @@ -421,15 +424,15 @@ class Stage extends FlxSpriteGroup implements IPlayStateScriptedClass implements // This ensures positioning is based on the idle animation. character.resetCharacter(true); - if (charData != null) + if (stageCharData != null) { - character.zIndex = charData.zIndex; + character.zIndex = stageCharData.zIndex; // Start with the per-stage character position. // Subtracting the origin ensures characters are positioned relative to their feet. // Subtracting the global offset allows positioning on a per-character basis. - character.x = charData.position[0] - character.characterOrigin.x + character.globalOffsets[0]; - character.y = charData.position[1] - character.characterOrigin.y + character.globalOffsets[1]; + character.x = stageCharData.position[0] - character.characterOrigin.x + character.globalOffsets[0]; + character.y = stageCharData.position[1] - character.characterOrigin.y + character.globalOffsets[1]; @:privateAccess(funkin.play.stage.Bopper) { @@ -438,16 +441,17 @@ class Stage extends FlxSpriteGroup implements IPlayStateScriptedClass implements character.originalPosition.y = character.y + character.animOffsets[1]; } - character.scale.set(charData.scale, charData.scale); - character.cameraFocusPoint.x += charData.cameraOffsets[0]; - character.cameraFocusPoint.y += charData.cameraOffsets[1]; + var finalScale = character.getBaseScale() * stageCharData.scale; + character.setScale(finalScale); // Don't use scale.set for characters! + character.cameraFocusPoint.x += stageCharData.cameraOffsets[0]; + character.cameraFocusPoint.y += stageCharData.cameraOffsets[1]; #if debug // Draw the debug icon at the character's feet. if (charType == BF || charType == DAD) { - debugIcon.x = charData.position[0]; - debugIcon.y = charData.position[1]; + debugIcon.x = stageCharData.position[0]; + debugIcon.y = stageCharData.position[1]; debugIcon2.x = character.x; debugIcon2.y = character.y; } diff --git a/source/funkin/util/plugins/ReloadAssetsDebugPlugin.hx b/source/funkin/util/plugins/ReloadAssetsDebugPlugin.hx index a43317cce..f69609531 100644 --- a/source/funkin/util/plugins/ReloadAssetsDebugPlugin.hx +++ b/source/funkin/util/plugins/ReloadAssetsDebugPlugin.hx @@ -22,7 +22,11 @@ class ReloadAssetsDebugPlugin extends FlxBasic { super.update(elapsed); + #if html5 + if (FlxG.keys.justPressed.FIVE && FlxG.keys.pressed.SHIFT) + #else if (FlxG.keys.justPressed.F5) + #end { funkin.modding.PolymodHandler.forceReloadAssets(); From 494a3c9e86dbc6ddb71a193488c3023c26558d9a Mon Sep 17 00:00:00 2001 From: Jenny Crowe Date: Sat, 16 Mar 2024 08:38:10 -0700 Subject: [PATCH 13/23] Bugfixes. New additive zoom mode for camera tweening. --- source/funkin/play/PlayState.hx | 64 ++++++++++++++----- .../funkin/play/event/ZoomCameraSongEvent.hx | 22 +++++-- 2 files changed, 66 insertions(+), 20 deletions(-) diff --git a/source/funkin/play/PlayState.hx b/source/funkin/play/PlayState.hx index d6cb5bd47..a5152e727 100644 --- a/source/funkin/play/PlayState.hx +++ b/source/funkin/play/PlayState.hx @@ -255,14 +255,23 @@ class PlayState extends MusicBeatSubState public var previousCameraFollowPoint:FlxPoint = null; /** - * The current camera zoom level. - * - * The camera zoom is increased every beat, and lerped back to this value every frame, creating a smooth 'zoom-in' effect. - * Defaults to 1.05 but may be larger or smaller depending on the current stage, - * and may be changed by the `ZoomCamera` song event. + * The current camera zoom level without any modifiers applied. + */ + public var currentCameraZoom:Float = FlxCamera.defaultZoom * 1.05; + + /** + * currentCameraZoom is increased every beat, and lerped back to this value every frame, creating a smooth 'zoom-in' effect. + * Defaults to 1.05, but may be larger or smaller depending on the current stage. + * Tweened via the `ZoomCamera` song event in direct mode. */ public var defaultCameraZoom:Float = FlxCamera.defaultZoom * 1.05; + /** + * Camera zoom applied on top of currentCameraZoom. + * Tweened via the `ZoomCamera` song event in additive mode. + */ + public var additiveCameraZoom:Float = 0; + /** * The current HUD camera zoom level. * @@ -959,7 +968,9 @@ class PlayState extends MusicBeatSubState // Lerp the camera zoom towards the target level. if (subState == null) { - FlxG.camera.zoom = FlxMath.lerp(defaultCameraZoom, FlxG.camera.zoom, 0.95); + currentCameraZoom = FlxMath.lerp(defaultCameraZoom, currentCameraZoom, 0.95); + FlxG.camera.zoom = currentCameraZoom + additiveCameraZoom; + camHUD.zoom = FlxMath.lerp(defaultHUDCameraZoom, camHUD.zoom, 0.95); } @@ -1349,7 +1360,7 @@ class PlayState extends MusicBeatSubState if (FlxG.camera.zoom < (1.35 * defaultCameraZoom) && cameraZoomRate > 0 && Conductor.instance.currentBeat % cameraZoomRate == 0) { // Zoom camera in (1.5%) - FlxG.camera.zoom += cameraZoomIntensity * defaultCameraZoom; + currentCameraZoom += cameraZoomIntensity * defaultCameraZoom; // Hud zooms double (3%) camHUD.zoom += hudCameraZoomIntensity * defaultHUDCameraZoom; } @@ -1541,6 +1552,11 @@ class PlayState extends MusicBeatSubState { // Apply camera zoom level from stage data. defaultCameraZoom = currentStage.camZoom; + currentCameraZoom = defaultCameraZoom; + FlxG.camera.zoom = currentCameraZoom; + + // Reset additive zoom. + additiveCameraZoom = 0; } /** @@ -3051,7 +3067,7 @@ class PlayState extends MusicBeatSubState if (resetZoom) { - FlxG.camera.zoom = defaultCameraZoom; + resetCameraZoom(); } // Snap the camera to the follow point immediately. @@ -3097,24 +3113,40 @@ class PlayState extends MusicBeatSubState } /** - * Tweens the camera zoom to the desired amount. Tweens defaultCameraZoom to avoid breaking camera bops. + * Tweens the camera zoom to the desired amount. */ - public function tweenCameraZoom(?zoom:Float, ?duration:Float, ?ease:NullFloat>):Void + public function tweenCameraZoom(?zoom:Float, ?duration:Float, ?directMode:Bool, ?ease:NullFloat>):Void { // Cancel the current tween if it's active. cancelCameraZoomTween(); var targetZoom = zoom * FlxCamera.defaultZoom; - if (duration == 0) + if (directMode) // Direct mode: Tween defaultCameraZoom for basic "smooth" zooms. { - // Instant zoom. No tween needed. - defaultCameraZoom = targetZoom; + if (duration == 0) + { + // Instant zoom. No tween needed. + defaultCameraZoom = targetZoom; + } + else + { + // Zoom tween! Caching it so we can cancel/pause it later if needed. + cameraZoomTween = FlxTween.tween(this, {defaultCameraZoom: targetZoom}, duration, {ease: ease}); + } } - else + else // Additive mode: Tween additiveCameraZoom for ease-based zooms. { - // Zoom tween! Caching it so we can cancel/pause it later if needed. - cameraZoomTween = FlxTween.tween(this, {defaultCameraZoom: targetZoom}, duration, {ease: ease}); + if (duration == 0) + { + // Instant zoom. No tween needed. + additiveCameraZoom = targetZoom; + } + else + { + // Zoom tween! Caching it so we can cancel/pause it later if needed. + cameraZoomTween = FlxTween.tween(this, {additiveCameraZoom: targetZoom}, duration, {ease: ease}); + } } } diff --git a/source/funkin/play/event/ZoomCameraSongEvent.hx b/source/funkin/play/event/ZoomCameraSongEvent.hx index b9b634ffe..d1741a463 100644 --- a/source/funkin/play/event/ZoomCameraSongEvent.hx +++ b/source/funkin/play/event/ZoomCameraSongEvent.hx @@ -62,17 +62,23 @@ class ZoomCameraSongEvent extends SongEvent var zoom:Null = data.getFloat('zoom'); if (zoom == null) zoom = 1.0; + var duration:Null = data.getFloat('duration'); if (duration == null) duration = 4.0; + var mode:Null = data.getString('mode'); + if (mode == null) mode = 'additive'; + var ease:Null = data.getString('ease'); if (ease == null) ease = 'linear'; + var directMode:Bool = mode == 'direct'; + // If it's a string, check the value. switch (ease) { case 'INSTANT': - PlayState.instance.tweenCameraZoom(zoom, 0); + PlayState.instance.tweenCameraZoom(zoom, 0, directMode); default: var durSeconds = Conductor.instance.stepLengthMs * duration / 1000; @@ -83,7 +89,7 @@ class ZoomCameraSongEvent extends SongEvent return; } - PlayState.instance.tweenCameraZoom(zoom, durSeconds, easeFunction); + PlayState.instance.tweenCameraZoom(zoom, durSeconds, directMode, easeFunction); } } @@ -96,8 +102,9 @@ class ZoomCameraSongEvent extends SongEvent * ``` * { * 'zoom': FLOAT, // Target zoom level. - * 'duration': FLOAT, // Optional duration in steps - * 'ease': ENUM, // Optional easing function + * 'duration': FLOAT, // Optional duration in steps. + * 'mode': ENUM, // Whether to set additive zoom or direct zoom. + * 'ease': ENUM, // Optional easing function. * } * @return SongEventSchema */ @@ -120,6 +127,13 @@ class ZoomCameraSongEvent extends SongEvent type: SongEventFieldType.FLOAT, units: 'steps' }, + { + name: 'mode', + title: 'Mode', + defaultValue: 'additive', + type: SongEventFieldType.ENUM, + keys: ['Additive' => 'additive', 'Direct' => 'direct'] + }, { name: 'ease', title: 'Easing Type', From a8ebdc5ee82e3cf0b04900756b104053e612c58e Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Mon, 18 Mar 2024 22:27:19 -0400 Subject: [PATCH 14/23] Update Polymod to fix several bugs on web --- hmm.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hmm.json b/hmm.json index 42d17743f..b16576e66 100644 --- a/hmm.json +++ b/hmm.json @@ -146,7 +146,7 @@ "name": "polymod", "type": "git", "dir": null, - "ref": "be712450e5d3ba446008884921bb56873b299a64", + "ref": "6d1bdf79b463ca0baa8471dfc6873ab7701c46ee", "url": "https://github.com/larsiusprime/polymod" }, { From a7780474feccce6e58c41f7339dc1837b3f53bf0 Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Tue, 19 Mar 2024 00:28:25 -0400 Subject: [PATCH 15/23] Improve error handling for bad script superclasses --- hmm.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hmm.json b/hmm.json index b16576e66..a75dee432 100644 --- a/hmm.json +++ b/hmm.json @@ -146,7 +146,7 @@ "name": "polymod", "type": "git", "dir": null, - "ref": "6d1bdf79b463ca0baa8471dfc6873ab7701c46ee", + "ref": "5547763a22858a1f10939e082de421d587c862bf", "url": "https://github.com/larsiusprime/polymod" }, { From 4d1bcbc193b316715a650b38f54cfaf8de12a488 Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Tue, 19 Mar 2024 00:29:01 -0400 Subject: [PATCH 16/23] Update assets submodule --- assets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets b/assets index 0e2c5bf21..6846ed8d2 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit 0e2c5bf2134c7e517b70cf74afd58abe5c7b5e50 +Subproject commit 6846ed8d26b0ab531b758bb009d0ebcd515acb21 From 34cb3ceb24e9418b43a391b040801cee4f28a012 Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Tue, 19 Mar 2024 00:53:01 -0400 Subject: [PATCH 17/23] Update assets submodule --- assets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets b/assets index 6846ed8d2..b272232aa 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit 6846ed8d26b0ab531b758bb009d0ebcd515acb21 +Subproject commit b272232aaf5a748db4b0dd5ac0cc98b72d4a636c From 42eec667532c330ed4e87ce7d3826a62f1ab5301 Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Tue, 19 Mar 2024 15:56:00 -0400 Subject: [PATCH 18/23] Rework HTML5 video cutscenes to properly support the pause menu and volume controls. --- source/funkin/audio/FunkinSound.hx | 24 +++- source/funkin/graphics/FunkinSprite.hx | 44 +++++++- .../graphics/framebuffer/FixedBitmapData.hx | 6 +- source/funkin/graphics/video/FlxVideo.hx | 105 +++++++++++++++--- 4 files changed, 153 insertions(+), 26 deletions(-) diff --git a/source/funkin/audio/FunkinSound.hx b/source/funkin/audio/FunkinSound.hx index 9efa6ed50..c64240909 100644 --- a/source/funkin/audio/FunkinSound.hx +++ b/source/funkin/audio/FunkinSound.hx @@ -1,11 +1,8 @@ package funkin.audio; -#if flash11 -import flash.media.Sound; -import flash.utils.ByteArray; -#end import flixel.sound.FlxSound; import flixel.group.FlxGroup.FlxTypedGroup; +import flixel.util.FlxSignal.FlxTypedSignal; import flixel.system.FlxAssets.FlxSoundAsset; import funkin.util.tools.ICloneable; import funkin.data.song.SongData.SongMusicData; @@ -27,6 +24,25 @@ class FunkinSound extends FlxSound implements ICloneable { static final MAX_VOLUME:Float = 1.0; + /** + * An FlxSignal which is dispatched when the volume changes. + */ + public static var onVolumeChanged(get, never):FlxTypedSignalVoid>; + + static var _onVolumeChanged:NullVoid>> = null; + + static function get_onVolumeChanged():FlxTypedSignalVoid> + { + if (_onVolumeChanged == null) + { + _onVolumeChanged = new FlxTypedSignalVoid>(); + FlxG.sound.volumeHandler = function(volume:Float) { + _onVolumeChanged.dispatch(volume); + } + } + return _onVolumeChanged; + } + /** * Using `FunkinSound.load` will override a dead instance from here rather than creating a new one, if possible! */ diff --git a/source/funkin/graphics/FunkinSprite.hx b/source/funkin/graphics/FunkinSprite.hx index 03382f757..7ead7f1fb 100644 --- a/source/funkin/graphics/FunkinSprite.hx +++ b/source/funkin/graphics/FunkinSprite.hx @@ -3,6 +3,9 @@ package funkin.graphics; import flixel.FlxSprite; import flixel.util.FlxColor; import flixel.graphics.FlxGraphic; +import openfl.display3D.textures.TextureBase; +import funkin.graphics.framebuffer.FixedBitmapData; +import openfl.display.BitmapData; /** * An FlxSprite with additional functionality. @@ -41,7 +44,7 @@ class FunkinSprite extends FlxSprite */ public static function create(x:Float = 0.0, y:Float = 0.0, key:String):FunkinSprite { - var sprite = new FunkinSprite(x, y); + var sprite:FunkinSprite = new FunkinSprite(x, y); sprite.loadTexture(key); return sprite; } @@ -55,7 +58,7 @@ class FunkinSprite extends FlxSprite */ public static function createSparrow(x:Float = 0.0, y:Float = 0.0, key:String):FunkinSprite { - var sprite = new FunkinSprite(x, y); + var sprite:FunkinSprite = new FunkinSprite(x, y); sprite.loadSparrow(key); return sprite; } @@ -69,7 +72,7 @@ class FunkinSprite extends FlxSprite */ public static function createPacker(x:Float = 0.0, y:Float = 0.0, key:String):FunkinSprite { - var sprite = new FunkinSprite(x, y); + var sprite:FunkinSprite = new FunkinSprite(x, y); sprite.loadPacker(key); return sprite; } @@ -89,6 +92,30 @@ class FunkinSprite extends FlxSprite return this; } + /** + * Apply an OpenFL `BitmapData` to this sprite. + * @param input The OpenFL `BitmapData` to apply + * @return This sprite, for chaining + */ + public function loadBitmapData(input:BitmapData):FunkinSprite + { + loadGraphic(input); + + return this; + } + + /** + * Apply an OpenFL `TextureBase` to this sprite. + * @param input The OpenFL `TextureBase` to apply + * @return This sprite, for chaining + */ + public function loadTextureBase(input:TextureBase):FunkinSprite + { + var inputBitmap:FixedBitmapData = FixedBitmapData.fromTexture(input); + + return loadBitmapData(inputBitmap); + } + /** * Load an animated texture (Sparrow atlas spritesheet) as the sprite's texture. * @param key The key of the texture to load. @@ -119,11 +146,20 @@ class FunkinSprite extends FlxSprite return this; } + /** + * Determine whether the texture with the given key is cached. + * @param key The key of the texture to check. + * @return Whether the texture is cached. + */ public static function isTextureCached(key:String):Bool { return FlxG.bitmap.get(key) != null; } + /** + * Ensure the texture with the given key is cached. + * @param key The key of the texture to cache. + */ public static function cacheTexture(key:String):Void { // We don't want to cache the same texture twice. @@ -139,7 +175,7 @@ class FunkinSprite extends FlxSprite } // Else, texture is currently uncached. - var graphic = flixel.graphics.FlxGraphic.fromAssetKey(key, false, null, true); + var graphic:FlxGraphic = FlxGraphic.fromAssetKey(key, false, null, true); if (graphic == null) { FlxG.log.warn('Failed to cache graphic: $key'); diff --git a/source/funkin/graphics/framebuffer/FixedBitmapData.hx b/source/funkin/graphics/framebuffer/FixedBitmapData.hx index 00b39ce1c..4ffcbb867 100644 --- a/source/funkin/graphics/framebuffer/FixedBitmapData.hx +++ b/source/funkin/graphics/framebuffer/FixedBitmapData.hx @@ -32,11 +32,11 @@ class FixedBitmapData extends BitmapData public static function fromTexture(texture:TextureBase):FixedBitmapData { if (texture == null) return null; - final bitmapData = new FixedBitmapData(texture.__width, texture.__height, true, 0); - bitmapData.readable = false; + final bitmapData:FixedBitmapData = new FixedBitmapData(texture.__width, texture.__height, true, 0); + // bitmapData.readable = false; bitmapData.__texture = texture; bitmapData.__textureContext = texture.__textureContext; - bitmapData.image = null; + // bitmapData.image = null; return bitmapData; } } diff --git a/source/funkin/graphics/video/FlxVideo.hx b/source/funkin/graphics/video/FlxVideo.hx index 5e178efb3..a0fab9c09 100644 --- a/source/funkin/graphics/video/FlxVideo.hx +++ b/source/funkin/graphics/video/FlxVideo.hx @@ -1,45 +1,58 @@ package funkin.graphics.video; -import flixel.FlxBasic; -import flixel.FlxSprite; +import flixel.util.FlxColor; +import flixel.util.FlxSignal.FlxTypedSignal; +import funkin.audio.FunkinSound; +import openfl.display3D.textures.TextureBase; import openfl.events.NetStatusEvent; +import openfl.media.SoundTransform; import openfl.media.Video; import openfl.net.NetConnection; import openfl.net.NetStream; /** * Plays a video via a NetStream. Only works on HTML5. - * This does NOT replace hxCodec, nor does hxCodec replace this. hxCodec only works on desktop and does not work on HTML5! + * This does NOT replace hxCodec, nor does hxCodec replace this. + * hxCodec only works on desktop and does not work on HTML5! */ -class FlxVideo extends FlxBasic +class FlxVideo extends FunkinSprite { var video:Video; var netStream:NetStream; - - public var finishCallback:Void->Void; + var videoPath:String; /** - * Doesn't actually interact with Flixel shit, only just a pleasant to use class + * A callback to execute when the video finishes. */ + public var finishCallback:Void->Void; + public function new(videoPath:String) { super(); + this.videoPath = videoPath; + + makeGraphic(2, 2, FlxColor.TRANSPARENT); + video = new Video(); video.x = 0; video.y = 0; + video.alpha = 0; - FlxG.addChildBelowMouse(video); + FlxG.game.addChild(video); - var netConnection = new NetConnection(); + var netConnection:NetConnection = new NetConnection(); netConnection.connect(null); netStream = new NetStream(netConnection); - netStream.client = {onMetaData: client_onMetaData}; - netConnection.addEventListener(NetStatusEvent.NET_STATUS, netConnection_onNetStatus); + netStream.client = {onMetaData: onClientMetaData}; + netConnection.addEventListener(NetStatusEvent.NET_STATUS, onNetConnectionNetStatus); netStream.play(videoPath); } + /** + * Tell the FlxVideo to pause playback. + */ public function pauseVideo():Void { if (netStream != null) @@ -48,6 +61,9 @@ class FlxVideo extends FlxBasic } } + /** + * Tell the FlxVideo to resume if it is paused. + */ public function resumeVideo():Void { // Resume playing the video. @@ -57,6 +73,29 @@ class FlxVideo extends FlxBasic } } + var videoAvailable:Bool = false; + var frameTimer:Float; + + static final FRAME_RATE:Float = 60; + + public override function update(elapsed:Float):Void + { + super.update(elapsed); + + if (frameTimer >= (1 / FRAME_RATE)) + { + frameTimer = 0; + // TODO: We just draw the video buffer to the sprite 60 times a second. + // Can we copy the video buffer instead somehow? + pixels.draw(video); + } + + if (videoAvailable) frameTimer += elapsed; + } + + /** + * Tell the FlxVideo to seek to the beginning. + */ public function restartVideo():Void { // Seek to the beginning of the video. @@ -66,6 +105,9 @@ class FlxVideo extends FlxBasic } } + /** + * Tell the FlxVideo to end. + */ public function finishVideo():Void { netStream.dispose(); @@ -74,15 +116,48 @@ class FlxVideo extends FlxBasic if (finishCallback != null) finishCallback(); } - public function client_onMetaData(metaData:Dynamic) + public override function destroy():Void + { + if (netStream != null) + { + netStream.dispose(); + + if (FlxG.game.contains(video)) FlxG.game.removeChild(video); + } + + super.destroy(); + } + + /** + * Callback executed when the video stream loads. + * @param metaData The metadata of the video + */ + public function onClientMetaData(metaData:Dynamic):Void { video.attachNetStream(netStream); - video.width = FlxG.width; - video.height = FlxG.height; + onVideoReady(); } - function netConnection_onNetStatus(event:NetStatusEvent):Void + function onVideoReady():Void + { + video.width = FlxG.width; + video.height = FlxG.height; + + videoAvailable = true; + + FunkinSound.onVolumeChanged.add(onVolumeChanged); + onVolumeChanged(FlxG.sound.muted ? 0 : FlxG.sound.volume); + + makeGraphic(Std.int(video.width), Std.int(video.height), FlxColor.TRANSPARENT); + } + + function onVolumeChanged(volume:Float):Void + { + netStream.soundTransform = new SoundTransform(volume); + } + + function onNetConnectionNetStatus(event:NetStatusEvent):Void { if (event.info.code == 'NetStream.Play.Complete') finishVideo(); } From 50b17b3dcaba13894a827f75e2bc79493b6cd4ea Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Tue, 19 Mar 2024 23:25:22 -0400 Subject: [PATCH 19/23] Update 2hot, Lit Up, and Blazin to polished audio --- assets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets b/assets index 0e2c5bf21..26e2b2c44 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit 0e2c5bf2134c7e517b70cf74afd58abe5c7b5e50 +Subproject commit 26e2b2c4419f6a39b4e7641f0f824117c03eb0b6 From a93aa6c68d5ee30c41fce642a9e4f3ad1a38acbf Mon Sep 17 00:00:00 2001 From: Cameron Taylor Date: Wed, 20 Mar 2024 15:40:33 -0700 Subject: [PATCH 20/23] submod update --- assets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets b/assets index b272232aa..86927859c 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit b272232aaf5a748db4b0dd5ac0cc98b72d4a636c +Subproject commit 86927859c8e73a9a0b44738a4b50ec97f38444e0 From 105aca4707b30f19f45cab09f732f5cf522e3b0d Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Thu, 21 Mar 2024 19:44:02 -0400 Subject: [PATCH 21/23] Fix an issue where hidden difficulties could end up in the difficulty list. --- source/funkin/play/song/Song.hx | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/source/funkin/play/song/Song.hx b/source/funkin/play/song/Song.hx index 1b7740408..42266a6ae 100644 --- a/source/funkin/play/song/Song.hx +++ b/source/funkin/play/song/Song.hx @@ -367,11 +367,14 @@ class Song implements IPlayStateScriptedClass implements IRegistryEntry):Array + public function listDifficulties(?variationId:String, ?variationIds:Array, showHidden:Bool = false):Array { if (variationIds == null) variationIds = []; if (variationId != null) variationIds.push(variationId); @@ -387,6 +390,15 @@ class Song implements IPlayStateScriptedClass implements IRegistryEntry Date: Thu, 21 Mar 2024 18:51:18 -0700 Subject: [PATCH 22/23] submod update --- assets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets b/assets index 26e2b2c44..907015a5c 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit 26e2b2c4419f6a39b4e7641f0f824117c03eb0b6 +Subproject commit 907015a5cd8617d0febccd4a5237b2a25ff1df61 From 5e0de6d1ce9dcf1a9785b9b2b23b2e73dc008a9e Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Thu, 21 Mar 2024 23:57:26 -0400 Subject: [PATCH 23/23] Fix some issues with events unintentionally sharing data after being edited via the toolbox. --- source/funkin/data/song/SongData.hx | 2 +- source/funkin/ui/debug/charting/ChartEditorState.hx | 9 +++++++++ .../debug/charting/commands/SetItemSelectionCommand.hx | 7 ++++++- .../charting/components/ChartEditorEventSprite.hx | 10 ++++++++-- .../charting/toolboxes/ChartEditorEventDataToolbox.hx | 7 ++++--- 5 files changed, 28 insertions(+), 7 deletions(-) diff --git a/source/funkin/data/song/SongData.hx b/source/funkin/data/song/SongData.hx index 938859ff2..26380947a 100644 --- a/source/funkin/data/song/SongData.hx +++ b/source/funkin/data/song/SongData.hx @@ -706,7 +706,7 @@ abstract SongEventData(SongEventDataRaw) from SongEventDataRaw to SongEventDataR this = new SongEventDataRaw(time, eventKind, value); } - public inline function valueAsStruct(?defaultKey:String = "key"):Dynamic + public function valueAsStruct(?defaultKey:String = "key"):Dynamic { if (this.value == null) return {}; if (Std.isOfType(this.value, Array)) diff --git a/source/funkin/ui/debug/charting/ChartEditorState.hx b/source/funkin/ui/debug/charting/ChartEditorState.hx index c59a5abdb..bdc0d311e 100644 --- a/source/funkin/ui/debug/charting/ChartEditorState.hx +++ b/source/funkin/ui/debug/charting/ChartEditorState.hx @@ -878,6 +878,8 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState */ var noteDisplayDirty:Bool = true; + var noteTooltipsDirty:Bool = true; + /** * Whether the selected charactesr have been modified and the health icons need to be updated. */ @@ -1541,6 +1543,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState // Make sure view is updated when the variation changes. noteDisplayDirty = true; notePreviewDirty = true; + noteTooltipsDirty = true; notePreviewViewportBoundsDirty = true; switchToCurrentInstrumental(); @@ -1562,6 +1565,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState // Make sure view is updated when the difficulty changes. noteDisplayDirty = true; notePreviewDirty = true; + noteTooltipsDirty = true; notePreviewViewportBoundsDirty = true; // Make sure the difficulty we selected is in the list of difficulties. @@ -3663,8 +3667,13 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState selectionSquare.width = eventSprite.width; selectionSquare.height = eventSprite.height; } + + // Additional cleanup on notes. + if (noteTooltipsDirty) eventSprite.updateTooltipText(); } + noteTooltipsDirty = false; + // Sort the notes DESCENDING. This keeps the sustain behind the associated note. renderedNotes.sort(FlxSort.byY, FlxSort.DESCENDING); // TODO: .group.insertionSort() diff --git a/source/funkin/ui/debug/charting/commands/SetItemSelectionCommand.hx b/source/funkin/ui/debug/charting/commands/SetItemSelectionCommand.hx index 46fcca87c..73cf80fa0 100644 --- a/source/funkin/ui/debug/charting/commands/SetItemSelectionCommand.hx +++ b/source/funkin/ui/debug/charting/commands/SetItemSelectionCommand.hx @@ -51,7 +51,12 @@ class SetItemSelectionCommand implements ChartEditorCommand } var eventData = eventSelected.valueAsStruct(defaultKey); - state.eventDataToPlace = eventData; + var eventDataClone = Reflect.copy(eventData); + + if (eventDataClone != null) + { + state.eventDataToPlace = eventDataClone; + } state.refreshToolbox(ChartEditorState.CHART_EDITOR_TOOLBOX_EVENT_DATA_LAYOUT); } diff --git a/source/funkin/ui/debug/charting/components/ChartEditorEventSprite.hx b/source/funkin/ui/debug/charting/components/ChartEditorEventSprite.hx index f680095d7..c996079bc 100644 --- a/source/funkin/ui/debug/charting/components/ChartEditorEventSprite.hx +++ b/source/funkin/ui/debug/charting/components/ChartEditorEventSprite.hx @@ -164,8 +164,7 @@ class ChartEditorEventSprite extends FlxSprite this.eventData = value; // Update the position to match the note data. updateEventPosition(); - // Update the tooltip text. - this.tooltip.tipData = {text: this.eventData.buildTooltip()}; + updateTooltipText(); return this.eventData; } } @@ -188,6 +187,13 @@ class ChartEditorEventSprite extends FlxSprite this.updateTooltipPosition(); } + public function updateTooltipText():Void + { + if (this.eventData == null) return; + if (this.isGhost) return; + this.tooltip.tipData = {text: this.eventData.buildTooltip()}; + } + public function updateTooltipPosition():Void { // No tooltip for ghost sprites. diff --git a/source/funkin/ui/debug/charting/toolboxes/ChartEditorEventDataToolbox.hx b/source/funkin/ui/debug/charting/toolboxes/ChartEditorEventDataToolbox.hx index 50b341272..f0949846d 100644 --- a/source/funkin/ui/debug/charting/toolboxes/ChartEditorEventDataToolbox.hx +++ b/source/funkin/ui/debug/charting/toolboxes/ChartEditorEventDataToolbox.hx @@ -258,14 +258,15 @@ class ChartEditorEventDataToolbox extends ChartEditorBaseToolbox // Edit the event data of any existing events. if (!_initializing && chartEditorState.currentEventSelection.length > 0) { - for (event in chartEditorState.currentEventSelection) + for (songEvent in chartEditorState.currentEventSelection) { - event.eventKind = chartEditorState.eventKindToPlace; - event.value = chartEditorState.eventDataToPlace; + songEvent.eventKind = chartEditorState.eventKindToPlace; + songEvent.value = Reflect.copy(chartEditorState.eventDataToPlace); } chartEditorState.saveDataDirty = true; chartEditorState.noteDisplayDirty = true; chartEditorState.notePreviewDirty = true; + chartEditorState.noteTooltipsDirty = true; } } }