From e64637ffdfd17436621a0a84e53a4283e9534326 Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Fri, 22 Mar 2024 19:51:47 -0400 Subject: [PATCH 1/2] 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/2] 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(); - } }