From 874a2d9e86adec6d606ad13a8e29ecbab63880a5 Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Sat, 16 Mar 2024 19:24:05 -0400 Subject: [PATCH 01/10] Formatting cleanup in assets folder --- .prettierignore | 1 + assets | 2 +- tests/unit/assets/shared/images/arrows.xml | 53 ++++++++++------------ 3 files changed, 26 insertions(+), 30 deletions(-) diff --git a/.prettierignore b/.prettierignore index 657ff3812..2e132c06f 100644 --- a/.prettierignore +++ b/.prettierignore @@ -4,6 +4,7 @@ export # Ignore all JSONS in the images folder (including FlxAnimate JSONs) assets/preload/images assets/shared/images +assets/weekend1/images # Don't ignore data files # TODO: These don't work. diff --git a/assets b/assets index 0e2c5bf21..8d393de26 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit 0e2c5bf2134c7e517b70cf74afd58abe5c7b5e50 +Subproject commit 8d393de26ecbbabcc8096258458df9eea8cb387f diff --git a/tests/unit/assets/shared/images/arrows.xml b/tests/unit/assets/shared/images/arrows.xml index 8f3355462..96a73a388 100644 --- a/tests/unit/assets/shared/images/arrows.xml +++ b/tests/unit/assets/shared/images/arrows.xml @@ -1,32 +1,27 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + From 3a35be916b0b544ef0c3f6fdcdc56685c653a05d Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Sat, 16 Mar 2024 22:20:22 -0400 Subject: [PATCH 02/10] A bunch of checkstyle fixes --- checkstyle.json | 2 +- source/Main.hx | 27 +- source/Postbuild.hx | 19 +- source/Prebuild.hx | 13 +- .../transition/FlxTransitionableSubState.hx | 234 ------------------ source/funkin/Conductor.hx | 64 +++-- source/funkin/InitState.hx | 37 +-- source/funkin/Paths.hx | 60 ++--- source/funkin/PlayerSettings.hx | 45 +++- source/funkin/Preferences.hx | 15 +- source/funkin/Preloader.hx | 4 +- source/funkin/play/PlayState.hx | 20 +- source/funkin/ui/MusicBeatSubState.hx | 2 +- source/funkin/ui/mainmenu/MainMenuState.hx | 6 +- source/funkin/util/MathUtil.hx | 27 +- source/funkin/util/MemoryUtil.hx | 14 +- source/funkin/util/MouseUtil.hx | 3 + source/funkin/util/PlatformUtil.hx | 8 +- source/funkin/util/SortUtil.hx | 50 +++- source/funkin/util/TimerUtil.hx | 21 +- source/funkin/util/TrackerUtil.hx | 2 +- source/funkin/util/VersionUtil.hx | 13 +- source/funkin/util/WindowUtil.hx | 12 +- source/haxe/ui/backend/flixel/UIStateBase.hx | 3 + .../haxe/ui/backend/flixel/UISubStateBase.hx | 3 + 25 files changed, 310 insertions(+), 394 deletions(-) delete mode 100644 source/flixel/addons/transition/FlxTransitionableSubState.hx diff --git a/checkstyle.json b/checkstyle.json index d41a6d617..5300d94ad 100644 --- a/checkstyle.json +++ b/checkstyle.json @@ -79,7 +79,7 @@ { "props": { "ignoreExtern": true, - "format": "^[A-Z][A-Z0-9]*(_[A-Z0-9_]+)*$", + "format": "^[a-z][A-Z][A-Z0-9]*(_[A-Z0-9_]+)*$", "tokens": ["INLINE", "NOTINLINE"] }, "type": "ConstantName" diff --git a/source/Main.hx b/source/Main.hx index a40fda29d..ee29eaf70 100644 --- a/source/Main.hx +++ b/source/Main.hx @@ -11,9 +11,11 @@ import openfl.display.Sprite; import openfl.events.Event; import openfl.Lib; import openfl.media.Video; -import funkin.util.CLIUtil; import openfl.net.NetStream; +/** + * The main class which initializes HaxeFlixel and starts the game in its initial state. + */ class Main extends Sprite { var gameWidth:Int = 1280; // Width of the game in pixels (might be less / more in actual pixels depending on your zoom). @@ -76,26 +78,27 @@ class Main extends Sprite var netStream:NetStream; var overlay:Sprite; + /** + * A frame counter displayed at the top left. + */ public static var fpsCounter:FPS; + + /** + * A RAM counter displayed at the top left. + */ public static var memoryCounter:MemoryCounter; function setupGame():Void { - /** - * The `zoom` argument of FlxGame was removed in the dev branch of Flixel, - * since it was considered confusing and unintuitive. - * If you want to change how the game scales when you resize the window, - * you can use `FlxG.scaleMode`. - * -Eric - */ - initHaxeUI(); + // addChild gets called by the user settings code. fpsCounter = new FPS(10, 3, 0xFFFFFF); - // addChild(fpsCounter); // Handled by Preferences.init + #if !html5 + // addChild gets called by the user settings code. + // TODO: disabled on HTML5 (todo: find another method that works?) memoryCounter = new MemoryCounter(10, 13, 0xFFFFFF); - // addChild(memoryCounter); #end // George recommends binding the save before FlxGame is created. @@ -105,6 +108,8 @@ class Main extends Sprite #if hxcpp_debug_server trace('hxcpp_debug_server is enabled! You can now connect to the game with a debugger.'); + #else + trace('hxcpp_debug_server is disabled! This build does not support debugging.'); #end } diff --git a/source/Postbuild.hx b/source/Postbuild.hx index f1827c4ab..405d0400b 100644 --- a/source/Postbuild.hx +++ b/source/Postbuild.hx @@ -3,34 +3,37 @@ package source; // Yeah, I know... import sys.FileSystem; import sys.io.File; +/** + * A script which executes after the game is built. + */ class Postbuild { - static inline final buildTimeFile = '.build_time'; + static inline final BUILD_TIME_FILE:String = '.build_time'; - static function main() + static function main():Void { printBuildTime(); } - static function printBuildTime() + static function printBuildTime():Void { // get buildEnd before fs operations since they are blocking var end:Float = Sys.time(); - if (FileSystem.exists(buildTimeFile)) + if (FileSystem.exists(BUILD_TIME_FILE)) { - var fi = File.read(buildTimeFile); + var fi:sys.io.FileInput = File.read(BUILD_TIME_FILE); var start:Float = fi.readDouble(); fi.close(); - sys.FileSystem.deleteFile(buildTimeFile); + sys.FileSystem.deleteFile(BUILD_TIME_FILE); - var buildTime = roundToTwoDecimals(end - start); + var buildTime:Float = roundToTwoDecimals(end - start); trace('Build took: ${buildTime} seconds'); } } - private static function roundToTwoDecimals(value:Float):Float + static function roundToTwoDecimals(value:Float):Float { return Math.round(value * 100) / 100; } diff --git a/source/Prebuild.hx b/source/Prebuild.hx index 18a5e2076..6856c414c 100644 --- a/source/Prebuild.hx +++ b/source/Prebuild.hx @@ -2,20 +2,23 @@ package source; // Yeah, I know... import sys.io.File; +/** + * A script which executes before the game is built. + */ class Prebuild { - static inline final buildTimeFile = '.build_time'; + static inline final BUILD_TIME_FILE:String = '.build_time'; - static function main() + static function main():Void { saveBuildTime(); trace('Building...'); } - static function saveBuildTime() + static function saveBuildTime():Void { - var fo = File.write(buildTimeFile); - var now = Sys.time(); + var fo:sys.io.FileOutput = File.write(BUILD_TIME_FILE); + var now:Float = Sys.time(); fo.writeDouble(now); fo.close(); } diff --git a/source/flixel/addons/transition/FlxTransitionableSubState.hx b/source/flixel/addons/transition/FlxTransitionableSubState.hx deleted file mode 100644 index ab416adbc..000000000 --- a/source/flixel/addons/transition/FlxTransitionableSubState.hx +++ /dev/null @@ -1,234 +0,0 @@ -package flixel.addons.transition; - -import flixel.FlxSubState; -import flixel.addons.transition.FlxTransitionableState; - -/** - * A `FlxSubState` which can perform visual transitions - * - * Usage: - * - * First, extend `FlxTransitionableSubState` as ie, `FooState`. - * - * Method 1: - * - * ```haxe - * var in:TransitionData = new TransitionData(...); // add your data where "..." is - * var out:TransitionData = new TransitionData(...); - * - * FlxG.switchState(() -> new FooState(in,out)); - * ``` - * - * Method 2: - * - * ```haxe - * FlxTransitionableSubState.defaultTransIn = new TransitionData(...); - * FlxTransitionableSubState.defaultTransOut = new TransitionData(...); - * - * FlxG.switchState(() -> new FooState()); - * ``` - */ -class FlxTransitionableSubState extends FlxSubState -{ - // global default transitions for ALL states, used if transIn/transOut are null - public static var defaultTransIn(get, set):TransitionData; - - static function get_defaultTransIn():TransitionData - { - return FlxTransitionableState.defaultTransIn; - } - - static function set_defaultTransIn(value:TransitionData):TransitionData - { - return FlxTransitionableState.defaultTransIn = value; - } - - public static var defaultTransOut(get, set):TransitionData; - - static function get_defaultTransOut():TransitionData - { - return FlxTransitionableState.defaultTransOut; - } - - static function set_defaultTransOut(value:TransitionData):TransitionData - { - return FlxTransitionableState.defaultTransOut = value; - } - - public static var skipNextTransIn(get, set):Bool; - - static function get_skipNextTransIn():Bool - { - return FlxTransitionableState.skipNextTransIn; - } - - static function set_skipNextTransIn(value:Bool):Bool - { - return FlxTransitionableState.skipNextTransIn = value; - } - - public static var skipNextTransOut(get, set):Bool; - - static function get_skipNextTransOut():Bool - { - return FlxTransitionableState.skipNextTransOut; - } - - static function set_skipNextTransOut(value:Bool):Bool - { - return FlxTransitionableState.skipNextTransOut = value; - } - - // beginning & ending transitions for THIS state: - public var transIn:TransitionData; - public var transOut:TransitionData; - - public var hasTransIn(get, never):Bool; - public var hasTransOut(get, never):Bool; - - /** - * Create a state with the ability to do visual transitions - * @param TransIn Plays when the state begins - * @param TransOut Plays when the state ends - */ - public function new(?TransIn:TransitionData, ?TransOut:TransitionData) - { - transIn = TransIn; - transOut = TransOut; - - if (transIn == null && defaultTransIn != null) - { - transIn = defaultTransIn; - } - if (transOut == null && defaultTransOut != null) - { - transOut = defaultTransOut; - } - super(); - } - - override function destroy():Void - { - super.destroy(); - transIn = null; - transOut = null; - _onExit = null; - } - - override function create():Void - { - super.create(); - transitionIn(); - } - - override function startOutro(onOutroComplete:() -> Void) - { - if (!hasTransOut) onOutroComplete(); - else if (!_exiting) - { - // play the exit transition, and when it's done call FlxG.switchState - _exiting = true; - transitionOut(onOutroComplete); - - if (skipNextTransOut) - { - skipNextTransOut = false; - finishTransOut(); - } - } - } - - /** - * Starts the in-transition. Can be called manually at any time. - */ - public function transitionIn():Void - { - if (transIn != null && transIn.type != NONE) - { - if (skipNextTransIn) - { - skipNextTransIn = false; - if (finishTransIn != null) - { - finishTransIn(); - } - return; - } - - var _trans = createTransition(transIn); - - _trans.setStatus(FULL); - openSubState(_trans); - - _trans.finishCallback = finishTransIn; - _trans.start(OUT); - } - } - - /** - * Starts the out-transition. Can be called manually at any time. - */ - public function transitionOut(?OnExit:Void->Void):Void - { - _onExit = OnExit; - if (hasTransOut) - { - var _trans = createTransition(transOut); - - _trans.setStatus(EMPTY); - openSubState(_trans); - - _trans.finishCallback = finishTransOut; - _trans.start(IN); - } - else - { - _onExit(); - } - } - - var transOutFinished:Bool = false; - - var _exiting:Bool = false; - var _onExit:Void->Void; - - function get_hasTransIn():Bool - { - return transIn != null && transIn.type != NONE; - } - - function get_hasTransOut():Bool - { - return transOut != null && transOut.type != NONE; - } - - function createTransition(data:TransitionData):Transition - { - return switch (data.type) - { - case TILES: new Transition(data); - case FADE: new Transition(data); - default: null; - } - } - - function finishTransIn() - { - closeSubState(); - } - - function finishTransOut() - { - transOutFinished = true; - - if (!_exiting) - { - closeSubState(); - } - - if (_onExit != null) - { - _onExit(); - } - } -} diff --git a/source/funkin/Conductor.hx b/source/funkin/Conductor.hx index 05c23108f..01147ce31 100644 --- a/source/funkin/Conductor.hx +++ b/source/funkin/Conductor.hx @@ -3,7 +3,6 @@ package funkin; import funkin.util.Constants; import flixel.util.FlxSignal; import flixel.math.FlxMath; -import funkin.play.song.Song.SongDifficulty; import funkin.data.song.SongData.SongTimeChange; import funkin.data.song.SongDataUtils; @@ -136,6 +135,9 @@ class Conductor return beatLengthMs / timeSignatureNumerator; } + /** + * The numerator for the current time signature (the `3` in `3/4`). + */ public var timeSignatureNumerator(get, never):Int; function get_timeSignatureNumerator():Int @@ -145,6 +147,9 @@ class Conductor return currentTimeChange.timeSignatureNum; } + /** + * The denominator for the current time signature (the `4` in `3/4`). + */ public var timeSignatureDenominator(get, never):Int; function get_timeSignatureDenominator():Int @@ -245,7 +250,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 function forceBPM(?bpm:Float = null) + public function forceBPM(?bpm:Float):Void { if (bpm != null) { @@ -253,7 +258,7 @@ class Conductor } else { - // trace('[CONDUCTOR] Resetting BPM to default'); + trace('[CONDUCTOR] Resetting BPM to default'); } this.bpmOverride = bpm; @@ -266,7 +271,7 @@ class Conductor * @param songPosition The current position in the song in milliseconds. * Leave blank to use the FlxG.sound.music position. */ - public function update(?songPos:Float) + public function update(?songPos:Float):Void { if (songPos == null) { @@ -274,9 +279,9 @@ class Conductor songPos = (FlxG.sound.music != null) ? (FlxG.sound.music.time + instrumentalOffset + formatOffset) : 0.0; } - var oldMeasure = this.currentMeasure; - var oldBeat = this.currentBeat; - var oldStep = this.currentStep; + var oldMeasure:Float = this.currentMeasure; + var oldBeat:Float = this.currentBeat; + var oldStep:Float = this.currentStep; // Set the song position we are at (for purposes of calculating note positions, etc). this.songPosition = songPos; @@ -338,39 +343,43 @@ class Conductor } } - public function mapTimeChanges(songTimeChanges:Array) + /** + * Apply the `SongTimeChange` data from the song metadata to this Conductor. + * @param songTimeChanges The SongTimeChanges. + */ + public function mapTimeChanges(songTimeChanges:Array):Void { timeChanges = []; // Sort in place just in case it's out of order. SongDataUtils.sortTimeChanges(songTimeChanges); - for (currentTimeChange in songTimeChanges) + for (songTimeChange in songTimeChanges) { // TODO: Maybe handle this different? // Do we care about BPM at negative timestamps? // Without any custom handling, `currentStepTime` becomes non-zero at `songPosition = 0`. - if (currentTimeChange.timeStamp < 0.0) currentTimeChange.timeStamp = 0.0; + if (songTimeChange.timeStamp < 0.0) songTimeChange.timeStamp = 0.0; - if (currentTimeChange.timeStamp <= 0.0) + if (songTimeChange.timeStamp <= 0.0) { - currentTimeChange.beatTime = 0.0; + songTimeChange.beatTime = 0.0; } else { // Calculate the beat time of this timestamp. - currentTimeChange.beatTime = 0.0; + songTimeChange.beatTime = 0.0; - if (currentTimeChange.timeStamp > 0.0 && timeChanges.length > 0) + if (songTimeChange.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), + songTimeChange.beatTime = FlxMath.roundDecimal(prevTimeChange.beatTime + + ((songTimeChange.timeStamp - prevTimeChange.timeStamp) * prevTimeChange.bpm / Constants.SECS_PER_MIN / Constants.MS_PER_SEC), 4); } } - timeChanges.push(currentTimeChange); + timeChanges.push(songTimeChange); } if (timeChanges.length > 0) @@ -384,6 +393,8 @@ class Conductor /** * Given a time in milliseconds, return a time in steps. + * @param ms The time in milliseconds. + * @return The time in steps. */ public function getTimeInSteps(ms:Float):Float { @@ -413,7 +424,7 @@ class Conductor var lastStepLengthMs:Float = ((Constants.SECS_PER_MIN / lastTimeChange.bpm) * Constants.MS_PER_SEC) / timeSignatureNumerator; var resultFractionalStep:Float = (ms - lastTimeChange.timeStamp) / lastStepLengthMs; - resultStep += resultFractionalStep; // Math.floor(); + resultStep += resultFractionalStep; return resultStep; } @@ -421,6 +432,8 @@ class Conductor /** * Given a time in steps and fractional steps, return a time in milliseconds. + * @param stepTime The time in steps. + * @return The time in milliseconds. */ public function getStepTimeInMs(stepTime:Float):Float { @@ -457,6 +470,8 @@ class Conductor /** * Given a time in beats and fractional beats, return a time in milliseconds. + * @param beatTime The time in beats. + * @return The time in milliseconds. */ public function getBeatTimeInMs(beatTime:Float):Float { @@ -491,13 +506,16 @@ class Conductor } } + /** + * Add variables of the current Conductor instance to the Flixel debugger. + */ 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); + 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); } /** diff --git a/source/funkin/InitState.hx b/source/funkin/InitState.hx index a9e8dbffa..401147ee4 100644 --- a/source/funkin/InitState.hx +++ b/source/funkin/InitState.hx @@ -12,7 +12,6 @@ import flixel.math.FlxRect; import flixel.FlxSprite; import flixel.system.debug.log.LogStyle; import flixel.util.FlxColor; -import funkin.ui.options.PreferencesMenu; import funkin.util.macro.MacroUtil; import funkin.util.WindowUtil; import funkin.play.PlayStatePlaylist; @@ -31,7 +30,6 @@ import funkin.ui.title.TitleState; import funkin.util.CLIUtil; import funkin.util.CLIUtil.CLIParams; import funkin.util.TimerUtil; -import funkin.ui.transition.LoadingState; import funkin.util.TrackerUtil; #if discord_rpc import Discord.DiscordClient; @@ -169,8 +167,9 @@ class InitState extends FlxState SpeakerRegistry.instance.loadEntries(); StageRegistry.instance.loadEntries(); - // TODO: CharacterDataParser doesn't use json2object, so it's way slower than the other parsers. - CharacterDataParser.loadCharacterCache(); // TODO: Migrate characters to BaseRegistry. + // TODO: CharacterDataParser doesn't use json2object, so it's way slower than the other parsers and more prone to syntax errors. + // Move it to use a BaseRegistry. + CharacterDataParser.loadCharacterCache(); ModuleHandler.buildModuleCallbacks(); ModuleHandler.loadModuleCache(); @@ -188,25 +187,35 @@ class InitState extends FlxState */ function startGame():Void { - #if SONG // -DSONG=bopeebo + #if SONG + // -DSONG=bopeebo startSong(defineSong(), defineDifficulty()); - #elseif LEVEL // -DLEVEL=week1 -DDIFFICULTY=hard + #elseif LEVEL + // -DLEVEL=week1 -DDIFFICULTY=hard startLevel(defineLevel(), defineDifficulty()); - #elseif FREEPLAY // -DFREEPLAY + #elseif FREEPLAY + // -DFREEPLAY FlxG.switchState(() -> new funkin.ui.freeplay.FreeplayState()); - #elseif DIALOGUE // -DDIALOGUE + #elseif DIALOGUE + // -DDIALOGUE FlxG.switchState(() -> new funkin.ui.debug.dialogue.ConversationDebugState()); - #elseif ANIMATE // -DANIMATE + #elseif ANIMATE + // -DANIMATE FlxG.switchState(() -> new funkin.ui.debug.anim.FlxAnimateTest()); - #elseif WAVEFORM // -DWAVEFORM + #elseif WAVEFORM + // -DWAVEFORM FlxG.switchState(() -> new funkin.ui.debug.WaveformTestState()); - #elseif CHARTING // -DCHARTING + #elseif CHARTING + // -DCHARTING FlxG.switchState(() -> new funkin.ui.debug.charting.ChartEditorState()); - #elseif STAGEBUILD // -DSTAGEBUILD + #elseif STAGEBUILD + // -DSTAGEBUILD FlxG.switchState(() -> new funkin.ui.debug.stage.StageBuilderState()); - #elseif ANIMDEBUG // -DANIMDEBUG + #elseif ANIMDEBUG + // -DANIMDEBUG FlxG.switchState(() -> new funkin.ui.debug.anim.DebugBoundingState()); - #elseif LATENCY // -DLATENCY + #elseif LATENCY + // -DLATENCY FlxG.switchState(() -> new funkin.LatencyState()); #else startGameNormally(); diff --git a/source/funkin/Paths.hx b/source/funkin/Paths.hx index 6006939be..d2c4833f2 100644 --- a/source/funkin/Paths.hx +++ b/source/funkin/Paths.hx @@ -11,144 +11,144 @@ class Paths { static var currentLevel:String; - static public function setCurrentLevel(name:String) + public static function setCurrentLevel(name:String):Void { currentLevel = name.toLowerCase(); } public static function stripLibrary(path:String):String { - var parts = path.split(':'); + var parts:Array = path.split(':'); if (parts.length < 2) return path; return parts[1]; } public static function getLibrary(path:String):String { - var parts = path.split(':'); - if (parts.length < 2) return "preload"; + var parts:Array = path.split(':'); + if (parts.length < 2) return 'preload'; return parts[0]; } - static function getPath(file:String, type:AssetType, library:Null) + static function getPath(file:String, type:AssetType, library:Null):String { if (library != null) return getLibraryPath(file, library); if (currentLevel != null) { - var levelPath = getLibraryPathForce(file, currentLevel); + var levelPath:String = getLibraryPathForce(file, currentLevel); if (OpenFlAssets.exists(levelPath, type)) return levelPath; } - var levelPath = getLibraryPathForce(file, "shared"); + var levelPath:String = getLibraryPathForce(file, 'shared'); if (OpenFlAssets.exists(levelPath, type)) return levelPath; return getPreloadPath(file); } - static public function getLibraryPath(file:String, library = "preload") + public static function getLibraryPath(file:String, library = 'preload'):String { - return if (library == "preload" || library == "default") getPreloadPath(file); else getLibraryPathForce(file, library); + return if (library == 'preload' || library == 'default') getPreloadPath(file); else getLibraryPathForce(file, library); } - inline static function getLibraryPathForce(file:String, library:String) + static inline function getLibraryPathForce(file:String, library:String):String { return '$library:assets/$library/$file'; } - inline static function getPreloadPath(file:String) + static inline function getPreloadPath(file:String):String { return 'assets/$file'; } - inline static public function file(file:String, type:AssetType = TEXT, ?library:String) + public static function file(file:String, type:AssetType = TEXT, ?library:String):String { return getPath(file, type, library); } - public static inline function animateAtlas(path:String, ?library:String) + public static function animateAtlas(path:String, ?library:String):String { return getLibraryPath('images/$path', library); } - inline static public function txt(key:String, ?library:String) + public static function txt(key:String, ?library:String):String { return getPath('data/$key.txt', TEXT, library); } - inline static public function frag(key:String, ?library:String) + public static function frag(key:String, ?library:String):String { return getPath('shaders/$key.frag', TEXT, library); } - inline static public function vert(key:String, ?library:String) + public static function vert(key:String, ?library:String):String { return getPath('shaders/$key.vert', TEXT, library); } - inline static public function xml(key:String, ?library:String) + public static function xml(key:String, ?library:String):String { return getPath('data/$key.xml', TEXT, library); } - inline static public function json(key:String, ?library:String) + public static function json(key:String, ?library:String):String { return getPath('data/$key.json', TEXT, library); } - static public function sound(key:String, ?library:String) + public static function sound(key:String, ?library:String):String { return getPath('sounds/$key.${Constants.EXT_SOUND}', SOUND, library); } - inline static public function soundRandom(key:String, min:Int, max:Int, ?library:String) + public static function soundRandom(key:String, min:Int, max:Int, ?library:String):String { return sound(key + FlxG.random.int(min, max), library); } - inline static public function music(key:String, ?library:String) + public static function music(key:String, ?library:String):String { return getPath('music/$key.${Constants.EXT_SOUND}', MUSIC, library); } - inline static public function videos(key:String, ?library:String) + public static function videos(key:String, ?library:String):String { return getPath('videos/$key.${Constants.EXT_VIDEO}', BINARY, library); } - inline static public function voices(song:String, ?suffix:String = '') + public static function voices(song:String, ?suffix:String = ''):String { - if (suffix == null) suffix = ""; // no suffix, for a sorta backwards compatibility with older-ish voice files + if (suffix == null) suffix = ''; // no suffix, for a sorta backwards compatibility with older-ish voice files return 'songs:assets/songs/${song.toLowerCase()}/Voices$suffix.${Constants.EXT_SOUND}'; } - inline static public function inst(song:String, ?suffix:String = '') + public static function inst(song:String, ?suffix:String = ''):String { return 'songs:assets/songs/${song.toLowerCase()}/Inst$suffix.${Constants.EXT_SOUND}'; } - inline static public function image(key:String, ?library:String) + public static function image(key:String, ?library:String):String { return getPath('images/$key.png', IMAGE, library); } - inline static public function font(key:String) + public static function font(key:String):String { return 'assets/fonts/$key'; } - inline static public function ui(key:String, ?library:String) + public static function ui(key:String, ?library:String):String { return xml('ui/$key', library); } - static public function getSparrowAtlas(key:String, ?library:String) + public static function getSparrowAtlas(key:String, ?library:String):FlxAtlasFrames { return FlxAtlasFrames.fromSparrow(image(key, library), file('images/$key.xml', library)); } - inline static public function getPackerAtlas(key:String, ?library:String) + public static function getPackerAtlas(key:String, ?library:String):FlxAtlasFrames { return FlxAtlasFrames.fromSpriteSheetPacker(image(key, library), file('images/$key.txt', library)); } diff --git a/source/funkin/PlayerSettings.hx b/source/funkin/PlayerSettings.hx index 5a9351bba..b4c871c29 100644 --- a/source/funkin/PlayerSettings.hx +++ b/source/funkin/PlayerSettings.hx @@ -13,6 +13,7 @@ import flixel.util.FlxSignal; */ class PlayerSettings { + // TODO: Finish implementation of second player. public static var numPlayers(default, null) = 0; public static var numAvatars(default, null) = 0; public static var player1(default, null):PlayerSettings; @@ -21,12 +22,21 @@ class PlayerSettings public static var onAvatarAdd(default, null) = new FlxTypedSignalVoid>(); public static var onAvatarRemove(default, null) = new FlxTypedSignalVoid>(); + /** + * The player number associated with this settings object. + */ public var id(default, null):Int; + /** + * The controls handler for this player. + */ public var controls(default, null):Controls; /** * Return the PlayerSettings for the given player number, or `null` if that player isn't active. + * + * @param id The player number this represents. + * @return The PlayerSettings for the given player number, or `null` if that player isn't active. */ public static function get(id:Int):Null { @@ -38,6 +48,9 @@ class PlayerSettings }; } + /** + * Initialize the PlayerSettings singletons for each player. + */ public static function init():Void { if (player1 == null) @@ -56,22 +69,30 @@ class PlayerSettings } } - public static function reset() + /** + * Forcibly destroy the PlayerSettings singletons for each player. + */ + public static function reset():Void { player1 = null; player2 = null; numPlayers = 0; } - static function onGamepadAdded(gamepad:FlxGamepad) + /** + * Callback invoked when a gamepad is added. + * @param gamepad The gamepad that was added. + */ + static function onGamepadAdded(gamepad:FlxGamepad):Void { + // TODO: Make this detect and handle multiple players player1.addGamepad(gamepad); } /** * @param id The player number this represents. This was refactored to START AT `1`. */ - private function new(id:Int) + function new(id:Int) { trace('loading player settings for id: $id'); @@ -83,11 +104,11 @@ class PlayerSettings function addKeyboard():Void { - var useDefault = true; + var useDefault:Bool = true; if (Save.instance.hasControls(id, Keys)) { var keyControlData = Save.instance.getControls(id, Keys); - trace("keyControlData: " + haxe.Json.stringify(keyControlData)); + trace('Loading keyboard control scheme from user save'); useDefault = false; controls.fromSaveData(keyControlData, Keys); } @@ -98,7 +119,7 @@ class PlayerSettings if (useDefault) { - trace("Loading default keyboard control scheme"); + trace('Loading default keyboard control scheme'); controls.setKeyboardScheme(Solo); } @@ -109,13 +130,13 @@ class PlayerSettings * Called after an FlxGamepad has been detected. * @param gamepad The gamepad that was detected. */ - function addGamepad(gamepad:FlxGamepad) + function addGamepad(gamepad:FlxGamepad):Void { var useDefault = true; if (Save.instance.hasControls(id, Gamepad(gamepad.id))) { var padControlData = Save.instance.getControls(id, Gamepad(gamepad.id)); - trace("padControlData: " + haxe.Json.stringify(padControlData)); + trace('Loading gamepad control scheme from user save'); useDefault = false; controls.addGamepadWithSaveData(gamepad.id, padControlData); } @@ -126,7 +147,7 @@ class PlayerSettings if (useDefault) { - trace("Loading gamepad control scheme"); + trace('Loading default gamepad control scheme'); controls.addDefaultGamepad(gamepad.id); } PreciseInputManager.instance.initializeButtons(controls, gamepad); @@ -135,12 +156,12 @@ class PlayerSettings /** * Save this player's controls to the game's persistent save. */ - public function saveControls() + public function saveControls():Void { var keyData = controls.createSaveData(Keys); if (keyData != null) { - trace("saving key data: " + haxe.Json.stringify(keyData)); + trace('Saving keyboard control scheme to user save'); Save.instance.setControls(id, Keys, keyData); } @@ -149,7 +170,7 @@ class PlayerSettings var padData = controls.createSaveData(Gamepad(controls.gamepadsAdded[0])); if (padData != null) { - trace("saving pad data: " + haxe.Json.stringify(padData)); + trace('Saving gamepad control scheme to user save'); Save.instance.setControls(id, Gamepad(controls.gamepadsAdded[0]), padData); } } diff --git a/source/funkin/Preferences.hx b/source/funkin/Preferences.hx index 60c7a996a..d8066c581 100644 --- a/source/funkin/Preferences.hx +++ b/source/funkin/Preferences.hx @@ -20,7 +20,7 @@ class Preferences static function set_naughtyness(value:Bool):Bool { - var save = Save.instance; + var save:Save = Save.instance; save.options.naughtyness = value; save.flush(); return value; @@ -39,7 +39,7 @@ class Preferences static function set_downscroll(value:Bool):Bool { - var save = Save.instance; + var save:Save = Save.instance; save.options.downscroll = value; save.flush(); return value; @@ -58,7 +58,7 @@ class Preferences static function set_flashingLights(value:Bool):Bool { - var save = Save.instance; + var save:Save = Save.instance; save.options.flashingLights = value; save.flush(); return value; @@ -77,7 +77,7 @@ class Preferences static function set_zoomCamera(value:Bool):Bool { - var save = Save.instance; + var save:Save = Save.instance; save.options.zoomCamera = value; save.flush(); return value; @@ -122,15 +122,20 @@ class Preferences { if (value != Save.instance.options.autoPause) FlxG.autoPause = value; - var save = Save.instance; + var save:Save = Save.instance; save.options.autoPause = value; save.flush(); return value; } + /** + * Loads the user's preferences from the save data and apply them. + */ public static function init():Void { + // Apply the autoPause setting (enables automatic pausing on focus lost). FlxG.autoPause = Preferences.autoPause; + // Apply the debugDisplay setting (enables the FPS and RAM display). toggleDebugDisplay(Preferences.debugDisplay); } diff --git a/source/funkin/Preloader.hx b/source/funkin/Preloader.hx index 2a73d8199..157015ba6 100644 --- a/source/funkin/Preloader.hx +++ b/source/funkin/Preloader.hx @@ -3,7 +3,6 @@ package funkin; import flash.Lib; import flash.display.Bitmap; import flash.display.BitmapData; -import flash.display.BlendMode; import flash.display.Sprite; import flixel.system.FlxBasePreloader; import openfl.display.Sprite; @@ -12,7 +11,8 @@ import openfl.text.TextField; import openfl.text.TextFormat; import flixel.system.FlxAssets; -@:bitmap("art/preloaderArt.png") class LogoImage extends BitmapData {} +@:bitmap('art/preloaderArt.png') +class LogoImage extends BitmapData {} class Preloader extends FlxBasePreloader { diff --git a/source/funkin/play/PlayState.hx b/source/funkin/play/PlayState.hx index 984f27c26..2db3a27b9 100644 --- a/source/funkin/play/PlayState.hx +++ b/source/funkin/play/PlayState.hx @@ -2,11 +2,7 @@ package funkin.play; import funkin.audio.FunkinSound; import flixel.addons.display.FlxPieDial; -import flixel.addons.display.FlxPieDial; import flixel.addons.transition.FlxTransitionableState; -import flixel.addons.transition.FlxTransitionableState; -import flixel.addons.transition.FlxTransitionableSubState; -import flixel.addons.transition.FlxTransitionableSubState; import flixel.addons.transition.Transition; import flixel.addons.transition.Transition; import flixel.FlxCamera; @@ -923,8 +919,8 @@ class PlayState extends MusicBeatSubState var pauseSubState:FlxSubState = new PauseSubState({mode: isChartingMode ? Charting : Standard}); - FlxTransitionableSubState.skipNextTransIn = true; - FlxTransitionableSubState.skipNextTransOut = true; + FlxTransitionableState.skipNextTransIn = true; + FlxTransitionableState.skipNextTransOut = true; pauseSubState.camera = camHUD; openSubState(pauseSubState); // boyfriendPos.put(); // TODO: Why is this here? @@ -1045,8 +1041,8 @@ class PlayState extends MusicBeatSubState isChartingMode: isChartingMode, transparent: persistentDraw }); - FlxTransitionableSubState.skipNextTransIn = true; - FlxTransitionableSubState.skipNextTransOut = true; + FlxTransitionableState.skipNextTransIn = true; + FlxTransitionableState.skipNextTransOut = true; openSubState(gameOverSubState); } @@ -2610,8 +2606,8 @@ class PlayState extends MusicBeatSubState var pauseSubState:FlxSubState = new PauseSubState({mode: Conversation}); persistentUpdate = false; - FlxTransitionableSubState.skipNextTransIn = true; - FlxTransitionableSubState.skipNextTransOut = true; + FlxTransitionableState.skipNextTransIn = true; + FlxTransitionableState.skipNextTransOut = true; pauseSubState.camera = camCutscene; openSubState(pauseSubState); } @@ -2626,8 +2622,8 @@ class PlayState extends MusicBeatSubState var pauseSubState:FlxSubState = new PauseSubState({mode: Cutscene}); persistentUpdate = false; - FlxTransitionableSubState.skipNextTransIn = true; - FlxTransitionableSubState.skipNextTransOut = true; + FlxTransitionableState.skipNextTransIn = true; + FlxTransitionableState.skipNextTransOut = true; pauseSubState.camera = camCutscene; openSubState(pauseSubState); } diff --git a/source/funkin/ui/MusicBeatSubState.hx b/source/funkin/ui/MusicBeatSubState.hx index dc742874f..e9effdbee 100644 --- a/source/funkin/ui/MusicBeatSubState.hx +++ b/source/funkin/ui/MusicBeatSubState.hx @@ -1,6 +1,6 @@ package funkin.ui; -import flixel.addons.transition.FlxTransitionableSubState; +import flixel.addons.transition.FlxTransitionableState; import flixel.FlxSubState; import flixel.text.FlxText; import funkin.ui.mainmenu.MainMenuState; diff --git a/source/funkin/ui/mainmenu/MainMenuState.hx b/source/funkin/ui/mainmenu/MainMenuState.hx index 1892bdec1..f4d48dba3 100644 --- a/source/funkin/ui/mainmenu/MainMenuState.hx +++ b/source/funkin/ui/mainmenu/MainMenuState.hx @@ -1,6 +1,6 @@ package funkin.ui.mainmenu; -import flixel.addons.transition.FlxTransitionableSubState; +import flixel.addons.transition.FlxTransitionableState; import funkin.ui.debug.DebugMenuSubState; import flixel.FlxObject; import flixel.FlxSprite; @@ -103,8 +103,8 @@ class MainMenuState extends MusicBeatState persistentDraw = true; persistentUpdate = false; // Freeplay has its own custom transition - FlxTransitionableSubState.skipNextTransIn = true; - FlxTransitionableSubState.skipNextTransOut = true; + FlxTransitionableState.skipNextTransIn = true; + FlxTransitionableState.skipNextTransOut = true; openSubState(new FreeplayState()); }); diff --git a/source/funkin/util/MathUtil.hx b/source/funkin/util/MathUtil.hx index 5fed1d3e1..0e7c29d73 100644 --- a/source/funkin/util/MathUtil.hx +++ b/source/funkin/util/MathUtil.hx @@ -13,12 +13,24 @@ class MathUtil /** * Perform linear interpolation between the base and the target, based on the current framerate. + * @param base The starting value, when `progress <= 0`. + * @param target The ending value, when `progress >= 1`. + * @param ratio Value used to interpolate between `base` and `target`. + * + * @return The interpolated value. */ public static function coolLerp(base:Float, target:Float, ratio:Float):Float { return base + cameraLerp(ratio) * (target - base); } + /** + * Perform linear interpolation based on the current framerate. + * @param lerp Value used to interpolate between `base` and `target`. + * + * @return The interpolated value. + */ + @:deprecated('Use smoothLerp instead') public static function cameraLerp(lerp:Float):Float { return lerp * (FlxG.elapsed / (1 / 60)); @@ -30,26 +42,30 @@ class MathUtil * @param value The value to get the logarithm of. * @return `log_base(value)` */ - public static function logBase(base:Float, value:Float) + public static function logBase(base:Float, value:Float):Float { return Math.log(value) / Math.log(base); } /** - * @returns `2^x` + * Get the base-2 logarithm of a value. + * @param x value + * @return `2^x` */ - public static function exp2(x:Float) + public static function exp2(x:Float):Float { return Math.pow(2, x); } /** * Linearly interpolate between two values. + * * @param base The starting value, when `progress <= 0`. * @param target The ending value, when `progress >= 1`. * @param progress Value used to interpolate between `base` and `target`. + * @return The interpolated value. */ - public static function lerp(base:Float, target:Float, progress:Float) + public static function lerp(base:Float, target:Float, progress:Float):Float { return base + progress * (target - base); } @@ -62,9 +78,12 @@ class MathUtil * @param duration The total duration of the interpolation. Nominal duration until remaining distance is less than `precision`. * @param precision The target precision of the interpolation. Defaults to 1% of distance remaining. * @see https://twitter.com/FreyaHolmer/status/1757918211679650262 + * + * @return The interpolated value. */ public static function smoothLerp(current:Float, target:Float, elapsed:Float, duration:Float, precision:Float = 1 / 100):Float { + // An alternative algorithm which uses a separate half-life value: // var halfLife:Float = -duration / logBase(2, precision); // lerp(current, target, 1 - exp2(-elapsed / halfLife)); diff --git a/source/funkin/util/MemoryUtil.hx b/source/funkin/util/MemoryUtil.hx index 6b5f7deea..f5935ed67 100644 --- a/source/funkin/util/MemoryUtil.hx +++ b/source/funkin/util/MemoryUtil.hx @@ -16,7 +16,7 @@ class MemoryUtil public static function buildGCInfo():String { #if cpp - var result = "HXCPP-Immix:"; + var result:String = 'HXCPP-Immix:'; result += '\n- Memory Used: ${cpp.vm.Gc.memInfo(cpp.vm.Gc.MEM_INFO_USAGE)} bytes'; result += '\n- Memory Reserved: ${cpp.vm.Gc.memInfo(cpp.vm.Gc.MEM_INFO_RESERVED)} bytes'; result += '\n- Memory Current Pool: ${cpp.vm.Gc.memInfo(cpp.vm.Gc.MEM_INFO_CURRENT)} bytes'; @@ -35,10 +35,10 @@ class MemoryUtil result += '\n- HXCPP C++11: ${#if HXCPP_CPP11 'Enabled' #else 'Disabled' #end}'; result += '\n- Source Annotation: ${#if annotate_source 'Enabled' #else 'Disabled' #end}'; #elseif js - var result = "JS-MNS:"; + var result:String = 'JS-MNS:'; result += '\n- Memory Used: ${getMemoryUsed()} bytes'; #else - var result = "Unknown GC"; + var result:String = 'Unknown GC'; #end return result; @@ -66,7 +66,7 @@ class MemoryUtil #if cpp cpp.vm.Gc.enable(true); #else - throw "Not implemented!"; + throw 'Not implemented!'; #end } @@ -78,7 +78,7 @@ class MemoryUtil #if cpp cpp.vm.Gc.enable(false); #else - throw "Not implemented!"; + throw 'Not implemented!'; #end } @@ -92,7 +92,7 @@ class MemoryUtil #if cpp cpp.vm.Gc.run(major); #else - throw "Not implemented!"; + throw 'Not implemented!'; #end } @@ -107,7 +107,7 @@ class MemoryUtil #if cpp cpp.vm.Gc.compact(); #else - throw "Not implemented!"; + throw 'Not implemented!'; #end } } diff --git a/source/funkin/util/MouseUtil.hx b/source/funkin/util/MouseUtil.hx index c3f46819e..5248437a8 100644 --- a/source/funkin/util/MouseUtil.hx +++ b/source/funkin/util/MouseUtil.hx @@ -38,6 +38,9 @@ class MouseUtil } } + /** + * Increment the zoom level of the current camera by the mouse wheel scroll value. + */ public static function mouseWheelZoom():Void { if (FlxG.mouse.wheel != 0) FlxG.camera.zoom += FlxG.mouse.wheel * (0.1 * FlxG.camera.zoom); diff --git a/source/funkin/util/PlatformUtil.hx b/source/funkin/util/PlatformUtil.hx index eecf6a7ea..ae8c1dcee 100644 --- a/source/funkin/util/PlatformUtil.hx +++ b/source/funkin/util/PlatformUtil.hx @@ -16,9 +16,9 @@ class PlatformUtil #if mac return true; #elseif html5 - return js.Browser.window.navigator.platform.startsWith("Mac") - || js.Browser.window.navigator.platform.startsWith("iPad") - || js.Browser.window.navigator.platform.startsWith("iPhone"); + return js.Browser.window.navigator.platform.startsWith('Mac') + || js.Browser.window.navigator.platform.startsWith('iPad') + || js.Browser.window.navigator.platform.startsWith('iPhone'); #else return false; #end @@ -27,7 +27,7 @@ class PlatformUtil /** * Detects and returns the current host platform. * Always returns `HTML5` on web, regardless of the computer running that browser. - * Returns `null` if the platform could not be detected. + * @return The host platform, or `null` if the platform could not be detected. */ public static function detectHostPlatform():Null { diff --git a/source/funkin/util/SortUtil.hx b/source/funkin/util/SortUtil.hx index d87592c91..c5ac175be 100644 --- a/source/funkin/util/SortUtil.hx +++ b/source/funkin/util/SortUtil.hx @@ -27,29 +27,53 @@ class SortUtil /** * You can use this function in FlxTypedGroup.sort() to sort FlxObjects by their z-index values. * The value defaults to 0, but by assigning it you can easily rearrange objects as desired. + * + * @param order Either `FlxSort.ASCENDING` or `FlxSort.DESCENDING` + * @param a The first FlxObject to compare. + * @param b The second FlxObject to compare. + * @return 1 if `a` has a higher z-index, -1 if `b` has a higher z-index. */ - public static inline function byZIndex(Order:Int, Obj1:FlxBasic, Obj2:FlxBasic):Int + public static inline function byZIndex(order:Int, a:FlxBasic, b:FlxBasic):Int { - if (Obj1 == null || Obj2 == null) return 0; - return FlxSort.byValues(Order, Obj1.zIndex, Obj2.zIndex); + if (a == null || b == null) return 0; + return FlxSort.byValues(order, a.zIndex, b.zIndex); } /** * Given two Notes, returns 1 or -1 based on whether `a` or `b` has an earlier strumtime. * * @param order Either `FlxSort.ASCENDING` or `FlxSort.DESCENDING` + * @param a The first Note to compare. + * @param b The second Note to compare. + * @return 1 if `a` has an earlier strumtime, -1 if `b` has an earlier strumtime. */ - public static inline function byStrumtime(order:Int, a:NoteSprite, b:NoteSprite) + public static inline function byStrumtime(order:Int, a:NoteSprite, b:NoteSprite):Int { return noteDataByTime(order, a.noteData, b.noteData); } - public static inline function noteDataByTime(order:Int, a:SongNoteData, b:SongNoteData) + /** + * Given two Note Data objects, returns 1 or -1 based on whether `a` or `b` has an earlier time. + * + * @param order Either `FlxSort.ASCENDING` or `FlxSort.DESCENDING` + * @param a The first Event to compare. + * @param b The second Event to compare. + * @return 1 if `a` has an earlier time, -1 if `b` has an earlier time. + */ + public static inline function noteDataByTime(order:Int, a:SongNoteData, b:SongNoteData):Int { return FlxSort.byValues(order, a.time, b.time); } - public static inline function eventDataByTime(order:Int, a:SongEventData, b:SongEventData) + /** + * Given two Event Data objects, returns 1 or -1 based on whether `a` or `b` has an earlier time. + * + * @param order Either `FlxSort.ASCENDING` or `FlxSort.DESCENDING` + * @param a The first Event to compare. + * @param b The second Event to compare. + * @return 1 if `a` has an earlier time, -1 if `b` has an earlier time. + */ + public static inline function eventDataByTime(order:Int, a:SongEventData, b:SongEventData):Int { return FlxSort.byValues(order, a.time, b.time); } @@ -58,8 +82,11 @@ class SortUtil * Given two FlxFrames, sort their names alphabetically. * * @param order Either `FlxSort.ASCENDING` or `FlxSort.DESCENDING` + * @param a The first Frame to compare. + * @param b The second Frame to compare. + * @return 1 if `a` has an earlier time, -1 if `b` has an earlier time. */ - public static inline function byFrameName(a:FlxFrame, b:FlxFrame) + public static inline function byFrameName(a:FlxFrame, b:FlxFrame):Int { return alphabetically(a.name, b.name); } @@ -68,6 +95,7 @@ class SortUtil * Sort predicate for sorting strings alphabetically. * @param a The first string to compare. * @param b The second string to compare. + * @return 1 if `a` comes before `b`, -1 if `b` comes before `a`, 0 if they are equal */ public static function alphabetically(a:String, b:String):Int { @@ -81,9 +109,11 @@ class SortUtil /** * Sort predicate which sorts two strings alphabetically, but prioritizes a specific string first. * Example usage: `array.sort(defaultThenAlphabetical.bind('test'))` will sort the array so that the string 'test' is first. + * + * @param defaultValue The value to prioritize. * @param a The first string to compare. * @param b The second string to compare. - * @param defaultValue The value to prioritize. + * @return 1 if `a` comes before `b`, -1 if `b` comes before `a`, 0 if they are equal */ public static function defaultThenAlphabetically(defaultValue:String, a:String, b:String):Int { @@ -96,9 +126,11 @@ class SortUtil /** * Sort predicate which sorts two strings alphabetically, but prioritizes a specific string first. * Example usage: `array.sort(defaultsThenAlphabetical.bind(['test']))` will sort the array so that the string 'test' is first. + * + * @param defaultValues The values to prioritize. * @param a The first string to compare. * @param b The second string to compare. - * @param defaultValues The values to prioritize. + * @return 1 if `a` comes before `b`, -1 if `b` comes before `a`, 0 if they are equal */ public static function defaultsThenAlphabetically(defaultValues:Array, a:String, b:String):Int { diff --git a/source/funkin/util/TimerUtil.hx b/source/funkin/util/TimerUtil.hx index caf49341b..eb2690e16 100644 --- a/source/funkin/util/TimerUtil.hx +++ b/source/funkin/util/TimerUtil.hx @@ -5,23 +5,42 @@ import haxe.Timer; class TimerUtil { + /** + * Store the current time. + */ public static function start():Float { return Timer.stamp(); } - private static function took(start:Float, ?end:Float):Float + /** + * Return the elapsed time. + */ + static function took(start:Float, ?end:Float):Float { var endOrNow:Float = end != null ? end : Timer.stamp(); return endOrNow - start; } + /** + * Return the elapsed time in seconds as a string. + * @param start The start time. + * @param end The end time. + * @param precision The number of decimal places to round to. + * @return The elapsed time in seconds as a string. + */ public static function seconds(start:Float, ?end:Float, ?precision = 2):String { var seconds:Float = FloatTools.round(took(start, end), precision); return '${seconds} seconds'; } + /** + * Return the elapsed time in milliseconds as a string. + * @param start The start time. + * @param end The end time. + * @return The elapsed time in milliseconds as a string. + */ public static function ms(start:Float, ?end:Float):String { var seconds:Float = took(start, end); diff --git a/source/funkin/util/TrackerUtil.hx b/source/funkin/util/TrackerUtil.hx index ffe374c5f..a2552f63e 100644 --- a/source/funkin/util/TrackerUtil.hx +++ b/source/funkin/util/TrackerUtil.hx @@ -18,7 +18,7 @@ class TrackerUtil public static function initTrackers():Void { #if FLX_DEBUG - Tracker.addProfile(new TrackerProfile(Highscore, ["tallies"])); + Tracker.addProfile(new TrackerProfile(Highscore, ['tallies'])); FlxG.console.registerClass(Highscore); #end } diff --git a/source/funkin/util/VersionUtil.hx b/source/funkin/util/VersionUtil.hx index e8d3d3652..247ba19db 100644 --- a/source/funkin/util/VersionUtil.hx +++ b/source/funkin/util/VersionUtil.hx @@ -15,6 +15,9 @@ class VersionUtil /** * Checks that a given verison number satisisfies a given version rule. * Version rule can be complex, e.g. "1.0.x" or ">=1.0.0,<1.1.0", or anything NPM supports. + * @param version The semantic version to validate. + * @param versionRule The version rule to validate against. + * @return `true` if the version satisfies the rule, `false` otherwise. */ public static function validateVersion(version:thx.semver.Version, versionRule:thx.semver.VersionRule):Bool { @@ -32,6 +35,9 @@ class VersionUtil /** * Checks that a given verison number satisisfies a given version rule. * Version rule can be complex, e.g. "1.0.x" or ">=1.0.0,<1.1.0", or anything NPM supports. + * @param version The semantic version to validate. + * @param versionRule The version rule to validate against. + * @return `true` if the version satisfies the rule, `false` otherwise. */ public static function validateVersionStr(version:String, versionRule:String):Bool { @@ -56,7 +62,7 @@ class VersionUtil public static function getVersionFromJSON(input:Null):Null { if (input == null) return null; - var parsed = SerializerUtil.fromJSON(input); + var parsed:Dynamic = SerializerUtil.fromJSON(input); if (parsed == null) return null; if (parsed.version == null) return null; var versionStr:String = parsed.version; // Dynamic -> String cast @@ -64,6 +70,11 @@ class VersionUtil return version; } + /** + * Get and parse the semantic version from a JSON string. + * @param input The JSON string to parse. + * @return The semantic version, or null if it could not be parsed. + */ public static function parseVersion(input:Dynamic):Null { if (input == null) return null; diff --git a/source/funkin/util/WindowUtil.hx b/source/funkin/util/WindowUtil.hx index 9f623c39d..f73fe11ce 100644 --- a/source/funkin/util/WindowUtil.hx +++ b/source/funkin/util/WindowUtil.hx @@ -24,7 +24,7 @@ class WindowUtil { #if CAN_OPEN_LINKS #if linux - Sys.command('/usr/bin/xdg-open', [targetUrl, "&"]); + Sys.command('/usr/bin/xdg-open', [targetUrl, '&']); #else // This should work on Windows and HTML5. FlxG.openURL(targetUrl); @@ -42,7 +42,7 @@ class WindowUtil { #if CAN_OPEN_LINKS #if windows - Sys.command('explorer', [targetPath.replace("/", "\\")]); + Sys.command('explorer', [targetPath.replace('/', '\\')]); #elseif mac Sys.command('open', [targetPath]); #elseif linux @@ -61,9 +61,9 @@ class WindowUtil { #if CAN_OPEN_LINKS #if windows - Sys.command('explorer', ["/select," + targetPath.replace("/", "\\")]); + Sys.command('explorer', ['/select,' + targetPath.replace('/', '\\')]); #elseif mac - Sys.command('open', ["-R", targetPath]); + Sys.command('open', ['-R', targetPath]); #elseif linux // TODO: unsure of the linux equivalent to opening a folder and then "selecting" a file. Sys.command('open', [targetPath]); @@ -82,7 +82,7 @@ class WindowUtil * Wires up FlxSignals that happen based on window activity. * For example, we can run a callback when the window is closed. */ - public static function initWindowEvents() + public static function initWindowEvents():Void { // onUpdate is called every frame just before rendering. @@ -95,7 +95,7 @@ class WindowUtil /** * Turns off that annoying "Report to Microsoft" dialog that pops up when the game crashes. */ - public static function disableCrashHandler() + public static function disableCrashHandler():Void { #if (cpp && windows) untyped __cpp__('SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX);'); diff --git a/source/haxe/ui/backend/flixel/UIStateBase.hx b/source/haxe/ui/backend/flixel/UIStateBase.hx index 9f1a53722..38377206c 100644 --- a/source/haxe/ui/backend/flixel/UIStateBase.hx +++ b/source/haxe/ui/backend/flixel/UIStateBase.hx @@ -1,3 +1,6 @@ package haxe.ui.backend.flixel; +/** + * Override HaxeUI to use `MusicBeatState` instead of `FlxState`. + */ typedef UIStateBase = funkin.ui.MusicBeatState; diff --git a/source/haxe/ui/backend/flixel/UISubStateBase.hx b/source/haxe/ui/backend/flixel/UISubStateBase.hx index 306c9b633..52c9a7231 100644 --- a/source/haxe/ui/backend/flixel/UISubStateBase.hx +++ b/source/haxe/ui/backend/flixel/UISubStateBase.hx @@ -1,3 +1,6 @@ package haxe.ui.backend.flixel; +/** + * Override HaxeUI to use `MusicBeatSubState` instead of `FlxSubState`. + */ typedef UISubStateBase = funkin.ui.MusicBeatSubState; From 83e8865a24611d515265d1159360dd7171420f2a Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Fri, 22 Mar 2024 20:29:35 -0400 Subject: [PATCH 03/10] Make the ZoomCamera events use sensible defaults. --- .../funkin/play/event/ZoomCameraSongEvent.hx | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/source/funkin/play/event/ZoomCameraSongEvent.hx b/source/funkin/play/event/ZoomCameraSongEvent.hx index d1741a463..b913aebe7 100644 --- a/source/funkin/play/event/ZoomCameraSongEvent.hx +++ b/source/funkin/play/event/ZoomCameraSongEvent.hx @@ -52,6 +52,11 @@ class ZoomCameraSongEvent extends SongEvent super('ZoomCamera'); } + static final DEFAULT_ZOOM:Float = 1.0; + static final DEFAULT_DURATION:Float = 4.0; + static final DEFAULT_MODE:String = 'direct'; + static final DEFAULT_EASE:String = 'linear'; + public override function handleEvent(data:SongEventData):Void { // Does nothing if there is no PlayState camera or stage. @@ -60,25 +65,20 @@ class ZoomCameraSongEvent extends SongEvent // Does nothing if we are minimal mode. if (PlayState.instance.isMinimalMode) return; - var zoom:Null = data.getFloat('zoom'); - if (zoom == null) zoom = 1.0; + var zoom:Float = data.getFloat('zoom') ?? DEFAULT_ZOOM; - var duration:Null = data.getFloat('duration'); - if (duration == null) duration = 4.0; + var duration:Float = data.getFloat('duration') ?? DEFAULT_DURATION; - var mode:Null = data.getString('mode'); - if (mode == null) mode = 'additive'; + var mode:String = data.getString('mode') ?? DEFAULT_MODE; + var isDirectMode:Bool = mode == 'direct'; - var ease:Null = data.getString('ease'); - if (ease == null) ease = 'linear'; - - var directMode:Bool = mode == 'direct'; + var ease:String = data.getString('ease') ?? DEFAULT_EASE; // If it's a string, check the value. switch (ease) { case 'INSTANT': - PlayState.instance.tweenCameraZoom(zoom, 0, directMode); + PlayState.instance.tweenCameraZoom(zoom, 0, isDirectMode); default: var durSeconds = Conductor.instance.stepLengthMs * duration / 1000; @@ -89,7 +89,7 @@ class ZoomCameraSongEvent extends SongEvent return; } - PlayState.instance.tweenCameraZoom(zoom, durSeconds, directMode, easeFunction); + PlayState.instance.tweenCameraZoom(zoom, durSeconds, isDirectMode, easeFunction); } } @@ -130,7 +130,7 @@ class ZoomCameraSongEvent extends SongEvent { name: 'mode', title: 'Mode', - defaultValue: 'additive', + defaultValue: 'direct', type: SongEventFieldType.ENUM, keys: ['Additive' => 'additive', 'Direct' => 'direct'] }, From 01e83d4713144f5bbe607879861b48cd2d404f4c Mon Sep 17 00:00:00 2001 From: Cameron Taylor Date: Fri, 22 Mar 2024 20:21:09 -0700 Subject: [PATCH 04/10] the funkin crew presents --- source/funkin/ui/title/TitleState.hx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/funkin/ui/title/TitleState.hx b/source/funkin/ui/title/TitleState.hx index 9dca759be..5cc7b8cc1 100644 --- a/source/funkin/ui/title/TitleState.hx +++ b/source/funkin/ui/title/TitleState.hx @@ -453,9 +453,9 @@ class TitleState extends MusicBeatState switch (i + 1) { case 1: - createCoolText(['ninjamuffin99', 'phantomArcade', 'kawaisprite', 'evilsk8r']); + createCoolText(['The', 'Funkin Crew Inc']); case 3: - addMoreText('present'); + addMoreText('presents'); case 4: deleteCoolText(); case 5: From 471b015d1ad8a4906be231fb3c75151df50a753c Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Fri, 22 Mar 2024 23:46:03 -0400 Subject: [PATCH 05/10] Add some FlxSignals and showVideo/hideVideo --- source/funkin/play/cutscene/VideoCutscene.hx | 71 ++++++++++++++++++++ 1 file changed, 71 insertions(+) diff --git a/source/funkin/play/cutscene/VideoCutscene.hx b/source/funkin/play/cutscene/VideoCutscene.hx index ff56e0919..7e500f05d 100644 --- a/source/funkin/play/cutscene/VideoCutscene.hx +++ b/source/funkin/play/cutscene/VideoCutscene.hx @@ -28,6 +28,31 @@ class VideoCutscene static var vid:FlxVideoSprite; #end + /** + * Called when the video is started. + */ + public static final onVideoStarted:FlxSignal = new FlxSignal(); + + /** + * Called if the video is paused. + */ + public static final onVideoPaused:FlxSignal = new FlxSignal(); + + /** + * Called if the video is resumed. + */ + public static final onVideoResumed:FlxSignal = new FlxSignal(); + + /** + * Called if the video is restarted. onVideoStarted is not called. + */ + public static final onVideoRestarted:FlxSignal = new FlxSignal(); + + /** + * Called when the video is ended or skipped. + */ + public static final onVideoEnded:FlxSignal = new FlxSignal(); + /** * Play a video cutscene. * TODO: Currently this is hardcoded to start the countdown after the video is done. @@ -94,6 +119,8 @@ class VideoCutscene PlayState.instance.add(vid); PlayState.instance.refresh(); + + onVideoStarted.dispatch(); } else { @@ -129,6 +156,8 @@ class VideoCutscene vid.y = 0; // vid.scale.set(0.5, 0.5); }); + + onVideoStarted.dispatch(); } else { @@ -143,6 +172,7 @@ class VideoCutscene if (vid != null) { vid.restartVideo(); + onVideoRestarted.dispatch(); } #end @@ -156,6 +186,8 @@ class VideoCutscene // Resume the video if it was paused. vid.resume(); } + + onVideoRestarted.dispatch(); } #end } @@ -166,6 +198,7 @@ class VideoCutscene if (vid != null) { vid.pauseVideo(); + onVideoPaused.dispatch(); } #end @@ -173,6 +206,41 @@ class VideoCutscene if (vid != null) { vid.pause(); + onVideoPaused.dispatch(); + } + #end + } + + public static function hideVideo():Void + { + #if html5 + if (vid != null) + { + vid.visible = false; + } + #end + + #if hxCodec + if (vid != null) + { + vid.visible = false; + } + #end + } + + public static function showVideo():Void + { + #if html5 + if (vid != null) + { + vid.visible = true; + } + #end + + #if hxCodec + if (vid != null) + { + vid.visible = true; } #end } @@ -183,6 +251,7 @@ class VideoCutscene if (vid != null) { vid.resumeVideo(); + onVideoResumed.dispatch(); } #end @@ -190,6 +259,7 @@ class VideoCutscene if (vid != null) { vid.resume(); + onVideoResumed.dispatch(); } #end } @@ -240,6 +310,7 @@ class VideoCutscene { ease: FlxEase.quadInOut, onComplete: function(twn:FlxTween) { + onVideoEnded.dispatch(); onCutsceneFinish(cutsceneType); } }); From e4a9d25ac01bf65b261076ffad753414967195ef Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Fri, 22 Mar 2024 23:53:29 -0400 Subject: [PATCH 06/10] Syntax fix --- source/funkin/play/cutscene/VideoCutscene.hx | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/source/funkin/play/cutscene/VideoCutscene.hx b/source/funkin/play/cutscene/VideoCutscene.hx index 7e500f05d..3da51185f 100644 --- a/source/funkin/play/cutscene/VideoCutscene.hx +++ b/source/funkin/play/cutscene/VideoCutscene.hx @@ -5,6 +5,7 @@ import flixel.FlxSprite; import flixel.tweens.FlxEase; import flixel.tweens.FlxTween; import flixel.util.FlxColor; +import flixel.util.FlxSignal; import flixel.util.FlxTimer; #if html5 import funkin.graphics.video.FlxVideo; @@ -217,6 +218,7 @@ class VideoCutscene if (vid != null) { vid.visible = false; + blackScreen.visible = false; } #end @@ -224,6 +226,7 @@ class VideoCutscene if (vid != null) { vid.visible = false; + blackScreen.visible = false; } #end } @@ -234,6 +237,7 @@ class VideoCutscene if (vid != null) { vid.visible = true; + blackScreen.visible = false; } #end @@ -241,6 +245,7 @@ class VideoCutscene if (vid != null) { vid.visible = true; + blackScreen.visible = false; } #end } From 8bbb528a9e1326bf01d9a235cadcbc16f0b85b68 Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Sat, 23 Mar 2024 13:44:27 -0400 Subject: [PATCH 07/10] Update assets submodule --- assets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets b/assets index 526743915..8b0aa1d56 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit 52674391511577300cdb8c08df293ea72099aa82 +Subproject commit 8b0aa1d5633f2f2e7f0eb03498ee71d19cc99564 From 709fbc859443f753b548f23760758d69b734101c Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Sat, 23 Mar 2024 18:11:06 -0400 Subject: [PATCH 08/10] Fix a bug where lag could cause the opponent to miss. --- source/funkin/play/PlayState.hx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/source/funkin/play/PlayState.hx b/source/funkin/play/PlayState.hx index 12b290afd..f7bf6fc22 100644 --- a/source/funkin/play/PlayState.hx +++ b/source/funkin/play/PlayState.hx @@ -2089,8 +2089,7 @@ class PlayState extends MusicBeatSubState holdNote.handledMiss = true; // We dropped a hold note. - // Mute vocals and play miss animation, but don't penalize. - vocals.opponentVolume = 0; + // Play miss animation, but don't penalize. currentStage.getOpponent().playSingAnimation(holdNote.noteData.getDirection(), true); } } From a8486a47dfd879e3370f804900cb61ee811b7675 Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Sat, 23 Mar 2024 18:22:15 -0400 Subject: [PATCH 09/10] Fix a bug where the album disappears never to return --- source/funkin/ui/freeplay/FreeplayState.hx | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/source/funkin/ui/freeplay/FreeplayState.hx b/source/funkin/ui/freeplay/FreeplayState.hx index fc11eec28..4e0d7ccf3 100644 --- a/source/funkin/ui/freeplay/FreeplayState.hx +++ b/source/funkin/ui/freeplay/FreeplayState.hx @@ -1013,7 +1013,14 @@ class FreeplayState extends MusicBeatSubState // Set the difficulty star count on the right. albumRoll.setDifficultyStars(daSong?.songRating); - albumRoll.albumId = daSong?.albumId ?? Constants.DEFAULT_ALBUM_ID; + + // Set the album graphic and play the animation if relevant. + var newAlbumId:String = daSong?.albumId ?? Constants.DEFAULT_ALBUM_ID; + if (albumRoll.albumId != newAlbumId) + { + albumRoll.albumId = newAlbumId; + albumRoll.playIntro(); + } } // Clears the cache of songs, frees up memory, they' ll have to be loaded in later tho function clearDaCache(actualSongTho:String) From 2b1fc1e7d722bf5e5663c432c35b4697a389e149 Mon Sep 17 00:00:00 2001 From: Hazel Date: Mon, 25 Mar 2024 16:12:37 +0100 Subject: [PATCH 10/10] bugfix: html5 builds (#418) --- .github/workflows/build-shit.yml | 6 ++++-- assets | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build-shit.yml b/.github/workflows/build-shit.yml index 49bab1ac1..e217d1f18 100644 --- a/.github/workflows/build-shit.yml +++ b/.github/workflows/build-shit.yml @@ -13,8 +13,9 @@ jobs: apt update apt install -y sudo git curl unzip - name: Fix git config on posix runner + # this can't be {{ github.workspace }} because that's not docker-aware run: | - git config --global --add safe.directory ${{ github.workspace }} + git config --global --add safe.directory $GITHUB_WORKSPACE - name: Get checkout token uses: actions/create-github-app-token@v1 id: app_token @@ -90,8 +91,9 @@ jobs: runs-on: [self-hosted, macos] steps: - name: Fix git config on posix runner + # this can't be {{ github.workspace }} because that's not docker-aware run: | - git config --global --add safe.directory ${{ github.workspace }} + git config --global --add safe.directory $GITHUB_WORKSPACE - name: Get checkout token uses: actions/create-github-app-token@v1 id: app_token diff --git a/assets b/assets index 8b0aa1d56..526743915 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit 8b0aa1d5633f2f2e7f0eb03498ee71d19cc99564 +Subproject commit 52674391511577300cdb8c08df293ea72099aa82