From e64637ffdfd17436621a0a84e53a4283e9534326 Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Fri, 22 Mar 2024 19:51:47 -0400 Subject: [PATCH 1/7] Rework Conductor to use instanced signals --- source/funkin/Conductor.hx | 158 ++++++++++++++++++++++++-------- source/funkin/play/song/Song.hx | 10 +- source/funkin/util/Constants.hx | 5 + 3 files changed, 132 insertions(+), 41 deletions(-) diff --git a/source/funkin/Conductor.hx b/source/funkin/Conductor.hx index 05c23108f..25694b973 100644 --- a/source/funkin/Conductor.hx +++ b/source/funkin/Conductor.hx @@ -36,23 +36,43 @@ class Conductor * You can also do stuff like store a reference to the Conductor and pass it around or temporarily replace it, * or have a second Conductor running at the same time, or other weird stuff like that if you need to. */ - public static var instance:Conductor = new Conductor(); + public static var instance(get, set):Conductor; + + static var _instance:Null = null; /** - * Signal fired when the current Conductor instance advances to a new measure. + * Signal fired when the current static Conductor instance advances to a new measure. */ public static var measureHit(default, null):FlxSignal = new FlxSignal(); + /** + * Signal fired when THIS Conductor instance advances to a new measure. + * TODO: This naming sucks but we can't make a static and instance field with the same name! + */ + public var onMeasureHit(default, null):FlxSignal = new FlxSignal(); + /** * Signal fired when the current Conductor instance advances to a new beat. */ public static var beatHit(default, null):FlxSignal = new FlxSignal(); + /** + * Signal fired when THIS Conductor instance advances to a new beat. + * TODO: This naming sucks but we can't make a static and instance field with the same name! + */ + public var onBeatHit(default, null):FlxSignal = new FlxSignal(); + /** * Signal fired when the current Conductor instance advances to a new step. */ public static var stepHit(default, null):FlxSignal = new FlxSignal(); + /** + * Signal fired when THIS Conductor instance advances to a new step. + * TODO: This naming sucks but we can't make a static and instance field with the same name! + */ + public var onStepHit(default, null):FlxSignal = new FlxSignal(); + /** * The list of time changes in the song. * There should be at least one time change (at the beginning of the song) to define the BPM. @@ -234,6 +254,81 @@ class Conductor return Std.int(timeSignatureNumerator / timeSignatureDenominator * Constants.STEPS_PER_BEAT * Constants.STEPS_PER_BEAT); } + /** + * Reset the Conductor, replacing the current instance with a fresh one. + */ + public static function reset():Void + { + set_instance(new Conductor()); + } + + /** + * Add values of the current main Conductor instance to the `FlxG.watch`. + */ + public static function watchQuick():Void + { + FlxG.watch.addQuick("songPosition", Conductor.instance.songPosition); + FlxG.watch.addQuick("bpm", Conductor.instance.bpm); + FlxG.watch.addQuick("currentMeasureTime", Conductor.instance.currentMeasureTime); + FlxG.watch.addQuick("currentBeatTime", Conductor.instance.currentBeatTime); + FlxG.watch.addQuick("currentStepTime", Conductor.instance.currentStepTime); + } + + static function dispatchMeasureHit():Void + { + Conductor.measureHit.dispatch(); + } + + static function dispatchBeatHit():Void + { + Conductor.beatHit.dispatch(); + } + + static function dispatchStepHit():Void + { + Conductor.stepHit.dispatch(); + } + + static function setupSingleton(input:Conductor):Void + { + input.onMeasureHit.add(dispatchMeasureHit); + + input.onBeatHit.add(dispatchBeatHit); + + input.onStepHit.add(dispatchStepHit); + } + + static function clearSingleton(input:Conductor):Void + { + input.onMeasureHit.remove(dispatchMeasureHit); + + input.onBeatHit.remove(dispatchBeatHit); + + input.onStepHit.remove(dispatchStepHit); + } + + static function get_instance():Conductor + { + if (Conductor._instance == null) set_instance(new Conductor()); + if (Conductor._instance == null) throw "Could not initialize singleton Conductor!"; + return Conductor._instance; + } + + static function set_instance(instance:Conductor):Conductor + { + // Use _instance in here to avoid recursion + if (Conductor._instance != null) clearSingleton(Conductor._instance); + + Conductor._instance = instance; + + if (Conductor._instance != null) setupSingleton(Conductor._instance); + + return Conductor._instance; + } + + /** + * The constructor. + */ public function new() {} /** @@ -244,6 +339,7 @@ class Conductor * * WARNING: Avoid this for things like setting the BPM of the title screen music, * you should have a metadata file for it instead. + * We should probably deprecate this in the future. */ public function forceBPM(?bpm:Float = null) { @@ -264,7 +360,7 @@ class Conductor * BPM, current step, etc. will be re-calculated based on the song position. * * @param songPosition The current position in the song in milliseconds. - * Leave blank to use the FlxG.sound.music position. + * Leave blank to use the `FlxG.sound.music` position. */ public function update(?songPos:Float) { @@ -317,27 +413,27 @@ class Conductor this.currentMeasure = Math.floor(currentMeasureTime); } - // Only fire the signal if we are THE Conductor. - if (this == Conductor.instance) + // FlxSignals are really cool. + if (currentStep != oldStep) { - // FlxSignals are really cool. - if (currentStep != oldStep) - { - Conductor.stepHit.dispatch(); - } + this.onStepHit.dispatch(); + } - if (currentBeat != oldBeat) - { - Conductor.beatHit.dispatch(); - } + if (currentBeat != oldBeat) + { + this.onBeatHit.dispatch(); + } - if (currentMeasure != oldMeasure) - { - Conductor.measureHit.dispatch(); - } + if (currentMeasure != oldMeasure) + { + this.onMeasureHit.dispatch(); } } + /** + * Apply the time changes from a SongMetadata file. + * @param songTimeChanges The time changes to apply. + */ public function mapTimeChanges(songTimeChanges:Array) { timeChanges = []; @@ -383,7 +479,8 @@ class Conductor } /** - * Given a time in milliseconds, return a time in steps. + * @param ms A timestamp in milliseconds. + * @return The corresponding time in steps. */ public function getTimeInSteps(ms:Float):Float { @@ -420,7 +517,8 @@ class Conductor } /** - * Given a time in steps and fractional steps, return a time in milliseconds. + * @param stepTime A timestamp in steps. + * @return The corresponding time in milliseconds. */ public function getStepTimeInMs(stepTime:Float):Float { @@ -456,7 +554,8 @@ class Conductor } /** - * Given a time in beats and fractional beats, return a time in milliseconds. + * @param beatTime A timestamp in fractional beats. + * @return The corresponding time in milliseconds. */ public function getBeatTimeInMs(beatTime:Float):Float { @@ -490,21 +589,4 @@ class Conductor return resultMs; } } - - public static function watchQuick():Void - { - FlxG.watch.addQuick("songPosition", Conductor.instance.songPosition); - FlxG.watch.addQuick("bpm", Conductor.instance.bpm); - FlxG.watch.addQuick("currentMeasureTime", Conductor.instance.currentMeasureTime); - FlxG.watch.addQuick("currentBeatTime", Conductor.instance.currentBeatTime); - FlxG.watch.addQuick("currentStepTime", Conductor.instance.currentStepTime); - } - - /** - * Reset the Conductor, replacing the current instance with a fresh one. - */ - public static function reset():Void - { - Conductor.instance = new Conductor(); - } } diff --git a/source/funkin/play/song/Song.hx b/source/funkin/play/song/Song.hx index 567c388c7..0d325876c 100644 --- a/source/funkin/play/song/Song.hx +++ b/source/funkin/play/song/Song.hx @@ -374,12 +374,16 @@ class Song implements IPlayStateScriptedClass implements IRegistryEntry):Null { - if (variations == null) possibleVariations = variations; + if (possibleVariations == null) + { + possibleVariations = variations; + possibleVariations.sort(SortUtil.defaultsThenAlphabetically.bind(Constants.DEFAULT_VARIATION_LIST)); + } if (diffId == null) diffId = listDifficulties(null, possibleVariations)[0]; - for (variation in variations) + for (variationId in possibleVariations) { - if (difficulties.exists('$diffId-$variation')) return variation; + if (difficulties.exists('$diffId-$variationId')) return variationId; } return null; diff --git a/source/funkin/util/Constants.hx b/source/funkin/util/Constants.hx index c9b99ed46..af3ae15b0 100644 --- a/source/funkin/util/Constants.hx +++ b/source/funkin/util/Constants.hx @@ -157,6 +157,11 @@ class Constants */ public static final DEFAULT_VARIATION:String = 'default'; + /** + * Standardized variations for charts + */ + public static final DEFAULT_VARIATION_LIST:Array = ['default', 'erect', 'pico']; + /** * The default intensity for camera zooms. */ From 77cf96716ef4ef3394c2b8fb58d0182a4b8049ef Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Wed, 27 Mar 2024 02:55:53 -0400 Subject: [PATCH 2/7] Work in progress on Conductor signal rework --- assets | 2 +- source/funkin/Conductor.hx | 20 -------------------- 2 files changed, 1 insertion(+), 21 deletions(-) diff --git a/assets b/assets index 8013845e3..82b8d637f 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit 8013845e331015b40c4cc35230f6d02bd2148d52 +Subproject commit 82b8d637fb402a4c69001fd3c4fb435b56a1b4f1 diff --git a/source/funkin/Conductor.hx b/source/funkin/Conductor.hx index 3c6d2951f..104682ffd 100644 --- a/source/funkin/Conductor.hx +++ b/source/funkin/Conductor.hx @@ -267,18 +267,6 @@ class Conductor set_instance(new Conductor()); } - /** - * Add values of the current main Conductor instance to the `FlxG.watch`. - */ - public static function watchQuick():Void - { - FlxG.watch.addQuick("songPosition", Conductor.instance.songPosition); - FlxG.watch.addQuick("bpm", Conductor.instance.bpm); - FlxG.watch.addQuick("currentMeasureTime", Conductor.instance.currentMeasureTime); - FlxG.watch.addQuick("currentBeatTime", Conductor.instance.currentBeatTime); - FlxG.watch.addQuick("currentStepTime", Conductor.instance.currentStepTime); - } - static function dispatchMeasureHit():Void { Conductor.measureHit.dispatch(); @@ -611,12 +599,4 @@ class Conductor FlxG.watch.addQuick('currentBeatTime', target.currentBeatTime); FlxG.watch.addQuick('currentStepTime', target.currentStepTime); } - - /** - * Reset the Conductor, replacing the current instance with a fresh one. - */ - public static function reset():Void - { - _instance = new Conductor(); - } } From 175c580fef64d38c6314021f37d0e4cc0cd762d5 Mon Sep 17 00:00:00 2001 From: FabsTheFabs Date: Fri, 29 Mar 2024 23:34:22 +0000 Subject: [PATCH 3/7] update assets submodule --- assets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets b/assets index 2a0afcd76..72287eede 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit 2a0afcd76a26251dbbebb6901df4651f25a92c23 +Subproject commit 72287eede3a46a162a1bf0651a742d17391b4a9b From 254648eb55b546c4aa34c62188b4ef8d6fae1386 Mon Sep 17 00:00:00 2001 From: FabsTheFabs Date: Sat, 30 Mar 2024 03:27:40 +0000 Subject: [PATCH 4/7] update assets submodule --- assets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets b/assets index 72287eede..811a3c208 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit 72287eede3a46a162a1bf0651a742d17391b4a9b +Subproject commit 811a3c208be2b5e1074d5bd166471f43b22eb453 From 2f22bb8abeb4ae93f20624067db4ae783a8d7cb2 Mon Sep 17 00:00:00 2001 From: FabsTheFabs Date: Sat, 30 Mar 2024 05:10:33 +0000 Subject: [PATCH 5/7] update assets submodule --- assets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets b/assets index 811a3c208..09ba7bfd8 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit 811a3c208be2b5e1074d5bd166471f43b22eb453 +Subproject commit 09ba7bfd84167f6a04922e9c6312224c8bcef6cd From e3c3623ad4d6ba66770fa5c177ee14b420206ece Mon Sep 17 00:00:00 2001 From: FabsTheFabs Date: Tue, 9 Apr 2024 05:00:40 +0100 Subject: [PATCH 6/7] update assets submodule --- assets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets b/assets index 09ba7bfd8..9c35ee01c 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit 09ba7bfd84167f6a04922e9c6312224c8bcef6cd +Subproject commit 9c35ee01c5305ba04cde618bc224535e56c051fb From 84c3fd452b8fcfd5005b630beb50f2a4820f0b91 Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Sat, 20 Apr 2024 02:11:04 -0400 Subject: [PATCH 7/7] Update Weekend 1 cutscenes to use the instanced Conductor --- assets | 2 +- source/funkin/play/PlayState.hx | 5 ++++- source/funkin/play/event/FocusCameraSongEvent.hx | 2 +- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/assets b/assets index 77a7f44a8..7ec8282b5 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit 77a7f44a89349d40a41b94c1d65381386759359b +Subproject commit 7ec8282b5358302f3d862f4670d9c60102aa1cf7 diff --git a/source/funkin/play/PlayState.hx b/source/funkin/play/PlayState.hx index 572eb6135..4e388407e 100644 --- a/source/funkin/play/PlayState.hx +++ b/source/funkin/play/PlayState.hx @@ -813,6 +813,7 @@ class PlayState extends MusicBeatSubState super.update(elapsed); + var list = FlxG.sound.list; updateHealthBar(); updateScoreText(); @@ -969,7 +970,7 @@ class PlayState extends MusicBeatSubState if (health < Constants.HEALTH_MIN) health = Constants.HEALTH_MIN; // Apply camera zoom + multipliers. - if (subState == null && cameraZoomRate > 0.0 && !isInCutscene) + if (subState == null && cameraZoomRate > 0.0) // && !isInCutscene) { cameraBopMultiplier = FlxMath.lerp(1.0, cameraBopMultiplier, 0.95); // Lerp bop multiplier back to 1.0x var zoomPlusBop = currentCameraZoom * cameraBopMultiplier; // Apply camera bop multiplier. @@ -1869,6 +1870,8 @@ class PlayState extends MusicBeatSubState isInCutscene = false; camCutscene.visible = false; + + // TODO: Maybe tween in the camera after any cutscenes. camHUD.visible = true; } diff --git a/source/funkin/play/event/FocusCameraSongEvent.hx b/source/funkin/play/event/FocusCameraSongEvent.hx index 1bcac9ad3..569dcb87a 100644 --- a/source/funkin/play/event/FocusCameraSongEvent.hx +++ b/source/funkin/play/event/FocusCameraSongEvent.hx @@ -127,7 +127,7 @@ class FocusCameraSongEvent extends SongEvent switch (ease) { case 'CLASSIC': // Old-school. No ease. Just set follow point. - PlayState.instance.cancelCameraFollowTween(); + PlayState.instance.resetCamera(); PlayState.instance.cameraFollowPoint.setPosition(targetX, targetY); case 'INSTANT': // Instant ease. Duration is automatically 0. PlayState.instance.tweenCameraToPosition(targetX, targetY, 0);