diff --git a/.vscode/settings.json b/.vscode/settings.json index 92d49c3d4..cefbadcf6 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -4,8 +4,7 @@ "editor.formatOnSave": true, "editor.formatOnPaste": true, "editor.codeActionsOnSave": { - // Compilation server issues can cause auto-cleanup to remove valid imports. - "source.organizeImports": false + "source.organizeImports": "never" }, "editor.defaultFormatter": "nadako.vshaxe", "editor.tabSize": 2 diff --git a/Project.xml b/Project.xml index 4c0ffdce7..e0677b026 100644 --- a/Project.xml +++ b/Project.xml @@ -99,18 +99,20 @@ - + + - + + + + - - diff --git a/art b/art index 1656bea53..03e7c2a23 160000 --- a/art +++ b/art @@ -1 +1 @@ -Subproject commit 1656bea5370c65879aaeb323e329f403c78071c5 +Subproject commit 03e7c2a2353b184e45955c96d763b7cdf1acbc34 diff --git a/assets b/assets index dfaf23dfa..b551cb290 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit dfaf23dfa11ff67be2eea9113a80ff5dc0040f76 +Subproject commit b551cb29078e3599a5d608a22238450f9380a3fc diff --git a/hmm.json b/hmm.json index a10eed1a6..d461edd24 100644 --- a/hmm.json +++ b/hmm.json @@ -11,15 +11,20 @@ "name": "flixel", "type": "git", "dir": null, - "ref": "da04cbda49a4c5eebe93fb61296dbaf4f0f1b556", - "url": "https://github.com/EliteMasterEric/flixel" + "ref": "a83738673e7edbf8acba3a1426af284dfe6719fe", + "url": "https://github.com/FunkinCrew/flixel" }, { "name": "flixel-addons", "type": "git", "dir": null, - "ref": "c8c41e26d463aaf2edc0582fb23b6e228235bd16", - "url": "https://github.com/EliteMasterEric/flixel-addons" + "ref": "fd3aecdeb5635fa0428dffee204fc78fc26b5885", + "url": "https://github.com/FunkinCrew/flixel-addons" + }, + { + "name": "flixel-text-input", + "type": "haxelib", + "version": "1.1.0" }, { "name": "flixel-ui", @@ -32,8 +37,8 @@ "name": "flxanimate", "type": "git", "dir": null, - "ref": "dd2903f7dc7024335b981edf2a770760cec912e1", - "url": "https://github.com/ninjamuffin99/flxanimate" + "ref": "d7c5621be742e2c98d523dfe5af7528835eaff1e", + "url": "https://github.com/FunkinCrew/flxanimate" }, { "name": "format", @@ -49,14 +54,14 @@ "name": "haxeui-core", "type": "git", "dir": null, - "ref": "032192e849cdb7d1070c0a3241c58ee555ffaccc", + "ref": "5086e59e7551d775ed4d1fb0188e31de22d1312b", "url": "https://github.com/haxeui/haxeui-core" }, { "name": "haxeui-flixel", "type": "git", "dir": null, - "ref": "d90758b229d05206400df867d333c79d9fdbd478", + "ref": "2b9cff727999b53ed292b1675ac1c9089ac77600", "url": "https://github.com/haxeui/haxeui-flixel" }, { @@ -95,15 +100,15 @@ "name": "json2object", "type": "git", "dir": null, - "ref": "f4df19cfa196f85eece55c3367021fc965f1fa9a", - "url": "https://github.com/EliteMasterEric/json2object" + "ref": "a8c26f18463c98da32f744c214fe02273e1823fa", + "url": "https://github.com/FunkinCrew/json2object" }, { "name": "lime", "type": "git", "dir": null, "ref": "737b86f121cdc90358d59e2e527934f267c94a2c", - "url": "https://github.com/EliteMasterEric/lime" + "url": "https://github.com/FunkinCrew/lime" }, { "name": "mconsole", @@ -124,21 +129,21 @@ "type": "git", "dir": "src", "ref": "master", - "url": "https://github.com/EliteMasterEric/mockatoo" + "url": "https://github.com/FunkinCrew/mockatoo" }, { "name": "munit", "type": "git", "dir": "src", "ref": "master", - "url": "https://github.com/EliteMasterEric/MassiveUnit" + "url": "https://github.com/FunkinCrew/MassiveUnit" }, { "name": "openfl", "type": "git", "dir": null, "ref": "f229d76361c7e31025a048fe7909847f75bb5d5e", - "url": "https://github.com/EliteMasterEric/openfl" + "url": "https://github.com/FunkinCrew/openfl" }, { "name": "polymod", diff --git a/source/funkin/Conductor.hx b/source/funkin/Conductor.hx index c531678ad..05c23108f 100644 --- a/source/funkin/Conductor.hx +++ b/source/funkin/Conductor.hx @@ -11,6 +11,7 @@ import funkin.data.song.SongDataUtils; * A core class which handles musical timing throughout the game, * both in gameplay and in menus. */ +@:nullSafety class Conductor { // onBeatHit is called every quarter note @@ -28,29 +29,53 @@ class Conductor // 60 BPM = 240 sixteenth notes per minute = 4 onStepHit per second // 7/8 = 3.5 beats per measure = 14 steps per measure + /** + * The current instance of the Conductor. + * If one doesn't currently exist, a new one will be created. + * + * 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(); + + /** + * Signal fired when the current Conductor instance advances to a new measure. + */ + public static var measureHit(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 the current Conductor instance advances to a new step. + */ + public static var stepHit(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. */ - static var timeChanges:Array = []; + var timeChanges:Array = []; /** * The most recent time change for the current song position. */ - public static var currentTimeChange(default, null):SongTimeChange; + public var currentTimeChange(default, null):Null; /** * The current position in the song in milliseconds. - * Update this every frame based on the audio position using `Conductor.update()`. + * Update this every frame based on the audio position using `Conductor.instance.update()`. */ - public static var songPosition(default, null):Float = 0; + public var songPosition(default, null):Float = 0; /** * Beats per minute of the current song at the current time. */ - public static var bpm(get, never):Float; + public var bpm(get, never):Float; - static function get_bpm():Float + function get_bpm():Float { if (bpmOverride != null) return bpmOverride; @@ -62,9 +87,9 @@ class Conductor /** * Beats per minute of the current song at the start time. */ - public static var startingBPM(get, never):Float; + public var startingBPM(get, never):Float; - static function get_startingBPM():Float + function get_startingBPM():Float { if (bpmOverride != null) return bpmOverride; @@ -78,14 +103,14 @@ class Conductor * The current value set by `forceBPM`. * If false, BPM is determined by time changes. */ - static var bpmOverride:Null = null; + var bpmOverride:Null = null; /** * Duration of a measure in milliseconds. Calculated based on bpm. */ - public static var measureLengthMs(get, never):Float; + public var measureLengthMs(get, never):Float; - static function get_measureLengthMs():Float + function get_measureLengthMs():Float { return beatLengthMs * timeSignatureNumerator; } @@ -93,9 +118,9 @@ class Conductor /** * Duration of a beat (quarter note) in milliseconds. Calculated based on bpm. */ - public static var beatLengthMs(get, never):Float; + public var beatLengthMs(get, never):Float; - static function get_beatLengthMs():Float + function get_beatLengthMs():Float { // Tied directly to BPM. return ((Constants.SECS_PER_MIN / bpm) * Constants.MS_PER_SEC); @@ -104,25 +129,25 @@ class Conductor /** * Duration of a step (sixtennth note) in milliseconds. Calculated based on bpm. */ - public static var stepLengthMs(get, never):Float; + public var stepLengthMs(get, never):Float; - static function get_stepLengthMs():Float + function get_stepLengthMs():Float { return beatLengthMs / timeSignatureNumerator; } - public static var timeSignatureNumerator(get, never):Int; + public var timeSignatureNumerator(get, never):Int; - static function get_timeSignatureNumerator():Int + function get_timeSignatureNumerator():Int { if (currentTimeChange == null) return Constants.DEFAULT_TIME_SIGNATURE_NUM; return currentTimeChange.timeSignatureNum; } - public static var timeSignatureDenominator(get, never):Int; + public var timeSignatureDenominator(get, never):Int; - static function get_timeSignatureDenominator():Int + function get_timeSignatureDenominator():Int { if (currentTimeChange == null) return Constants.DEFAULT_TIME_SIGNATURE_DEN; @@ -132,44 +157,44 @@ class Conductor /** * Current position in the song, in measures. */ - public static var currentMeasure(default, null):Int; + public var currentMeasure(default, null):Int = 0; /** * Current position in the song, in beats. */ - public static var currentBeat(default, null):Int; + public var currentBeat(default, null):Int = 0; /** * Current position in the song, in steps. */ - public static var currentStep(default, null):Int; + public var currentStep(default, null):Int = 0; /** * Current position in the song, in measures and fractions of a measure. */ - public static var currentMeasureTime(default, null):Float; + public var currentMeasureTime(default, null):Float = 0; /** * Current position in the song, in beats and fractions of a measure. */ - public static var currentBeatTime(default, null):Float; + public var currentBeatTime(default, null):Float = 0; /** * Current position in the song, in steps and fractions of a step. */ - public static var currentStepTime(default, null):Float; + public var currentStepTime(default, null):Float = 0; /** * An offset tied to the current chart file to compensate for a delay in the instrumental. */ - public static var instrumentalOffset:Float = 0; + public var instrumentalOffset:Float = 0; /** * The instrumental offset, in terms of steps. */ - public static var instrumentalOffsetSteps(get, never):Float; + public var instrumentalOffsetSteps(get, never):Float; - static function get_instrumentalOffsetSteps():Float + function get_instrumentalOffsetSteps():Float { var startingStepLengthMs:Float = ((Constants.SECS_PER_MIN / startingBPM) * Constants.MS_PER_SEC) / timeSignatureNumerator; @@ -179,19 +204,19 @@ class Conductor /** * An offset tied to the file format of the audio file being played. */ - public static var formatOffset:Float = 0; + public var formatOffset:Float = 0; /** * An offset set by the user to compensate for input lag. */ - public static var inputOffset:Float = 0; + public var inputOffset:Float = 0; /** * The number of beats in a measure. May be fractional depending on the time signature. */ - public static var beatsPerMeasure(get, never):Float; + public var beatsPerMeasure(get, never):Float; - static function get_beatsPerMeasure():Float + function get_beatsPerMeasure():Float { // NOTE: Not always an integer, for example 7/8 is 3.5 beats per measure return stepsPerMeasure / Constants.STEPS_PER_BEAT; @@ -201,30 +226,15 @@ class Conductor * The number of steps in a measure. * TODO: I don't think this can be fractional? */ - public static var stepsPerMeasure(get, never):Int; + public var stepsPerMeasure(get, never):Int; - static function get_stepsPerMeasure():Int + function get_stepsPerMeasure():Int { // TODO: Is this always an integer? return Std.int(timeSignatureNumerator / timeSignatureDenominator * Constants.STEPS_PER_BEAT * Constants.STEPS_PER_BEAT); } - /** - * Signal fired when the Conductor advances to a new measure. - */ - public static var measureHit(default, null):FlxSignal = new FlxSignal(); - - /** - * Signal fired when the Conductor advances to a new beat. - */ - public static var beatHit(default, null):FlxSignal = new FlxSignal(); - - /** - * Signal fired when the Conductor advances to a new step. - */ - public static var stepHit(default, null):FlxSignal = new FlxSignal(); - - function new() {} + public function new() {} /** * Forcibly defines the current BPM of the song. @@ -235,7 +245,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. */ - public static function forceBPM(?bpm:Float = null) + public function forceBPM(?bpm:Float = null) { if (bpm != null) { @@ -246,7 +256,7 @@ class Conductor // trace('[CONDUCTOR] Resetting BPM to default'); } - Conductor.bpmOverride = bpm; + this.bpmOverride = bpm; } /** @@ -256,29 +266,29 @@ class Conductor * @param songPosition The current position in the song in milliseconds. * Leave blank to use the FlxG.sound.music position. */ - public static function update(?songPosition:Float) + public function update(?songPos:Float) { - if (songPosition == null) + if (songPos == null) { // Take into account instrumental and file format song offsets. - songPosition = (FlxG.sound.music != null) ? (FlxG.sound.music.time + instrumentalOffset + formatOffset) : 0.0; + songPos = (FlxG.sound.music != null) ? (FlxG.sound.music.time + instrumentalOffset + formatOffset) : 0.0; } - var oldMeasure = currentMeasure; - var oldBeat = currentBeat; - var oldStep = currentStep; + var oldMeasure = this.currentMeasure; + var oldBeat = this.currentBeat; + var oldStep = this.currentStep; // Set the song position we are at (for purposes of calculating note positions, etc). - Conductor.songPosition = songPosition; + this.songPosition = songPos; currentTimeChange = timeChanges[0]; - if (Conductor.songPosition > 0.0) + if (this.songPosition > 0.0) { for (i in 0...timeChanges.length) { - if (songPosition >= timeChanges[i].timeStamp) currentTimeChange = timeChanges[i]; + if (this.songPosition >= timeChanges[i].timeStamp) currentTimeChange = timeChanges[i]; - if (songPosition < timeChanges[i].timeStamp) break; + if (this.songPosition < timeChanges[i].timeStamp) break; } } @@ -286,45 +296,49 @@ class Conductor { trace('WARNING: Conductor is broken, timeChanges is empty.'); } - else if (currentTimeChange != null && Conductor.songPosition > 0.0) + else if (currentTimeChange != null && this.songPosition > 0.0) { // roundDecimal prevents representing 8 as 7.9999999 - currentStepTime = FlxMath.roundDecimal((currentTimeChange.beatTime * 4) + (songPosition - currentTimeChange.timeStamp) / stepLengthMs, 6); - currentBeatTime = currentStepTime / Constants.STEPS_PER_BEAT; - currentMeasureTime = currentStepTime / stepsPerMeasure; - currentStep = Math.floor(currentStepTime); - currentBeat = Math.floor(currentBeatTime); - currentMeasure = Math.floor(currentMeasureTime); + this.currentStepTime = FlxMath.roundDecimal((currentTimeChange.beatTime * 4) + (this.songPosition - currentTimeChange.timeStamp) / stepLengthMs, 6); + this.currentBeatTime = currentStepTime / Constants.STEPS_PER_BEAT; + this.currentMeasureTime = currentStepTime / stepsPerMeasure; + this.currentStep = Math.floor(currentStepTime); + this.currentBeat = Math.floor(currentBeatTime); + this.currentMeasure = Math.floor(currentMeasureTime); } else { // Assume a constant BPM equal to the forced value. - currentStepTime = FlxMath.roundDecimal((songPosition / stepLengthMs), 4); - currentBeatTime = currentStepTime / Constants.STEPS_PER_BEAT; - currentMeasureTime = currentStepTime / stepsPerMeasure; - currentStep = Math.floor(currentStepTime); - currentBeat = Math.floor(currentBeatTime); - currentMeasure = Math.floor(currentMeasureTime); + this.currentStepTime = FlxMath.roundDecimal((songPosition / stepLengthMs), 4); + this.currentBeatTime = currentStepTime / Constants.STEPS_PER_BEAT; + this.currentMeasureTime = currentStepTime / stepsPerMeasure; + this.currentStep = Math.floor(currentStepTime); + this.currentBeat = Math.floor(currentBeatTime); + this.currentMeasure = Math.floor(currentMeasureTime); } - // FlxSignals are really cool. - if (currentStep != oldStep) + // Only fire the signal if we are THE Conductor. + if (this == Conductor.instance) { - stepHit.dispatch(); - } + // FlxSignals are really cool. + if (currentStep != oldStep) + { + Conductor.stepHit.dispatch(); + } - if (currentBeat != oldBeat) - { - beatHit.dispatch(); - } + if (currentBeat != oldBeat) + { + Conductor.beatHit.dispatch(); + } - if (currentMeasure != oldMeasure) - { - measureHit.dispatch(); + if (currentMeasure != oldMeasure) + { + Conductor.measureHit.dispatch(); + } } } - public static function mapTimeChanges(songTimeChanges:Array) + public function mapTimeChanges(songTimeChanges:Array) { timeChanges = []; @@ -338,24 +352,21 @@ class Conductor // Without any custom handling, `currentStepTime` becomes non-zero at `songPosition = 0`. if (currentTimeChange.timeStamp < 0.0) currentTimeChange.timeStamp = 0.0; - if (currentTimeChange.beatTime == null) + if (currentTimeChange.timeStamp <= 0.0) { - if (currentTimeChange.timeStamp <= 0.0) - { - currentTimeChange.beatTime = 0.0; - } - else - { - // Calculate the beat time of this timestamp. - currentTimeChange.beatTime = 0.0; + currentTimeChange.beatTime = 0.0; + } + else + { + // Calculate the beat time of this timestamp. + currentTimeChange.beatTime = 0.0; - if (currentTimeChange.timeStamp > 0.0 && timeChanges.length > 0) - { - var prevTimeChange:SongTimeChange = timeChanges[timeChanges.length - 1]; - currentTimeChange.beatTime = FlxMath.roundDecimal(prevTimeChange.beatTime - + ((currentTimeChange.timeStamp - prevTimeChange.timeStamp) * prevTimeChange.bpm / Constants.SECS_PER_MIN / Constants.MS_PER_SEC), - 4); - } + if (currentTimeChange.timeStamp > 0.0 && timeChanges.length > 0) + { + var prevTimeChange:SongTimeChange = timeChanges[timeChanges.length - 1]; + currentTimeChange.beatTime = FlxMath.roundDecimal(prevTimeChange.beatTime + + ((currentTimeChange.timeStamp - prevTimeChange.timeStamp) * prevTimeChange.bpm / Constants.SECS_PER_MIN / Constants.MS_PER_SEC), + 4); } } @@ -368,13 +379,13 @@ class Conductor } // Update currentStepTime - Conductor.update(Conductor.songPosition); + this.update(Conductor.instance.songPosition); } /** * Given a time in milliseconds, return a time in steps. */ - public static function getTimeInSteps(ms:Float):Float + public function getTimeInSteps(ms:Float):Float { if (timeChanges.length == 0) { @@ -411,7 +422,7 @@ class Conductor /** * Given a time in steps and fractional steps, return a time in milliseconds. */ - public static function getStepTimeInMs(stepTime:Float):Float + public function getStepTimeInMs(stepTime:Float):Float { if (timeChanges.length == 0) { @@ -447,7 +458,7 @@ class Conductor /** * Given a time in beats and fractional beats, return a time in milliseconds. */ - public static function getBeatTimeInMs(beatTime:Float):Float + public function getBeatTimeInMs(beatTime:Float):Float { if (timeChanges.length == 0) { @@ -480,13 +491,20 @@ class Conductor } } + 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 { - beatHit.removeAll(); - stepHit.removeAll(); - - mapTimeChanges([]); - forceBPM(null); - update(0); + Conductor.instance = new Conductor(); } } diff --git a/source/funkin/audio/visualize/ABotVis.hx b/source/funkin/audio/visualize/ABotVis.hx index 681287808..89b004df4 100644 --- a/source/funkin/audio/visualize/ABotVis.hx +++ b/source/funkin/audio/visualize/ABotVis.hx @@ -64,7 +64,7 @@ class ABotVis extends FlxTypedSpriteGroup if (vis.snd.playing) remappedShit = Std.int(FlxMath.remapToRange(vis.snd.time, 0, vis.snd.length, 0, vis.numSamples)); else - remappedShit = Std.int(FlxMath.remapToRange(Conductor.songPosition, 0, vis.snd.length, 0, vis.numSamples)); + remappedShit = Std.int(FlxMath.remapToRange(Conductor.instance.songPosition, 0, vis.snd.length, 0, vis.numSamples)); var fftSamples:Array = []; diff --git a/source/funkin/audio/visualize/SpectogramSprite.hx b/source/funkin/audio/visualize/SpectogramSprite.hx index 63d0fcd2e..b4e024a4c 100644 --- a/source/funkin/audio/visualize/SpectogramSprite.hx +++ b/source/funkin/audio/visualize/SpectogramSprite.hx @@ -164,7 +164,7 @@ class SpectogramSprite extends FlxTypedSpriteGroup if (vis.snd.playing) remappedShit = Std.int(FlxMath.remapToRange(vis.snd.time, 0, vis.snd.length, 0, numSamples)); else - remappedShit = Std.int(FlxMath.remapToRange(Conductor.songPosition, 0, vis.snd.length, 0, numSamples)); + remappedShit = Std.int(FlxMath.remapToRange(Conductor.instance.songPosition, 0, vis.snd.length, 0, numSamples)); var fftSamples:Array = []; var i = remappedShit; @@ -235,15 +235,15 @@ class SpectogramSprite extends FlxTypedSpriteGroup if (vis.snd.playing) remappedShit = Std.int(FlxMath.remapToRange(vis.snd.time, 0, vis.snd.length, 0, numSamples)); else { - if (curTime == Conductor.songPosition) + if (curTime == Conductor.instance.songPosition) { wavOptimiz = 3; return; // already did shit, so finishes function early } - curTime = Conductor.songPosition; + curTime = Conductor.instance.songPosition; - remappedShit = Std.int(FlxMath.remapToRange(Conductor.songPosition, 0, vis.snd.length, 0, numSamples)); + remappedShit = Std.int(FlxMath.remapToRange(Conductor.instance.songPosition, 0, vis.snd.length, 0, numSamples)); } wavOptimiz = 8; diff --git a/source/funkin/data/DataParse.hx b/source/funkin/data/DataParse.hx index cbd168a61..49dde0198 100644 --- a/source/funkin/data/DataParse.hx +++ b/source/funkin/data/DataParse.hx @@ -178,7 +178,31 @@ class DataParse switch (json.value) { case JObject(fields): - return cast Tools.getValue(json); + var result:LegacyNoteSection = + { + mustHitSection: false, + sectionNotes: [], + }; + for (field in fields) + { + switch (field.name) + { + case 'sectionNotes': + result.sectionNotes = legacyNotes(field.value, field.name); + + case 'mustHitSection': + result.mustHitSection = Tools.getValue(field.value); + case 'typeOfSection': + result.typeOfSection = Tools.getValue(field.value); + case 'lengthInSteps': + result.lengthInSteps = Tools.getValue(field.value); + case 'changeBPM': + result.changeBPM = Tools.getValue(field.value); + case 'bpm': + result.bpm = Tools.getValue(field.value); + } + } + return result; default: throw 'Expected property $name to be an object, but it was ${json.value}.'; } @@ -189,7 +213,12 @@ class DataParse switch (json.value) { case JObject(fields): - return cast Tools.getValue(json); + var result = {}; + for (field in fields) + { + Reflect.setField(result, field.name, legacyNoteSectionArray(field.value, field.name)); + } + return result; default: throw 'Expected property $name to be an object, but it was ${json.value}.'; } @@ -211,13 +240,13 @@ class DataParse switch (json.value) { case JArray(values): - // var time:Null = values[0] == null ? null : Tools.getValue(values[0]); - // var data:Null = values[1] == null ? null : Tools.getValue(values[1]); - // var length:Null = values[2] == null ? null : Tools.getValue(values[2]); - // var alt:Null = values[3] == null ? null : Tools.getValue(values[3]); + var time:Null = values[0] == null ? null : Tools.getValue(values[0]); + var data:Null = values[1] == null ? null : Tools.getValue(values[1]); + var length:Null = values[2] == null ? null : Tools.getValue(values[2]); + var alt:Null = values[3] == null ? null : Tools.getValue(values[3]); - // return new LegacyNote(time, data, length, alt); - return null; + return new LegacyNote(time, data, length, alt); + // return null; default: throw 'Expected property $name to be a note, but it was ${json.value}.'; } diff --git a/source/funkin/data/level/LevelRegistry.hx b/source/funkin/data/level/LevelRegistry.hx index 75b0b11f6..b5c15de0f 100644 --- a/source/funkin/data/level/LevelRegistry.hx +++ b/source/funkin/data/level/LevelRegistry.hx @@ -30,6 +30,7 @@ class LevelRegistry extends BaseRegistry // JsonParser does not take type parameters, // otherwise this function would be in BaseRegistry. var parser = new json2object.JsonParser(); + parser.ignoreUnknownVariables = false; switch (loadEntryFile(id)) { @@ -57,6 +58,7 @@ class LevelRegistry extends BaseRegistry public function parseEntryDataRaw(contents:String, ?fileName:String):Null { var parser = new json2object.JsonParser(); + parser.ignoreUnknownVariables = false; parser.fromJson(contents, fileName); if (parser.errors.length > 0) diff --git a/source/funkin/data/notestyle/NoteStyleRegistry.hx b/source/funkin/data/notestyle/NoteStyleRegistry.hx index 4255a644b..ffb9bf490 100644 --- a/source/funkin/data/notestyle/NoteStyleRegistry.hx +++ b/source/funkin/data/notestyle/NoteStyleRegistry.hx @@ -35,6 +35,7 @@ class NoteStyleRegistry extends BaseRegistry // JsonParser does not take type parameters, // otherwise this function would be in BaseRegistry. var parser = new json2object.JsonParser(); + parser.ignoreUnknownVariables = false; switch (loadEntryFile(id)) { @@ -62,6 +63,7 @@ class NoteStyleRegistry extends BaseRegistry public function parseEntryDataRaw(contents:String, ?fileName:String):Null { var parser = new json2object.JsonParser(); + parser.ignoreUnknownVariables = false; parser.fromJson(contents, fileName); if (parser.errors.length > 0) diff --git a/source/funkin/data/song/SongData.hx b/source/funkin/data/song/SongData.hx index fe4e66032..78b3cd3fe 100644 --- a/source/funkin/data/song/SongData.hx +++ b/source/funkin/data/song/SongData.hx @@ -150,7 +150,7 @@ class SongTimeChange implements ICloneable */ @:optional @:alias("b") - public var beatTime:Null; + public var beatTime:Float; /** * Quarter notes per minute (float). Cannot be empty in the first element of the list, @@ -657,7 +657,7 @@ class SongEventDataRaw implements ICloneable { if (_stepTime != null && !force) return _stepTime; - return _stepTime = Conductor.getTimeInSteps(this.time); + return _stepTime = Conductor.instance.getTimeInSteps(this.time); } public function clone():SongEventDataRaw @@ -802,7 +802,7 @@ class SongNoteDataRaw implements ICloneable /** * The kind of the note. * This can allow the note to include information used for custom behavior. - * Defaults to blank or `"normal"`. + * Defaults to blank or `Constants.DEFAULT_DIFFICULTY`. */ @:alias("k") @:default("normal") @@ -851,7 +851,7 @@ class SongNoteDataRaw implements ICloneable { if (_stepTime != null && !force) return _stepTime; - return _stepTime = Conductor.getTimeInSteps(this.time); + return _stepTime = Conductor.instance.getTimeInSteps(this.time); } @:jignored @@ -867,7 +867,7 @@ class SongNoteDataRaw implements ICloneable if (_stepLength != null && !force) return _stepLength; - return _stepLength = Conductor.getTimeInSteps(this.time + this.length) - getStepTime(); + return _stepLength = Conductor.instance.getTimeInSteps(this.time + this.length) - getStepTime(); } public function setStepLength(value:Float):Void @@ -878,7 +878,7 @@ class SongNoteDataRaw implements ICloneable } else { - var lengthMs:Float = Conductor.getStepTimeInMs(value) - this.time; + var lengthMs:Float = Conductor.instance.getStepTimeInMs(value) - this.time; this.length = lengthMs; } _stepLength = null; diff --git a/source/funkin/data/song/SongDataUtils.hx b/source/funkin/data/song/SongDataUtils.hx index 4ae4b1426..309676884 100644 --- a/source/funkin/data/song/SongDataUtils.hx +++ b/source/funkin/data/song/SongDataUtils.hx @@ -230,6 +230,7 @@ class SongDataUtils trace('Read ${notesString.length} characters from clipboard.'); var parser = new json2object.JsonParser(); + parser.ignoreUnknownVariables = false; parser.fromJson(notesString, 'clipboard'); if (parser.errors.length > 0) { diff --git a/source/funkin/data/song/SongRegistry.hx b/source/funkin/data/song/SongRegistry.hx index 850654eb7..5a0835f57 100644 --- a/source/funkin/data/song/SongRegistry.hx +++ b/source/funkin/data/song/SongRegistry.hx @@ -126,6 +126,8 @@ class SongRegistry extends BaseRegistry variation = variation == null ? Constants.DEFAULT_VARIATION : variation; var parser = new json2object.JsonParser(); + parser.ignoreUnknownVariables = false; + switch (loadEntryMetadataFile(id, variation)) { case {fileName: fileName, contents: contents}: @@ -147,6 +149,7 @@ class SongRegistry extends BaseRegistry variation = variation == null ? Constants.DEFAULT_VARIATION : variation; var parser = new json2object.JsonParser(); + parser.ignoreUnknownVariables = false; parser.fromJson(contents, fileName); if (parser.errors.length > 0) @@ -206,6 +209,8 @@ class SongRegistry extends BaseRegistry variation = variation == null ? Constants.DEFAULT_VARIATION : variation; var parser = new json2object.JsonParser(); + parser.ignoreUnknownVariables = false; + switch (loadEntryMetadataFile(id, variation)) { case {fileName: fileName, contents: contents}: @@ -226,6 +231,8 @@ class SongRegistry extends BaseRegistry variation = variation == null ? Constants.DEFAULT_VARIATION : variation; var parser = new json2object.JsonParser(); + parser.ignoreUnknownVariables = false; + switch (loadEntryMetadataFile(id, variation)) { case {fileName: fileName, contents: contents}: @@ -244,6 +251,7 @@ class SongRegistry extends BaseRegistry function parseEntryMetadataRaw_v2_1_0(contents:String, ?fileName:String = 'raw'):Null { var parser = new json2object.JsonParser(); + parser.ignoreUnknownVariables = false; parser.fromJson(contents, fileName); if (parser.errors.length > 0) @@ -257,6 +265,7 @@ class SongRegistry extends BaseRegistry function parseEntryMetadataRaw_v2_0_0(contents:String, ?fileName:String = 'raw'):Null { var parser = new json2object.JsonParser(); + parser.ignoreUnknownVariables = false; parser.fromJson(contents, fileName); if (parser.errors.length > 0) @@ -272,6 +281,8 @@ class SongRegistry extends BaseRegistry variation = variation == null ? Constants.DEFAULT_VARIATION : variation; var parser = new json2object.JsonParser(); + parser.ignoreUnknownVariables = false; + switch (loadMusicDataFile(id, variation)) { case {fileName: fileName, contents: contents}: @@ -291,6 +302,7 @@ class SongRegistry extends BaseRegistry public function parseMusicDataRaw(contents:String, ?fileName:String = 'raw'):Null { var parser = new json2object.JsonParser(); + parser.ignoreUnknownVariables = false; parser.fromJson(contents, fileName); if (parser.errors.length > 0) @@ -334,6 +346,7 @@ class SongRegistry extends BaseRegistry variation = variation == null ? Constants.DEFAULT_VARIATION : variation; var parser = new json2object.JsonParser(); + parser.ignoreUnknownVariables = false; switch (loadEntryChartFile(id, variation)) { @@ -356,6 +369,7 @@ class SongRegistry extends BaseRegistry variation = variation == null ? Constants.DEFAULT_VARIATION : variation; var parser = new json2object.JsonParser(); + parser.ignoreUnknownVariables = false; parser.fromJson(contents, fileName); if (parser.errors.length > 0) diff --git a/source/funkin/data/song/importer/ChartManifestData.hx b/source/funkin/data/song/importer/ChartManifestData.hx index 0c7d2f0b0..dd0d28479 100644 --- a/source/funkin/data/song/importer/ChartManifestData.hx +++ b/source/funkin/data/song/importer/ChartManifestData.hx @@ -68,6 +68,7 @@ class ChartManifestData public static function deserialize(contents:String):Null { var parser = new json2object.JsonParser(); + parser.ignoreUnknownVariables = false; parser.fromJson(contents, 'manifest.json'); if (parser.errors.length > 0) diff --git a/source/funkin/data/song/importer/FNFLegacyData.hx b/source/funkin/data/song/importer/FNFLegacyData.hx index 5b75368c9..52380d344 100644 --- a/source/funkin/data/song/importer/FNFLegacyData.hx +++ b/source/funkin/data/song/importer/FNFLegacyData.hx @@ -19,7 +19,8 @@ class LegacySongData @:jcustomparse(funkin.data.DataParse.eitherLegacyScrollSpeeds) public var speed:Either; - public var stageDefault:String; + @:optional + public var stageDefault:Null; public var bpm:Float; @:jcustomparse(funkin.data.DataParse.eitherLegacyNoteData) diff --git a/source/funkin/data/song/importer/FNFLegacyImporter.hx b/source/funkin/data/song/importer/FNFLegacyImporter.hx index ee68513dc..ab2abda8e 100644 --- a/source/funkin/data/song/importer/FNFLegacyImporter.hx +++ b/source/funkin/data/song/importer/FNFLegacyImporter.hx @@ -14,6 +14,7 @@ class FNFLegacyImporter public static function parseLegacyDataRaw(input:String, fileName:String = 'raw'):FNFLegacyData { var parser = new json2object.JsonParser(); + parser.ignoreUnknownVariables = true; // Set to true to ignore extra variables that might be included in the JSON. parser.fromJson(input, fileName); if (parser.errors.length > 0) @@ -185,15 +186,34 @@ class FNFLegacyImporter return result; } + static final STRUMLINE_SIZE = 4; + static function migrateNoteSections(input:Array):Array { var result:Array = []; for (section in input) { + var mustHitSection = section.mustHitSection ?? false; for (note in section.sectionNotes) { - result.push(new SongNoteData(note.time, note.data, note.length, note.getKind())); + // Handle the dumb logic for mustHitSection. + var noteData = note.data; + + // Flip notes if mustHitSection is FALSE (not true lol). + if (!mustHitSection) + { + if (noteData >= STRUMLINE_SIZE) + { + noteData -= STRUMLINE_SIZE; + } + else + { + noteData += STRUMLINE_SIZE; + } + } + + result.push(new SongNoteData(note.time, noteData, note.length, note.getKind())); } } diff --git a/source/funkin/input/Cursor.hx b/source/funkin/input/Cursor.hx index b4bf43808..39f399465 100644 --- a/source/funkin/input/Cursor.hx +++ b/source/funkin/input/Cursor.hx @@ -34,6 +34,18 @@ class Cursor Cursor.cursorMode = null; } + public static inline function toggle():Void + { + if (FlxG.mouse.visible) + { + hide(); + } + else + { + show(); + } + } + public static final CURSOR_DEFAULT_PARAMS:CursorParams = { graphic: "assets/images/cursor/cursor-default.png", diff --git a/source/funkin/play/Countdown.hx b/source/funkin/play/Countdown.hx index d23574ce2..5b7ce9fc2 100644 --- a/source/funkin/play/Countdown.hx +++ b/source/funkin/play/Countdown.hx @@ -40,7 +40,7 @@ class Countdown stopCountdown(); PlayState.instance.isInCountdown = true; - Conductor.update(PlayState.instance.startTimestamp + Conductor.beatLengthMs * -5); + Conductor.instance.update(PlayState.instance.startTimestamp + Conductor.instance.beatLengthMs * -5); // Handle onBeatHit events manually // @:privateAccess // PlayState.instance.dispatchEvent(new SongTimeScriptEvent(SONG_BEAT_HIT, 0, 0)); @@ -48,7 +48,7 @@ class Countdown // The timer function gets called based on the beat of the song. countdownTimer = new FlxTimer(); - countdownTimer.start(Conductor.beatLengthMs / 1000, function(tmr:FlxTimer) { + countdownTimer.start(Conductor.instance.beatLengthMs / 1000, function(tmr:FlxTimer) { if (PlayState.instance == null) { tmr.cancel(); @@ -158,7 +158,7 @@ class Countdown { stopCountdown(); // This will trigger PlayState.startSong() - Conductor.update(0); + Conductor.instance.update(0); // PlayState.isInCountdown = false; } @@ -225,7 +225,7 @@ class Countdown countdownSprite.screenCenter(); // Fade sprite in, then out, then destroy it. - FlxTween.tween(countdownSprite, {y: countdownSprite.y += 100, alpha: 0}, Conductor.beatLengthMs / 1000, + FlxTween.tween(countdownSprite, {y: countdownSprite.y += 100, alpha: 0}, Conductor.instance.beatLengthMs / 1000, { ease: FlxEase.cubeInOut, onComplete: function(twn:FlxTween) { diff --git a/source/funkin/play/GameOverSubState.hx b/source/funkin/play/GameOverSubState.hx index 6eb53e2d5..137bf3905 100644 --- a/source/funkin/play/GameOverSubState.hx +++ b/source/funkin/play/GameOverSubState.hx @@ -64,9 +64,16 @@ class GameOverSubState extends MusicBeatSubState */ var isEnding:Bool = false; - public function new() + var isChartingMode:Bool = false; + + var transparent:Bool; + + public function new(params:GameOverParams) { super(); + + this.isChartingMode = params?.isChartingMode ?? false; + transparent = params.transparent; } /** @@ -87,9 +94,10 @@ class GameOverSubState extends MusicBeatSubState // // Add a black background to the screen. - // We make this transparent so that we can see the stage underneath during debugging. var bg = new FlxSprite().makeGraphic(FlxG.width, FlxG.height, FlxColor.BLACK); - bg.alpha = 0.25; + // We make this transparent so that we can see the stage underneath during debugging, + // but it's normally opaque. + bg.alpha = transparent ? 0.25 : 1.0; bg.scrollFactor.set(); add(bg); @@ -121,7 +129,7 @@ class GameOverSubState extends MusicBeatSubState gameOverMusic.stop(); // The conductor now represents the BPM of the game over music. - Conductor.update(0); + Conductor.instance.update(0); } var hasStartedAnimation:Bool = false; @@ -176,16 +184,27 @@ class GameOverSubState extends MusicBeatSubState // PlayState.seenCutscene = false; // old thing... gameOverMusic.stop(); - if (PlayStatePlaylist.isStoryMode) FlxG.switchState(new StoryMenuState()); + if (isChartingMode) + { + this.close(); + if (FlxG.sound.music != null) FlxG.sound.music.pause(); // Don't reset song position! + PlayState.instance.close(); // This only works because PlayState is a substate! + } + else if (PlayStatePlaylist.isStoryMode) + { + FlxG.switchState(new StoryMenuState()); + } else + { FlxG.switchState(new FreeplayState()); + } } if (gameOverMusic.playing) { // Match the conductor to the music. // This enables the stepHit and beatHit events. - Conductor.update(gameOverMusic.time); + Conductor.instance.update(gameOverMusic.time); } else { @@ -270,6 +289,7 @@ class GameOverSubState extends MusicBeatSubState { gameOverMusic.loadEmbedded(musicPath); gameOverMusic.volume = startingVolume; + gameOverMusic.looped = !isEnding; gameOverMusic.play(); } } @@ -307,3 +327,9 @@ class GameOverSubState extends MusicBeatSubState }); } } + +typedef GameOverParams = +{ + var isChartingMode:Bool; + var transparent:Bool; +} diff --git a/source/funkin/play/PlayState.hx b/source/funkin/play/PlayState.hx index 81757bcae..f15529a04 100644 --- a/source/funkin/play/PlayState.hx +++ b/source/funkin/play/PlayState.hx @@ -561,15 +561,15 @@ class PlayState extends MusicBeatSubState } // Prepare the Conductor. - Conductor.forceBPM(null); + Conductor.instance.forceBPM(null); if (currentChart.offsets != null) { - Conductor.instrumentalOffset = currentChart.offsets.getInstrumentalOffset(); + Conductor.instance.instrumentalOffset = currentChart.offsets.getInstrumentalOffset(); } - Conductor.mapTimeChanges(currentChart.timeChanges); - Conductor.update((Conductor.beatLengthMs * -5) + startTimestamp); + Conductor.instance.mapTimeChanges(currentChart.timeChanges); + Conductor.instance.update((Conductor.instance.beatLengthMs * -5) + startTimestamp); // The song is now loaded. We can continue to initialize the play state. initCameras(); @@ -734,7 +734,7 @@ class PlayState extends MusicBeatSubState // Reset music properly. - FlxG.sound.music.time = Math.max(0, startTimestamp - Conductor.instrumentalOffset); + FlxG.sound.music.time = Math.max(0, startTimestamp - Conductor.instance.instrumentalOffset); FlxG.sound.music.pause(); if (!overrideMusic) @@ -785,22 +785,22 @@ class PlayState extends MusicBeatSubState { if (isInCountdown) { - Conductor.update(Conductor.songPosition + elapsed * 1000); - if (Conductor.songPosition >= (startTimestamp)) startSong(); + Conductor.instance.update(Conductor.instance.songPosition + elapsed * 1000); + if (Conductor.instance.songPosition >= (startTimestamp)) startSong(); } } else { if (Constants.EXT_SOUND == 'mp3') { - Conductor.formatOffset = Constants.MP3_DELAY_MS; + Conductor.instance.formatOffset = Constants.MP3_DELAY_MS; } else { - Conductor.formatOffset = 0.0; + Conductor.instance.formatOffset = 0.0; } - Conductor.update(); // Normal conductor update. + Conductor.instance.update(); // Normal conductor update. } var androidPause:Bool = false; @@ -922,7 +922,11 @@ class PlayState extends MusicBeatSubState } #end - var gameOverSubState = new GameOverSubState(); + var gameOverSubState = new GameOverSubState( + { + isChartingMode: isChartingMode, + transparent: persistentDraw + }); FlxTransitionableSubState.skipNextTransIn = true; FlxTransitionableSubState.skipNextTransOut = true; openSubState(gameOverSubState); @@ -938,7 +942,7 @@ class PlayState extends MusicBeatSubState // TODO: Check that these work even when songPosition is less than 0. if (songEvents != null && songEvents.length > 0) { - var songEventsToActivate:Array = SongEventParser.queryEvents(songEvents, Conductor.songPosition); + var songEventsToActivate:Array = SongEventParser.queryEvents(songEvents, Conductor.instance.songPosition); if (songEventsToActivate.length > 0) { @@ -946,7 +950,7 @@ class PlayState extends MusicBeatSubState for (event in songEventsToActivate) { // If an event is trying to play, but it's over 5 seconds old, skip it. - if (event.time - Conductor.songPosition < -5000) + if (event.time - Conductor.instance.songPosition < -5000) { event.activated = true; continue; @@ -1048,7 +1052,7 @@ class PlayState extends MusicBeatSubState if (startTimer.finished) { DiscordClient.changePresence(detailsText, '${currentChart.songName} ($storyDifficultyText)', iconRPC, true, - currentSongLengthMs - Conductor.songPosition); + currentSongLengthMs - Conductor.instance.songPosition); } else { @@ -1072,12 +1076,12 @@ class PlayState extends MusicBeatSubState { if (health > Constants.HEALTH_MIN && !paused && FlxG.autoPause) { - if (Conductor.songPosition > 0.0) DiscordClient.changePresence(detailsText, currentSong.song + if (Conductor.instance.songPosition > 0.0) DiscordClient.changePresence(detailsText, currentSong.song + ' (' + storyDifficultyText + ')', iconRPC, true, currentSongLengthMs - - Conductor.songPosition); + - Conductor.instance.songPosition); else DiscordClient.changePresence(detailsText, currentSong.song + ' (' + storyDifficultyText + ')', iconRPC); } @@ -1097,23 +1101,6 @@ class PlayState extends MusicBeatSubState } #end - /** - * This function is called whenever Flixel switches switching to a new FlxState. - * @return Whether to actually switch to the new state. - */ - @:haxe.warning("-WDeprecated") - override function switchTo(nextState:FlxState):Bool - { - var result:Bool = super.switchTo(nextState); - - if (result) - { - performCleanup(); - } - - return result; - } - /** * Removes any references to the current stage, then clears the stage cache, * then reloads all the stages. @@ -1167,17 +1154,17 @@ class PlayState extends MusicBeatSubState if (!startingSong && FlxG.sound.music != null - && (Math.abs(FlxG.sound.music.time - (Conductor.songPosition + Conductor.instrumentalOffset)) > 200 - || Math.abs(vocals.checkSyncError(Conductor.songPosition + Conductor.instrumentalOffset)) > 200)) + && (Math.abs(FlxG.sound.music.time - (Conductor.instance.songPosition + Conductor.instance.instrumentalOffset)) > 200 + || Math.abs(vocals.checkSyncError(Conductor.instance.songPosition + Conductor.instance.instrumentalOffset)) > 200)) { trace("VOCALS NEED RESYNC"); - if (vocals != null) trace(vocals.checkSyncError(Conductor.songPosition + Conductor.instrumentalOffset)); - trace(FlxG.sound.music.time - (Conductor.songPosition + Conductor.instrumentalOffset)); + if (vocals != null) trace(vocals.checkSyncError(Conductor.instance.songPosition + Conductor.instance.instrumentalOffset)); + trace(FlxG.sound.music.time - (Conductor.instance.songPosition + Conductor.instance.instrumentalOffset)); resyncVocals(); } - if (iconP1 != null) iconP1.onStepHit(Std.int(Conductor.currentStep)); - if (iconP2 != null) iconP2.onStepHit(Std.int(Conductor.currentStep)); + if (iconP1 != null) iconP1.onStepHit(Std.int(Conductor.instance.currentStep)); + if (iconP2 != null) iconP2.onStepHit(Std.int(Conductor.instance.currentStep)); return true; } @@ -1198,14 +1185,14 @@ class PlayState extends MusicBeatSubState } // Only zoom camera if we are zoomed by less than 35%. - if (FlxG.camera.zoom < (1.35 * defaultCameraZoom) && cameraZoomRate > 0 && Conductor.currentBeat % cameraZoomRate == 0) + if (FlxG.camera.zoom < (1.35 * defaultCameraZoom) && cameraZoomRate > 0 && Conductor.instance.currentBeat % cameraZoomRate == 0) { // Zoom camera in (1.5%) FlxG.camera.zoom += cameraZoomIntensity * defaultCameraZoom; // Hud zooms double (3%) camHUD.zoom += hudCameraZoomIntensity * defaultHUDCameraZoom; } - // trace('Not bopping camera: ${FlxG.camera.zoom} < ${(1.35 * defaultCameraZoom)} && ${cameraZoomRate} > 0 && ${Conductor.currentBeat} % ${cameraZoomRate} == ${Conductor.currentBeat % cameraZoomRate}}'); + // trace('Not bopping camera: ${FlxG.camera.zoom} < ${(1.35 * defaultCameraZoom)} && ${cameraZoomRate} > 0 && ${Conductor.instance.currentBeat} % ${cameraZoomRate} == ${Conductor.instance.currentBeat % cameraZoomRate}}'); // That combo milestones that got spoiled that one time. // Comes with NEAT visual and audio effects. @@ -1218,13 +1205,13 @@ class PlayState extends MusicBeatSubState // TODO: Re-enable combo text (how to do this without sections?). // if (currentSong != null) // { - // shouldShowComboText = (Conductor.currentBeat % 8 == 7); - // var daSection = .getSong()[Std.int(Conductor.currentBeat / 16)]; + // shouldShowComboText = (Conductor.instance.currentBeat % 8 == 7); + // var daSection = .getSong()[Std.int(Conductor.instance.currentBeat / 16)]; // shouldShowComboText = shouldShowComboText && (daSection != null && daSection.mustHitSection); // shouldShowComboText = shouldShowComboText && (Highscore.tallies.combo > 5); // - // var daNextSection = .getSong()[Std.int(Conductor.currentBeat / 16) + 1]; - // var isEndOfSong = .getSong().length < Std.int(Conductor.currentBeat / 16); + // var daNextSection = .getSong()[Std.int(Conductor.instance.currentBeat / 16) + 1]; + // var isEndOfSong = .getSong().length < Std.int(Conductor.instance.currentBeat / 16); // shouldShowComboText = shouldShowComboText && (isEndOfSong || (daNextSection != null && !daNextSection.mustHitSection)); // } @@ -1237,7 +1224,7 @@ class PlayState extends MusicBeatSubState var frameShit:Float = (1 / 24) * 2; // equals 2 frames in the animation - new FlxTimer().start(((Conductor.beatLengthMs / 1000) * 1.25) - frameShit, function(tmr) { + new FlxTimer().start(((Conductor.instance.beatLengthMs / 1000) * 1.25) - frameShit, function(tmr) { animShit.forceFinish(); }); } @@ -1251,7 +1238,7 @@ class PlayState extends MusicBeatSubState return true; } - override function destroy():Void + public override function destroy():Void { if (currentConversation != null) { @@ -1259,6 +1246,8 @@ class PlayState extends MusicBeatSubState currentConversation.kill(); } + performCleanup(); + super.destroy(); } @@ -1272,10 +1261,10 @@ class PlayState extends MusicBeatSubState if (currentStage == null) return; // TODO: Add HEY! song events to Tutorial. - if (Conductor.currentBeat % 16 == 15 + if (Conductor.instance.currentBeat % 16 == 15 && currentStage.getDad().characterId == 'gf' - && Conductor.currentBeat > 16 - && Conductor.currentBeat < 48) + && Conductor.instance.currentBeat > 16 + && Conductor.instance.currentBeat < 48) { currentStage.getBoyfriend().playAnimation('hey', true); currentStage.getDad().playAnimation('cheer', true); @@ -1586,7 +1575,7 @@ class PlayState extends MusicBeatSubState trace('Song difficulty could not be loaded.'); } - // Conductor.forceBPM(currentChart.getStartingBPM()); + // Conductor.instance.forceBPM(currentChart.getStartingBPM()); if (!overrideMusic) { @@ -1717,7 +1706,7 @@ class PlayState extends MusicBeatSubState FlxG.sound.music.onComplete = endSong; // A negative instrumental offset means the song skips the first few milliseconds of the track. // This just gets added into the startTimestamp behavior so we don't need to do anything extra. - FlxG.sound.music.time = startTimestamp - Conductor.instrumentalOffset; + FlxG.sound.music.time = startTimestamp - Conductor.instance.instrumentalOffset; trace('Playing vocals...'); add(vocals); @@ -1733,7 +1722,7 @@ class PlayState extends MusicBeatSubState if (startTimestamp > 0) { - // FlxG.sound.music.time = startTimestamp - Conductor.instrumentalOffset; + // FlxG.sound.music.time = startTimestamp - Conductor.instance.instrumentalOffset; handleSkippedNotes(); } } @@ -1811,7 +1800,7 @@ class PlayState extends MusicBeatSubState var hitWindowCenter = note.strumTime; var hitWindowEnd = note.strumTime + Constants.HIT_WINDOW_MS; - if (Conductor.songPosition > hitWindowEnd) + if (Conductor.instance.songPosition > hitWindowEnd) { if (note.hasMissed) continue; @@ -1821,7 +1810,7 @@ class PlayState extends MusicBeatSubState if (note.holdNoteSprite != null) note.holdNoteSprite.missedNote = true; } - else if (Conductor.songPosition > hitWindowCenter) + else if (Conductor.instance.songPosition > hitWindowCenter) { if (note.hasBeenHit) continue; @@ -1842,7 +1831,7 @@ class PlayState extends MusicBeatSubState opponentStrumline.playNoteHoldCover(note.holdNoteSprite); } } - else if (Conductor.songPosition > hitWindowStart) + else if (Conductor.instance.songPosition > hitWindowStart) { if (note.hasBeenHit || note.hasMissed) continue; @@ -1888,14 +1877,14 @@ class PlayState extends MusicBeatSubState var hitWindowCenter = note.strumTime; var hitWindowEnd = note.strumTime + Constants.HIT_WINDOW_MS; - if (Conductor.songPosition > hitWindowEnd) + if (Conductor.instance.songPosition > hitWindowEnd) { note.tooEarly = false; note.mayHit = false; note.hasMissed = true; if (note.holdNoteSprite != null) note.holdNoteSprite.missedNote = true; } - else if (Conductor.songPosition > hitWindowStart) + else if (Conductor.instance.songPosition > hitWindowStart) { note.tooEarly = false; note.mayHit = true; @@ -1962,7 +1951,7 @@ class PlayState extends MusicBeatSubState if (note == null || note.hasBeenHit) continue; var hitWindowEnd = note.strumTime + Constants.HIT_WINDOW_MS; - if (Conductor.songPosition > hitWindowEnd) + if (Conductor.instance.songPosition > hitWindowEnd) { // We have passed this note. // Flag the note for deletion without actually penalizing the player. @@ -2126,7 +2115,7 @@ class PlayState extends MusicBeatSubState { inputSpitter.push( { - t: Std.int(Conductor.songPosition), + t: Std.int(Conductor.instance.songPosition), d: indices[i], l: 20 }); @@ -2136,7 +2125,7 @@ class PlayState extends MusicBeatSubState { inputSpitter.push( { - t: Std.int(Conductor.songPosition), + t: Std.int(Conductor.instance.songPosition), d: -1, l: 20 }); @@ -2197,7 +2186,7 @@ class PlayState extends MusicBeatSubState { inputSpitter.push( { - t: Std.int(Conductor.songPosition), + t: Std.int(Conductor.instance.songPosition), d: indices[i], l: 20 }); @@ -2286,7 +2275,7 @@ class PlayState extends MusicBeatSubState // Get the offset and compensate for input latency. // Round inward (trim remainder) for consistency. - var noteDiff:Int = Std.int(Conductor.songPosition - daNote.noteData.time - inputLatencyMs); + var noteDiff:Int = Std.int(Conductor.instance.songPosition - daNote.noteData.time - inputLatencyMs); var score = Scoring.scoreNote(noteDiff, PBOT1); var daRating = Scoring.judgeNote(noteDiff, PBOT1); @@ -2341,7 +2330,7 @@ class PlayState extends MusicBeatSubState { inputSpitter.push( { - t: Std.int(Conductor.songPosition), + t: Std.int(Conductor.instance.songPosition), d: indices[i], l: 20 }); @@ -2351,7 +2340,7 @@ class PlayState extends MusicBeatSubState { inputSpitter.push( { - t: Std.int(Conductor.songPosition), + t: Std.int(Conductor.instance.songPosition), d: -1, l: 20 }); @@ -2750,15 +2739,15 @@ class PlayState extends MusicBeatSubState { FlxG.sound.music.pause(); - var targetTimeSteps:Float = Conductor.currentStepTime + (Conductor.timeSignatureNumerator * Constants.STEPS_PER_BEAT * sections); - var targetTimeMs:Float = Conductor.getStepTimeInMs(targetTimeSteps); + var targetTimeSteps:Float = Conductor.instance.currentStepTime + (Conductor.instance.timeSignatureNumerator * Constants.STEPS_PER_BEAT * sections); + var targetTimeMs:Float = Conductor.instance.getStepTimeInMs(targetTimeSteps); FlxG.sound.music.time = targetTimeMs; handleSkippedNotes(); // regenNoteData(FlxG.sound.music.time); - Conductor.update(FlxG.sound.music.time); + Conductor.instance.update(FlxG.sound.music.time); resyncVocals(); } diff --git a/source/funkin/play/character/BaseCharacter.hx b/source/funkin/play/character/BaseCharacter.hx index 7ad0892f6..390864148 100644 --- a/source/funkin/play/character/BaseCharacter.hx +++ b/source/funkin/play/character/BaseCharacter.hx @@ -367,7 +367,7 @@ class BaseCharacter extends Bopper // This lets you add frames to the end of the sing animation to ease back into the idle! holdTimer += event.elapsed; - var singTimeSec:Float = singTimeSec * (Conductor.beatLengthMs * 0.001); // x beats, to ms. + var singTimeSec:Float = singTimeSec * (Conductor.instance.beatLengthMs * 0.001); // x beats, to ms. if (getCurrentAnimation().endsWith('miss')) singTimeSec *= 2; // makes it feel more awkward when you miss diff --git a/source/funkin/play/character/MultiSparrowCharacter.hx b/source/funkin/play/character/MultiSparrowCharacter.hx index 968f613ff..0fc07399c 100644 --- a/source/funkin/play/character/MultiSparrowCharacter.hx +++ b/source/funkin/play/character/MultiSparrowCharacter.hx @@ -205,7 +205,7 @@ class MultiSparrowCharacter extends BaseCharacter graphic = value.parent; this.frames = value; this.frame = value.getByIndex(0); - this.numFrames = value.numFrames; + // this.numFrames = value.numFrames; resetHelpers(); this.bakedRotationAngle = 0; this.animation.frameIndex = 0; diff --git a/source/funkin/play/components/ComboMilestone.hx b/source/funkin/play/components/ComboMilestone.hx index 54d1438f1..4119e45c2 100644 --- a/source/funkin/play/components/ComboMilestone.hx +++ b/source/funkin/play/components/ComboMilestone.hx @@ -40,7 +40,7 @@ class ComboMilestone extends FlxTypedSpriteGroup { if (onScreenTime < 0.9) { - new FlxTimer().start((Conductor.beatLengthMs / 1000) * 0.25, function(tmr) { + new FlxTimer().start((Conductor.instance.beatLengthMs / 1000) * 0.25, function(tmr) { forceFinish(); }); } diff --git a/source/funkin/play/components/PopUpStuff.hx b/source/funkin/play/components/PopUpStuff.hx index 38a6ec15a..9553856a9 100644 --- a/source/funkin/play/components/PopUpStuff.hx +++ b/source/funkin/play/components/PopUpStuff.hx @@ -59,7 +59,7 @@ class PopUpStuff extends FlxTypedGroup remove(rating, true); rating.destroy(); }, - startDelay: Conductor.beatLengthMs * 0.001 + startDelay: Conductor.instance.beatLengthMs * 0.001 }); } @@ -110,7 +110,7 @@ class PopUpStuff extends FlxTypedGroup remove(comboSpr, true); comboSpr.destroy(); }, - startDelay: Conductor.beatLengthMs * 0.001 + startDelay: Conductor.instance.beatLengthMs * 0.001 }); var seperatedScore:Array = []; @@ -157,7 +157,7 @@ class PopUpStuff extends FlxTypedGroup remove(numScore, true); numScore.destroy(); }, - startDelay: Conductor.beatLengthMs * 0.002 + startDelay: Conductor.instance.beatLengthMs * 0.002 }); daLoop++; diff --git a/source/funkin/play/event/ZoomCameraSongEvent.hx b/source/funkin/play/event/ZoomCameraSongEvent.hx index 1ae76039e..4ad2ed390 100644 --- a/source/funkin/play/event/ZoomCameraSongEvent.hx +++ b/source/funkin/play/event/ZoomCameraSongEvent.hx @@ -79,7 +79,8 @@ class ZoomCameraSongEvent extends SongEvent return; } - FlxTween.tween(PlayState.instance, {defaultCameraZoom: zoom * FlxCamera.defaultZoom}, (Conductor.stepLengthMs * duration / 1000), {ease: easeFunction}); + FlxTween.tween(PlayState.instance, {defaultCameraZoom: zoom * FlxCamera.defaultZoom}, (Conductor.instance.stepLengthMs * duration / 1000), + {ease: easeFunction}); } } diff --git a/source/funkin/play/notes/Strumline.hx b/source/funkin/play/notes/Strumline.hx index 0145dee3f..b312494cf 100644 --- a/source/funkin/play/notes/Strumline.hx +++ b/source/funkin/play/notes/Strumline.hx @@ -274,10 +274,12 @@ class Strumline extends FlxSpriteGroup static function calculateNoteYPos(strumTime:Float, vwoosh:Bool = true):Float { // Make the note move faster visually as it moves offscreen. - var vwoosh:Float = (strumTime < Conductor.songPosition) && vwoosh ? 2.0 : 1.0; + // var vwoosh:Float = (strumTime < Conductor.songPosition) && vwoosh ? 2.0 : 1.0; + // ^^^ commented this out... do NOT make it move faster as it moves offscreen! + var vwoosh:Float = 1.0; var scrollSpeed:Float = PlayState.instance?.currentChart?.scrollSpeed ?? 1.0; - return Constants.PIXELS_PER_MS * (Conductor.songPosition - strumTime) * scrollSpeed * vwoosh * (Preferences.downscroll ? 1 : -1); + return Constants.PIXELS_PER_MS * (Conductor.instance.songPosition - strumTime) * scrollSpeed * vwoosh * (Preferences.downscroll ? 1 : -1); } function updateNotes():Void @@ -285,8 +287,8 @@ class Strumline extends FlxSpriteGroup if (noteData.length == 0) return; var songStart:Float = PlayState.instance?.startTimestamp ?? 0.0; - var hitWindowStart:Float = Conductor.songPosition - Constants.HIT_WINDOW_MS; - var renderWindowStart:Float = Conductor.songPosition + RENDER_DISTANCE_MS; + var hitWindowStart:Float = Conductor.instance.songPosition - Constants.HIT_WINDOW_MS; + var renderWindowStart:Float = Conductor.instance.songPosition + RENDER_DISTANCE_MS; for (noteIndex in nextNoteIndex...noteData.length) { @@ -333,7 +335,7 @@ class Strumline extends FlxSpriteGroup { if (holdNote == null || !holdNote.alive) continue; - if (Conductor.songPosition > holdNote.strumTime && holdNote.hitNote && !holdNote.missedNote) + if (Conductor.instance.songPosition > holdNote.strumTime && holdNote.hitNote && !holdNote.missedNote) { if (isPlayer && !isKeyHeld(holdNote.noteDirection)) { @@ -347,7 +349,7 @@ class Strumline extends FlxSpriteGroup var renderWindowEnd = holdNote.strumTime + holdNote.fullSustainLength + Constants.HIT_WINDOW_MS + RENDER_DISTANCE_MS / 8; - if (holdNote.missedNote && Conductor.songPosition >= renderWindowEnd) + if (holdNote.missedNote && Conductor.instance.songPosition >= renderWindowEnd) { // Hold note is offscreen, kill it. holdNote.visible = false; @@ -397,13 +399,13 @@ class Strumline extends FlxSpriteGroup holdNote.y = this.y - INITIAL_OFFSET + calculateNoteYPos(holdNote.strumTime, vwoosh) + yOffset + STRUMLINE_SIZE / 2; } } - else if (Conductor.songPosition > holdNote.strumTime && holdNote.hitNote) + else if (Conductor.instance.songPosition > holdNote.strumTime && holdNote.hitNote) { // Hold note is currently being hit, clip it off. holdConfirm(holdNote.noteDirection); holdNote.visible = true; - holdNote.sustainLength = (holdNote.strumTime + holdNote.fullSustainLength) - Conductor.songPosition; + holdNote.sustainLength = (holdNote.strumTime + holdNote.fullSustainLength) - Conductor.instance.songPosition; if (holdNote.sustainLength <= 10) { diff --git a/source/funkin/play/notes/SustainTrail.hx b/source/funkin/play/notes/SustainTrail.hx index ab4bf5f16..7367b97af 100644 --- a/source/funkin/play/notes/SustainTrail.hx +++ b/source/funkin/play/notes/SustainTrail.hx @@ -149,9 +149,9 @@ class SustainTrail extends FlxSprite if (sustainLength == s) return s; height = sustainHeight(s, getScrollSpeed()); - // updateColorTransform(); + this.sustainLength = s; updateClipping(); - return sustainLength = s; + return this.sustainLength; } /** @@ -162,13 +162,15 @@ class SustainTrail extends FlxSprite public function updateClipping(songTime:Float = 0):Void { var clipHeight:Float = FlxMath.bound(sustainHeight(sustainLength - (songTime - strumTime), getScrollSpeed()), 0, height); - if (clipHeight == 0) + if (clipHeight <= 0.1) { visible = false; return; } else + { visible = true; + } var bottomHeight:Float = graphic.height * zoom * endOffset; var partHeight:Float = clipHeight - bottomHeight; diff --git a/source/funkin/play/stage/StageData.hx b/source/funkin/play/stage/StageData.hx index d89995ef3..2d87dec31 100644 --- a/source/funkin/play/stage/StageData.hx +++ b/source/funkin/play/stage/StageData.hx @@ -164,6 +164,7 @@ class StageDataParser try { var parser = new json2object.JsonParser(); + parser.ignoreUnknownVariables = false; parser.fromJson(rawJson, '$stageId.json'); if (parser.errors.length > 0) diff --git a/source/funkin/ui/MusicBeatState.hx b/source/funkin/ui/MusicBeatState.hx index 077e9e495..848985563 100644 --- a/source/funkin/ui/MusicBeatState.hx +++ b/source/funkin/ui/MusicBeatState.hx @@ -83,13 +83,13 @@ class MusicBeatState extends FlxTransitionableState implements IEventHandler function handleQuickWatch():Void { // Display Conductor info in the watch window. - FlxG.watch.addQuick("songPosition", Conductor.songPosition); - FlxG.watch.addQuick("songPositionNoOffset", Conductor.songPosition + Conductor.instrumentalOffset); + FlxG.watch.addQuick("songPosition", Conductor.instance.songPosition); + FlxG.watch.addQuick("songPositionNoOffset", Conductor.instance.songPosition + Conductor.instance.instrumentalOffset); FlxG.watch.addQuick("musicTime", FlxG.sound.music?.time ?? 0.0); - FlxG.watch.addQuick("bpm", Conductor.bpm); - FlxG.watch.addQuick("currentMeasureTime", Conductor.currentBeatTime); - FlxG.watch.addQuick("currentBeatTime", Conductor.currentBeatTime); - FlxG.watch.addQuick("currentStepTime", Conductor.currentStepTime); + FlxG.watch.addQuick("bpm", Conductor.instance.bpm); + FlxG.watch.addQuick("currentMeasureTime", Conductor.instance.currentBeatTime); + FlxG.watch.addQuick("currentBeatTime", Conductor.instance.currentBeatTime); + FlxG.watch.addQuick("currentStepTime", Conductor.instance.currentStepTime); } override function update(elapsed:Float) @@ -139,7 +139,7 @@ class MusicBeatState extends FlxTransitionableState implements IEventHandler public function stepHit():Bool { - var event = new SongTimeScriptEvent(SONG_STEP_HIT, Conductor.currentBeat, Conductor.currentStep); + var event = new SongTimeScriptEvent(SONG_STEP_HIT, Conductor.instance.currentBeat, Conductor.instance.currentStep); dispatchEvent(event); @@ -150,7 +150,7 @@ class MusicBeatState extends FlxTransitionableState implements IEventHandler public function beatHit():Bool { - var event = new SongTimeScriptEvent(SONG_BEAT_HIT, Conductor.currentBeat, Conductor.currentStep); + var event = new SongTimeScriptEvent(SONG_BEAT_HIT, Conductor.instance.currentBeat, Conductor.instance.currentStep); dispatchEvent(event); diff --git a/source/funkin/ui/MusicBeatSubState.hx b/source/funkin/ui/MusicBeatSubState.hx index 9dd755b62..0fa55c234 100644 --- a/source/funkin/ui/MusicBeatSubState.hx +++ b/source/funkin/ui/MusicBeatSubState.hx @@ -65,12 +65,8 @@ class MusicBeatSubState extends FlxTransitionableSubState implements IEventHandl if (FlxG.keys.justPressed.F5) debug_refreshModules(); // Display Conductor info in the watch window. - FlxG.watch.addQuick("songPosition", Conductor.songPosition); FlxG.watch.addQuick("musicTime", FlxG.sound.music?.time ?? 0.0); - FlxG.watch.addQuick("bpm", Conductor.bpm); - FlxG.watch.addQuick("currentMeasureTime", Conductor.currentBeatTime); - FlxG.watch.addQuick("currentBeatTime", Conductor.currentBeatTime); - FlxG.watch.addQuick("currentStepTime", Conductor.currentStepTime); + Conductor.watchQuick(); dispatchEvent(new UpdateScriptEvent(elapsed)); } @@ -99,7 +95,7 @@ class MusicBeatSubState extends FlxTransitionableSubState implements IEventHandl */ public function stepHit():Bool { - var event:ScriptEvent = new SongTimeScriptEvent(SONG_STEP_HIT, Conductor.currentBeat, Conductor.currentStep); + var event:ScriptEvent = new SongTimeScriptEvent(SONG_STEP_HIT, Conductor.instance.currentBeat, Conductor.instance.currentStep); dispatchEvent(event); @@ -115,7 +111,7 @@ class MusicBeatSubState extends FlxTransitionableSubState implements IEventHandl */ public function beatHit():Bool { - var event:ScriptEvent = new SongTimeScriptEvent(SONG_BEAT_HIT, Conductor.currentBeat, Conductor.currentStep); + var event:ScriptEvent = new SongTimeScriptEvent(SONG_BEAT_HIT, Conductor.instance.currentBeat, Conductor.instance.currentStep); dispatchEvent(event); diff --git a/source/funkin/ui/debug/charting/ChartEditorState.hx b/source/funkin/ui/debug/charting/ChartEditorState.hx index c120bb9e4..78b651734 100644 --- a/source/funkin/ui/debug/charting/ChartEditorState.hx +++ b/source/funkin/ui/debug/charting/ChartEditorState.hx @@ -21,6 +21,7 @@ import flixel.system.FlxAssets.FlxSoundAsset; import flixel.tweens.FlxEase; import flixel.tweens.FlxTween; import flixel.tweens.misc.VarTween; +import haxe.ui.Toolkit; import flixel.util.FlxColor; import flixel.util.FlxSort; import flixel.util.FlxTimer; @@ -124,6 +125,7 @@ import flixel.group.FlxGroup.FlxTypedGroup; import funkin.audio.visualize.PolygonVisGroup; import flixel.input.mouse.FlxMouseEvent; import flixel.text.FlxText; +import flixel.system.debug.log.LogStyle; using Lambda; @@ -273,13 +275,13 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState function get_songLengthInSteps():Float { - return Conductor.getTimeInSteps(songLengthInMs); + return Conductor.instance.getTimeInSteps(songLengthInMs); } function set_songLengthInSteps(value:Float):Float { - // Getting a reasonable result from setting songLengthInSteps requires that Conductor.mapBPMChanges be called first. - songLengthInMs = Conductor.getStepTimeInMs(value); + // Getting a reasonable result from setting songLengthInSteps requires that Conductor.instance.mapBPMChanges be called first. + songLengthInMs = Conductor.instance.getStepTimeInMs(value); return value; } @@ -393,12 +395,12 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState function get_scrollPositionInMs():Float { - return Conductor.getStepTimeInMs(scrollPositionInSteps); + return Conductor.instance.getStepTimeInMs(scrollPositionInSteps); } function set_scrollPositionInMs(value:Float):Float { - scrollPositionInSteps = Conductor.getTimeInSteps(value); + scrollPositionInSteps = Conductor.instance.getTimeInSteps(value); return value; } @@ -452,13 +454,13 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState function get_playheadPositionInMs():Float { if (audioVisGroup != null && audioVisGroup.playerVis != null) - audioVisGroup.playerVis.realtimeStartOffset = -Conductor.getStepTimeInMs(playheadPositionInSteps); - return Conductor.getStepTimeInMs(playheadPositionInSteps); + audioVisGroup.playerVis.realtimeStartOffset = -Conductor.instance.getStepTimeInMs(playheadPositionInSteps); + return Conductor.instance.getStepTimeInMs(playheadPositionInSteps); } function set_playheadPositionInMs(value:Float):Float { - playheadPositionInSteps = Conductor.getTimeInSteps(value); + playheadPositionInSteps = Conductor.instance.getTimeInSteps(value); if (audioVisGroup != null && audioVisGroup.playerVis != null) audioVisGroup.playerVis.realtimeStartOffset = -value; return value; @@ -544,6 +546,11 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState */ var playtestPracticeMode:Bool = false; + /** + * Enables or disables the "debugger" popup that appears when you run into a flixel error. + */ + var enabledDebuggerPopup:Bool = true; + // Visuals /** @@ -753,15 +760,23 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState function set_currentNoteSelection(value:Array):Array { + // This value is true if all elements of the current selection are also in the new selection. + var isSuperset:Bool = currentNoteSelection.isSubset(value); + var isEqual:Bool = currentNoteSelection.isEqualUnordered(value); + currentNoteSelection = value; - if (currentNoteSelection.length > 0) + if (!isEqual) { - notePreview.addNotes(currentNoteSelection, Std.int(songLengthInMs), true); - } - else - { - notePreviewDirty = true; + if (currentNoteSelection.length > 0 && isSuperset) + { + notePreview.addSelectedNotes(currentNoteSelection, Std.int(songLengthInMs)); + } + else + { + // The new selection removes elements from the old selection, so we have to redraw the note preview. + notePreviewDirty = true; + } } return currentNoteSelection; @@ -1080,7 +1095,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState function get_availableDifficulties():Array { var m:Null = songMetadata.get(selectedVariation); - return m?.playData?.difficulties ?? []; + return m?.playData?.difficulties ?? [Constants.DEFAULT_DIFFICULTY]; } /** @@ -1139,7 +1154,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState var result:Null = songChartData.get(selectedVariation); if (result == null) { - result = new SongChartData(["normal" => 1.0], [], ["normal" => []]); + result = new SongChartData([Constants.DEFAULT_DIFFICULTY => 1.0], [], [Constants.DEFAULT_DIFFICULTY => []]); songChartData.set(selectedVariation, result); } return result; @@ -1363,6 +1378,8 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState function set_selectedDifficulty(value:String):String { + if (value == null) value = availableDifficulties[0] ?? Constants.DEFAULT_DIFFICULTY; + selectedDifficulty = value; // Make sure view is updated when the difficulty changes. @@ -2408,16 +2425,33 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState } else { - Conductor.currentTimeChange.bpm += 1; + Conductor.instance.currentTimeChange.bpm += 1; this.refreshToolbox(CHART_EDITOR_TOOLBOX_METADATA_LAYOUT); } } playbarBPM.onRightClick = _ -> { - Conductor.currentTimeChange.bpm -= 1; + Conductor.instance.currentTimeChange.bpm -= 1; this.refreshToolbox(CHART_EDITOR_TOOLBOX_METADATA_LAYOUT); } + playbarDifficulty.onClick = _ -> { + if (FlxG.keys.pressed.CONTROL) + { + this.setToolboxState(CHART_EDITOR_TOOLBOX_DIFFICULTY_LAYOUT, true); + } + else + { + incrementDifficulty(-1); + this.refreshToolbox(CHART_EDITOR_TOOLBOX_DIFFICULTY_LAYOUT); + } + } + + playbarDifficulty.onRightClick = _ -> { + incrementDifficulty(1); + this.refreshToolbox(CHART_EDITOR_TOOLBOX_DIFFICULTY_LAYOUT); + } + // Add functionality to the menu items. // File @@ -2462,9 +2496,9 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState menubarItemPaste.onClick = _ -> { var targetMs:Float = scrollPositionInMs + playheadPositionInMs; - var targetStep:Float = Conductor.getTimeInSteps(targetMs); + var targetStep:Float = Conductor.instance.getTimeInSteps(targetMs); var targetSnappedStep:Float = Math.floor(targetStep / noteSnapRatio) * noteSnapRatio; - var targetSnappedMs:Float = Conductor.getStepTimeInMs(targetSnappedStep); + var targetSnappedMs:Float = Conductor.instance.getStepTimeInMs(targetSnappedStep); performCommand(new PasteItemsCommand(targetSnappedMs)); }; @@ -2552,8 +2586,25 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState menubarItemPlayPause.onClick = _ -> toggleAudioPlayback(); - menubarItemLoadInstrumental.onClick = _ -> this.openUploadInstDialog(true); - menubarItemLoadVocals.onClick = _ -> this.openUploadVocalsDialog(true); + menubarItemLoadInstrumental.onClick = _ -> { + var dialog = this.openUploadInstDialog(true); + // Ensure instrumental and vocals are reloaded properly. + dialog.onDialogClosed = function(_) { + this.isHaxeUIDialogOpen = false; + this.switchToCurrentInstrumental(); + this.postLoadInstrumental(); + } + }; + + menubarItemLoadVocals.onClick = _ -> { + var dialog = this.openUploadVocalsDialog(true); + // Ensure instrumental and vocals are reloaded properly. + dialog.onDialogClosed = function(_) { + this.isHaxeUIDialogOpen = false; + this.switchToCurrentInstrumental(); + this.postLoadInstrumental(); + } + }; menubarItemVolumeMetronome.onChange = event -> { var volume:Float = event.value.toFloat() / 100.0; @@ -2598,10 +2649,6 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState menubarLabelPlaybackSpeed.text = 'Playback Speed - ${pitchDisplay}x'; } - playbarDifficulty.onClick = _ -> { - this.setToolboxState(CHART_EDITOR_TOOLBOX_DIFFICULTY_LAYOUT, true); - } - menubarItemToggleToolboxDifficulty.onChange = event -> this.setToolboxState(CHART_EDITOR_TOOLBOX_DIFFICULTY_LAYOUT, event.value); menubarItemToggleToolboxMetadata.onChange = event -> this.setToolboxState(CHART_EDITOR_TOOLBOX_METADATA_LAYOUT, event.value); menubarItemToggleToolboxNotes.onChange = event -> this.setToolboxState(CHART_EDITOR_TOOLBOX_NOTEDATA_LAYOUT, event.value); @@ -2645,10 +2692,12 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState saveDataDirty = false; } + var displayAutosavePopup:Bool = false; + /** * UPDATE FUNCTIONS */ - function autoSave():Void + function autoSave(?beforePlaytest:Bool = false):Void { var needsAutoSave:Bool = saveDataDirty; @@ -2666,13 +2715,21 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState if (needsAutoSave) { this.exportAllSongData(true, null); - var absoluteBackupsPath:String = Path.join([Sys.getCwd(), ChartEditorImportExportHandler.BACKUPS_PATH]); - this.infoWithActions('Auto-Save', 'Chart auto-saved to ${absoluteBackupsPath}.', [ - { - text: "Take Me There", - callback: openBackupsFolder, - } - ]); + if (beforePlaytest) + { + displayAutosavePopup = true; + } + else + { + displayAutosavePopup = false; + var absoluteBackupsPath:String = Path.join([Sys.getCwd(), ChartEditorImportExportHandler.BACKUPS_PATH]); + this.infoWithActions('Auto-Save', 'Chart auto-saved to ${absoluteBackupsPath}.', [ + { + text: "Take Me There", + callback: openBackupsFolder, + } + ]); + } } #end } @@ -2681,14 +2738,16 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState * Open the backups folder in the file explorer. * Don't call this on HTML5. */ - function openBackupsFolder(?_):Void + function openBackupsFolder(?_):Bool { #if sys // TODO: Is there a way to open a folder and highlight a file in it? var absoluteBackupsPath:String = Path.join([Sys.getCwd(), ChartEditorImportExportHandler.BACKUPS_PATH]); WindowUtil.openFolder(absoluteBackupsPath); + return true; #else trace('No file system access, cannot open backups folder.'); + return false; #end } @@ -2788,7 +2847,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState if (metronomeVolume > 0.0 && this.subState == null && (audioInstTrack != null && audioInstTrack.isPlaying)) { - playMetronomeTick(Conductor.currentBeat % 4 == 0); + playMetronomeTick(Conductor.instance.currentBeat % 4 == 0); } return true; @@ -2804,8 +2863,8 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState if (audioInstTrack != null && audioInstTrack.isPlaying) { - if (healthIconDad != null) healthIconDad.onStepHit(Conductor.currentStep); - if (healthIconBF != null) healthIconBF.onStepHit(Conductor.currentStep); + if (healthIconDad != null) healthIconDad.onStepHit(Conductor.instance.currentStep); + if (healthIconBF != null) healthIconBF.onStepHit(Conductor.instance.currentStep); } // Updating these every step keeps it more accurate. @@ -2833,12 +2892,12 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState audioInstTrack.update(elapsed); // If the song starts 50ms in, make sure we start the song there. - if (Conductor.instrumentalOffset < 0) + if (Conductor.instance.instrumentalOffset < 0) { - if (audioInstTrack.time < -Conductor.instrumentalOffset) + if (audioInstTrack.time < -Conductor.instance.instrumentalOffset) { - trace('Resetting instrumental time to ${- Conductor.instrumentalOffset}ms'); - audioInstTrack.time = -Conductor.instrumentalOffset; + trace('Resetting instrumental time to ${- Conductor.instance.instrumentalOffset}ms'); + audioInstTrack.time = -Conductor.instance.instrumentalOffset; } } } @@ -2849,16 +2908,16 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState { // If middle mouse panning during song playback, we move ONLY the playhead, without scrolling. Neat! - var oldStepTime:Float = Conductor.currentStepTime; - var oldSongPosition:Float = Conductor.songPosition + Conductor.instrumentalOffset; - Conductor.update(audioInstTrack.time); - handleHitsounds(oldSongPosition, Conductor.songPosition + Conductor.instrumentalOffset); + var oldStepTime:Float = Conductor.instance.currentStepTime; + var oldSongPosition:Float = Conductor.instance.songPosition + Conductor.instance.instrumentalOffset; + Conductor.instance.update(audioInstTrack.time); + handleHitsounds(oldSongPosition, Conductor.instance.songPosition + Conductor.instance.instrumentalOffset); // Resync vocals. if (audioVocalTrackGroup != null && Math.abs(audioInstTrack.time - audioVocalTrackGroup.time) > 100) { audioVocalTrackGroup.time = audioInstTrack.time; } - var diffStepTime:Float = Conductor.currentStepTime - oldStepTime; + var diffStepTime:Float = Conductor.instance.currentStepTime - oldStepTime; // Move the playhead. playheadPositionInPixels += diffStepTime * GRID_SIZE; @@ -2868,9 +2927,9 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState else { // Else, move the entire view. - var oldSongPosition:Float = Conductor.songPosition + Conductor.instrumentalOffset; - Conductor.update(audioInstTrack.time); - handleHitsounds(oldSongPosition, Conductor.songPosition + Conductor.instrumentalOffset); + var oldSongPosition:Float = Conductor.instance.songPosition + Conductor.instance.instrumentalOffset; + Conductor.instance.update(audioInstTrack.time); + handleHitsounds(oldSongPosition, Conductor.instance.songPosition + Conductor.instance.instrumentalOffset); // Resync vocals. if (audioVocalTrackGroup != null && Math.abs(audioInstTrack.time - audioVocalTrackGroup.time) > 100) { @@ -2879,7 +2938,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState // We need time in fractional steps here to allow the song to actually play. // Also account for a potentially offset playhead. - scrollPositionInPixels = (Conductor.currentStepTime + Conductor.instrumentalOffsetSteps) * GRID_SIZE - playheadPositionInPixels; + scrollPositionInPixels = (Conductor.instance.currentStepTime + Conductor.instance.instrumentalOffsetSteps) * GRID_SIZE - playheadPositionInPixels; // DO NOT move song to scroll position here specifically. @@ -3008,8 +3067,8 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState // Let's try testing only notes within a certain range of the view area. // TODO: I don't think this messes up really long sustains, does it? - var viewAreaTopMs:Float = scrollPositionInMs - (Conductor.measureLengthMs * 2); // Is 2 measures enough? - var viewAreaBottomMs:Float = scrollPositionInMs + (Conductor.measureLengthMs * 2); // Is 2 measures enough? + var viewAreaTopMs:Float = scrollPositionInMs - (Conductor.instance.measureLengthMs * 2); // Is 2 measures enough? + var viewAreaBottomMs:Float = scrollPositionInMs + (Conductor.instance.measureLengthMs * 2); // Is 2 measures enough? // Add notes that are now visible. for (noteData in currentSongChartNoteData) @@ -3296,14 +3355,14 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState // PAGE UP = Jump up to nearest measure if (pageUpKeyHandler.activated) { - var measureHeight:Float = GRID_SIZE * 4 * Conductor.beatsPerMeasure; + var measureHeight:Float = GRID_SIZE * 4 * Conductor.instance.beatsPerMeasure; var playheadPos:Float = scrollPositionInPixels + playheadPositionInPixels; var targetScrollPosition:Float = Math.floor(playheadPos / measureHeight) * measureHeight; // If we would move less than one grid, instead move to the top of the previous measure. var targetScrollAmount = Math.abs(targetScrollPosition - playheadPos); if (targetScrollAmount < GRID_SIZE) { - targetScrollPosition -= GRID_SIZE * Constants.STEPS_PER_BEAT * Conductor.beatsPerMeasure; + targetScrollPosition -= GRID_SIZE * Constants.STEPS_PER_BEAT * Conductor.instance.beatsPerMeasure; } scrollAmount = targetScrollPosition - playheadPos; @@ -3312,21 +3371,21 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState if (playbarButtonPressed == 'playbarBack') { playbarButtonPressed = ''; - scrollAmount = -GRID_SIZE * 4 * Conductor.beatsPerMeasure; + scrollAmount = -GRID_SIZE * 4 * Conductor.instance.beatsPerMeasure; shouldPause = true; } // PAGE DOWN = Jump down to nearest measure if (pageDownKeyHandler.activated) { - var measureHeight:Float = GRID_SIZE * 4 * Conductor.beatsPerMeasure; + var measureHeight:Float = GRID_SIZE * 4 * Conductor.instance.beatsPerMeasure; var playheadPos:Float = scrollPositionInPixels + playheadPositionInPixels; var targetScrollPosition:Float = Math.ceil(playheadPos / measureHeight) * measureHeight; // If we would move less than one grid, instead move to the top of the next measure. var targetScrollAmount = Math.abs(targetScrollPosition - playheadPos); if (targetScrollAmount < GRID_SIZE) { - targetScrollPosition += GRID_SIZE * Constants.STEPS_PER_BEAT * Conductor.beatsPerMeasure; + targetScrollPosition += GRID_SIZE * Constants.STEPS_PER_BEAT * Conductor.instance.beatsPerMeasure; } scrollAmount = targetScrollPosition - playheadPos; @@ -3335,7 +3394,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState if (playbarButtonPressed == 'playbarForward') { playbarButtonPressed = ''; - scrollAmount = GRID_SIZE * 4 * Conductor.beatsPerMeasure; + scrollAmount = GRID_SIZE * 4 * Conductor.instance.beatsPerMeasure; shouldPause = true; } @@ -3538,10 +3597,10 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState // The song position of the cursor, in steps. var cursorFractionalStep:Float = cursorY / GRID_SIZE; - var cursorMs:Float = Conductor.getStepTimeInMs(cursorFractionalStep); + var cursorMs:Float = Conductor.instance.getStepTimeInMs(cursorFractionalStep); // Round the cursor step to the nearest snap quant. var cursorSnappedStep:Float = Math.floor(cursorFractionalStep / noteSnapRatio) * noteSnapRatio; - var cursorSnappedMs:Float = Conductor.getStepTimeInMs(cursorSnappedStep); + var cursorSnappedMs:Float = Conductor.instance.getStepTimeInMs(cursorSnappedStep); // The direction value for the column at the cursor. var cursorGridPos:Int = Math.floor(cursorX / GRID_SIZE); @@ -3563,7 +3622,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState // We released the mouse. Select the notes in the box. var cursorFractionalStepStart:Float = cursorYStart / GRID_SIZE; var cursorStepStart:Int = Math.floor(cursorFractionalStepStart); - var cursorMsStart:Float = Conductor.getStepTimeInMs(cursorStepStart); + var cursorMsStart:Float = Conductor.instance.getStepTimeInMs(cursorStepStart); var cursorColumnBase:Int = Math.floor(cursorX / GRID_SIZE); var cursorColumnBaseStart:Int = Math.floor(cursorXStart / GRID_SIZE); @@ -3799,11 +3858,11 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState var dragDistanceMs:Float = 0; if (dragTargetNote != null && dragTargetNote.noteData != null) { - dragDistanceMs = Conductor.getStepTimeInMs(dragTargetNote.noteData.getStepTime() + dragDistanceSteps) - dragTargetNote.noteData.time; + dragDistanceMs = Conductor.instance.getStepTimeInMs(dragTargetNote.noteData.getStepTime() + dragDistanceSteps) - dragTargetNote.noteData.time; } else if (dragTargetEvent != null && dragTargetEvent.eventData != null) { - dragDistanceMs = Conductor.getStepTimeInMs(dragTargetEvent.eventData.getStepTime() + dragDistanceSteps) - dragTargetEvent.eventData.time; + dragDistanceMs = Conductor.instance.getStepTimeInMs(dragTargetEvent.eventData.getStepTime() + dragDistanceSteps) - dragTargetEvent.eventData.time; } var dragDistanceColumns:Int = dragTargetCurrentColumn; @@ -3863,7 +3922,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState { stepTime = dragTargetEvent.eventData.getStepTime(); } - var dragDistanceSteps:Float = Conductor.getTimeInSteps(cursorSnappedMs).clamp(0, songLengthInSteps - (1 * noteSnapRatio)) - stepTime; + var dragDistanceSteps:Float = Conductor.instance.getTimeInSteps(cursorSnappedMs).clamp(0, songLengthInSteps - (1 * noteSnapRatio)) - stepTime; var data:Int = 0; var noteGridPos:Int = 0; if (dragTargetNote != null && dragTargetNote.noteData != null) @@ -3895,8 +3954,8 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState // Handle extending the note as you drag. var stepTime:Float = inline currentPlaceNoteData.getStepTime(); - var dragLengthSteps:Float = Conductor.getTimeInSteps(cursorSnappedMs) - stepTime; - var dragLengthMs:Float = dragLengthSteps * Conductor.stepLengthMs; + var dragLengthSteps:Float = Conductor.instance.getTimeInSteps(cursorSnappedMs) - stepTime; + var dragLengthMs:Float = dragLengthSteps * Conductor.instance.stepLengthMs; var dragLengthPixels:Float = dragLengthSteps * GRID_SIZE; if (gridGhostNote != null && gridGhostNote.noteData != null && gridGhostHoldNote != null) @@ -4051,7 +4110,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState } else { - // If we clicked and released outside the grid, do nothing. + // If we clicked and released outside the grid (or on HaxeUI), do nothing. } } @@ -4357,7 +4416,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState if (playbarHeadLayout.playbarHead.value != songPosPercent) playbarHeadLayout.playbarHead.value = songPosPercent; } - var songPos:Float = Conductor.songPosition + Conductor.instrumentalOffset; + var songPos:Float = Conductor.instance.songPosition + Conductor.instance.instrumentalOffset; var songPosSeconds:String = Std.string(Math.floor((Math.abs(songPos) / 1000) % 60)).lpad('0', 2); var songPosMinutes:String = Std.string(Math.floor((Math.abs(songPos) / 1000) / 60)).lpad('0', 2); if (songPos < 0) songPosMinutes = '-' + songPosMinutes; @@ -4373,8 +4432,8 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState if (playbarSongRemaining.value != songRemainingString) playbarSongRemaining.value = songRemainingString; playbarNoteSnap.text = '1/${noteSnapQuant}'; - playbarDifficulty.text = "Difficulty: " + selectedDifficulty.toTitleCase(); - playbarBPM.text = "BPM: " + Conductor.currentTimeChange.bpm; + playbarDifficulty.text = '${selectedDifficulty.toTitleCase()}'; + // playbarBPM.text = 'BPM: ${(Conductor.currentTimeChange?.bpm ?? 0.0)}'; } function handlePlayhead():Void @@ -4413,11 +4472,11 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState var playheadPos:Float = scrollPositionInPixels + playheadPositionInPixels; var playheadPosFractionalStep:Float = playheadPos / GRID_SIZE / noteSnapRatio; var playheadPosStep:Int = Std.int(Math.floor(playheadPosFractionalStep)); - var playheadPosSnappedMs:Float = playheadPosStep * Conductor.stepLengthMs * noteSnapRatio; + var playheadPosSnappedMs:Float = playheadPosStep * Conductor.instance.stepLengthMs * noteSnapRatio; // Look for notes within 1 step of the playhead. var notesAtPos:Array = SongDataUtils.getNotesInTimeRange(currentSongChartNoteData, playheadPosSnappedMs, - playheadPosSnappedMs + Conductor.stepLengthMs * noteSnapRatio); + playheadPosSnappedMs + Conductor.instance.stepLengthMs * noteSnapRatio); notesAtPos = SongDataUtils.getNotesWithData(notesAtPos, [column]); if (notesAtPos.length == 0) @@ -4616,9 +4675,9 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState else { var targetMs:Float = scrollPositionInMs + playheadPositionInMs; - var targetStep:Float = Conductor.getTimeInSteps(targetMs); + var targetStep:Float = Conductor.instance.getTimeInSteps(targetMs); var targetSnappedStep:Float = Math.floor(targetStep / noteSnapRatio) * noteSnapRatio; - var targetSnappedMs:Float = Conductor.getStepTimeInMs(targetSnappedStep); + var targetSnappedMs:Float = Conductor.instance.getStepTimeInMs(targetSnappedStep); targetSnappedMs; } performCommand(new PasteItemsCommand(targetMs)); @@ -4731,16 +4790,16 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState { super.handleQuickWatch(); - FlxG.watch.addQuick('musicTime', audioInstTrack?.time ?? 0.0); + FlxG.watch.addQuick('musicTime', audioInstTrack?.time); FlxG.watch.addQuick('scrollPosInPixels', scrollPositionInPixels); FlxG.watch.addQuick('playheadPosInPixels', playheadPositionInPixels); - FlxG.watch.addQuick("tapNotesRendered", renderedNotes.members.length); - FlxG.watch.addQuick("holdNotesRendered", renderedHoldNotes.members.length); - FlxG.watch.addQuick("eventsRendered", renderedEvents.members.length); - FlxG.watch.addQuick("notesSelected", currentNoteSelection.length); - FlxG.watch.addQuick("eventsSelected", currentEventSelection.length); + FlxG.watch.addQuick("tapNotesRendered", renderedNotes?.members?.length); + FlxG.watch.addQuick("holdNotesRendered", renderedHoldNotes?.members?.length); + FlxG.watch.addQuick("eventsRendered", renderedEvents?.members?.length); + FlxG.watch.addQuick("notesSelected", currentNoteSelection?.length); + FlxG.watch.addQuick("eventsSelected", currentEventSelection?.length); } function handlePostUpdate():Void @@ -4758,7 +4817,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState */ function testSongInPlayState(minimal:Bool = false):Void { - autoSave(); + autoSave(true); stopWelcomeMusic(); @@ -4776,6 +4835,9 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState return; } + LogStyle.WARNING.openConsole = enabledDebuggerPopup; + LogStyle.ERROR.openConsole = enabledDebuggerPopup; + // TODO: Rework asset system so we can remove this. switch (currentSongStage) { @@ -4959,7 +5021,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState // Remove any notes past the end of the song. var songCutoffPointSteps:Float = songLengthInSteps - 0.1; - var songCutoffPointMs:Float = Conductor.getStepTimeInMs(songCutoffPointSteps); + var songCutoffPointMs:Float = Conductor.instance.getStepTimeInMs(songCutoffPointSteps); currentSongChartNoteData = SongDataUtils.clampSongNoteData(currentSongChartNoteData, 0.0, songCutoffPointMs); currentSongChartEventData = SongDataUtils.clampSongEventData(currentSongChartEventData, 0.0, songCutoffPointMs); @@ -5061,7 +5123,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState var prevDifficulty = availableDifficulties[availableDifficulties.length - 1]; selectedDifficulty = prevDifficulty; - Conductor.mapTimeChanges(this.currentSongMetadata.timeChanges); + Conductor.instance.mapTimeChanges(this.currentSongMetadata.timeChanges); refreshDifficultyTreeSelection(); this.refreshToolbox(CHART_EDITOR_TOOLBOX_METADATA_LAYOUT); @@ -5105,7 +5167,8 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState } } - this.success('Switch Difficulty', 'Switched difficulty to ${selectedDifficulty.toTitleCase()}'); + // Removed this notification because you can see your difficulty in the playbar now. + // this.success('Switch Difficulty', 'Switched difficulty to ${selectedDifficulty.toTitleCase()}'); } /** @@ -5122,9 +5185,9 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState // Update the songPosition in the audio tracks. if (audioInstTrack != null) { - audioInstTrack.time = scrollPositionInMs + playheadPositionInMs - Conductor.instrumentalOffset; + audioInstTrack.time = scrollPositionInMs + playheadPositionInMs - Conductor.instance.instrumentalOffset; // Update the songPosition in the Conductor. - Conductor.update(audioInstTrack.time); + Conductor.instance.update(audioInstTrack.time); if (audioVocalTrackGroup != null) audioVocalTrackGroup.time = audioInstTrack.time; } @@ -5184,6 +5247,20 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState this.persistentUpdate = true; this.persistentDraw = true; + if (displayAutosavePopup) + { + displayAutosavePopup = false; + Toolkit.callLater(() -> { + var absoluteBackupsPath:String = Path.join([Sys.getCwd(), ChartEditorImportExportHandler.BACKUPS_PATH]); + this.infoWithActions('Auto-Save', 'Chart auto-saved to ${absoluteBackupsPath}.', [ + { + text: "Take Me There", + callback: openBackupsFolder, + } + ]); + }); + } + moveSongToScrollPosition(); fadeInWelcomeMusic(7, 10); @@ -5305,6 +5382,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState // TODO: Only update the notes that have changed. notePreview.erase(); notePreview.addNotes(currentSongChartNoteData, Std.int(songLengthInMs)); + notePreview.addSelectedNotes(currentNoteSelection, Std.int(songLengthInMs)); notePreview.addEvents(currentSongChartEventData, Std.int(songLengthInMs)); } @@ -5442,7 +5520,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState trace('ERROR: Instrumental track is null!'); } - this.songLengthInMs = (audioInstTrack?.length ?? 1000.0) + Conductor.instrumentalOffset; + this.songLengthInMs = (audioInstTrack?.length ?? 1000.0) + Conductor.instance.instrumentalOffset; // Many things get reset when song length changes. healthIconsDirty = true; diff --git a/source/funkin/ui/debug/charting/commands/ChangeStartingBPMCommand.hx b/source/funkin/ui/debug/charting/commands/ChangeStartingBPMCommand.hx index d80dd7c38..ea821afa9 100644 --- a/source/funkin/ui/debug/charting/commands/ChangeStartingBPMCommand.hx +++ b/source/funkin/ui/debug/charting/commands/ChangeStartingBPMCommand.hx @@ -39,7 +39,7 @@ class ChangeStartingBPMCommand implements ChartEditorCommand state.notePreviewViewportBoundsDirty = true; state.scrollPositionInPixels = 0; - Conductor.mapTimeChanges(state.currentSongMetadata.timeChanges); + Conductor.instance.mapTimeChanges(state.currentSongMetadata.timeChanges); } public function undo(state:ChartEditorState):Void @@ -61,7 +61,7 @@ class ChangeStartingBPMCommand implements ChartEditorCommand state.notePreviewViewportBoundsDirty = true; state.scrollPositionInPixels = 0; - Conductor.mapTimeChanges(state.currentSongMetadata.timeChanges); + Conductor.instance.mapTimeChanges(state.currentSongMetadata.timeChanges); } public function toString():String diff --git a/source/funkin/ui/debug/charting/commands/MoveEventsCommand.hx b/source/funkin/ui/debug/charting/commands/MoveEventsCommand.hx index efe9c25d5..8331ed397 100644 --- a/source/funkin/ui/debug/charting/commands/MoveEventsCommand.hx +++ b/source/funkin/ui/debug/charting/commands/MoveEventsCommand.hx @@ -33,7 +33,7 @@ class MoveEventsCommand implements ChartEditorCommand { // Clone the notes to prevent editing from affecting the history. var resultEvent = event.clone(); - resultEvent.time = (resultEvent.time + offset).clamp(0, Conductor.getStepTimeInMs(state.songLengthInSteps - (1 * state.noteSnapRatio))); + resultEvent.time = (resultEvent.time + offset).clamp(0, Conductor.instance.getStepTimeInMs(state.songLengthInSteps - (1 * state.noteSnapRatio))); movedEvents.push(resultEvent); } diff --git a/source/funkin/ui/debug/charting/commands/MoveItemsCommand.hx b/source/funkin/ui/debug/charting/commands/MoveItemsCommand.hx index 53090a6cc..9fac8a0c4 100644 --- a/source/funkin/ui/debug/charting/commands/MoveItemsCommand.hx +++ b/source/funkin/ui/debug/charting/commands/MoveItemsCommand.hx @@ -41,7 +41,7 @@ class MoveItemsCommand implements ChartEditorCommand { // Clone the notes to prevent editing from affecting the history. var resultNote = note.clone(); - resultNote.time = (resultNote.time + offset).clamp(0, Conductor.getStepTimeInMs(state.songLengthInSteps - (1 * state.noteSnapRatio))); + resultNote.time = (resultNote.time + offset).clamp(0, Conductor.instance.getStepTimeInMs(state.songLengthInSteps - (1 * state.noteSnapRatio))); resultNote.data = ChartEditorState.gridColumnToNoteData((ChartEditorState.noteDataToGridColumn(resultNote.data) + columns).clamp(0, ChartEditorState.STRUMLINE_SIZE * 2 - 1)); @@ -52,7 +52,7 @@ class MoveItemsCommand implements ChartEditorCommand { // Clone the notes to prevent editing from affecting the history. var resultEvent = event.clone(); - resultEvent.time = (resultEvent.time + offset).clamp(0, Conductor.getStepTimeInMs(state.songLengthInSteps - (1 * state.noteSnapRatio))); + resultEvent.time = (resultEvent.time + offset).clamp(0, Conductor.instance.getStepTimeInMs(state.songLengthInSteps - (1 * state.noteSnapRatio))); movedEvents.push(resultEvent); } diff --git a/source/funkin/ui/debug/charting/commands/MoveNotesCommand.hx b/source/funkin/ui/debug/charting/commands/MoveNotesCommand.hx index 8bce747a1..0308d8fc8 100644 --- a/source/funkin/ui/debug/charting/commands/MoveNotesCommand.hx +++ b/source/funkin/ui/debug/charting/commands/MoveNotesCommand.hx @@ -34,7 +34,7 @@ class MoveNotesCommand implements ChartEditorCommand { // Clone the notes to prevent editing from affecting the history. var resultNote = note.clone(); - resultNote.time = (resultNote.time + offset).clamp(0, Conductor.getStepTimeInMs(state.songLengthInSteps - (1 * state.noteSnapRatio))); + resultNote.time = (resultNote.time + offset).clamp(0, Conductor.instance.getStepTimeInMs(state.songLengthInSteps - (1 * state.noteSnapRatio))); resultNote.data = ChartEditorState.gridColumnToNoteData((ChartEditorState.noteDataToGridColumn(resultNote.data) + columns).clamp(0, ChartEditorState.STRUMLINE_SIZE * 2 - 1)); diff --git a/source/funkin/ui/debug/charting/commands/PasteItemsCommand.hx b/source/funkin/ui/debug/charting/commands/PasteItemsCommand.hx index 75382da41..7e40bc49b 100644 --- a/source/funkin/ui/debug/charting/commands/PasteItemsCommand.hx +++ b/source/funkin/ui/debug/charting/commands/PasteItemsCommand.hx @@ -32,9 +32,9 @@ class PasteItemsCommand implements ChartEditorCommand return; } - var stepEndOfSong:Float = Conductor.getTimeInSteps(state.songLengthInMs); + var stepEndOfSong:Float = Conductor.instance.getTimeInSteps(state.songLengthInMs); var stepCutoff:Float = stepEndOfSong - 1.0; - var msCutoff:Float = Conductor.getStepTimeInMs(stepCutoff); + var msCutoff:Float = Conductor.instance.getStepTimeInMs(stepCutoff); addedNotes = SongDataUtils.offsetSongNoteData(currentClipboard.notes, Std.int(targetTimestamp)); addedNotes = SongDataUtils.clampSongNoteData(addedNotes, 0.0, msCutoff); diff --git a/source/funkin/ui/debug/charting/components/ChartEditorNotePreview.hx b/source/funkin/ui/debug/charting/components/ChartEditorNotePreview.hx index 09c99531d..598cbb544 100644 --- a/source/funkin/ui/debug/charting/components/ChartEditorNotePreview.hx +++ b/source/funkin/ui/debug/charting/components/ChartEditorNotePreview.hx @@ -80,11 +80,24 @@ class ChartEditorNotePreview extends FlxSprite * @param notes The data for the notes. * @param songLengthInMs The total length of the song in milliseconds. */ - public function addNotes(notes:Array, songLengthInMs:Int, ?isSelection:Bool = false):Void + public function addNotes(notes:Array, songLengthInMs:Int):Void { for (note in notes) { - addNote(note, songLengthInMs, isSelection); + addNote(note, songLengthInMs, false); + } + } + + /** + * Add an array of selected notes to the preview. + * @param notes The data for the notes. + * @param songLengthInMs The total length of the song in milliseconds. + */ + public function addSelectedNotes(notes:Array, songLengthInMs:Int):Void + { + for (note in notes) + { + addNote(note, songLengthInMs, true); } } diff --git a/source/funkin/ui/debug/charting/dialogs/ChartEditorAboutDialog.hx b/source/funkin/ui/debug/charting/dialogs/ChartEditorAboutDialog.hx index e6f57c49f..8b55be540 100644 --- a/source/funkin/ui/debug/charting/dialogs/ChartEditorAboutDialog.hx +++ b/source/funkin/ui/debug/charting/dialogs/ChartEditorAboutDialog.hx @@ -5,14 +5,14 @@ import funkin.ui.debug.charting.dialogs.ChartEditorBaseDialog.DialogParams; @:build(haxe.ui.ComponentBuilder.build("assets/exclude/data/ui/chart-editor/dialogs/about.xml")) class ChartEditorAboutDialog extends ChartEditorBaseDialog { - public function new(state2:ChartEditorState, params2:DialogParams) + public function new(chartEditorState2:ChartEditorState, params2:DialogParams) { - super(state2, params2); + super(chartEditorState2, params2); } - public static function build(state:ChartEditorState, ?closable:Bool, ?modal:Bool):ChartEditorAboutDialog + public static function build(chartEditorState:ChartEditorState, ?closable:Bool, ?modal:Bool):ChartEditorAboutDialog { - var dialog = new ChartEditorAboutDialog(state, + var dialog = new ChartEditorAboutDialog(chartEditorState, { closable: closable ?? true, modal: modal ?? true diff --git a/source/funkin/ui/debug/charting/dialogs/ChartEditorBaseDialog.hx b/source/funkin/ui/debug/charting/dialogs/ChartEditorBaseDialog.hx index 6f76e543e..5b7cb15e1 100644 --- a/source/funkin/ui/debug/charting/dialogs/ChartEditorBaseDialog.hx +++ b/source/funkin/ui/debug/charting/dialogs/ChartEditorBaseDialog.hx @@ -11,16 +11,16 @@ import haxe.ui.core.Component; @:access(funkin.ui.debug.charting.ChartEditorState) class ChartEditorBaseDialog extends Dialog { - var state:ChartEditorState; + var chartEditorState:ChartEditorState; var params:DialogParams; var locked:Bool = false; - public function new(state:ChartEditorState, params:DialogParams) + public function new(chartEditorState:ChartEditorState, params:DialogParams) { super(); - this.state = state; + this.chartEditorState = chartEditorState; this.params = params; this.destroyOnClose = true; @@ -47,7 +47,7 @@ class ChartEditorBaseDialog extends Dialog */ public function onClose(event:DialogEvent):Void { - state.isHaxeUIDialogOpen = false; + chartEditorState.isHaxeUIDialogOpen = false; } /** diff --git a/source/funkin/ui/debug/charting/dialogs/ChartEditorBaseMenu.hx b/source/funkin/ui/debug/charting/dialogs/ChartEditorBaseMenu.hx index cb4cb447b..19ca2535c 100644 --- a/source/funkin/ui/debug/charting/dialogs/ChartEditorBaseMenu.hx +++ b/source/funkin/ui/debug/charting/dialogs/ChartEditorBaseMenu.hx @@ -11,13 +11,13 @@ import haxe.ui.containers.menus.Menu; @:access(funkin.ui.debug.charting.ChartEditorState) class ChartEditorBaseMenu extends Menu { - var state:ChartEditorState; + var chartEditorState:ChartEditorState; - public function new(state:ChartEditorState) + public function new(chartEditorState:ChartEditorState) { super(); - this.state = state; + this.chartEditorState = chartEditorState; // this.destroyOnClose = true; } diff --git a/source/funkin/ui/debug/charting/dialogs/ChartEditorCharacterIconSelectorMenu.hx b/source/funkin/ui/debug/charting/dialogs/ChartEditorCharacterIconSelectorMenu.hx index d7e9c259b..eb60cb6db 100644 --- a/source/funkin/ui/debug/charting/dialogs/ChartEditorCharacterIconSelectorMenu.hx +++ b/source/funkin/ui/debug/charting/dialogs/ChartEditorCharacterIconSelectorMenu.hx @@ -24,9 +24,9 @@ class ChartEditorCharacterIconSelectorMenu extends ChartEditorBaseMenu public var charSelectScroll:ScrollView; public var charIconName:Label; - public function new(state2:ChartEditorState, charType:CharacterType, lockPosition:Bool = false) + public function new(chartEditorState2:ChartEditorState, charType:CharacterType, lockPosition:Bool = false) { - super(state2); + super(chartEditorState2); initialize(charType, lockPosition); this.alpha = 0; @@ -38,17 +38,17 @@ class ChartEditorCharacterIconSelectorMenu extends ChartEditorBaseMenu { var currentCharId:String = switch (charType) { - case BF: state.currentSongMetadata.playData.characters.player; - case GF: state.currentSongMetadata.playData.characters.girlfriend; - case DAD: state.currentSongMetadata.playData.characters.opponent; + case BF: chartEditorState.currentSongMetadata.playData.characters.player; + case GF: chartEditorState.currentSongMetadata.playData.characters.girlfriend; + case DAD: chartEditorState.currentSongMetadata.playData.characters.opponent; default: throw 'Invalid charType: ' + charType; }; // Position this menu. var targetHealthIcon:Null = switch (charType) { - case BF: state.healthIconBF; - case DAD: state.healthIconDad; + case BF: chartEditorState.healthIconBF; + case DAD: chartEditorState.healthIconDad; default: null; }; @@ -101,14 +101,14 @@ class ChartEditorCharacterIconSelectorMenu extends ChartEditorBaseMenu charButton.onClick = _ -> { switch (charType) { - case BF: state.currentSongMetadata.playData.characters.player = charId; - case GF: state.currentSongMetadata.playData.characters.girlfriend = charId; - case DAD: state.currentSongMetadata.playData.characters.opponent = charId; + case BF: chartEditorState.currentSongMetadata.playData.characters.player = charId; + case GF: chartEditorState.currentSongMetadata.playData.characters.girlfriend = charId; + case DAD: chartEditorState.currentSongMetadata.playData.characters.opponent = charId; default: throw 'Invalid charType: ' + charType; }; - state.healthIconsDirty = true; - state.refreshToolbox(ChartEditorState.CHART_EDITOR_TOOLBOX_METADATA_LAYOUT); + chartEditorState.healthIconsDirty = true; + chartEditorState.refreshToolbox(ChartEditorState.CHART_EDITOR_TOOLBOX_METADATA_LAYOUT); }; charButton.onMouseOver = _ -> { @@ -123,9 +123,9 @@ class ChartEditorCharacterIconSelectorMenu extends ChartEditorBaseMenu charIconName.text = defaultText; } - public static function build(state2:ChartEditorState, charType:CharacterType, lockPosition:Bool = false):ChartEditorCharacterIconSelectorMenu + public static function build(chartEditorState:ChartEditorState, charType:CharacterType, lockPosition:Bool = false):ChartEditorCharacterIconSelectorMenu { - var menu = new ChartEditorCharacterIconSelectorMenu(state2, charType, lockPosition); + var menu = new ChartEditorCharacterIconSelectorMenu(chartEditorState, charType, lockPosition); Screen.instance.addComponent(menu); diff --git a/source/funkin/ui/debug/charting/dialogs/ChartEditorUploadChartDialog.hx b/source/funkin/ui/debug/charting/dialogs/ChartEditorUploadChartDialog.hx index 4b7a950be..5b84148c6 100644 --- a/source/funkin/ui/debug/charting/dialogs/ChartEditorUploadChartDialog.hx +++ b/source/funkin/ui/debug/charting/dialogs/ChartEditorUploadChartDialog.hx @@ -64,12 +64,12 @@ class ChartEditorUploadChartDialog extends ChartEditorBaseDialog if (event.button != DialogButton.APPLY && !this.closable) { // User cancelled the wizard! Back to the welcome dialog. - state.openWelcomeDialog(this.closable); + chartEditorState.openWelcomeDialog(this.closable); } for (dropTarget in dropHandlers) { - state.removeDropHandler(dropTarget); + chartEditorState.removeDropHandler(dropTarget); } } @@ -111,20 +111,21 @@ class ChartEditorUploadChartDialog extends ChartEditorBaseDialog try { - var result:Null> = ChartEditorImportExportHandler.loadFromFNFCPath(state, path.toString()); + var result:Null> = ChartEditorImportExportHandler.loadFromFNFCPath(chartEditorState, path.toString()); if (result != null) { - state.success('Loaded Chart', result.length == 0 ? 'Loaded chart (${path.toString()})' : 'Loaded chart (${path.toString()})\n${result.join("\n")}'); + chartEditorState.success('Loaded Chart', + result.length == 0 ? 'Loaded chart (${path.toString()})' : 'Loaded chart (${path.toString()})\n${result.join("\n")}'); this.hideDialog(DialogButton.APPLY); } else { - state.failure('Failed to Load Chart', 'Failed to load chart (${path.toString()})'); + chartEditorState.failure('Failed to Load Chart', 'Failed to load chart (${path.toString()})'); } } catch (err) { - state.failure('Failed to Load Chart', 'Failed to load chart (${path.toString()}): ${err}'); + chartEditorState.failure('Failed to Load Chart', 'Failed to load chart (${path.toString()}): ${err}'); } } @@ -139,19 +140,19 @@ class ChartEditorUploadChartDialog extends ChartEditorBaseDialog { try { - var result:Null> = ChartEditorImportExportHandler.loadFromFNFC(state, selectedFile.bytes); + var result:Null> = ChartEditorImportExportHandler.loadFromFNFC(chartEditorState, selectedFile.bytes); if (result != null) { - state.success('Loaded Chart', + chartEditorState.success('Loaded Chart', result.length == 0 ? 'Loaded chart (${selectedFile.name})' : 'Loaded chart (${selectedFile.name})\n${result.join("\n")}'); - if (selectedFile.fullPath != null) state.currentWorkingFilePath = selectedFile.fullPath; + if (selectedFile.fullPath != null) chartEditorState.currentWorkingFilePath = selectedFile.fullPath; this.hideDialog(DialogButton.APPLY); } } catch (err) { - state.failure('Failed to Load Chart', 'Failed to load chart (${selectedFile.name}): ${err}'); + chartEditorState.failure('Failed to Load Chart', 'Failed to load chart (${selectedFile.name}): ${err}'); } } } diff --git a/source/funkin/ui/debug/charting/dialogs/ChartEditorWelcomeDialog.hx b/source/funkin/ui/debug/charting/dialogs/ChartEditorWelcomeDialog.hx index 2a30c7d9e..7539b9725 100644 --- a/source/funkin/ui/debug/charting/dialogs/ChartEditorWelcomeDialog.hx +++ b/source/funkin/ui/debug/charting/dialogs/ChartEditorWelcomeDialog.hx @@ -41,26 +41,26 @@ class ChartEditorWelcomeDialog extends ChartEditorBaseDialog // Add items to the Recent Charts list #if sys - for (chartPath in state.previousWorkingFilePaths) + for (chartPath in chartEditorState.previousWorkingFilePaths) { if (chartPath == null) continue; - this.addRecentFilePath(state, chartPath); + this.addRecentFilePath(chartEditorState, chartPath); } #else this.addHTML5RecentFileMessage(); #end // Add items to the Load From Template list - this.buildTemplateSongList(state); + this.buildTemplateSongList(chartEditorState); } /** * @param state The current state of the chart editor. * @return A newly created `ChartEditorWelcomeDialog`. */ - public static function build(state:ChartEditorState, ?closable:Bool, ?modal:Bool):ChartEditorWelcomeDialog + public static function build(chartEditorState:ChartEditorState, ?closable:Bool, ?modal:Bool):ChartEditorWelcomeDialog { - var dialog = new ChartEditorWelcomeDialog(state, + var dialog = new ChartEditorWelcomeDialog(chartEditorState, { closable: closable ?? false, modal: modal ?? true @@ -102,12 +102,12 @@ class ChartEditorWelcomeDialog extends ChartEditorBaseDialog var result:Null> = ChartEditorImportExportHandler.loadFromFNFCPath(state, chartPath); if (result != null) { - state.success('Loaded Chart', + chartEditorState.success('Loaded Chart', result.length == 0 ? 'Loaded chart (${chartPath.toString()})' : 'Loaded chart (${chartPath.toString()})\n${result.join("\n")}'); } else { - state.error('Failed to Load Chart', 'Failed to load chart (${chartPath.toString()})'); + chartEditorState.error('Failed to Load Chart', 'Failed to load chart (${chartPath.toString()})'); } } @@ -157,7 +157,7 @@ class ChartEditorWelcomeDialog extends ChartEditorBaseDialog this.hideDialog(DialogButton.CANCEL); // Load song from template - state.loadSongAsTemplate(targetSongId); + chartEditorState.loadSongAsTemplate(targetSongId); }); } } @@ -184,7 +184,7 @@ class ChartEditorWelcomeDialog extends ChartEditorBaseDialog this.hideDialog(DialogButton.CANCEL); // Open the "Open Chart" dialog - state.openBrowseFNFC(false); + chartEditorState.openBrowseFNFC(false); } /** @@ -199,7 +199,7 @@ class ChartEditorWelcomeDialog extends ChartEditorBaseDialog // // Create Song Wizard // - state.openCreateSongWizardBasicOnly(false); + chartEditorState.openCreateSongWizardBasicOnly(false); } /** @@ -214,7 +214,7 @@ class ChartEditorWelcomeDialog extends ChartEditorBaseDialog // // Create Song Wizard // - state.openCreateSongWizardErectOnly(false); + chartEditorState.openCreateSongWizardErectOnly(false); } /** @@ -229,7 +229,7 @@ class ChartEditorWelcomeDialog extends ChartEditorBaseDialog // // Create Song Wizard // - state.openCreateSongWizardBasicErect(false); + chartEditorState.openCreateSongWizardBasicErect(false); } /** @@ -242,6 +242,6 @@ class ChartEditorWelcomeDialog extends ChartEditorBaseDialog this.hideDialog(DialogButton.CANCEL); // Open the "Import Chart" dialog - state.openImportChartWizard('legacy', false); + chartEditorState.openImportChartWizard('legacy', false); } } diff --git a/source/funkin/ui/debug/charting/handlers/ChartEditorAudioHandler.hx b/source/funkin/ui/debug/charting/handlers/ChartEditorAudioHandler.hx index 272291a94..2ef3fd683 100644 --- a/source/funkin/ui/debug/charting/handlers/ChartEditorAudioHandler.hx +++ b/source/funkin/ui/debug/charting/handlers/ChartEditorAudioHandler.hx @@ -28,11 +28,11 @@ class ChartEditorAudioHandler * @param instId The instrumental this vocal track will be for. * @return Success or failure. */ - public static function loadVocalsFromPath(state:ChartEditorState, path:Path, charId:String, instId:String = ''):Bool + public static function loadVocalsFromPath(state:ChartEditorState, path:Path, charId:String, instId:String = '', wipeFirst:Bool = false):Bool { #if sys var fileBytes:Bytes = sys.io.File.getBytes(path.toString()); - return loadVocalsFromBytes(state, fileBytes, charId, instId); + return loadVocalsFromBytes(state, fileBytes, charId, instId, wipeFirst); #else trace("[WARN] This platform can't load audio from a file path, you'll need to fetch the bytes some other way."); return false; @@ -47,12 +47,12 @@ class ChartEditorAudioHandler * @param instId The instrumental this vocal track will be for. * @return Success or failure. */ - public static function loadVocalsFromAsset(state:ChartEditorState, path:String, charId:String, instId:String = ''):Bool + public static function loadVocalsFromAsset(state:ChartEditorState, path:String, charId:String, instId:String = '', wipeFirst:Bool = false):Bool { var trackData:Null = Assets.getBytes(path); if (trackData != null) { - return loadVocalsFromBytes(state, trackData, charId, instId); + return loadVocalsFromBytes(state, trackData, charId, instId, wipeFirst); } return false; } @@ -63,10 +63,12 @@ class ChartEditorAudioHandler * @param bytes The audio byte data. * @param charId The character this vocal track will be for. * @param instId The instrumental this vocal track will be for. + * @param wipeFirst Whether to wipe the existing vocal data before loading. */ - public static function loadVocalsFromBytes(state:ChartEditorState, bytes:Bytes, charId:String, instId:String = ''):Bool + public static function loadVocalsFromBytes(state:ChartEditorState, bytes:Bytes, charId:String, instId:String = '', wipeFirst:Bool = false):Bool { var trackId:String = '${charId}${instId == '' ? '' : '-${instId}'}'; + if (wipeFirst) wipeVocalData(state); state.audioVocalTrackData.set(trackId, bytes); return true; } @@ -78,11 +80,11 @@ class ChartEditorAudioHandler * @param instId The instrumental this vocal track will be for. * @return Success or failure. */ - public static function loadInstFromPath(state:ChartEditorState, path:Path, instId:String = ''):Bool + public static function loadInstFromPath(state:ChartEditorState, path:Path, instId:String = '', wipeFirst:Bool = false):Bool { #if sys var fileBytes:Bytes = sys.io.File.getBytes(path.toString()); - return loadInstFromBytes(state, fileBytes, instId); + return loadInstFromBytes(state, fileBytes, instId, wipeFirst); #else trace("[WARN] This platform can't load audio from a file path, you'll need to fetch the bytes some other way."); return false; @@ -96,12 +98,12 @@ class ChartEditorAudioHandler * @param instId The instrumental this vocal track will be for. * @return Success or failure. */ - public static function loadInstFromAsset(state:ChartEditorState, path:String, instId:String = ''):Bool + public static function loadInstFromAsset(state:ChartEditorState, path:String, instId:String = '', wipeFirst:Bool = false):Bool { var trackData:Null = Assets.getBytes(path); if (trackData != null) { - return loadInstFromBytes(state, trackData, instId); + return loadInstFromBytes(state, trackData, instId, wipeFirst); } return false; } @@ -113,9 +115,10 @@ class ChartEditorAudioHandler * @param charId The character this vocal track will be for. * @param instId The instrumental this vocal track will be for. */ - public static function loadInstFromBytes(state:ChartEditorState, bytes:Bytes, instId:String = ''):Bool + public static function loadInstFromBytes(state:ChartEditorState, bytes:Bytes, instId:String = '', wipeFirst:Bool = false):Bool { if (instId == '') instId = 'default'; + if (wipeFirst) wipeInstrumentalData(state); state.audioInstTrackData.set(instId, bytes); return true; } @@ -127,9 +130,9 @@ class ChartEditorAudioHandler stopExistingVocals(state); result = playVocals(state, BF, playerId, instId); - if (!result) return false; + // if (!result) return false; result = playVocals(state, DAD, opponentId, instId); - if (!result) return false; + // if (!result) return false; return true; } @@ -182,7 +185,7 @@ class ChartEditorAudioHandler state.audioVocalTrackGroup.addPlayerVoice(vocalTrack); state.audioVisGroup.addPlayerVis(vocalTrack); state.audioVisGroup.playerVis.x = 885; - state.audioVisGroup.playerVis.realtimeVisLenght = Conductor.getStepTimeInMs(16) * 0.00195; + state.audioVisGroup.playerVis.realtimeVisLenght = Conductor.instance.getStepTimeInMs(16) * 0.00195; state.audioVisGroup.playerVis.daHeight = (ChartEditorState.GRID_SIZE) * 16; state.audioVisGroup.playerVis.detail = 1; @@ -193,7 +196,7 @@ class ChartEditorAudioHandler state.audioVisGroup.addOpponentVis(vocalTrack); state.audioVisGroup.opponentVis.x = 435; - state.audioVisGroup.opponentVis.realtimeVisLenght = Conductor.getStepTimeInMs(16) * 0.00195; + state.audioVisGroup.opponentVis.realtimeVisLenght = Conductor.instance.getStepTimeInMs(16) * 0.00195; state.audioVisGroup.opponentVis.daHeight = (ChartEditorState.GRID_SIZE) * 16; state.audioVisGroup.opponentVis.detail = 1; diff --git a/source/funkin/ui/debug/charting/handlers/ChartEditorDialogHandler.hx b/source/funkin/ui/debug/charting/handlers/ChartEditorDialogHandler.hx index 666b3656c..1d53dfebd 100644 --- a/source/funkin/ui/debug/charting/handlers/ChartEditorDialogHandler.hx +++ b/source/funkin/ui/debug/charting/handlers/ChartEditorDialogHandler.hx @@ -684,8 +684,11 @@ class ChartEditorDialogHandler state.songMetadata.set(targetVariation, newSongMetadata); - Conductor.instrumentalOffset = state.currentInstrumentalOffset; // Loads from the metadata. - Conductor.mapTimeChanges(state.currentSongMetadata.timeChanges); + Conductor.instance.instrumentalOffset = state.currentInstrumentalOffset; // Loads from the metadata. + Conductor.instance.mapTimeChanges(state.currentSongMetadata.timeChanges); + + state.selectedVariation = Constants.DEFAULT_VARIATION; + state.selectedDifficulty = state.availableDifficulties[0]; state.difficultySelectDirty = true; @@ -755,14 +758,9 @@ class ChartEditorDialogHandler trace('Selected file: $pathStr'); var path:Path = new Path(pathStr); - if (!hasClearedVocals) + if (state.loadVocalsFromPath(path, charKey, instId, !hasClearedVocals)) { hasClearedVocals = true; - state.stopExistingVocals(); - } - - if (state.loadVocalsFromPath(path, charKey, instId)) - { // Tell the user the load was successful. state.success('Loaded Vocals', 'Loaded vocals for $charName (${path.file}.${path.ext}), variation ${state.selectedVariation}'); #if FILE_DROP_SUPPORTED @@ -796,13 +794,10 @@ class ChartEditorDialogHandler if (selectedFile != null && selectedFile.bytes != null) { trace('Selected file: ' + selectedFile.name); - if (!hasClearedVocals) + + if (state.loadVocalsFromBytes(selectedFile.bytes, charKey, instId, !hasClearedVocals)) { hasClearedVocals = true; - state.stopExistingVocals(); - } - if (state.loadVocalsFromBytes(selectedFile.bytes, charKey, instId)) - { // Tell the user the load was successful. state.success('Loaded Vocals', 'Loaded vocals for $charName (${selectedFile.name}), variation ${state.selectedVariation}'); diff --git a/source/funkin/ui/debug/charting/handlers/ChartEditorImportExportHandler.hx b/source/funkin/ui/debug/charting/handlers/ChartEditorImportExportHandler.hx index d8c893d4d..a38916c3b 100644 --- a/source/funkin/ui/debug/charting/handlers/ChartEditorImportExportHandler.hx +++ b/source/funkin/ui/debug/charting/handlers/ChartEditorImportExportHandler.hx @@ -115,9 +115,9 @@ class ChartEditorImportExportHandler state.songMetadata = newSongMetadata; state.songChartData = newSongChartData; - Conductor.forceBPM(null); // Disable the forced BPM. - Conductor.instrumentalOffset = state.currentInstrumentalOffset; // Loads from the metadata. - Conductor.mapTimeChanges(state.currentSongMetadata.timeChanges); + Conductor.instance.forceBPM(null); // Disable the forced BPM. + Conductor.instance.instrumentalOffset = state.currentInstrumentalOffset; // Loads from the metadata. + Conductor.instance.mapTimeChanges(state.currentSongMetadata.timeChanges); state.notePreviewDirty = true; state.notePreviewViewportBoundsDirty = true; @@ -316,6 +316,8 @@ class ChartEditorImportExportHandler public static function getLatestBackupPath():Null { #if sys + if (!sys.FileSystem.exists(BACKUPS_PATH)) sys.FileSystem.createDirectory(BACKUPS_PATH); + var entries:Array = sys.FileSystem.readDirectory(BACKUPS_PATH); entries.sort(SortUtil.alphabetically); @@ -414,16 +416,34 @@ class ChartEditorImportExportHandler ]); // We have to force write because the program will die before the save dialog is closed. trace('Force exporting to $targetPath...'); - FileUtil.saveFilesAsZIPToPath(zipEntries, targetPath, targetMode); - if (onSaveCb != null) onSaveCb(targetPath); + try + { + FileUtil.saveFilesAsZIPToPath(zipEntries, targetPath, targetMode); + // On success. + if (onSaveCb != null) onSaveCb(targetPath); + } + catch (e) + { + // On failure. + if (onCancelCb != null) onCancelCb(); + } } else { // Force write since we know what file the user wants to overwrite. trace('Force exporting to $targetPath...'); - FileUtil.saveFilesAsZIPToPath(zipEntries, targetPath, targetMode); - state.saveDataDirty = false; - if (onSaveCb != null) onSaveCb(targetPath); + try + { + // On success. + FileUtil.saveFilesAsZIPToPath(zipEntries, targetPath, targetMode); + state.saveDataDirty = false; + if (onSaveCb != null) onSaveCb(targetPath); + } + catch (e) + { + // On failure. + if (onCancelCb != null) onCancelCb(); + } } } else diff --git a/source/funkin/ui/debug/charting/handlers/ChartEditorThemeHandler.hx b/source/funkin/ui/debug/charting/handlers/ChartEditorThemeHandler.hx index 4197ebdd3..1625c53bc 100644 --- a/source/funkin/ui/debug/charting/handlers/ChartEditorThemeHandler.hx +++ b/source/funkin/ui/debug/charting/handlers/ChartEditorThemeHandler.hx @@ -125,7 +125,7 @@ class ChartEditorThemeHandler // 2 * (Strumline Size) + 1 grid squares wide, by (4 * quarter notes per measure) grid squares tall. // This gets reused to fill the screen. var gridWidth:Int = Std.int(ChartEditorState.GRID_SIZE * TOTAL_COLUMN_COUNT); - var gridHeight:Int = Std.int(ChartEditorState.GRID_SIZE * Conductor.stepsPerMeasure); + var gridHeight:Int = Std.int(ChartEditorState.GRID_SIZE * Conductor.instance.stepsPerMeasure); state.gridBitmap = FlxGridOverlay.createGrid(ChartEditorState.GRID_SIZE, ChartEditorState.GRID_SIZE, gridWidth, gridHeight, true, gridColor1, gridColor2); // Selection borders @@ -142,7 +142,7 @@ class ChartEditorThemeHandler selectionBorderColor); // Selection borders horizontally along the middle. - for (i in 1...(Conductor.stepsPerMeasure)) + for (i in 1...(Conductor.instance.stepsPerMeasure)) { state.gridBitmap.fillRect(new Rectangle(0, (ChartEditorState.GRID_SIZE * i) - (ChartEditorState.GRID_SELECTION_BORDER_WIDTH / 2), state.gridBitmap.width, ChartEditorState.GRID_SELECTION_BORDER_WIDTH), @@ -197,9 +197,9 @@ class ChartEditorThemeHandler }; // Selection borders horizontally in the middle. - for (i in 1...(Conductor.stepsPerMeasure)) + for (i in 1...(Conductor.instance.stepsPerMeasure)) { - if ((i % Conductor.beatsPerMeasure) == 0) + if ((i % Conductor.instance.beatsPerMeasure) == 0) { state.gridBitmap.fillRect(new Rectangle(0, (ChartEditorState.GRID_SIZE * i) - (GRID_BEAT_DIVIDER_WIDTH / 2), state.gridBitmap.width, GRID_BEAT_DIVIDER_WIDTH), diff --git a/source/funkin/ui/debug/charting/handlers/ChartEditorToolboxHandler.hx b/source/funkin/ui/debug/charting/handlers/ChartEditorToolboxHandler.hx index a9a9c375d..98d04887d 100644 --- a/source/funkin/ui/debug/charting/handlers/ChartEditorToolboxHandler.hx +++ b/source/funkin/ui/debug/charting/handlers/ChartEditorToolboxHandler.hx @@ -488,6 +488,16 @@ class ChartEditorToolboxHandler state.playtestStartTime = checkboxStartTime.selected; }; + var checkboxDebugger:Null = toolbox.findComponent('playtestDebuggerCheckbox', CheckBox); + + if (checkboxDebugger == null) throw 'ChartEditorToolboxHandler.buildToolboxPlaytestPropertiesLayout() - Could not find playtestDebuggerCheckbox component.'; + + state.enabledDebuggerPopup = checkboxDebugger.selected; + + checkboxDebugger.onClick = _ -> { + state.enabledDebuggerPopup = checkboxDebugger.selected; + }; + return toolbox; } diff --git a/source/funkin/ui/debug/charting/toolboxes/ChartEditorBaseToolbox.hx b/source/funkin/ui/debug/charting/toolboxes/ChartEditorBaseToolbox.hx index c4c532205..7df06c249 100644 --- a/source/funkin/ui/debug/charting/toolboxes/ChartEditorBaseToolbox.hx +++ b/source/funkin/ui/debug/charting/toolboxes/ChartEditorBaseToolbox.hx @@ -12,13 +12,13 @@ import haxe.ui.core.Component; @:access(funkin.ui.debug.charting.ChartEditorState) class ChartEditorBaseToolbox extends CollapsibleDialog { - var state:ChartEditorState; + var chartEditorState:ChartEditorState; - private function new(state:ChartEditorState) + private function new(chartEditorState:ChartEditorState) { super(); - this.state = state; + this.chartEditorState = chartEditorState; } /** diff --git a/source/funkin/ui/debug/charting/toolboxes/ChartEditorMetadataToolbox.hx b/source/funkin/ui/debug/charting/toolboxes/ChartEditorMetadataToolbox.hx index e0ee4aca3..700e5ec6a 100644 --- a/source/funkin/ui/debug/charting/toolboxes/ChartEditorMetadataToolbox.hx +++ b/source/funkin/ui/debug/charting/toolboxes/ChartEditorMetadataToolbox.hx @@ -40,9 +40,9 @@ class ChartEditorMetadataToolbox extends ChartEditorBaseToolbox var frameVariation:Frame; var frameDifficulty:Frame; - public function new(state2:ChartEditorState) + public function new(chartEditorState2:ChartEditorState) { - super(state2); + super(chartEditorState2); initialize(); @@ -51,7 +51,7 @@ class ChartEditorMetadataToolbox extends ChartEditorBaseToolbox function onClose(event:UIEvent) { - state.menubarItemToggleToolboxMetadata.selected = false; + chartEditorState.menubarItemToggleToolboxMetadata.selected = false; } function initialize():Void @@ -67,11 +67,11 @@ class ChartEditorMetadataToolbox extends ChartEditorBaseToolbox if (valid) { inputSongName.removeClass('invalid-value'); - state.currentSongMetadata.songName = event.target.text; + chartEditorState.currentSongMetadata.songName = event.target.text; } else { - state.currentSongMetadata.songName = ''; + chartEditorState.currentSongMetadata.songName = ''; } }; @@ -81,11 +81,11 @@ class ChartEditorMetadataToolbox extends ChartEditorBaseToolbox if (valid) { inputSongArtist.removeClass('invalid-value'); - state.currentSongMetadata.artist = event.target.text; + chartEditorState.currentSongMetadata.artist = event.target.text; } else { - state.currentSongMetadata.artist = ''; + chartEditorState.currentSongMetadata.artist = ''; } }; @@ -94,41 +94,41 @@ class ChartEditorMetadataToolbox extends ChartEditorBaseToolbox if (valid) { - state.currentSongMetadata.playData.stage = event.data.id; + chartEditorState.currentSongMetadata.playData.stage = event.data.id; } }; - var startingValueStage = ChartEditorDropdowns.populateDropdownWithStages(inputStage, state.currentSongMetadata.playData.stage); + var startingValueStage = ChartEditorDropdowns.populateDropdownWithStages(inputStage, chartEditorState.currentSongMetadata.playData.stage); inputStage.value = startingValueStage; inputNoteStyle.onChange = function(event:UIEvent) { if (event.data?.id == null) return; - state.currentSongNoteStyle = event.data.id; + chartEditorState.currentSongNoteStyle = event.data.id; }; inputBPM.onChange = function(event:UIEvent) { if (event.value == null || event.value <= 0) return; // Use a command so we can undo/redo this action. - var startingBPM = state.currentSongMetadata.timeChanges[0].bpm; + var startingBPM = chartEditorState.currentSongMetadata.timeChanges[0].bpm; if (event.value != startingBPM) { - state.performCommand(new ChangeStartingBPMCommand(event.value)); + chartEditorState.performCommand(new ChangeStartingBPMCommand(event.value)); } }; inputOffsetInst.onChange = function(event:UIEvent) { if (event.value == null) return; - state.currentInstrumentalOffset = event.value; - Conductor.instrumentalOffset = event.value; + chartEditorState.currentInstrumentalOffset = event.value; + Conductor.instance.instrumentalOffset = event.value; // Update song length. - state.songLengthInMs = (state.audioInstTrack?.length ?? 1000.0) + Conductor.instrumentalOffset; + chartEditorState.songLengthInMs = (chartEditorState.audioInstTrack?.length ?? 1000.0) + Conductor.instance.instrumentalOffset; }; inputOffsetVocal.onChange = function(event:UIEvent) { if (event.value == null) return; - state.currentSongMetadata.offsets.setVocalOffset(state.currentSongMetadata.playData.characters.player, event.value); + chartEditorState.currentSongMetadata.offsets.setVocalOffset(chartEditorState.currentSongMetadata.playData.characters.player, event.value); }; inputScrollSpeed.onChange = function(event:UIEvent) { var valid:Bool = event.target.value != null && event.target.value > 0; @@ -136,25 +136,25 @@ class ChartEditorMetadataToolbox extends ChartEditorBaseToolbox if (valid) { inputScrollSpeed.removeClass('invalid-value'); - state.currentSongChartScrollSpeed = event.target.value; + chartEditorState.currentSongChartScrollSpeed = event.target.value; } else { - state.currentSongChartScrollSpeed = 1.0; + chartEditorState.currentSongChartScrollSpeed = 1.0; } - labelScrollSpeed.text = 'Scroll Speed: ${state.currentSongChartScrollSpeed}x'; + labelScrollSpeed.text = 'Scroll Speed: ${chartEditorState.currentSongChartScrollSpeed}x'; }; buttonCharacterOpponent.onClick = function(_) { - state.openCharacterDropdown(CharacterType.DAD, false); + chartEditorState.openCharacterDropdown(CharacterType.DAD, false); }; buttonCharacterGirlfriend.onClick = function(_) { - state.openCharacterDropdown(CharacterType.GF, false); + chartEditorState.openCharacterDropdown(CharacterType.GF, false); }; buttonCharacterPlayer.onClick = function(_) { - state.openCharacterDropdown(CharacterType.BF, false); + chartEditorState.openCharacterDropdown(CharacterType.BF, false); }; refresh(); @@ -162,17 +162,17 @@ class ChartEditorMetadataToolbox extends ChartEditorBaseToolbox public override function refresh():Void { - inputSongName.value = state.currentSongMetadata.songName; - inputSongArtist.value = state.currentSongMetadata.artist; - inputStage.value = state.currentSongMetadata.playData.stage; - inputNoteStyle.value = state.currentSongMetadata.playData.noteStyle; - inputBPM.value = state.currentSongMetadata.timeChanges[0].bpm; - inputScrollSpeed.value = state.currentSongChartScrollSpeed; - labelScrollSpeed.text = 'Scroll Speed: ${state.currentSongChartScrollSpeed}x'; - frameVariation.text = 'Variation: ${state.selectedVariation.toTitleCase()}'; - frameDifficulty.text = 'Difficulty: ${state.selectedDifficulty.toTitleCase()}'; + inputSongName.value = chartEditorState.currentSongMetadata.songName; + inputSongArtist.value = chartEditorState.currentSongMetadata.artist; + inputStage.value = chartEditorState.currentSongMetadata.playData.stage; + inputNoteStyle.value = chartEditorState.currentSongMetadata.playData.noteStyle; + inputBPM.value = chartEditorState.currentSongMetadata.timeChanges[0].bpm; + inputScrollSpeed.value = chartEditorState.currentSongChartScrollSpeed; + labelScrollSpeed.text = 'Scroll Speed: ${chartEditorState.currentSongChartScrollSpeed}x'; + frameVariation.text = 'Variation: ${chartEditorState.selectedVariation.toTitleCase()}'; + frameDifficulty.text = 'Difficulty: ${chartEditorState.selectedDifficulty.toTitleCase()}'; - var stageId:String = state.currentSongMetadata.playData.stage; + var stageId:String = chartEditorState.currentSongMetadata.playData.stage; var stageData:Null = StageDataParser.parseStageData(stageId); if (inputStage != null) { @@ -183,21 +183,45 @@ class ChartEditorMetadataToolbox extends ChartEditorBaseToolbox var LIMIT = 6; - var charDataOpponent:CharacterData = CharacterDataParser.fetchCharacterData(state.currentSongMetadata.playData.characters.opponent); - buttonCharacterOpponent.icon = CharacterDataParser.getCharPixelIconAsset(state.currentSongMetadata.playData.characters.opponent); - buttonCharacterOpponent.text = charDataOpponent.name.length > LIMIT ? '${charDataOpponent.name.substr(0, LIMIT)}.' : '${charDataOpponent.name}'; + var charDataOpponent:Null = CharacterDataParser.fetchCharacterData(chartEditorState.currentSongMetadata.playData.characters.opponent); + if (charDataOpponent != null) + { + buttonCharacterOpponent.icon = CharacterDataParser.getCharPixelIconAsset(chartEditorState.currentSongMetadata.playData.characters.opponent); + buttonCharacterOpponent.text = charDataOpponent.name.length > LIMIT ? '${charDataOpponent.name.substr(0, LIMIT)}.' : '${charDataOpponent.name}'; + } + else + { + buttonCharacterOpponent.icon = null; + buttonCharacterOpponent.text = "None"; + } - var charDataGirlfriend:CharacterData = CharacterDataParser.fetchCharacterData(state.currentSongMetadata.playData.characters.girlfriend); - buttonCharacterGirlfriend.icon = CharacterDataParser.getCharPixelIconAsset(state.currentSongMetadata.playData.characters.girlfriend); - buttonCharacterGirlfriend.text = charDataGirlfriend.name.length > LIMIT ? '${charDataGirlfriend.name.substr(0, LIMIT)}.' : '${charDataGirlfriend.name}'; + var charDataGirlfriend:Null = CharacterDataParser.fetchCharacterData(chartEditorState.currentSongMetadata.playData.characters.girlfriend); + if (charDataGirlfriend != null) + { + buttonCharacterGirlfriend.icon = CharacterDataParser.getCharPixelIconAsset(chartEditorState.currentSongMetadata.playData.characters.girlfriend); + buttonCharacterGirlfriend.text = charDataGirlfriend.name.length > LIMIT ? '${charDataGirlfriend.name.substr(0, LIMIT)}.' : '${charDataGirlfriend.name}'; + } + else + { + buttonCharacterGirlfriend.icon = null; + buttonCharacterGirlfriend.text = "None"; + } - var charDataPlayer:CharacterData = CharacterDataParser.fetchCharacterData(state.currentSongMetadata.playData.characters.player); - buttonCharacterPlayer.icon = CharacterDataParser.getCharPixelIconAsset(state.currentSongMetadata.playData.characters.player); - buttonCharacterPlayer.text = charDataPlayer.name.length > LIMIT ? '${charDataPlayer.name.substr(0, LIMIT)}.' : '${charDataPlayer.name}'; + var charDataPlayer:Null = CharacterDataParser.fetchCharacterData(chartEditorState.currentSongMetadata.playData.characters.player); + if (charDataPlayer != null) + { + buttonCharacterPlayer.icon = CharacterDataParser.getCharPixelIconAsset(chartEditorState.currentSongMetadata.playData.characters.player); + buttonCharacterPlayer.text = charDataPlayer.name.length > LIMIT ? '${charDataPlayer.name.substr(0, LIMIT)}.' : '${charDataPlayer.name}'; + } + else + { + buttonCharacterPlayer.icon = null; + buttonCharacterPlayer.text = "None"; + } } - public static function build(state:ChartEditorState):ChartEditorMetadataToolbox + public static function build(chartEditorState:ChartEditorState):ChartEditorMetadataToolbox { - return new ChartEditorMetadataToolbox(state); + return new ChartEditorMetadataToolbox(chartEditorState); } } diff --git a/source/funkin/ui/debug/latency/LatencyState.hx b/source/funkin/ui/debug/latency/LatencyState.hx index 18b0010b2..70ef97fd0 100644 --- a/source/funkin/ui/debug/latency/LatencyState.hx +++ b/source/funkin/ui/debug/latency/LatencyState.hx @@ -75,7 +75,7 @@ class LatencyState extends MusicBeatSubState // funnyStatsGraph.hi - Conductor.forceBPM(60); + Conductor.instance.forceBPM(60); noteGrp = new FlxTypedGroup(); add(noteGrp); @@ -91,14 +91,14 @@ class LatencyState extends MusicBeatSubState // // musSpec.visType = FREQUENCIES; // add(musSpec); - for (beat in 0...Math.floor(FlxG.sound.music.length / Conductor.beatLengthMs)) + for (beat in 0...Math.floor(FlxG.sound.music.length / Conductor.instance.beatLengthMs)) { - var beatTick:FlxSprite = new FlxSprite(songPosToX(beat * Conductor.beatLengthMs), FlxG.height - 15); + var beatTick:FlxSprite = new FlxSprite(songPosToX(beat * Conductor.instance.beatLengthMs), FlxG.height - 15); beatTick.makeGraphic(2, 15); beatTick.alpha = 0.3; add(beatTick); - var offsetTxt:FlxText = new FlxText(songPosToX(beat * Conductor.beatLengthMs), FlxG.height - 26, 0, "swag"); + var offsetTxt:FlxText = new FlxText(songPosToX(beat * Conductor.instance.beatLengthMs), FlxG.height - 26, 0, "swag"); offsetTxt.alpha = 0.5; diffGrp.add(offsetTxt); @@ -130,7 +130,7 @@ class LatencyState extends MusicBeatSubState for (i in 0...32) { - var note:NoteSprite = new NoteSprite(NoteStyleRegistry.instance.fetchDefault(), Conductor.beatLengthMs * i); + var note:NoteSprite = new NoteSprite(NoteStyleRegistry.instance.fetchDefault(), Conductor.instance.beatLengthMs * i); noteGrp.add(note); } @@ -146,9 +146,9 @@ class LatencyState extends MusicBeatSubState override function stepHit():Bool { - if (Conductor.currentStep % 4 == 2) + if (Conductor.instance.currentStep % 4 == 2) { - blocks.members[((Conductor.currentBeat % 8) + 1) % 8].alpha = 0.5; + blocks.members[((Conductor.instance.currentBeat % 8) + 1) % 8].alpha = 0.5; } return super.stepHit(); @@ -156,11 +156,11 @@ class LatencyState extends MusicBeatSubState override function beatHit():Bool { - if (Conductor.currentBeat % 8 == 0) blocks.forEach(blok -> { + if (Conductor.instance.currentBeat % 8 == 0) blocks.forEach(blok -> { blok.alpha = 0; }); - blocks.members[Conductor.currentBeat % 8].alpha = 1; + blocks.members[Conductor.instance.currentBeat % 8].alpha = 1; // block.visible = !block.visible; return super.beatHit(); @@ -192,17 +192,17 @@ class LatencyState extends MusicBeatSubState if (FlxG.keys.pressed.D) FlxG.sound.music.time += 1000 * FlxG.elapsed; - Conductor.update(swagSong.getTimeWithDiff() - Conductor.inputOffset); - // Conductor.songPosition += (Timer.stamp() * 1000) - FlxG.sound.music.prevTimestamp; + Conductor.instance.update(swagSong.getTimeWithDiff() - Conductor.instance.inputOffset); + // Conductor.instance.songPosition += (Timer.stamp() * 1000) - FlxG.sound.music.prevTimestamp; - songPosVis.x = songPosToX(Conductor.songPosition); - songVisFollowAudio.x = songPosToX(Conductor.songPosition - Conductor.instrumentalOffset); - songVisFollowVideo.x = songPosToX(Conductor.songPosition - Conductor.inputOffset); + songPosVis.x = songPosToX(Conductor.instance.songPosition); + songVisFollowAudio.x = songPosToX(Conductor.instance.songPosition - Conductor.instance.instrumentalOffset); + songVisFollowVideo.x = songPosToX(Conductor.instance.songPosition - Conductor.instance.inputOffset); - offsetText.text = "INST Offset: " + Conductor.instrumentalOffset + "ms"; - offsetText.text += "\nINPUT Offset: " + Conductor.inputOffset + "ms"; - offsetText.text += "\ncurrentStep: " + Conductor.currentStep; - offsetText.text += "\ncurrentBeat: " + Conductor.currentBeat; + offsetText.text = "INST Offset: " + Conductor.instance.instrumentalOffset + "ms"; + offsetText.text += "\nINPUT Offset: " + Conductor.instance.inputOffset + "ms"; + offsetText.text += "\ncurrentStep: " + Conductor.instance.currentStep; + offsetText.text += "\ncurrentBeat: " + Conductor.instance.currentBeat; var avgOffsetInput:Float = 0; @@ -221,24 +221,24 @@ class LatencyState extends MusicBeatSubState { if (FlxG.keys.justPressed.RIGHT) { - Conductor.instrumentalOffset += 1.0 * multiply; + Conductor.instance.instrumentalOffset += 1.0 * multiply; } if (FlxG.keys.justPressed.LEFT) { - Conductor.instrumentalOffset -= 1.0 * multiply; + Conductor.instance.instrumentalOffset -= 1.0 * multiply; } } else { if (FlxG.keys.justPressed.RIGHT) { - Conductor.inputOffset += 1.0 * multiply; + Conductor.instance.inputOffset += 1.0 * multiply; } if (FlxG.keys.justPressed.LEFT) { - Conductor.inputOffset -= 1.0 * multiply; + Conductor.instance.inputOffset -= 1.0 * multiply; } } @@ -250,7 +250,7 @@ class LatencyState extends MusicBeatSubState }*/ noteGrp.forEach(function(daNote:NoteSprite) { - daNote.y = (strumLine.y - ((Conductor.songPosition - Conductor.instrumentalOffset) - daNote.noteData.time) * 0.45); + daNote.y = (strumLine.y - ((Conductor.instance.songPosition - Conductor.instance.instrumentalOffset) - daNote.noteData.time) * 0.45); daNote.x = strumLine.x + 30; if (daNote.y < strumLine.y) daNote.alpha = 0.5; @@ -258,7 +258,7 @@ class LatencyState extends MusicBeatSubState if (daNote.y < 0 - daNote.height) { daNote.alpha = 1; - // daNote.data.strumTime += Conductor.beatLengthMs * 8; + // daNote.data.strumTime += Conductor.instance.beatLengthMs * 8; } }); @@ -267,14 +267,14 @@ class LatencyState extends MusicBeatSubState function generateBeatStuff() { - Conductor.update(swagSong.getTimeWithDiff()); + Conductor.instance.update(swagSong.getTimeWithDiff()); - var closestBeat:Int = Math.round(Conductor.songPosition / Conductor.beatLengthMs) % diffGrp.members.length; - var getDiff:Float = Conductor.songPosition - (closestBeat * Conductor.beatLengthMs); - getDiff -= Conductor.inputOffset; + var closestBeat:Int = Math.round(Conductor.instance.songPosition / Conductor.instance.beatLengthMs) % diffGrp.members.length; + var getDiff:Float = Conductor.instance.songPosition - (closestBeat * Conductor.instance.beatLengthMs); + getDiff -= Conductor.instance.inputOffset; // lil fix for end of song - if (closestBeat == 0 && getDiff >= Conductor.beatLengthMs * 2) getDiff -= FlxG.sound.music.length; + if (closestBeat == 0 && getDiff >= Conductor.instance.beatLengthMs * 2) getDiff -= FlxG.sound.music.length; trace("\tDISTANCE TO CLOSEST BEAT: " + getDiff + "ms"); trace("\tCLOSEST BEAT: " + closestBeat); diff --git a/source/funkin/ui/freeplay/FreeplayState.hx b/source/funkin/ui/freeplay/FreeplayState.hx index 371021114..f17c3d91e 100644 --- a/source/funkin/ui/freeplay/FreeplayState.hx +++ b/source/funkin/ui/freeplay/FreeplayState.hx @@ -97,7 +97,7 @@ class FreeplayState extends MusicBeatSubState var stickerSubState:StickerSubState; // - static var rememberedDifficulty:Null = "normal"; + static var rememberedDifficulty:Null = Constants.DEFAULT_DIFFICULTY; static var rememberedSongId:Null = null; public function new(?stickers:StickerSubState = null) @@ -874,15 +874,14 @@ class FreeplayState extends MusicBeatSubState } } - @:haxe.warning("-WDeprecated") - override function switchTo(nextState:FlxState):Bool + public override function destroy():Void { + super.destroy(); var daSong = songs[curSelected]; if (daSong != null) { clearDaCache(daSong.songName); } - return super.switchTo(nextState); } function changeDiff(change:Int = 0) diff --git a/source/funkin/ui/haxeui/components/CharacterPlayer.hx b/source/funkin/ui/haxeui/components/CharacterPlayer.hx index 66b94bfa2..c7171fac7 100644 --- a/source/funkin/ui/haxeui/components/CharacterPlayer.hx +++ b/source/funkin/ui/haxeui/components/CharacterPlayer.hx @@ -35,7 +35,7 @@ class CharacterPlayer extends Box public function new(defaultToBf:Bool = true) { super(); - _overrideSkipTransformChildren = false; + // _overrideSkipTransformChildren = false; if (defaultToBf) { diff --git a/source/funkin/ui/story/StoryMenuState.hx b/source/funkin/ui/story/StoryMenuState.hx index 456988873..d6dd536f7 100644 --- a/source/funkin/ui/story/StoryMenuState.hx +++ b/source/funkin/ui/story/StoryMenuState.hx @@ -106,7 +106,7 @@ class StoryMenuState extends MusicBeatState var stickerSubState:StickerSubState; static var rememberedLevelId:Null = null; - static var rememberedDifficulty:Null = "normal"; + static var rememberedDifficulty:Null = Constants.DEFAULT_DIFFICULTY; public function new(?stickers:StickerSubState = null) { @@ -238,7 +238,7 @@ class StoryMenuState extends MusicBeatState var freakyMenuMetadata:Null = SongRegistry.instance.parseMusicData('freakyMenu'); if (freakyMenuMetadata != null) { - Conductor.mapTimeChanges(freakyMenuMetadata.timeChanges); + Conductor.instance.mapTimeChanges(freakyMenuMetadata.timeChanges); } FlxG.sound.playMusic(Paths.music('freakyMenu/freakyMenu'), 0); @@ -317,7 +317,7 @@ class StoryMenuState extends MusicBeatState override function update(elapsed:Float) { - Conductor.update(); + Conductor.instance.update(); highScoreLerp = Std.int(MathUtil.coolLerp(highScoreLerp, highScore, 0.5)); diff --git a/source/funkin/ui/title/TitleState.hx b/source/funkin/ui/title/TitleState.hx index 7671bb336..bc44af073 100644 --- a/source/funkin/ui/title/TitleState.hx +++ b/source/funkin/ui/title/TitleState.hx @@ -221,7 +221,7 @@ class TitleState extends MusicBeatState var freakyMenuMetadata:Null = SongRegistry.instance.parseMusicData('freakyMenu'); if (freakyMenuMetadata != null) { - Conductor.mapTimeChanges(freakyMenuMetadata.timeChanges); + Conductor.instance.mapTimeChanges(freakyMenuMetadata.timeChanges); } FlxG.sound.playMusic(Paths.music('freakyMenu/freakyMenu'), 0); FlxG.sound.music.fadeIn(4, 0, 0.7); @@ -256,7 +256,7 @@ class TitleState extends MusicBeatState if (FlxG.keys.pressed.DOWN) FlxG.sound.music.pitch -= 0.5 * elapsed; #end - Conductor.update(); + Conductor.instance.update(); /* if (FlxG.onMobile) { @@ -280,7 +280,7 @@ class TitleState extends MusicBeatState FlxTween.tween(FlxG.stage.window, {y: FlxG.stage.window.y + 100}, 0.7, {ease: FlxEase.quadInOut, type: PINGPONG}); } - if (FlxG.sound.music != null) Conductor.update(FlxG.sound.music.time); + if (FlxG.sound.music != null) Conductor.instance.update(FlxG.sound.music.time); if (FlxG.keys.justPressed.F) FlxG.fullscreen = !FlxG.fullscreen; // do controls.PAUSE | controls.ACCEPT instead? @@ -390,7 +390,7 @@ class TitleState extends MusicBeatState var spec:SpectogramSprite = new SpectogramSprite(FlxG.sound.music); add(spec); - Conductor.forceBPM(190); + Conductor.instance.forceBPM(190); FlxG.camera.flash(FlxColor.WHITE, 1); FlxG.sound.play(Paths.sound('confirmMenu'), 0.7); } @@ -442,13 +442,13 @@ class TitleState extends MusicBeatState if (!skippedIntro) { - // FlxG.log.add(Conductor.currentBeat); + // FlxG.log.add(Conductor.instance.currentBeat); // if the user is draggin the window some beats will // be missed so this is just to compensate - if (Conductor.currentBeat > lastBeat) + if (Conductor.instance.currentBeat > lastBeat) { // TODO: Why does it perform ALL the previous steps each beat? - for (i in lastBeat...Conductor.currentBeat) + for (i in lastBeat...Conductor.instance.currentBeat) { switch (i + 1) { @@ -483,11 +483,11 @@ class TitleState extends MusicBeatState } } } - lastBeat = Conductor.currentBeat; + lastBeat = Conductor.instance.currentBeat; } if (skippedIntro) { - if (cheatActive && Conductor.currentBeat % 2 == 0) swagShader.update(0.125); + if (cheatActive && Conductor.instance.currentBeat % 2 == 0) swagShader.update(0.125); if (logoBl != null && logoBl.animation != null) logoBl.animation.play('bump', true); diff --git a/source/funkin/util/Constants.hx b/source/funkin/util/Constants.hx index f8749567b..123267a49 100644 --- a/source/funkin/util/Constants.hx +++ b/source/funkin/util/Constants.hx @@ -123,6 +123,7 @@ class Constants /** * Default list of difficulties for charts. + * Assumes no Erect mode, etc. */ public static final DEFAULT_DIFFICULTY_LIST:Array = ['easy', 'normal', 'hard']; diff --git a/tests/unit/source/funkin/ConductorTest.hx b/tests/unit/source/funkin/ConductorTest.hx index c65f3f297..a0cfedbab 100644 --- a/tests/unit/source/funkin/ConductorTest.hx +++ b/tests/unit/source/funkin/ConductorTest.hx @@ -31,23 +31,23 @@ class ConductorTest extends FunkinTest { // NOTE: Expected value comes first. - Assert.areEqual([], Conductor.timeChanges); - Assert.areEqual(null, Conductor.currentTimeChange); + Assert.areEqual([], Conductor.instance.timeChanges); + Assert.areEqual(null, Conductor.instance.currentTimeChange); - Assert.areEqual(0, Conductor.songPosition); - Assert.areEqual(Constants.DEFAULT_BPM, Conductor.bpm); - Assert.areEqual(null, Conductor.bpmOverride); + Assert.areEqual(0, Conductor.instance.songPosition); + Assert.areEqual(Constants.DEFAULT_BPM, Conductor.instance.bpm); + Assert.areEqual(null, Conductor.instance.bpmOverride); - Assert.areEqual(600, Conductor.beatLengthMs); + Assert.areEqual(600, Conductor.instance.beatLengthMs); - Assert.areEqual(4, Conductor.timeSignatureNumerator); - Assert.areEqual(4, Conductor.timeSignatureDenominator); + Assert.areEqual(4, Conductor.instance.timeSignatureNumerator); + Assert.areEqual(4, Conductor.instance.timeSignatureDenominator); - Assert.areEqual(0, Conductor.currentBeat); - Assert.areEqual(0, Conductor.currentStep); - Assert.areEqual(0.0, Conductor.currentStepTime); + Assert.areEqual(0, Conductor.instance.currentBeat); + Assert.areEqual(0, Conductor.instance.currentStep); + Assert.areEqual(0.0, Conductor.instance.currentStepTime); - Assert.areEqual(150, Conductor.stepLengthMs); + Assert.areEqual(150, Conductor.instance.stepLengthMs); } /** @@ -60,23 +60,23 @@ class ConductorTest extends FunkinTest var currentConductorState:Null = conductorState; Assert.isNotNull(currentConductorState); - Assert.areEqual(0, Conductor.songPosition); + Assert.areEqual(0, Conductor.instance.songPosition); step(); // 1 var BPM_100_STEP_TIME = 1 / 9; - FunkinAssert.areNear(FunkinTest.MS_PER_STEP * 1, Conductor.songPosition); - Assert.areEqual(0, Conductor.currentBeat); - Assert.areEqual(0, Conductor.currentStep); - FunkinAssert.areNear(1 / 9, Conductor.currentStepTime); + FunkinAssert.areNear(FunkinTest.MS_PER_STEP * 1, Conductor.instance.songPosition); + Assert.areEqual(0, Conductor.instance.currentBeat); + Assert.areEqual(0, Conductor.instance.currentStep); + FunkinAssert.areNear(1 / 9, Conductor.instance.currentStepTime); step(7); // 8 - FunkinAssert.areNear(FunkinTest.MS_PER_STEP * 8, Conductor.songPosition); - Assert.areEqual(0, Conductor.currentBeat); - Assert.areEqual(0, Conductor.currentStep); - FunkinAssert.areNear(8 / 9, Conductor.currentStepTime); + FunkinAssert.areNear(FunkinTest.MS_PER_STEP * 8, Conductor.instance.songPosition); + Assert.areEqual(0, Conductor.instance.currentBeat); + Assert.areEqual(0, Conductor.instance.currentStep); + FunkinAssert.areNear(8 / 9, Conductor.instance.currentStepTime); Assert.areEqual(0, currentConductorState.beatsHit); Assert.areEqual(0, currentConductorState.stepsHit); @@ -88,10 +88,10 @@ class ConductorTest extends FunkinTest currentConductorState.beatsHit = 0; currentConductorState.stepsHit = 0; - FunkinAssert.areNear(FunkinTest.MS_PER_STEP * 9, Conductor.songPosition); - Assert.areEqual(0, Conductor.currentBeat); - Assert.areEqual(1, Conductor.currentStep); - FunkinAssert.areNear(1.0, Conductor.currentStepTime); + FunkinAssert.areNear(FunkinTest.MS_PER_STEP * 9, Conductor.instance.songPosition); + Assert.areEqual(0, Conductor.instance.currentBeat); + Assert.areEqual(1, Conductor.instance.currentStep); + FunkinAssert.areNear(1.0, Conductor.instance.currentStepTime); step(35 - 9); // 35 @@ -100,10 +100,10 @@ class ConductorTest extends FunkinTest currentConductorState.beatsHit = 0; currentConductorState.stepsHit = 0; - FunkinAssert.areNear(FunkinTest.MS_PER_STEP * 35, Conductor.songPosition); - Assert.areEqual(0, Conductor.currentBeat); - Assert.areEqual(3, Conductor.currentStep); - FunkinAssert.areNear(3.0 + 8 / 9, Conductor.currentStepTime); + FunkinAssert.areNear(FunkinTest.MS_PER_STEP * 35, Conductor.instance.songPosition); + Assert.areEqual(0, Conductor.instance.currentBeat); + Assert.areEqual(3, Conductor.instance.currentStep); + FunkinAssert.areNear(3.0 + 8 / 9, Conductor.instance.currentStepTime); step(); // 36 @@ -112,83 +112,83 @@ class ConductorTest extends FunkinTest currentConductorState.beatsHit = 0; currentConductorState.stepsHit = 0; - FunkinAssert.areNear(FunkinTest.MS_PER_STEP * 36, Conductor.songPosition); - Assert.areEqual(1, Conductor.currentBeat); - Assert.areEqual(4, Conductor.currentStep); - FunkinAssert.areNear(4.0, Conductor.currentStepTime); + FunkinAssert.areNear(FunkinTest.MS_PER_STEP * 36, Conductor.instance.songPosition); + Assert.areEqual(1, Conductor.instance.currentBeat); + Assert.areEqual(4, Conductor.instance.currentStep); + FunkinAssert.areNear(4.0, Conductor.instance.currentStepTime); step(50 - 36); // 50 - FunkinAssert.areNear(FunkinTest.MS_PER_STEP * 50, Conductor.songPosition); - Assert.areEqual(1, Conductor.currentBeat); - Assert.areEqual(5, Conductor.currentStep); - FunkinAssert.areNear(5.555555, Conductor.currentStepTime); + FunkinAssert.areNear(FunkinTest.MS_PER_STEP * 50, Conductor.instance.songPosition); + Assert.areEqual(1, Conductor.instance.currentBeat); + Assert.areEqual(5, Conductor.instance.currentStep); + FunkinAssert.areNear(5.555555, Conductor.instance.currentStepTime); step(49); // 99 - FunkinAssert.areNear(FunkinTest.MS_PER_STEP * 99, Conductor.songPosition); - Assert.areEqual(2, Conductor.currentBeat); - Assert.areEqual(11, Conductor.currentStep); - FunkinAssert.areNear(11.0, Conductor.currentStepTime); + FunkinAssert.areNear(FunkinTest.MS_PER_STEP * 99, Conductor.instance.songPosition); + Assert.areEqual(2, Conductor.instance.currentBeat); + Assert.areEqual(11, Conductor.instance.currentStep); + FunkinAssert.areNear(11.0, Conductor.instance.currentStepTime); step(1); // 100 - FunkinAssert.areNear(FunkinTest.MS_PER_STEP * 100, Conductor.songPosition); - Assert.areEqual(2, Conductor.currentBeat); - Assert.areEqual(11, Conductor.currentStep); - FunkinAssert.areNear(11.111111, Conductor.currentStepTime); + FunkinAssert.areNear(FunkinTest.MS_PER_STEP * 100, Conductor.instance.songPosition); + Assert.areEqual(2, Conductor.instance.currentBeat); + Assert.areEqual(11, Conductor.instance.currentStep); + FunkinAssert.areNear(11.111111, Conductor.instance.currentStepTime); } @Test function testUpdateForcedBPM():Void { - Conductor.forceBPM(60); + Conductor.instance.forceBPM(60); - Assert.areEqual(0, Conductor.songPosition); + Assert.areEqual(0, Conductor.instance.songPosition); // 60 beats per minute = 1 beat per second // 1 beat per second = 1/60 beats per frame = 4/60 steps per frame step(); // Advances time 1/60 of 1 second. - FunkinAssert.areNear(FunkinTest.MS_PER_STEP * 1, Conductor.songPosition); - Assert.areEqual(0, Conductor.currentBeat); - Assert.areEqual(0, Conductor.currentStep); - FunkinAssert.areNear(4 / 60, Conductor.currentStepTime); // 1/60 of 1 beat = 4/60 of 1 step + FunkinAssert.areNear(FunkinTest.MS_PER_STEP * 1, Conductor.instance.songPosition); + Assert.areEqual(0, Conductor.instance.currentBeat); + Assert.areEqual(0, Conductor.instance.currentStep); + FunkinAssert.areNear(4 / 60, Conductor.instance.currentStepTime); // 1/60 of 1 beat = 4/60 of 1 step step(14 - 1); // 14 - FunkinAssert.areNear(FunkinTest.MS_PER_STEP * 14, Conductor.songPosition); - Assert.areEqual(0, Conductor.currentBeat); - Assert.areEqual(0, Conductor.currentStep); - FunkinAssert.areNear(1.0 - 4 / 60, Conductor.currentStepTime); // 1/60 of 1 beat = 4/60 of 1 step + FunkinAssert.areNear(FunkinTest.MS_PER_STEP * 14, Conductor.instance.songPosition); + Assert.areEqual(0, Conductor.instance.currentBeat); + Assert.areEqual(0, Conductor.instance.currentStep); + FunkinAssert.areNear(1.0 - 4 / 60, Conductor.instance.currentStepTime); // 1/60 of 1 beat = 4/60 of 1 step step(); // 15 - FunkinAssert.areNear(FunkinTest.MS_PER_STEP * 15, Conductor.songPosition); - Assert.areEqual(0, Conductor.currentBeat); - Assert.areEqual(1, Conductor.currentStep); - FunkinAssert.areNear(1.0, Conductor.currentStepTime); // 1/60 of 1 beat = 4/60 of 1 step + FunkinAssert.areNear(FunkinTest.MS_PER_STEP * 15, Conductor.instance.songPosition); + Assert.areEqual(0, Conductor.instance.currentBeat); + Assert.areEqual(1, Conductor.instance.currentStep); + FunkinAssert.areNear(1.0, Conductor.instance.currentStepTime); // 1/60 of 1 beat = 4/60 of 1 step step(45 - 1); // 59 - FunkinAssert.areNear(FunkinTest.MS_PER_STEP * 59, Conductor.songPosition); - Assert.areEqual(0, Conductor.currentBeat); - Assert.areEqual(3, Conductor.currentStep); - FunkinAssert.areNear(4.0 - 4 / 60, Conductor.currentStepTime); + FunkinAssert.areNear(FunkinTest.MS_PER_STEP * 59, Conductor.instance.songPosition); + Assert.areEqual(0, Conductor.instance.currentBeat); + Assert.areEqual(3, Conductor.instance.currentStep); + FunkinAssert.areNear(4.0 - 4 / 60, Conductor.instance.currentStepTime); step(); // 60 - FunkinAssert.areNear(FunkinTest.MS_PER_STEP * 60, Conductor.songPosition); - Assert.areEqual(1, Conductor.currentBeat); - Assert.areEqual(4, Conductor.currentStep); - FunkinAssert.areNear(4.0, Conductor.currentStepTime); + FunkinAssert.areNear(FunkinTest.MS_PER_STEP * 60, Conductor.instance.songPosition); + Assert.areEqual(1, Conductor.instance.currentBeat); + Assert.areEqual(4, Conductor.instance.currentStep); + FunkinAssert.areNear(4.0, Conductor.instance.currentStepTime); step(); // 61 - FunkinAssert.areNear(FunkinTest.MS_PER_STEP * 61, Conductor.songPosition); - Assert.areEqual(1, Conductor.currentBeat); - Assert.areEqual(4, Conductor.currentStep); - FunkinAssert.areNear(4.0 + 4 / 60, Conductor.currentStepTime); + FunkinAssert.areNear(FunkinTest.MS_PER_STEP * 61, Conductor.instance.songPosition); + Assert.areEqual(1, Conductor.instance.currentBeat); + Assert.areEqual(4, Conductor.instance.currentStep); + FunkinAssert.areNear(4.0 + 4 / 60, Conductor.instance.currentStepTime); } @Test @@ -196,50 +196,50 @@ class ConductorTest extends FunkinTest { // Start the song with a BPM of 120. var songTimeChanges:Array = [new SongTimeChange(0, 120)]; - Conductor.mapTimeChanges(songTimeChanges); + Conductor.instance.mapTimeChanges(songTimeChanges); // All should be at 0. - FunkinAssert.areNear(0, Conductor.songPosition); - Assert.areEqual(0, Conductor.currentBeat); - Assert.areEqual(0, Conductor.currentStep); - FunkinAssert.areNear(0.0, Conductor.currentStepTime); // 2/120 of 1 beat = 8/120 of 1 step + FunkinAssert.areNear(0, Conductor.instance.songPosition); + Assert.areEqual(0, Conductor.instance.currentBeat); + Assert.areEqual(0, Conductor.instance.currentStep); + FunkinAssert.areNear(0.0, Conductor.instance.currentStepTime); // 2/120 of 1 beat = 8/120 of 1 step // 120 beats per minute = 2 beat per second // 2 beat per second = 2/60 beats per frame = 16/120 steps per frame step(); // Advances time 1/60 of 1 second. - FunkinAssert.areNear(FunkinTest.MS_PER_STEP * 1, Conductor.songPosition); - Assert.areEqual(0, Conductor.currentBeat); - Assert.areEqual(0, Conductor.currentStep); - FunkinAssert.areNear(16 / 120, Conductor.currentStepTime); // 2/120 of 1 beat = 8/120 of 1 step + FunkinAssert.areNear(FunkinTest.MS_PER_STEP * 1, Conductor.instance.songPosition); + Assert.areEqual(0, Conductor.instance.currentBeat); + Assert.areEqual(0, Conductor.instance.currentStep); + FunkinAssert.areNear(16 / 120, Conductor.instance.currentStepTime); // 2/120 of 1 beat = 8/120 of 1 step step(15 - 1); // 15 - FunkinAssert.areNear(FunkinTest.MS_PER_STEP * 15, Conductor.songPosition); - Assert.areEqual(0, Conductor.currentBeat); - Assert.areEqual(2, Conductor.currentStep); - FunkinAssert.areNear(2.0, Conductor.currentStepTime); // 2/60 of 1 beat = 8/60 of 1 step + FunkinAssert.areNear(FunkinTest.MS_PER_STEP * 15, Conductor.instance.songPosition); + Assert.areEqual(0, Conductor.instance.currentBeat); + Assert.areEqual(2, Conductor.instance.currentStep); + FunkinAssert.areNear(2.0, Conductor.instance.currentStepTime); // 2/60 of 1 beat = 8/60 of 1 step step(45 - 1); // 59 - FunkinAssert.areNear(FunkinTest.MS_PER_STEP * 59, Conductor.songPosition); - Assert.areEqual(1, Conductor.currentBeat); - Assert.areEqual(7, Conductor.currentStep); - FunkinAssert.areNear(7.0 + 104 / 120, Conductor.currentStepTime); + FunkinAssert.areNear(FunkinTest.MS_PER_STEP * 59, Conductor.instance.songPosition); + Assert.areEqual(1, Conductor.instance.currentBeat); + Assert.areEqual(7, Conductor.instance.currentStep); + FunkinAssert.areNear(7.0 + 104 / 120, Conductor.instance.currentStepTime); step(); // 60 - FunkinAssert.areNear(FunkinTest.MS_PER_STEP * 60, Conductor.songPosition); - Assert.areEqual(2, Conductor.currentBeat); - Assert.areEqual(8, Conductor.currentStep); - FunkinAssert.areNear(8.0, Conductor.currentStepTime); + FunkinAssert.areNear(FunkinTest.MS_PER_STEP * 60, Conductor.instance.songPosition); + Assert.areEqual(2, Conductor.instance.currentBeat); + Assert.areEqual(8, Conductor.instance.currentStep); + FunkinAssert.areNear(8.0, Conductor.instance.currentStepTime); step(); // 61 - FunkinAssert.areNear(FunkinTest.MS_PER_STEP * 61, Conductor.songPosition); - Assert.areEqual(2, Conductor.currentBeat); - Assert.areEqual(8, Conductor.currentStep); - FunkinAssert.areNear(8.0 + 8 / 60, Conductor.currentStepTime); + FunkinAssert.areNear(FunkinTest.MS_PER_STEP * 61, Conductor.instance.songPosition); + Assert.areEqual(2, Conductor.instance.currentBeat); + Assert.areEqual(8, Conductor.instance.currentStep); + FunkinAssert.areNear(8.0 + 8 / 60, Conductor.instance.currentStepTime); } @Test @@ -247,57 +247,57 @@ class ConductorTest extends FunkinTest { // Start the song with a BPM of 120. var songTimeChanges:Array = [new SongTimeChange(0, 120), new SongTimeChange(3000, 90)]; - Conductor.mapTimeChanges(songTimeChanges); + Conductor.instance.mapTimeChanges(songTimeChanges); // All should be at 0. - FunkinAssert.areNear(0, Conductor.songPosition); - Assert.areEqual(0, Conductor.currentBeat); - Assert.areEqual(0, Conductor.currentStep); - FunkinAssert.areNear(0.0, Conductor.currentStepTime); // 2/120 of 1 beat = 8/120 of 1 step + FunkinAssert.areNear(0, Conductor.instance.songPosition); + Assert.areEqual(0, Conductor.instance.currentBeat); + Assert.areEqual(0, Conductor.instance.currentStep); + FunkinAssert.areNear(0.0, Conductor.instance.currentStepTime); // 2/120 of 1 beat = 8/120 of 1 step // 120 beats per minute = 2 beat per second // 2 beat per second = 2/60 beats per frame = 16/120 steps per frame step(); // Advances time 1/60 of 1 second. - FunkinAssert.areNear(FunkinTest.MS_PER_STEP * 1, Conductor.songPosition); - Assert.areEqual(0, Conductor.currentBeat); - Assert.areEqual(0, Conductor.currentStep); - FunkinAssert.areNear(16 / 120, Conductor.currentStepTime); // 4/120 of 1 beat = 16/120 of 1 step + FunkinAssert.areNear(FunkinTest.MS_PER_STEP * 1, Conductor.instance.songPosition); + Assert.areEqual(0, Conductor.instance.currentBeat); + Assert.areEqual(0, Conductor.instance.currentStep); + FunkinAssert.areNear(16 / 120, Conductor.instance.currentStepTime); // 4/120 of 1 beat = 16/120 of 1 step step(60 - 1 - 1); // 59 - FunkinAssert.areNear(FunkinTest.MS_PER_STEP * 59, Conductor.songPosition); - Assert.areEqual(1, Conductor.currentBeat); - Assert.areEqual(7, Conductor.currentStep); - FunkinAssert.areNear(7.0 + 104 / 120, Conductor.currentStepTime); + FunkinAssert.areNear(FunkinTest.MS_PER_STEP * 59, Conductor.instance.songPosition); + Assert.areEqual(1, Conductor.instance.currentBeat); + Assert.areEqual(7, Conductor.instance.currentStep); + FunkinAssert.areNear(7.0 + 104 / 120, Conductor.instance.currentStepTime); step(); // 60 - FunkinAssert.areNear(FunkinTest.MS_PER_STEP * 60, Conductor.songPosition); - Assert.areEqual(2, Conductor.currentBeat); - Assert.areEqual(8, Conductor.currentStep); - FunkinAssert.areNear(8.0, Conductor.currentStepTime); + FunkinAssert.areNear(FunkinTest.MS_PER_STEP * 60, Conductor.instance.songPosition); + Assert.areEqual(2, Conductor.instance.currentBeat); + Assert.areEqual(8, Conductor.instance.currentStep); + FunkinAssert.areNear(8.0, Conductor.instance.currentStepTime); step(); // 61 - FunkinAssert.areNear(FunkinTest.MS_PER_STEP * 61, Conductor.songPosition); - Assert.areEqual(2, Conductor.currentBeat); - Assert.areEqual(8, Conductor.currentStep); - FunkinAssert.areNear(8.0 + 8 / 60, Conductor.currentStepTime); + FunkinAssert.areNear(FunkinTest.MS_PER_STEP * 61, Conductor.instance.songPosition); + Assert.areEqual(2, Conductor.instance.currentBeat); + Assert.areEqual(8, Conductor.instance.currentStep); + FunkinAssert.areNear(8.0 + 8 / 60, Conductor.instance.currentStepTime); step(179 - 61); // 179 - FunkinAssert.areNear(FunkinTest.MS_PER_STEP * 179, Conductor.songPosition); - Assert.areEqual(5, Conductor.currentBeat); - Assert.areEqual(23, Conductor.currentStep); - FunkinAssert.areNear(23.0 + 52 / 60, Conductor.currentStepTime); + FunkinAssert.areNear(FunkinTest.MS_PER_STEP * 179, Conductor.instance.songPosition); + Assert.areEqual(5, Conductor.instance.currentBeat); + Assert.areEqual(23, Conductor.instance.currentStep); + FunkinAssert.areNear(23.0 + 52 / 60, Conductor.instance.currentStepTime); step(); // 180 (3 seconds) - FunkinAssert.areNear(FunkinTest.MS_PER_STEP * 180, Conductor.songPosition); - Assert.areEqual(6, Conductor.currentBeat); - Assert.areEqual(24, Conductor.currentStep); - FunkinAssert.areNear(24.0, Conductor.currentStepTime); + FunkinAssert.areNear(FunkinTest.MS_PER_STEP * 180, Conductor.instance.songPosition); + Assert.areEqual(6, Conductor.instance.currentBeat); + Assert.areEqual(24, Conductor.instance.currentStep); + FunkinAssert.areNear(24.0, Conductor.instance.currentStepTime); step(); // 181 (3 + 1/60 seconds) // BPM has switched to 90! @@ -305,24 +305,24 @@ class ConductorTest extends FunkinTest // 1.5 beat per second = 1.5/60 beats per frame = 3/120 beats per frame // = 12/120 steps per frame - FunkinAssert.areNear(FunkinTest.MS_PER_STEP * 181, Conductor.songPosition); - Assert.areEqual(6, Conductor.currentBeat); - Assert.areEqual(24, Conductor.currentStep); - FunkinAssert.areNear(24.0 + 12 / 120, Conductor.currentStepTime); + FunkinAssert.areNear(FunkinTest.MS_PER_STEP * 181, Conductor.instance.songPosition); + Assert.areEqual(6, Conductor.instance.currentBeat); + Assert.areEqual(24, Conductor.instance.currentStep); + FunkinAssert.areNear(24.0 + 12 / 120, Conductor.instance.currentStepTime); step(59); // 240 (4 seconds) - FunkinAssert.areNear(FunkinTest.MS_PER_STEP * 240, Conductor.songPosition); - Assert.areEqual(7, Conductor.currentBeat); - Assert.areEqual(30, Conductor.currentStep); - FunkinAssert.areNear(30.0, Conductor.currentStepTime); + FunkinAssert.areNear(FunkinTest.MS_PER_STEP * 240, Conductor.instance.songPosition); + Assert.areEqual(7, Conductor.instance.currentBeat); + Assert.areEqual(30, Conductor.instance.currentStep); + FunkinAssert.areNear(30.0, Conductor.instance.currentStepTime); step(); // 241 (4 + 1/60 seconds) - FunkinAssert.areNear(FunkinTest.MS_PER_STEP * 241, Conductor.songPosition); - Assert.areEqual(7, Conductor.currentBeat); - Assert.areEqual(30, Conductor.currentStep); - FunkinAssert.areNear(30.0 + 12 / 120, Conductor.currentStepTime); + FunkinAssert.areNear(FunkinTest.MS_PER_STEP * 241, Conductor.instance.songPosition); + Assert.areEqual(7, Conductor.instance.currentBeat); + Assert.areEqual(30, Conductor.instance.currentStep); + FunkinAssert.areNear(30.0 + 12 / 120, Conductor.instance.currentStepTime); } @Test @@ -334,63 +334,63 @@ class ConductorTest extends FunkinTest new SongTimeChange(3000, 90), new SongTimeChange(6000, 180) ]; - Conductor.mapTimeChanges(songTimeChanges); + Conductor.instance.mapTimeChanges(songTimeChanges); // Verify time changes. - Assert.areEqual(3, Conductor.timeChanges.length); - FunkinAssert.areNear(0, Conductor.timeChanges[0].beatTime); - FunkinAssert.areNear(6, Conductor.timeChanges[1].beatTime); - FunkinAssert.areNear(10.5, Conductor.timeChanges[2].beatTime); + Assert.areEqual(3, Conductor.instance.timeChanges.length); + FunkinAssert.areNear(0, Conductor.instance.timeChanges[0].beatTime); + FunkinAssert.areNear(6, Conductor.instance.timeChanges[1].beatTime); + FunkinAssert.areNear(10.5, Conductor.instance.timeChanges[2].beatTime); // All should be at 0. - FunkinAssert.areNear(0, Conductor.songPosition); - Assert.areEqual(0, Conductor.currentBeat); - Assert.areEqual(0, Conductor.currentStep); - FunkinAssert.areNear(0.0, Conductor.currentStepTime); // 2/120 of 1 beat = 8/120 of 1 step + FunkinAssert.areNear(0, Conductor.instance.songPosition); + Assert.areEqual(0, Conductor.instance.currentBeat); + Assert.areEqual(0, Conductor.instance.currentStep); + FunkinAssert.areNear(0.0, Conductor.instance.currentStepTime); // 2/120 of 1 beat = 8/120 of 1 step // 120 beats per minute = 2 beat per second // 2 beat per second = 2/60 beats per frame = 16/120 steps per frame step(); // Advances time 1/60 of 1 second. - FunkinAssert.areNear(FunkinTest.MS_PER_STEP * 1, Conductor.songPosition); - Assert.areEqual(0, Conductor.currentBeat); - Assert.areEqual(0, Conductor.currentStep); - FunkinAssert.areNear(16 / 120, Conductor.currentStepTime); // 4/120 of 1 beat = 16/120 of 1 step + FunkinAssert.areNear(FunkinTest.MS_PER_STEP * 1, Conductor.instance.songPosition); + Assert.areEqual(0, Conductor.instance.currentBeat); + Assert.areEqual(0, Conductor.instance.currentStep); + FunkinAssert.areNear(16 / 120, Conductor.instance.currentStepTime); // 4/120 of 1 beat = 16/120 of 1 step step(60 - 1 - 1); // 59 - FunkinAssert.areNear(FunkinTest.MS_PER_STEP * 59, Conductor.songPosition); - Assert.areEqual(1, Conductor.currentBeat); - Assert.areEqual(7, Conductor.currentStep); - FunkinAssert.areNear(7 + 104 / 120, Conductor.currentStepTime); + FunkinAssert.areNear(FunkinTest.MS_PER_STEP * 59, Conductor.instance.songPosition); + Assert.areEqual(1, Conductor.instance.currentBeat); + Assert.areEqual(7, Conductor.instance.currentStep); + FunkinAssert.areNear(7 + 104 / 120, Conductor.instance.currentStepTime); step(); // 60 - FunkinAssert.areNear(FunkinTest.MS_PER_STEP * 60, Conductor.songPosition); - Assert.areEqual(2, Conductor.currentBeat); - Assert.areEqual(8, Conductor.currentStep); - FunkinAssert.areNear(8.0, Conductor.currentStepTime); + FunkinAssert.areNear(FunkinTest.MS_PER_STEP * 60, Conductor.instance.songPosition); + Assert.areEqual(2, Conductor.instance.currentBeat); + Assert.areEqual(8, Conductor.instance.currentStep); + FunkinAssert.areNear(8.0, Conductor.instance.currentStepTime); step(); // 61 - FunkinAssert.areNear(FunkinTest.MS_PER_STEP * 61, Conductor.songPosition); - Assert.areEqual(2, Conductor.currentBeat); - Assert.areEqual(8, Conductor.currentStep); - FunkinAssert.areNear(8.0 + 8 / 60, Conductor.currentStepTime); + FunkinAssert.areNear(FunkinTest.MS_PER_STEP * 61, Conductor.instance.songPosition); + Assert.areEqual(2, Conductor.instance.currentBeat); + Assert.areEqual(8, Conductor.instance.currentStep); + FunkinAssert.areNear(8.0 + 8 / 60, Conductor.instance.currentStepTime); step(179 - 61); // 179 - FunkinAssert.areNear(FunkinTest.MS_PER_STEP * 179, Conductor.songPosition); - Assert.areEqual(5, Conductor.currentBeat); - Assert.areEqual(23, Conductor.currentStep); - FunkinAssert.areNear(23.0 + 52 / 60, Conductor.currentStepTime); + FunkinAssert.areNear(FunkinTest.MS_PER_STEP * 179, Conductor.instance.songPosition); + Assert.areEqual(5, Conductor.instance.currentBeat); + Assert.areEqual(23, Conductor.instance.currentStep); + FunkinAssert.areNear(23.0 + 52 / 60, Conductor.instance.currentStepTime); step(); // 180 (3 seconds) - FunkinAssert.areNear(FunkinTest.MS_PER_STEP * 180, Conductor.songPosition); - Assert.areEqual(6, Conductor.currentBeat); - Assert.areEqual(24, Conductor.currentStep); // 23.999 => 24 - FunkinAssert.areNear(24.0, Conductor.currentStepTime); + FunkinAssert.areNear(FunkinTest.MS_PER_STEP * 180, Conductor.instance.songPosition); + Assert.areEqual(6, Conductor.instance.currentBeat); + Assert.areEqual(24, Conductor.instance.currentStep); // 23.999 => 24 + FunkinAssert.areNear(24.0, Conductor.instance.currentStepTime); step(); // 181 (3 + 1/60 seconds) // BPM has switched to 90! @@ -398,45 +398,45 @@ class ConductorTest extends FunkinTest // 1.5 beat per second = 1.5/60 beats per frame = 3/120 beats per frame // = 12/120 steps per frame - FunkinAssert.areNear(FunkinTest.MS_PER_STEP * 181, Conductor.songPosition); - Assert.areEqual(6, Conductor.currentBeat); - Assert.areEqual(24, Conductor.currentStep); - FunkinAssert.areNear(24.0 + 12 / 120, Conductor.currentStepTime); + FunkinAssert.areNear(FunkinTest.MS_PER_STEP * 181, Conductor.instance.songPosition); + Assert.areEqual(6, Conductor.instance.currentBeat); + Assert.areEqual(24, Conductor.instance.currentStep); + FunkinAssert.areNear(24.0 + 12 / 120, Conductor.instance.currentStepTime); step(60 - 1 - 1); // 240 (4 seconds) - FunkinAssert.areNear(FunkinTest.MS_PER_STEP * 239, Conductor.songPosition); - Assert.areEqual(7, Conductor.currentBeat); - Assert.areEqual(29, Conductor.currentStep); - FunkinAssert.areNear(29.0 + 108 / 120, Conductor.currentStepTime); + FunkinAssert.areNear(FunkinTest.MS_PER_STEP * 239, Conductor.instance.songPosition); + Assert.areEqual(7, Conductor.instance.currentBeat); + Assert.areEqual(29, Conductor.instance.currentStep); + FunkinAssert.areNear(29.0 + 108 / 120, Conductor.instance.currentStepTime); step(); // 240 (4 seconds) - FunkinAssert.areNear(FunkinTest.MS_PER_STEP * 240, Conductor.songPosition); - Assert.areEqual(7, Conductor.currentBeat); - Assert.areEqual(30, Conductor.currentStep); - FunkinAssert.areNear(30.0, Conductor.currentStepTime); + FunkinAssert.areNear(FunkinTest.MS_PER_STEP * 240, Conductor.instance.songPosition); + Assert.areEqual(7, Conductor.instance.currentBeat); + Assert.areEqual(30, Conductor.instance.currentStep); + FunkinAssert.areNear(30.0, Conductor.instance.currentStepTime); step(); // 241 (4 + 1/60 seconds) - FunkinAssert.areNear(FunkinTest.MS_PER_STEP * 241, Conductor.songPosition); - Assert.areEqual(7, Conductor.currentBeat); - Assert.areEqual(30, Conductor.currentStep); - FunkinAssert.areNear(30.0 + 12 / 120, Conductor.currentStepTime); + FunkinAssert.areNear(FunkinTest.MS_PER_STEP * 241, Conductor.instance.songPosition); + Assert.areEqual(7, Conductor.instance.currentBeat); + Assert.areEqual(30, Conductor.instance.currentStep); + FunkinAssert.areNear(30.0 + 12 / 120, Conductor.instance.currentStepTime); step(359 - 241); // 359 (5 + 59/60 seconds) - FunkinAssert.areNear(FunkinTest.MS_PER_STEP * 359, Conductor.songPosition); - Assert.areEqual(10, Conductor.currentBeat); - Assert.areEqual(41, Conductor.currentStep); - FunkinAssert.areNear(41 + 108 / 120, Conductor.currentStepTime); + FunkinAssert.areNear(FunkinTest.MS_PER_STEP * 359, Conductor.instance.songPosition); + Assert.areEqual(10, Conductor.instance.currentBeat); + Assert.areEqual(41, Conductor.instance.currentStep); + FunkinAssert.areNear(41 + 108 / 120, Conductor.instance.currentStepTime); step(); // 360 - FunkinAssert.areNear(FunkinTest.MS_PER_STEP * 360, Conductor.songPosition); - Assert.areEqual(10, Conductor.currentBeat); - Assert.areEqual(42, Conductor.currentStep); // 41.999 - FunkinAssert.areNear(42.0, Conductor.currentStepTime); + FunkinAssert.areNear(FunkinTest.MS_PER_STEP * 360, Conductor.instance.songPosition); + Assert.areEqual(10, Conductor.instance.currentBeat); + Assert.areEqual(42, Conductor.instance.currentStep); // 41.999 + FunkinAssert.areNear(42.0, Conductor.instance.currentStepTime); step(); // 361 // BPM has switched to 180! @@ -444,24 +444,24 @@ class ConductorTest extends FunkinTest // 3 beat per second = 3/60 beats per frame // = 12/60 steps per frame - FunkinAssert.areNear(FunkinTest.MS_PER_STEP * 361, Conductor.songPosition); - Assert.areEqual(10, Conductor.currentBeat); - Assert.areEqual(42, Conductor.currentStep); - FunkinAssert.areNear(42.0 + 12 / 60, Conductor.currentStepTime); + FunkinAssert.areNear(FunkinTest.MS_PER_STEP * 361, Conductor.instance.songPosition); + Assert.areEqual(10, Conductor.instance.currentBeat); + Assert.areEqual(42, Conductor.instance.currentStep); + FunkinAssert.areNear(42.0 + 12 / 60, Conductor.instance.currentStepTime); step(); // 362 - FunkinAssert.areNear(FunkinTest.MS_PER_STEP * 362, Conductor.songPosition); - Assert.areEqual(10, Conductor.currentBeat); - Assert.areEqual(42, Conductor.currentStep); - FunkinAssert.areNear(42.0 + 24 / 60, Conductor.currentStepTime); + FunkinAssert.areNear(FunkinTest.MS_PER_STEP * 362, Conductor.instance.songPosition); + Assert.areEqual(10, Conductor.instance.currentBeat); + Assert.areEqual(42, Conductor.instance.currentStep); + FunkinAssert.areNear(42.0 + 24 / 60, Conductor.instance.currentStepTime); step(3); // 365 - FunkinAssert.areNear(FunkinTest.MS_PER_STEP * 365, Conductor.songPosition); - Assert.areEqual(10, Conductor.currentBeat); - Assert.areEqual(43, Conductor.currentStep); // 42.999 => 42 - FunkinAssert.areNear(43.0, Conductor.currentStepTime); + FunkinAssert.areNear(FunkinTest.MS_PER_STEP * 365, Conductor.instance.songPosition); + Assert.areEqual(10, Conductor.instance.currentBeat); + Assert.areEqual(43, Conductor.instance.currentStep); // 42.999 => 42 + FunkinAssert.areNear(43.0, Conductor.instance.currentStepTime); } } @@ -504,6 +504,6 @@ class ConductorState extends FlxState super.update(elapsed); // On each step, increment the Conductor as though the song was playing. - Conductor.update(Conductor.songPosition + elapsed * Constants.MS_PER_SEC); + Conductor.instance.update(Conductor.instance.songPosition + elapsed * Constants.MS_PER_SEC); } } diff --git a/tests/unit/source/funkin/data/BaseRegistryTest.hx b/tests/unit/source/funkin/data/BaseRegistryTest.hx index 0be932d35..5f837ba97 100644 --- a/tests/unit/source/funkin/data/BaseRegistryTest.hx +++ b/tests/unit/source/funkin/data/BaseRegistryTest.hx @@ -156,6 +156,7 @@ class MyTypeRegistry extends BaseRegistry // JsonParser does not take type parameters, // otherwise this function would be in BaseRegistry. var parser = new json2object.JsonParser(); + parser.ignoreUnknownVariables = false; switch (loadEntryFile(id)) { @@ -181,6 +182,7 @@ class MyTypeRegistry extends BaseRegistry // JsonParser does not take type parameters, // otherwise this function would be in BaseRegistry. var parser = new json2object.JsonParser(); + parser.ignoreUnknownVariables = false; switch (loadEntryFile(id)) {