From 4804b9ae22eec299d84569402cb25ca21baf6a86 Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Sat, 6 Jan 2024 01:06:10 -0500 Subject: [PATCH 001/130] Work in progress for Chart Editor gamepad support (navigation implemented, note placement WIP) --- source/funkin/input/Controls.hx | 367 +++++++++++----- source/funkin/input/TurboActionHandler.hx | 111 +++++ source/funkin/input/TurboButtonHandler.hx | 127 ++++++ .../ui/debug/charting/ChartEditorState.hx | 397 ++++++++++++++++-- .../charting/commands/RemoveEventsCommand.hx | 4 + .../charting/commands/RemoveItemsCommand.hx | 4 + .../charting/commands/RemoveNotesCommand.hx | 4 + .../components/ChartEditorHoldNoteSprite.hx | 9 +- .../handlers/ChartEditorGamepadHandler.hx | 133 ++++++ source/funkin/ui/debug/charting/import.hx | 1 + 10 files changed, 1009 insertions(+), 148 deletions(-) create mode 100644 source/funkin/input/TurboActionHandler.hx create mode 100644 source/funkin/input/TurboButtonHandler.hx create mode 100644 source/funkin/ui/debug/charting/handlers/ChartEditorGamepadHandler.hx diff --git a/source/funkin/input/Controls.hx b/source/funkin/input/Controls.hx index 3fa4e0f75..5c761cd19 100644 --- a/source/funkin/input/Controls.hx +++ b/source/funkin/input/Controls.hx @@ -30,47 +30,31 @@ class Controls extends FlxActionSet * A list of actions that a player would invoke via some input device. * Uses FlxActions to funnel various inputs to a single action. */ - var _ui_up = new FlxActionDigital(Action.UI_UP); - var _ui_left = new FlxActionDigital(Action.UI_LEFT); - var _ui_right = new FlxActionDigital(Action.UI_RIGHT); - var _ui_down = new FlxActionDigital(Action.UI_DOWN); - var _ui_upP = new FlxActionDigital(Action.UI_UP_P); - var _ui_leftP = new FlxActionDigital(Action.UI_LEFT_P); - var _ui_rightP = new FlxActionDigital(Action.UI_RIGHT_P); - var _ui_downP = new FlxActionDigital(Action.UI_DOWN_P); - var _ui_upR = new FlxActionDigital(Action.UI_UP_R); - var _ui_leftR = new FlxActionDigital(Action.UI_LEFT_R); - var _ui_rightR = new FlxActionDigital(Action.UI_RIGHT_R); - var _ui_downR = new FlxActionDigital(Action.UI_DOWN_R); - var _note_up = new FlxActionDigital(Action.NOTE_UP); - var _note_left = new FlxActionDigital(Action.NOTE_LEFT); - var _note_right = new FlxActionDigital(Action.NOTE_RIGHT); - var _note_down = new FlxActionDigital(Action.NOTE_DOWN); - var _note_upP = new FlxActionDigital(Action.NOTE_UP_P); - var _note_leftP = new FlxActionDigital(Action.NOTE_LEFT_P); - var _note_rightP = new FlxActionDigital(Action.NOTE_RIGHT_P); - var _note_downP = new FlxActionDigital(Action.NOTE_DOWN_P); - var _note_upR = new FlxActionDigital(Action.NOTE_UP_R); - var _note_leftR = new FlxActionDigital(Action.NOTE_LEFT_R); - var _note_rightR = new FlxActionDigital(Action.NOTE_RIGHT_R); - var _note_downR = new FlxActionDigital(Action.NOTE_DOWN_R); - var _accept = new FlxActionDigital(Action.ACCEPT); - var _back = new FlxActionDigital(Action.BACK); - var _pause = new FlxActionDigital(Action.PAUSE); - var _reset = new FlxActionDigital(Action.RESET); - var _cutscene_advance = new FlxActionDigital(Action.CUTSCENE_ADVANCE); - var _cutscene_skip = new FlxActionDigital(Action.CUTSCENE_SKIP); - var _debug_menu = new FlxActionDigital(Action.DEBUG_MENU); - var _debug_chart = new FlxActionDigital(Action.DEBUG_CHART); - var _debug_stage = new FlxActionDigital(Action.DEBUG_STAGE); - var _volume_up = new FlxActionDigital(Action.VOLUME_UP); - var _volume_down = new FlxActionDigital(Action.VOLUME_DOWN); - var _volume_mute = new FlxActionDigital(Action.VOLUME_MUTE); + var _ui_up = new FunkinAction(Action.UI_UP, Action.UI_UP_P, Action.UI_UP_R); + var _ui_left = new FunkinAction(Action.UI_LEFT, Action.UI_LEFT_P, Action.UI_LEFT_R); + var _ui_right = new FunkinAction(Action.UI_RIGHT, Action.UI_RIGHT_P, Action.UI_RIGHT_R); + var _ui_down = new FunkinAction(Action.UI_DOWN, Action.UI_DOWN_P, Action.UI_DOWN_R); + var _note_up = new FunkinAction(Action.NOTE_UP, Action.NOTE_UP_P, Action.NOTE_UP_R); + var _note_left = new FunkinAction(Action.NOTE_LEFT, Action.NOTE_LEFT_P, Action.NOTE_LEFT_R); + var _note_right = new FunkinAction(Action.NOTE_RIGHT, Action.NOTE_RIGHT_P, Action.NOTE_RIGHT_R); + var _note_down = new FunkinAction(Action.NOTE_DOWN, Action.NOTE_DOWN_P, Action.NOTE_DOWN_R); + var _accept = new FunkinAction(Action.ACCEPT); + var _back = new FunkinAction(Action.BACK); + var _pause = new FunkinAction(Action.PAUSE); + var _reset = new FunkinAction(Action.RESET); + var _cutscene_advance = new FunkinAction(Action.CUTSCENE_ADVANCE); + var _cutscene_skip = new FunkinAction(Action.CUTSCENE_SKIP); + var _debug_menu = new FunkinAction(Action.DEBUG_MENU); + var _debug_chart = new FunkinAction(Action.DEBUG_CHART); + var _debug_stage = new FunkinAction(Action.DEBUG_STAGE); + var _volume_up = new FunkinAction(Action.VOLUME_UP); + var _volume_down = new FunkinAction(Action.VOLUME_DOWN); + var _volume_mute = new FunkinAction(Action.VOLUME_MUTE); #if CAN_CHEAT - var _cheat = new FlxActionDigital(Action.CHEAT); + var _cheat = new FunkinAction(Action.CHEAT); #end - var byName:Map = new Map(); + var byName:Map = new Map(); public var gamepadsAdded:Array = []; public var keyboardScheme = KeyboardScheme.None; @@ -78,122 +62,142 @@ class Controls extends FlxActionSet public var UI_UP(get, never):Bool; inline function get_UI_UP() - return _ui_up.check(); + return _ui_up.checkPressed(); public var UI_LEFT(get, never):Bool; inline function get_UI_LEFT() - return _ui_left.check(); + return _ui_left.checkPressed(); public var UI_RIGHT(get, never):Bool; inline function get_UI_RIGHT() - return _ui_right.check(); + return _ui_right.checkPressed(); public var UI_DOWN(get, never):Bool; inline function get_UI_DOWN() - return _ui_down.check(); + return _ui_down.checkPressed(); public var UI_UP_P(get, never):Bool; inline function get_UI_UP_P() - return _ui_upP.check(); + return _ui_up.checkJustPressed(); public var UI_LEFT_P(get, never):Bool; inline function get_UI_LEFT_P() - return _ui_leftP.check(); + return _ui_left.checkJustPressed(); public var UI_RIGHT_P(get, never):Bool; inline function get_UI_RIGHT_P() - return _ui_rightP.check(); + return _ui_right.checkJustPressed(); public var UI_DOWN_P(get, never):Bool; inline function get_UI_DOWN_P() - return _ui_downP.check(); + return _ui_down.checkJustPressed(); public var UI_UP_R(get, never):Bool; inline function get_UI_UP_R() - return _ui_upR.check(); + return _ui_up.checkJustReleased(); public var UI_LEFT_R(get, never):Bool; inline function get_UI_LEFT_R() - return _ui_leftR.check(); + return _ui_left.checkJustReleased(); public var UI_RIGHT_R(get, never):Bool; inline function get_UI_RIGHT_R() - return _ui_rightR.check(); + return _ui_right.checkJustReleased(); public var UI_DOWN_R(get, never):Bool; inline function get_UI_DOWN_R() - return _ui_downR.check(); + return _ui_down.checkJustReleased(); + + public var UI_UP_GAMEPAD(get, never):Bool; + + inline function get_UI_UP_GAMEPAD() + return _ui_up.checkPressedGamepad(); + + public var UI_LEFT_GAMEPAD(get, never):Bool; + + inline function get_UI_LEFT_GAMEPAD() + return _ui_left.checkPressedGamepad(); + + public var UI_RIGHT_GAMEPAD(get, never):Bool; + + inline function get_UI_RIGHT_GAMEPAD() + return _ui_right.checkPressedGamepad(); + + public var UI_DOWN_GAMEPAD(get, never):Bool; + + inline function get_UI_DOWN_GAMEPAD() + return _ui_down.checkPressedGamepad(); public var NOTE_UP(get, never):Bool; inline function get_NOTE_UP() - return _note_up.check(); + return _note_up.checkPressed(); public var NOTE_LEFT(get, never):Bool; inline function get_NOTE_LEFT() - return _note_left.check(); + return _note_left.checkPressed(); public var NOTE_RIGHT(get, never):Bool; inline function get_NOTE_RIGHT() - return _note_right.check(); + return _note_right.checkPressed(); public var NOTE_DOWN(get, never):Bool; inline function get_NOTE_DOWN() - return _note_down.check(); + return _note_down.checkPressed(); public var NOTE_UP_P(get, never):Bool; inline function get_NOTE_UP_P() - return _note_upP.check(); + return _note_up.checkJustPressed(); public var NOTE_LEFT_P(get, never):Bool; inline function get_NOTE_LEFT_P() - return _note_leftP.check(); + return _note_left.checkJustPressed(); public var NOTE_RIGHT_P(get, never):Bool; inline function get_NOTE_RIGHT_P() - return _note_rightP.check(); + return _note_right.checkJustPressed(); public var NOTE_DOWN_P(get, never):Bool; inline function get_NOTE_DOWN_P() - return _note_downP.check(); + return _note_down.checkJustPressed(); public var NOTE_UP_R(get, never):Bool; inline function get_NOTE_UP_R() - return _note_upR.check(); + return _note_up.checkJustReleased(); public var NOTE_LEFT_R(get, never):Bool; inline function get_NOTE_LEFT_R() - return _note_leftR.check(); + return _note_left.checkJustReleased(); public var NOTE_RIGHT_R(get, never):Bool; inline function get_NOTE_RIGHT_R() - return _note_rightR.check(); + return _note_right.checkJustReleased(); public var NOTE_DOWN_R(get, never):Bool; inline function get_NOTE_DOWN_R() - return _note_downR.check(); + return _note_down.checkJustReleased(); public var ACCEPT(get, never):Bool; @@ -270,26 +274,10 @@ class Controls extends FlxActionSet add(_ui_left); add(_ui_right); add(_ui_down); - add(_ui_upP); - add(_ui_leftP); - add(_ui_rightP); - add(_ui_downP); - add(_ui_upR); - add(_ui_leftR); - add(_ui_rightR); - add(_ui_downR); add(_note_up); add(_note_left); add(_note_right); add(_note_down); - add(_note_upP); - add(_note_leftP); - add(_note_rightP); - add(_note_downP); - add(_note_upR); - add(_note_leftR); - add(_note_rightR); - add(_note_downR); add(_accept); add(_back); add(_pause); @@ -303,8 +291,16 @@ class Controls extends FlxActionSet add(_cheat); #end - for (action in digitalActions) - byName[action.name] = action; + for (action in digitalActions) { + if (Std.isOfType(action, FunkinAction)) { + var funkinAction:FunkinAction = cast action; + byName[funkinAction.name] = funkinAction; + if (funkinAction.namePressed != null) + byName[funkinAction.namePressed] = funkinAction; + if (funkinAction.nameReleased != null) + byName[funkinAction.nameReleased] = funkinAction; + } + } if (scheme == null) scheme = None; @@ -317,14 +313,17 @@ class Controls extends FlxActionSet super.update(); } - // inline - public function checkByName(name:Action):Bool + public function check(name:Action, trigger:FlxInputState = JUST_PRESSED, gamepadOnly:Bool = false):Bool { #if debug if (!byName.exists(name)) throw 'Invalid name: $name'; #end - return byName[name].check(); + var action = byName[name]; + if (gamepadOnly) + return action.checkFiltered(trigger, GAMEPAD); + else + return action.checkFiltered(trigger); } public function getKeysForAction(name:Action):Array { @@ -411,36 +410,36 @@ class Controls extends FlxActionSet { case UI_UP: func(_ui_up, PRESSED); - func(_ui_upP, JUST_PRESSED); - func(_ui_upR, JUST_RELEASED); + func(_ui_up, JUST_PRESSED); + func(_ui_up, JUST_RELEASED); case UI_LEFT: func(_ui_left, PRESSED); - func(_ui_leftP, JUST_PRESSED); - func(_ui_leftR, JUST_RELEASED); + func(_ui_left, JUST_PRESSED); + func(_ui_left, JUST_RELEASED); case UI_RIGHT: func(_ui_right, PRESSED); - func(_ui_rightP, JUST_PRESSED); - func(_ui_rightR, JUST_RELEASED); + func(_ui_right, JUST_PRESSED); + func(_ui_right, JUST_RELEASED); case UI_DOWN: func(_ui_down, PRESSED); - func(_ui_downP, JUST_PRESSED); - func(_ui_downR, JUST_RELEASED); + func(_ui_down, JUST_PRESSED); + func(_ui_down, JUST_RELEASED); case NOTE_UP: func(_note_up, PRESSED); - func(_note_upP, JUST_PRESSED); - func(_note_upR, JUST_RELEASED); + func(_note_up, JUST_PRESSED); + func(_note_up, JUST_RELEASED); case NOTE_LEFT: func(_note_left, PRESSED); - func(_note_leftP, JUST_PRESSED); - func(_note_leftR, JUST_RELEASED); + func(_note_left, JUST_PRESSED); + func(_note_left, JUST_RELEASED); case NOTE_RIGHT: func(_note_right, PRESSED); - func(_note_rightP, JUST_PRESSED); - func(_note_rightR, JUST_RELEASED); + func(_note_right, JUST_PRESSED); + func(_note_right, JUST_RELEASED); case NOTE_DOWN: func(_note_down, PRESSED); - func(_note_downP, JUST_PRESSED); - func(_note_downR, JUST_RELEASED); + func(_note_down, JUST_PRESSED); + func(_note_down, JUST_RELEASED); case ACCEPT: func(_accept, JUST_PRESSED); case BACK: @@ -1053,6 +1052,173 @@ typedef Swipes = ?curTouchPos:FlxPoint }; +/** + * An FlxActionDigital with additional functionality, including: + * - Combining `pressed` and `released` inputs into one action. + * - Filtering by input method (`KEYBOARD`, `MOUSE`, `GAMEPAD`, etc). + */ +class FunkinAction extends FlxActionDigital { + public var namePressed(default, null):Null; + public var nameReleased(default, null):Null; + + var cache:Map = []; + + public function new(?name:String = "", ?namePressed:String, ?nameReleased:String) + { + super(name); + + this.namePressed = namePressed; + this.nameReleased = nameReleased; + } + + /** + * Input checks default to whether the input was just pressed, on any input device. + */ + public override function check():Bool { + return checkFiltered(JUST_PRESSED); + } + + /** + * Check whether the input is currently being held. + */ + public function checkPressed():Bool { + return checkFiltered(PRESSED); + } + + /** + * Check whether the input is currently being held, and was not held last frame. + */ + public function checkJustPressed():Bool { + return checkFiltered(JUST_PRESSED); + } + + /** + * Check whether the input is not currently being held. + */ + public function checkReleased():Bool { + return checkFiltered(RELEASED); + } + + /** + * Check whether the input is not currently being held, and was held last frame. + */ + public function checkJustReleased():Bool { + return checkFiltered(JUST_RELEASED); + } + + /** + * Check whether the input is currently being held by a gamepad device. + */ + public function checkPressedGamepad():Bool { + return checkFiltered(PRESSED, GAMEPAD); + } + + /** + * Check whether the input is currently being held by a gamepad device, and was not held last frame. + */ + public function checkJustPressedGamepad():Bool { + return checkFiltered(JUST_PRESSED, GAMEPAD); + } + + /** + * Check whether the input is not currently being held by a gamepad device. + */ + public function checkReleasedGamepad():Bool { + return checkFiltered(RELEASED, GAMEPAD); + } + + /** + * Check whether the input is not currently being held by a gamepad device, and was held last frame. + */ + public function checkJustReleasedGamepad():Bool { + return checkFiltered(JUST_RELEASED, GAMEPAD); + } + + public function checkMultiFiltered(?filterTriggers:Array, ?filterDevices:Array):Bool { + if (filterTriggers == null) { + filterTriggers = [PRESSED, JUST_PRESSED]; + } + if (filterDevices == null) { + filterDevices = []; + } + + // Perform checkFiltered for each combination. + for (i in filterTriggers) { + if (filterDevices.length == 0) { + if (checkFiltered(i)) { + return true; + } + } else { + for (j in filterDevices) { + if (checkFiltered(i, j)) { + return true; + } + } + } + } + return false; + } + + /** + * Performs the functionality of `FlxActionDigital.check()`, but with optional filters. + * @param action The action to check for. + * @param filterTrigger Optionally filter by trigger condition (`JUST_PRESSED`, `PRESSED`, `JUST_RELEASED`, `RELEASED`). + * @param filterDevice Optionally filter by device (`KEYBOARD`, `MOUSE`, `GAMEPAD`, `OTHER`). + */ + public function checkFiltered(?filterTrigger:FlxInputState, ?filterDevice:FlxInputDevice):Bool { + // The normal + + // Make sure we only update the inputs once per frame. + var key = '${filterTrigger}:${filterDevice}'; + var cacheEntry = cache.get(key); + + if (cacheEntry != null && cacheEntry.timestamp == FlxG.game.ticks) { + return cacheEntry.value; + } + // Use a for loop instead so we can remove inputs while iterating. + + // We don't return early because we need to call check() on ALL inputs. + var result = false; + var len = inputs != null ? inputs.length : 0; + for (i in 0...len) + { + var j = len - i - 1; + var input = inputs[j]; + + // Filter out dead inputs. + if (input.destroyed) + { + inputs.splice(j, 1); + continue; + } + + // Update the input. + input.update(); + + // Check whether the input is the right trigger. + if (filterTrigger != null && input.trigger != filterTrigger) { + continue; + } + + // Check whether the input is the right device. + if (filterDevice != null && input.device != filterDevice) { + continue; + } + + // Check whether the input has triggered. + if (input.check(this)) + { + result = true; + } + } + + // We need to cache this result. + cache.set(key, {timestamp: FlxG.game.ticks, value: result}); + + return result; + } +} + class FlxActionInputDigitalMobileSwipeGameplay extends FlxActionInputDigital { var touchMap:Map = new Map(); @@ -1242,8 +1408,7 @@ enum Control #end } -enum -abstract Action(String) to String from String +enum abstract Action(String) to String from String { // NOTE var NOTE_UP = "note_up"; diff --git a/source/funkin/input/TurboActionHandler.hx b/source/funkin/input/TurboActionHandler.hx new file mode 100644 index 000000000..9425db8cd --- /dev/null +++ b/source/funkin/input/TurboActionHandler.hx @@ -0,0 +1,111 @@ +package funkin.input; + +import flixel.input.keyboard.FlxKey; +import flixel.FlxBasic; +import funkin.input.Controls; +import funkin.input.Controls.Action; + +/** + * Handles repeating behavior when holding down a control action. + * + * When the `action` is pressed, `activated` will be true for the first frame, + * then wait `delay` seconds before becoming true for one frame every `interval` seconds. + * + * Example: Pressing Ctrl+Z will undo, while holding Ctrl+Z will start to undo repeatedly. + */ +class TurboActionHandler extends FlxBasic +{ + /** + * Default delay before repeating. + */ + static inline final DEFAULT_DELAY:Float = 0.4; + + /** + * Default interval between repeats. + */ + static inline final DEFAULT_INTERVAL:Float = 0.1; + + /** + * Whether the action for this handler is pressed. + */ + public var pressed(get, never):Bool; + + /** + * Whether the action for this handler is pressed, + * and the handler is ready to repeat. + */ + public var activated(default, null):Bool = false; + + /** + * The Funkin Controls handler. + */ + var controls(get, never):Controls; + + function get_controls():Controls + { + return PlayerSettings.player1.controls; + } + + var action:Action; + + var delay:Float; + var interval:Float; + var gamepadOnly:Bool; + + var pressedTime:Float = 0; + + function new(action:Action, delay:Float = DEFAULT_DELAY, interval:Float = DEFAULT_INTERVAL, gamepadOnly:Bool = false) + { + super(); + this.action = action; + this.delay = delay; + this.interval = interval; + this.gamepadOnly = gamepadOnly; + } + + function get_pressed():Bool + { + return controls.check(action, PRESSED, gamepadOnly); + } + + public override function update(elapsed:Float):Void + { + super.update(elapsed); + + if (pressed) + { + if (pressedTime == 0) + { + activated = true; + } + else if (pressedTime >= (delay + interval)) + { + activated = true; + pressedTime -= interval; + } + else + { + activated = false; + } + pressedTime += elapsed; + } + else + { + pressedTime = 0; + activated = false; + } + } + + /** + * Builds a TurboActionHandler that monitors from a single key. + * @param inputKey The key to monitor. + * @param delay How long to wait before repeating. + * @param repeatDelay How long to wait between repeats. + * @return A TurboActionHandler + */ + public static overload inline extern function build(action:Action, ?delay:Float = DEFAULT_DELAY, ?interval:Float = DEFAULT_INTERVAL, + ?gamepadOnly:Bool = false):TurboActionHandler + { + return new TurboActionHandler(action, delay, interval); + } +} diff --git a/source/funkin/input/TurboButtonHandler.hx b/source/funkin/input/TurboButtonHandler.hx new file mode 100644 index 000000000..63c2a294b --- /dev/null +++ b/source/funkin/input/TurboButtonHandler.hx @@ -0,0 +1,127 @@ +package funkin.input; + +import flixel.input.gamepad.FlxGamepadInputID; +import flixel.input.gamepad.FlxGamepad; +import flixel.FlxBasic; + +/** + * Handles repeating behavior when holding down a gamepad button or button combination. + * + * When the `inputs` are pressed, `activated` will be true for the first frame, + * then wait `delay` seconds before becoming true for one frame every `interval` seconds. + * + * Example: Pressing Ctrl+Z will undo, while holding Ctrl+Z will start to undo repeatedly. + */ +class TurboButtonHandler extends FlxBasic +{ + /** + * Default delay before repeating. + */ + static inline final DEFAULT_DELAY:Float = 0.4; + + /** + * Default interval between repeats. + */ + static inline final DEFAULT_INTERVAL:Float = 0.1; + + /** + * Whether all of the keys for this handler are pressed. + */ + public var allPressed(get, never):Bool; + + /** + * Whether all of the keys for this handler are activated, + * and the handler is ready to repeat. + */ + public var activated(default, null):Bool = false; + + var inputs:Array; + var delay:Float; + var interval:Float; + var targetGamepad:FlxGamepad; + + var allPressedTime:Float = 0; + + function new(inputs:Array, delay:Float = DEFAULT_DELAY, interval:Float = DEFAULT_INTERVAL, ?targetGamepad:FlxGamepad) + { + super(); + this.inputs = inputs; + this.delay = delay; + this.interval = interval; + this.targetGamepad = targetGamepad ?? FlxG.gamepads.firstActive; + } + + function get_allPressed():Bool + { + if (targetGamepad == null) return false; + if (inputs == null || inputs.length == 0) return false; + if (inputs.length == 1) return targetGamepad.anyPressed(inputs); + + // Check if ANY keys are unpressed + for (input in inputs) + { + if (!targetGamepad.anyPressed([input])) return false; + } + return true; + } + + public override function update(elapsed:Float):Void + { + super.update(elapsed); + + // Try to find a gamepad if we don't have one + if (targetGamepad == null) + { + targetGamepad = FlxG.gamepads.firstActive; + } + + if (allPressed) + { + if (allPressedTime == 0) + { + activated = true; + } + else if (allPressedTime >= (delay + interval)) + { + activated = true; + allPressedTime -= interval; + } + else + { + activated = false; + } + allPressedTime += elapsed; + } + else + { + allPressedTime = 0; + activated = false; + } + } + + /** + * Builds a TurboButtonHandler that monitors from a single input. + * @param input The input to monitor. + * @param delay How long to wait before repeating. + * @param repeatDelay How long to wait between repeats. + * @return A TurboKeyHandler + */ + public static overload inline extern function build(input:FlxGamepadInputID, ?delay:Float = DEFAULT_DELAY, + ?interval:Float = DEFAULT_INTERVAL):TurboButtonHandler + { + return new TurboButtonHandler([input], delay, interval); + } + + /** + * Builds a TurboKeyHandler that monitors a key combination. + * @param inputs The combination of inputs to monitor. + * @param delay How long to wait before repeating. + * @param repeatDelay How long to wait between repeats. + * @return A TurboKeyHandler + */ + public static overload inline extern function build(inputs:Array, ?delay:Float = DEFAULT_DELAY, + ?interval:Float = DEFAULT_INTERVAL):TurboButtonHandler + { + return new TurboButtonHandler(inputs, delay, interval); + } +} diff --git a/source/funkin/ui/debug/charting/ChartEditorState.hx b/source/funkin/ui/debug/charting/ChartEditorState.hx index 1773a84fe..f3236578a 100644 --- a/source/funkin/ui/debug/charting/ChartEditorState.hx +++ b/source/funkin/ui/debug/charting/ChartEditorState.hx @@ -1,24 +1,25 @@ package funkin.ui.debug.charting; -import funkin.util.logging.CrashHandler; -import haxe.ui.containers.HBox; -import haxe.ui.containers.Grid; -import haxe.ui.containers.ScrollView; -import haxe.ui.containers.menus.MenuBar; import flixel.addons.display.FlxSliceSprite; import flixel.addons.display.FlxTiledSprite; import flixel.addons.transition.FlxTransitionableState; import flixel.FlxCamera; import flixel.FlxSprite; import flixel.FlxSubState; +import flixel.graphics.FlxGraphic; +import flixel.group.FlxGroup.FlxTypedGroup; import flixel.group.FlxSpriteGroup; +import flixel.input.gamepad.FlxGamepadInputID; import flixel.input.keyboard.FlxKey; +import flixel.input.mouse.FlxMouseEvent; import flixel.math.FlxMath; import flixel.math.FlxPoint; import flixel.graphics.FlxGraphic; import flixel.math.FlxRect; import flixel.sound.FlxSound; +import flixel.system.debug.log.LogStyle; import flixel.system.FlxAssets.FlxSoundAsset; +import flixel.text.FlxText; import flixel.tweens.FlxEase; import flixel.tweens.FlxTween; import flixel.tweens.misc.VarTween; @@ -26,19 +27,31 @@ import haxe.ui.Toolkit; import flixel.util.FlxColor; import flixel.util.FlxSort; import flixel.util.FlxTimer; -import funkin.audio.visualize.PolygonSpectogram; -import funkin.audio.VoicesGroup; import funkin.audio.FunkinSound; +import funkin.audio.visualize.PolygonSpectogram; +import funkin.audio.visualize.PolygonSpectogram; +import funkin.audio.visualize.PolygonVisGroup; +import funkin.audio.VoicesGroup; import funkin.data.notestyle.NoteStyleRegistry; import funkin.data.song.SongData.SongCharacterData; +import funkin.data.song.SongData.SongCharacterData; +import funkin.data.song.SongData.SongChartData; import funkin.data.song.SongData.SongChartData; import funkin.data.song.SongData.SongEventData; +import funkin.data.song.SongData.SongEventData; import funkin.data.song.SongData.SongMetadata; +import funkin.data.song.SongData.SongMetadata; +import funkin.data.song.SongData.SongNoteData; import funkin.data.song.SongData.SongNoteData; import funkin.data.song.SongData.SongOffsets; import funkin.data.song.SongDataUtils; +import funkin.data.song.SongDataUtils; import funkin.data.song.SongRegistry; +import funkin.data.song.SongRegistry; +import funkin.input.Controls.Action; import funkin.input.Cursor; +import funkin.input.TurboActionHandler; +import funkin.input.TurboButtonHandler; import funkin.input.TurboKeyHandler; import funkin.modding.events.ScriptEvent; import funkin.play.character.BaseCharacter.CharacterType; @@ -48,20 +61,13 @@ import funkin.play.components.HealthIcon; import funkin.play.notes.NoteSprite; import funkin.play.PlayState; import funkin.play.song.Song; -import funkin.data.song.SongData.SongChartData; -import funkin.data.song.SongRegistry; -import funkin.data.song.SongData.SongEventData; -import funkin.data.song.SongData.SongMetadata; -import funkin.data.song.SongData.SongNoteData; -import funkin.data.song.SongData.SongCharacterData; -import funkin.data.song.SongDataUtils; -import funkin.ui.debug.charting.commands.ChartEditorCommand; import funkin.play.stage.StageData; import funkin.save.Save; import funkin.ui.debug.charting.commands.AddEventsCommand; import funkin.ui.debug.charting.commands.AddNotesCommand; import funkin.ui.debug.charting.commands.ChartEditorCommand; import funkin.ui.debug.charting.commands.ChartEditorCommand; +import funkin.ui.debug.charting.commands.ChartEditorCommand; import funkin.ui.debug.charting.commands.CutItemsCommand; import funkin.ui.debug.charting.commands.DeselectAllItemsCommand; import funkin.ui.debug.charting.commands.DeselectItemsCommand; @@ -80,17 +86,20 @@ import funkin.ui.debug.charting.commands.SelectItemsCommand; import funkin.ui.debug.charting.commands.SetItemSelectionCommand; import funkin.ui.debug.charting.components.ChartEditorEventSprite; import funkin.ui.debug.charting.components.ChartEditorHoldNoteSprite; +import funkin.ui.debug.charting.components.ChartEditorMeasureTicks; import funkin.ui.debug.charting.components.ChartEditorNotePreview; import funkin.ui.debug.charting.components.ChartEditorNoteSprite; import funkin.ui.debug.charting.components.ChartEditorMeasureTicks; import funkin.ui.debug.charting.components.ChartEditorPlaybarHead; import funkin.ui.debug.charting.components.ChartEditorSelectionSquareSprite; import funkin.ui.debug.charting.handlers.ChartEditorShortcutHandler; +import funkin.ui.debug.charting.toolboxes.ChartEditorBaseToolbox; import funkin.ui.haxeui.components.CharacterPlayer; import funkin.ui.haxeui.HaxeUIState; import funkin.ui.mainmenu.MainMenuState; import funkin.util.Constants; import funkin.util.FileUtil; +import funkin.util.logging.CrashHandler; import funkin.util.SortUtil; import funkin.util.WindowUtil; import haxe.DynamicAccess; @@ -98,22 +107,25 @@ import haxe.io.Bytes; import haxe.io.Path; import haxe.ui.backend.flixel.UIRuntimeState; import haxe.ui.backend.flixel.UIState; -import haxe.ui.components.DropDown; -import haxe.ui.components.Label; import haxe.ui.components.Button; +import haxe.ui.components.DropDown; +import haxe.ui.components.Image; +import haxe.ui.components.Label; import haxe.ui.components.NumberStepper; import haxe.ui.components.Slider; import haxe.ui.components.TextField; import haxe.ui.containers.dialogs.CollapsibleDialog; import haxe.ui.containers.Frame; +import haxe.ui.containers.Grid; +import haxe.ui.containers.HBox; import haxe.ui.containers.menus.Menu; import haxe.ui.containers.menus.MenuBar; -import haxe.ui.containers.menus.MenuItem; +import haxe.ui.containers.menus.MenuBar; import haxe.ui.containers.menus.MenuCheckBox; +import haxe.ui.containers.menus.MenuItem; +import haxe.ui.containers.ScrollView; import haxe.ui.containers.TreeView; import haxe.ui.containers.TreeViewNode; -import haxe.ui.components.Image; -import funkin.ui.debug.charting.toolboxes.ChartEditorBaseToolbox; import haxe.ui.core.Component; import haxe.ui.core.Screen; import haxe.ui.events.DragEvent; @@ -122,12 +134,6 @@ import haxe.ui.events.UIEvent; import haxe.ui.events.UIEvent; import haxe.ui.focus.FocusManager; import openfl.display.BitmapData; -import funkin.audio.visualize.PolygonSpectogram; -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; @@ -360,6 +366,8 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState } } + updatePlayheadGhostHoldNotes(); + // Move the rendered notes to the correct position. renderedNotes.setPosition(gridTiledSprite?.x ?? 0.0, gridTiledSprite?.y ?? 0.0); renderedHoldNotes.setPosition(gridTiledSprite?.x ?? 0.0, gridTiledSprite?.y ?? 0.0); @@ -429,6 +437,8 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState // Move the playhead sprite to the correct position. gridPlayhead.y = this.playheadPositionInPixels + (MENU_BAR_HEIGHT + GRID_TOP_PAD); + updatePlayheadGhostHoldNotes(); + return this.playheadPositionInPixels; } @@ -720,6 +730,13 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState */ var currentPlaceNoteData:Null = null; + /** + * The SongNoteData which is currently being placed, for each column. + * `null` if the user isn't currently placing a note. + * As the user moves down, we will update this note's sustain length, and finalize the note when they release. + */ + var currentLiveInputPlaceNoteData:Array = []; + // Note Movement /** @@ -750,6 +767,12 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState */ var dragLengthCurrent:Float = 0; + /** + * The current length of the hold note we are placing with the playhead, in steps. + * Play a sound when this value changes. + */ + var playheadDragLengthCurrent:Array = []; + /** * Flip-flop to alternate between two stretching sounds. */ @@ -1020,6 +1043,66 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState */ var pageDownKeyHandler:TurboKeyHandler = TurboKeyHandler.build(FlxKey.PAGEDOWN); + /** + * Variable used to track how long the user has been holding up on the dpad. + */ + var dpadUpGamepadHandler:TurboButtonHandler = TurboButtonHandler.build(FlxGamepadInputID.DPAD_UP); + + /** + * Variable used to track how long the user has been holding down on the dpad. + */ + var dpadDownGamepadHandler:TurboButtonHandler = TurboButtonHandler.build(FlxGamepadInputID.DPAD_DOWN); + + /** + * Variable used to track how long the user has been holding left on the dpad. + */ + var dpadLeftGamepadHandler:TurboButtonHandler = TurboButtonHandler.build(FlxGamepadInputID.DPAD_LEFT); + + /** + * Variable used to track how long the user has been holding right on the dpad. + */ + var dpadRightGamepadHandler:TurboButtonHandler = TurboButtonHandler.build(FlxGamepadInputID.DPAD_RIGHT); + + /** + * Variable used to track how long the user has been holding up on the left stick. + */ + var leftStickUpGamepadHandler:TurboButtonHandler = TurboButtonHandler.build(FlxGamepadInputID.LEFT_STICK_DIGITAL_UP); + + /** + * Variable used to track how long the user has been holding down on the left stick. + */ + var leftStickDownGamepadHandler:TurboButtonHandler = TurboButtonHandler.build(FlxGamepadInputID.LEFT_STICK_DIGITAL_DOWN); + + /** + * Variable used to track how long the user has been holding left on the left stick. + */ + var leftStickLeftGamepadHandler:TurboButtonHandler = TurboButtonHandler.build(FlxGamepadInputID.LEFT_STICK_DIGITAL_LEFT); + + /** + * Variable used to track how long the user has been holding right on the left stick. + */ + var leftStickRightGamepadHandler:TurboButtonHandler = TurboButtonHandler.build(FlxGamepadInputID.LEFT_STICK_DIGITAL_RIGHT); + + /** + * Variable used to track how long the user has been holding up on the right stick. + */ + var rightStickUpGamepadHandler:TurboButtonHandler = TurboButtonHandler.build(FlxGamepadInputID.RIGHT_STICK_DIGITAL_UP); + + /** + * Variable used to track how long the user has been holding down on the right stick. + */ + var rightStickDownGamepadHandler:TurboButtonHandler = TurboButtonHandler.build(FlxGamepadInputID.RIGHT_STICK_DIGITAL_DOWN); + + /** + * Variable used to track how long the user has been holding left on the right stick. + */ + var rightStickLeftGamepadHandler:TurboButtonHandler = TurboButtonHandler.build(FlxGamepadInputID.RIGHT_STICK_DIGITAL_LEFT); + + /** + * Variable used to track how long the user has been holding right on the right stick. + */ + var rightStickRightGamepadHandler:TurboButtonHandler = TurboButtonHandler.build(FlxGamepadInputID.RIGHT_STICK_DIGITAL_RIGHT); + /** * AUDIO AND SOUND DATA */ @@ -1733,10 +1816,15 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState var gridGhostNote:Null = null; /** - * A sprite used to indicate the note that will be placed on click. + * A sprite used to indicate the hold note that will be placed on click. */ var gridGhostHoldNote:Null = null; + /** + * A sprite used to indicate the hold note that will be placed on button release. + */ + var gridPlayheadGhostHoldNotes:Array = []; + /** * A sprite used to indicate the event that will be placed on click. */ @@ -2126,11 +2214,23 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState gridGhostHoldNote = new ChartEditorHoldNoteSprite(this); gridGhostHoldNote.alpha = 0.6; - gridGhostHoldNote.noteData = new SongNoteData(0, 0, 0, ""); + gridGhostHoldNote.noteData = null; gridGhostHoldNote.visible = false; add(gridGhostHoldNote); gridGhostHoldNote.zIndex = 11; + while (gridPlayheadGhostHoldNotes.length < (STRUMLINE_SIZE * 2)) + { + var ghost = new ChartEditorHoldNoteSprite(this); + ghost.alpha = 0.6; + ghost.noteData = null; + ghost.visible = false; + add(ghost); + ghost.zIndex = 11; + + gridPlayheadGhostHoldNotes.push(ghost); + } + gridGhostEvent = new ChartEditorEventSprite(this); gridGhostEvent.alpha = 0.6; gridGhostEvent.eventData = new SongEventData(-1, '', {}); @@ -2702,6 +2802,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState */ function setupTurboKeyHandlers():Void { + // Keyboard shortcuts add(undoKeyHandler); add(redoKeyHandler); add(upKeyHandler); @@ -2710,6 +2811,20 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState add(sKeyHandler); add(pageUpKeyHandler); add(pageDownKeyHandler); + + // Gamepad inputs + add(dpadUpGamepadHandler); + add(dpadDownGamepadHandler); + add(dpadLeftGamepadHandler); + add(dpadRightGamepadHandler); + add(leftStickUpGamepadHandler); + add(leftStickDownGamepadHandler); + add(leftStickLeftGamepadHandler); + add(leftStickRightGamepadHandler); + add(rightStickUpGamepadHandler); + add(rightStickDownGamepadHandler); + add(rightStickLeftGamepadHandler); + add(rightStickRightGamepadHandler); } /** @@ -2865,6 +2980,8 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState handleTestKeybinds(); handleHelpKeybinds(); + this.handleGamepadControls(); + #if debug handleQuickWatch(); #end @@ -3370,32 +3487,56 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState // Up Arrow = Scroll Up if (upKeyHandler.activated && currentLiveInputStyle == None) { - scrollAmount = -GRID_SIZE * 0.25 * 25.0; + scrollAmount = -GRID_SIZE * 4; shouldPause = true; } // Down Arrow = Scroll Down if (downKeyHandler.activated && currentLiveInputStyle == None) { - scrollAmount = GRID_SIZE * 0.25 * 25.0; + scrollAmount = GRID_SIZE * 4; shouldPause = true; } // W = Scroll Up (doesn't work with Ctrl+Scroll) if (wKeyHandler.activated && currentLiveInputStyle == None && !FlxG.keys.pressed.CONTROL) { - scrollAmount = -GRID_SIZE * 0.25 * 25.0; + scrollAmount = -GRID_SIZE * 4; shouldPause = true; } // S = Scroll Down (doesn't work with Ctrl+Scroll) if (sKeyHandler.activated && currentLiveInputStyle == None && !FlxG.keys.pressed.CONTROL) { - scrollAmount = GRID_SIZE * 0.25 * 25.0; + scrollAmount = GRID_SIZE * 4; shouldPause = true; } - // PAGE UP = Jump up to nearest measure - if (pageUpKeyHandler.activated) + // GAMEPAD LEFT STICK UP = Scroll Up by 1 note snap + if (leftStickUpGamepadHandler.activated) { + scrollAmount = -GRID_SIZE * noteSnapRatio; + shouldPause = true; + } + // GAMEPAD LEFT STICK DOWN = Scroll Down by 1 note snap + if (leftStickDownGamepadHandler.activated) + { + scrollAmount = GRID_SIZE * noteSnapRatio; + shouldPause = true; + } + + // GAMEPAD RIGHT STICK UP = Scroll Up by 1 note snap (playhead only) + if (rightStickUpGamepadHandler.activated) + { + playheadAmount = -GRID_SIZE * noteSnapRatio; + shouldPause = true; + } + // GAMEPAD RIGHT STICK DOWN = Scroll Down by 1 note snap (playhead only) + if (rightStickDownGamepadHandler.activated) + { + playheadAmount = GRID_SIZE * noteSnapRatio; + shouldPause = true; + } + + var funcJumpUp = (playheadOnly:Bool) -> { var measureHeight:Float = GRID_SIZE * 4 * Conductor.instance.beatsPerMeasure; var playheadPos:Float = scrollPositionInPixels + playheadPositionInPixels; var targetScrollPosition:Float = Math.floor(playheadPos / measureHeight) * measureHeight; @@ -3405,20 +3546,37 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState { targetScrollPosition -= GRID_SIZE * Constants.STEPS_PER_BEAT * Conductor.instance.beatsPerMeasure; } - scrollAmount = targetScrollPosition - playheadPos; + if (playheadOnly) + { + playheadAmount = targetScrollPosition - playheadPos; + } + else + { + scrollAmount = targetScrollPosition - playheadPos; + } + } + + // PAGE UP = Jump up to nearest measure + // GAMEPAD LEFT STICK LEFT = Jump up to nearest measure + if (pageUpKeyHandler.activated || leftStickLeftGamepadHandler.activated) + { + funcJumpUp(false); + shouldPause = true; + } + if (rightStickLeftGamepadHandler.activated) + { + funcJumpUp(true); shouldPause = true; } if (playbarButtonPressed == 'playbarBack') { playbarButtonPressed = ''; - scrollAmount = -GRID_SIZE * 4 * Conductor.instance.beatsPerMeasure; + funcJumpUp(false); shouldPause = true; } - // PAGE DOWN = Jump down to nearest measure - if (pageDownKeyHandler.activated) - { + var funcJumpDown = (playheadOnly:Bool) -> { var measureHeight:Float = GRID_SIZE * 4 * Conductor.instance.beatsPerMeasure; var playheadPos:Float = scrollPositionInPixels + playheadPositionInPixels; var targetScrollPosition:Float = Math.ceil(playheadPos / measureHeight) * measureHeight; @@ -3428,26 +3586,46 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState { targetScrollPosition += GRID_SIZE * Constants.STEPS_PER_BEAT * Conductor.instance.beatsPerMeasure; } - scrollAmount = targetScrollPosition - playheadPos; + if (playheadOnly) + { + playheadAmount = targetScrollPosition - playheadPos; + } + else + { + scrollAmount = targetScrollPosition - playheadPos; + } + } + + // PAGE DOWN = Jump down to nearest measure + // GAMEPAD LEFT STICK RIGHT = Jump down to nearest measure + if (pageDownKeyHandler.activated || leftStickRightGamepadHandler.activated) + { + funcJumpDown(false); + shouldPause = true; + } + if (rightStickRightGamepadHandler.activated) + { + funcJumpDown(true); shouldPause = true; } if (playbarButtonPressed == 'playbarForward') { playbarButtonPressed = ''; - scrollAmount = GRID_SIZE * 4 * Conductor.instance.beatsPerMeasure; + funcJumpDown(false); shouldPause = true; } // SHIFT + Scroll = Scroll Fast - if (FlxG.keys.pressed.SHIFT) + // GAMEPAD LEFT STICK CLICK + Scroll = Scroll Fast + if (FlxG.keys.pressed.SHIFT || (FlxG.gamepads.firstActive?.pressed?.LEFT_STICK_CLICK ?? false)) { scrollAmount *= 2; } // CONTROL + Scroll = Scroll Precise if (FlxG.keys.pressed.CONTROL) { - scrollAmount /= 10; + scrollAmount /= 4; } // Alt + Drag = Scroll but move the playhead the same amount. @@ -4520,37 +4698,77 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState function handlePlayhead():Void { - // Place notes at the playhead. + // Place notes at the playhead with the keyboard. switch (currentLiveInputStyle) { case ChartEditorLiveInputStyle.WASD: if (FlxG.keys.justPressed.A) placeNoteAtPlayhead(4); + if (FlxG.keys.justReleased.A) finishPlaceNoteAtPlayhead(4); if (FlxG.keys.justPressed.S) placeNoteAtPlayhead(5); + if (FlxG.keys.justReleased.S) finishPlaceNoteAtPlayhead(5); if (FlxG.keys.justPressed.W) placeNoteAtPlayhead(6); + if (FlxG.keys.justReleased.W) finishPlaceNoteAtPlayhead(6); if (FlxG.keys.justPressed.D) placeNoteAtPlayhead(7); + if (FlxG.keys.justReleased.D) finishPlaceNoteAtPlayhead(7); if (FlxG.keys.justPressed.LEFT) placeNoteAtPlayhead(0); + if (FlxG.keys.justReleased.LEFT) finishPlaceNoteAtPlayhead(0); if (FlxG.keys.justPressed.DOWN) placeNoteAtPlayhead(1); + if (FlxG.keys.justReleased.DOWN) finishPlaceNoteAtPlayhead(1); if (FlxG.keys.justPressed.UP) placeNoteAtPlayhead(2); + if (FlxG.keys.justReleased.UP) finishPlaceNoteAtPlayhead(2); if (FlxG.keys.justPressed.RIGHT) placeNoteAtPlayhead(3); + if (FlxG.keys.justReleased.RIGHT) finishPlaceNoteAtPlayhead(3); case ChartEditorLiveInputStyle.NumberKeys: // Flipped because Dad is on the left but represents data 0-3. if (FlxG.keys.justPressed.ONE) placeNoteAtPlayhead(4); + if (FlxG.keys.justReleased.ONE) finishPlaceNoteAtPlayhead(4); if (FlxG.keys.justPressed.TWO) placeNoteAtPlayhead(5); + if (FlxG.keys.justReleased.TWO) finishPlaceNoteAtPlayhead(5); if (FlxG.keys.justPressed.THREE) placeNoteAtPlayhead(6); + if (FlxG.keys.justReleased.THREE) finishPlaceNoteAtPlayhead(6); if (FlxG.keys.justPressed.FOUR) placeNoteAtPlayhead(7); + if (FlxG.keys.justReleased.FOUR) finishPlaceNoteAtPlayhead(7); if (FlxG.keys.justPressed.FIVE) placeNoteAtPlayhead(0); + if (FlxG.keys.justReleased.FIVE) finishPlaceNoteAtPlayhead(0); if (FlxG.keys.justPressed.SIX) placeNoteAtPlayhead(1); if (FlxG.keys.justPressed.SEVEN) placeNoteAtPlayhead(2); + if (FlxG.keys.justReleased.SEVEN) finishPlaceNoteAtPlayhead(2); if (FlxG.keys.justPressed.EIGHT) placeNoteAtPlayhead(3); + if (FlxG.keys.justReleased.EIGHT) finishPlaceNoteAtPlayhead(3); case ChartEditorLiveInputStyle.None: // Do nothing. } + + // Place notes at the playhead with the gamepad. + if (FlxG.gamepads.firstActive != null) + { + if (FlxG.gamepads.firstActive.justPressed.DPAD_LEFT) placeNoteAtPlayhead(4); + if (FlxG.gamepads.firstActive.justReleased.DPAD_LEFT) finishPlaceNoteAtPlayhead(4); + if (FlxG.gamepads.firstActive.justPressed.DPAD_DOWN) placeNoteAtPlayhead(5); + if (FlxG.gamepads.firstActive.justReleased.DPAD_DOWN) finishPlaceNoteAtPlayhead(5); + if (FlxG.gamepads.firstActive.justPressed.DPAD_UP) placeNoteAtPlayhead(6); + if (FlxG.gamepads.firstActive.justReleased.DPAD_UP) finishPlaceNoteAtPlayhead(6); + if (FlxG.gamepads.firstActive.justPressed.DPAD_RIGHT) placeNoteAtPlayhead(7); + if (FlxG.gamepads.firstActive.justReleased.DPAD_RIGHT) finishPlaceNoteAtPlayhead(7); + + if (FlxG.gamepads.firstActive.justPressed.X) placeNoteAtPlayhead(0); + if (FlxG.gamepads.firstActive.justReleased.X) finishPlaceNoteAtPlayhead(0); + if (FlxG.gamepads.firstActive.justPressed.A) placeNoteAtPlayhead(1); + if (FlxG.gamepads.firstActive.justReleased.A) finishPlaceNoteAtPlayhead(1); + if (FlxG.gamepads.firstActive.justPressed.Y) placeNoteAtPlayhead(2); + if (FlxG.gamepads.firstActive.justReleased.Y) finishPlaceNoteAtPlayhead(2); + if (FlxG.gamepads.firstActive.justPressed.B) placeNoteAtPlayhead(3); + if (FlxG.gamepads.firstActive.justReleased.B) finishPlaceNoteAtPlayhead(3); + } } function placeNoteAtPlayhead(column:Int):Void { + // SHIFT + press or LEFT_SHOULDER + press to remove notes instead of placing them. + var removeNoteInstead:Bool = FlxG.keys.pressed.SHIFT || (FlxG.gamepads.firstActive?.pressed?.LEFT_SHOULDER ?? false); + var playheadPos:Float = scrollPositionInPixels + playheadPositionInPixels; var playheadPosFractionalStep:Float = playheadPos / GRID_SIZE / noteSnapRatio; var playheadPosStep:Int = Std.int(Math.floor(playheadPosFractionalStep)); @@ -4561,10 +4779,18 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState playheadPosSnappedMs + Conductor.instance.stepLengthMs * noteSnapRatio); notesAtPos = SongDataUtils.getNotesWithData(notesAtPos, [column]); - if (notesAtPos.length == 0) + if (notesAtPos.length == 0 && !removeNoteInstead) { var newNoteData:SongNoteData = new SongNoteData(playheadPosSnappedMs, column, 0, noteKindToPlace); performCommand(new AddNotesCommand([newNoteData], FlxG.keys.pressed.CONTROL)); + currentLiveInputPlaceNoteData[column] = newNoteData; + gridPlayheadGhostHoldNotes[column].noteData = newNoteData.clone(); + gridPlayheadGhostHoldNotes[column].noteDirection = newNoteData.getDirection(); + } + else if (removeNoteInstead) + { + trace('Removing existing note at position.'); + performCommand(new RemoveNotesCommand(notesAtPos)); } else { @@ -4572,6 +4798,87 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState } } + function updatePlayheadGhostHoldNotes():Void + { + // Update playhead ghost hold notes. + for (index in 0...gridPlayheadGhostHoldNotes.length) + { + var ghostHold = gridPlayheadGhostHoldNotes[index]; + if (ghostHold == null) continue; + + if (ghostHold.noteData == null) + { + ghostHold.visible = false; + ghostHold.setHeightDirectly(0); + playheadDragLengthCurrent[index] = 0; + continue; + }; + + 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.instance.stepLengthMs * noteSnapRatio; + + var newNoteLength:Float = playheadPosSnappedMs - ghostHold.noteData.time; + trace('newNoteLength: ${newNoteLength}'); + + if (newNoteLength > 0) + { + ghostHold.noteData.length = newNoteLength; + var targetNoteLengthSteps:Float = ghostHold.noteData.getStepLength(true); + var targetNoteLengthStepsInt:Int = Std.int(Math.floor(targetNoteLengthSteps)); + var targetNoteLengthPixels:Float = targetNoteLengthSteps * GRID_SIZE; + + if (playheadDragLengthCurrent[index] != targetNoteLengthStepsInt) + { + stretchySounds = !stretchySounds; + this.playSound(Paths.sound('chartingSounds/stretch' + (stretchySounds ? '1' : '2') + '_UI')); + playheadDragLengthCurrent[index] = targetNoteLengthStepsInt; + } + ghostHold.visible = true; + trace('newHeight: ${targetNoteLengthPixels}'); + ghostHold.setHeightDirectly(targetNoteLengthPixels, true); + ghostHold.updateHoldNotePosition(renderedHoldNotes); + } + else + { + ghostHold.visible = false; + ghostHold.setHeightDirectly(0); + playheadDragLengthCurrent[index] = 0; + } + } + } + + function finishPlaceNoteAtPlayhead(column:Int):Void + { + if (currentLiveInputPlaceNoteData[column] == null) return; + + 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.instance.stepLengthMs * noteSnapRatio; + + var newNoteLength:Float = playheadPosSnappedMs - currentLiveInputPlaceNoteData[column].time; + trace('finishPlace newNoteLength: ${newNoteLength}'); + + if (newNoteLength < Conductor.instance.stepLengthMs) + { + // Don't extend the note if it's too short. + trace('Not extending note.'); + currentLiveInputPlaceNoteData[column] = null; + gridPlayheadGhostHoldNotes[column].noteData = null; + } + else + { + // Extend the note to the playhead position. + trace('Extending note.'); + this.playSound(Paths.sound('chartingSounds/stretchSNAP_UI')); + performCommand(new ExtendNoteLengthCommand(currentLiveInputPlaceNoteData[column], newNoteLength)); + currentLiveInputPlaceNoteData[column] = null; + gridPlayheadGhostHoldNotes[column].noteData = null; + } + } + /** * Handle aligning the health icons next to the grid. */ diff --git a/source/funkin/ui/debug/charting/commands/RemoveEventsCommand.hx b/source/funkin/ui/debug/charting/commands/RemoveEventsCommand.hx index 7e620c210..102257fc8 100644 --- a/source/funkin/ui/debug/charting/commands/RemoveEventsCommand.hx +++ b/source/funkin/ui/debug/charting/commands/RemoveEventsCommand.hx @@ -20,6 +20,8 @@ class RemoveEventsCommand implements ChartEditorCommand public function execute(state:ChartEditorState):Void { + if (events.length == 0) return; + state.currentSongChartEventData = SongDataUtils.subtractEvents(state.currentSongChartEventData, events); state.currentEventSelection = []; @@ -34,6 +36,8 @@ class RemoveEventsCommand implements ChartEditorCommand public function undo(state:ChartEditorState):Void { + if (events.length == 0) return; + for (event in events) { state.currentSongChartEventData.push(event); diff --git a/source/funkin/ui/debug/charting/commands/RemoveItemsCommand.hx b/source/funkin/ui/debug/charting/commands/RemoveItemsCommand.hx index 77184209e..376908726 100644 --- a/source/funkin/ui/debug/charting/commands/RemoveItemsCommand.hx +++ b/source/funkin/ui/debug/charting/commands/RemoveItemsCommand.hx @@ -23,6 +23,8 @@ class RemoveItemsCommand implements ChartEditorCommand public function execute(state:ChartEditorState):Void { + if ((notes.length + events.length) == 0) return; + state.currentSongChartNoteData = SongDataUtils.subtractNotes(state.currentSongChartNoteData, notes); state.currentSongChartEventData = SongDataUtils.subtractEvents(state.currentSongChartEventData, events); @@ -40,6 +42,8 @@ class RemoveItemsCommand implements ChartEditorCommand public function undo(state:ChartEditorState):Void { + if ((notes.length + events.length) == 0) return; + for (note in notes) { state.currentSongChartNoteData.push(note); diff --git a/source/funkin/ui/debug/charting/commands/RemoveNotesCommand.hx b/source/funkin/ui/debug/charting/commands/RemoveNotesCommand.hx index e189be83e..4e7b480dd 100644 --- a/source/funkin/ui/debug/charting/commands/RemoveNotesCommand.hx +++ b/source/funkin/ui/debug/charting/commands/RemoveNotesCommand.hx @@ -20,6 +20,8 @@ class RemoveNotesCommand implements ChartEditorCommand public function execute(state:ChartEditorState):Void { + if (notes.length == 0) return; + state.currentSongChartNoteData = SongDataUtils.subtractNotes(state.currentSongChartNoteData, notes); state.currentNoteSelection = []; state.currentEventSelection = []; @@ -35,6 +37,8 @@ class RemoveNotesCommand implements ChartEditorCommand public function undo(state:ChartEditorState):Void { + if (notes.length == 0) return; + for (note in notes) { state.currentSongChartNoteData.push(note); diff --git a/source/funkin/ui/debug/charting/components/ChartEditorHoldNoteSprite.hx b/source/funkin/ui/debug/charting/components/ChartEditorHoldNoteSprite.hx index e5971db08..193390341 100644 --- a/source/funkin/ui/debug/charting/components/ChartEditorHoldNoteSprite.hx +++ b/source/funkin/ui/debug/charting/components/ChartEditorHoldNoteSprite.hx @@ -43,11 +43,16 @@ class ChartEditorHoldNoteSprite extends SustainTrail * Set the height directly, to a value in pixels. * @param h The desired height in pixels. */ - public function setHeightDirectly(h:Float, ?lerp:Bool = false) + public function setHeightDirectly(h:Float, lerp:Bool = false) { - if (lerp != null && lerp) sustainLength = FlxMath.lerp(sustainLength, h / (getScrollSpeed() * Constants.PIXELS_PER_MS), 0.25); + if (lerp) + { + sustainLength = FlxMath.lerp(sustainLength, h / (getScrollSpeed() * Constants.PIXELS_PER_MS), 0.25); + } else + { sustainLength = h / (getScrollSpeed() * Constants.PIXELS_PER_MS); + } fullSustainLength = sustainLength; } diff --git a/source/funkin/ui/debug/charting/handlers/ChartEditorGamepadHandler.hx b/source/funkin/ui/debug/charting/handlers/ChartEditorGamepadHandler.hx new file mode 100644 index 000000000..896e2df68 --- /dev/null +++ b/source/funkin/ui/debug/charting/handlers/ChartEditorGamepadHandler.hx @@ -0,0 +1,133 @@ +package funkin.ui.debug.charting.handlers; + +/** + * Yes, we're that crazy. Gamepad support for the chart editor. + */ +@:nullSafety +@:access(funkin.ui.debug.charting.ChartEditorState) +class ChartEditorGamepadHandler +{ + public static function handleGamepadControls(chartEditorState:ChartEditorState) + { + if (FlxG.gamepads.firstActive == null) return; + + if (FlxG.gamepads.firstActive.justPressed.A) + { + // trace('Gamepad: A pressed'); + } + if (FlxG.gamepads.firstActive.justPressed.B) + { + // trace('Gamepad: B pressed'); + } + if (FlxG.gamepads.firstActive.justPressed.X) + { + // trace('Gamepad: X pressed'); + } + if (FlxG.gamepads.firstActive.justPressed.Y) + { + // trace('Gamepad: Y pressed'); + } + + if (FlxG.gamepads.firstActive.justPressed.LEFT_SHOULDER) + { + // trace('Gamepad: LEFT_SHOULDER pressed'); + } + if (FlxG.gamepads.firstActive.justPressed.RIGHT_SHOULDER) + { + // trace('Gamepad: RIGHT_SHOULDER pressed'); + } + + if (FlxG.gamepads.firstActive.justPressed.LEFT_STICK_CLICK) + { + // trace('Gamepad: LEFT_STICK_CLICK pressed'); + } + if (FlxG.gamepads.firstActive.justPressed.RIGHT_STICK_CLICK) + { + // trace('Gamepad: RIGHT_STICK_CLICK pressed'); + } + + if (FlxG.gamepads.firstActive.justPressed.LEFT_TRIGGER) + { + // trace('Gamepad: LEFT_TRIGGER pressed'); + } + if (FlxG.gamepads.firstActive.justPressed.RIGHT_TRIGGER) + { + // trace('Gamepad: RIGHT_TRIGGER pressed'); + } + + if (FlxG.gamepads.firstActive.justPressed.START) + { + // trace('Gamepad: START pressed'); + } + + if (FlxG.gamepads.firstActive.justPressed.BACK) + { + // trace('Gamepad: BACK pressed'); + } + + if (FlxG.gamepads.firstActive.justPressed.GUIDE) + { + // trace('Gamepad: GUIDE pressed'); + } + + if (FlxG.gamepads.firstActive.justPressed.DPAD_UP) + { + // trace('Gamepad: DPAD_UP pressed'); + } + + if (FlxG.gamepads.firstActive.justPressed.DPAD_DOWN) + { + // trace('Gamepad: DPAD_DOWN pressed'); + } + + if (FlxG.gamepads.firstActive.justPressed.DPAD_LEFT) + { + // trace('Gamepad: DPAD_LEFT pressed'); + } + + if (FlxG.gamepads.firstActive.justPressed.DPAD_RIGHT) + { + // trace('Gamepad: DPAD_RIGHT pressed'); + } + + if (FlxG.gamepads.firstActive.justPressed.LEFT_STICK_DIGITAL_UP) + { + // trace('Gamepad: LEFT_STICK_DIGITAL_UP pressed'); + } + + if (FlxG.gamepads.firstActive.justPressed.LEFT_STICK_DIGITAL_DOWN) + { + // trace('Gamepad: LEFT_STICK_DIGITAL_DOWN pressed'); + } + + if (FlxG.gamepads.firstActive.justPressed.LEFT_STICK_DIGITAL_LEFT) + { + // trace('Gamepad: LEFT_STICK_DIGITAL_LEFT pressed'); + } + + if (FlxG.gamepads.firstActive.justPressed.LEFT_STICK_DIGITAL_RIGHT) + { + // trace('Gamepad: LEFT_STICK_DIGITAL_RIGHT pressed'); + } + + if (FlxG.gamepads.firstActive.justPressed.RIGHT_STICK_DIGITAL_UP) + { + // trace('Gamepad: RIGHT_STICK_DIGITAL_UP pressed'); + } + + if (FlxG.gamepads.firstActive.justPressed.RIGHT_STICK_DIGITAL_DOWN) + { + // trace('Gamepad: RIGHT_STICK_DIGITAL_DOWN pressed'); + } + + if (FlxG.gamepads.firstActive.justPressed.RIGHT_STICK_DIGITAL_LEFT) + { + // trace('Gamepad: RIGHT_STICK_DIGITAL_LEFT pressed'); + } + + if (FlxG.gamepads.firstActive.justPressed.RIGHT_STICK_DIGITAL_RIGHT) + { + // trace('Gamepad: RIGHT_STICK_DIGITAL_RIGHT pressed'); + } + } +} diff --git a/source/funkin/ui/debug/charting/import.hx b/source/funkin/ui/debug/charting/import.hx index b0569e3bb..2c3d59ef7 100644 --- a/source/funkin/ui/debug/charting/import.hx +++ b/source/funkin/ui/debug/charting/import.hx @@ -5,6 +5,7 @@ package funkin.ui.debug.charting; using funkin.ui.debug.charting.handlers.ChartEditorAudioHandler; using funkin.ui.debug.charting.handlers.ChartEditorContextMenuHandler; using funkin.ui.debug.charting.handlers.ChartEditorDialogHandler; +using funkin.ui.debug.charting.handlers.ChartEditorGamepadHandler; using funkin.ui.debug.charting.handlers.ChartEditorImportExportHandler; using funkin.ui.debug.charting.handlers.ChartEditorNotificationHandler; using funkin.ui.debug.charting.handlers.ChartEditorShortcutHandler; From c6b3499897fd81090f2e7f564dc8d4bf7fe84b0d Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Mon, 8 Jan 2024 21:26:24 -0500 Subject: [PATCH 002/130] Finished up hold note placement on gamepad, implemented note preview playhead --- source/Main.hx | 2 + .../ui/debug/charting/ChartEditorState.hx | 130 ++++---- .../handlers/ChartEditorGamepadHandler.hx | 278 +++++++++++------- .../ui/haxeui/FlxGamepadActionInputSource.hx | 53 ++++ 4 files changed, 301 insertions(+), 162 deletions(-) create mode 100644 source/funkin/ui/haxeui/FlxGamepadActionInputSource.hx diff --git a/source/Main.hx b/source/Main.hx index 86e520e69..a7482c8d6 100644 --- a/source/Main.hx +++ b/source/Main.hx @@ -111,6 +111,8 @@ class Main extends Sprite Toolkit.init(); Toolkit.theme = 'dark'; // don't be cringe Toolkit.autoScale = false; + // Don't focus on UI elements when they first appear. + haxe.ui.focus.FocusManager.instance.autoFocus = false; funkin.input.Cursor.registerHaxeUICursors(); haxe.ui.tooltips.ToolTipManager.defaultDelay = 200; } diff --git a/source/funkin/ui/debug/charting/ChartEditorState.hx b/source/funkin/ui/debug/charting/ChartEditorState.hx index f3236578a..1b9176174 100644 --- a/source/funkin/ui/debug/charting/ChartEditorState.hx +++ b/source/funkin/ui/debug/charting/ChartEditorState.hx @@ -366,8 +366,6 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState } } - updatePlayheadGhostHoldNotes(); - // Move the rendered notes to the correct position. renderedNotes.setPosition(gridTiledSprite?.x ?? 0.0, gridTiledSprite?.y ?? 0.0); renderedHoldNotes.setPosition(gridTiledSprite?.x ?? 0.0, gridTiledSprite?.y ?? 0.0); @@ -375,8 +373,11 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState renderedSelectionSquares.setPosition(gridTiledSprite?.x ?? 0.0, gridTiledSprite?.y ?? 0.0); // Offset the selection box start position, if we are dragging. if (selectionBoxStartPos != null) selectionBoxStartPos.y -= diff; - // Update the note preview viewport box. + + // Update the note preview. setNotePreviewViewportBounds(calculateNotePreviewViewportBounds()); + refreshNotePreviewPlayheadPosition(); + // Update the measure tick display. if (measureTicks != null) measureTicks.y = gridTiledSprite?.y ?? 0.0; return this.scrollPositionInPixels; @@ -438,6 +439,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState gridPlayhead.y = this.playheadPositionInPixels + (MENU_BAR_HEIGHT + GRID_TOP_PAD); updatePlayheadGhostHoldNotes(); + refreshNotePreviewPlayheadPosition(); return this.playheadPositionInPixels; } @@ -1842,6 +1844,12 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState */ var notePreviewViewport:Null = null; + /** + * The thin sprite used for representing the playhead on the note preview. + * We move this up and down to represent the current position. + */ + var notePreviewPlayhead:Null = null; + /** * The rectangular sprite used for rendering the selection box. * Uses a 9-slice to stretch the selection box to the correct size without warping. @@ -2219,18 +2227,6 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState add(gridGhostHoldNote); gridGhostHoldNote.zIndex = 11; - while (gridPlayheadGhostHoldNotes.length < (STRUMLINE_SIZE * 2)) - { - var ghost = new ChartEditorHoldNoteSprite(this); - ghost.alpha = 0.6; - ghost.noteData = null; - ghost.visible = false; - add(ghost); - ghost.zIndex = 11; - - gridPlayheadGhostHoldNotes.push(ghost); - } - gridGhostEvent = new ChartEditorEventSprite(this); gridGhostEvent.alpha = 0.6; gridGhostEvent.eventData = new SongEventData(-1, '', {}); @@ -2300,6 +2296,15 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState add(notePreviewViewport); notePreviewViewport.zIndex = 30; + notePreviewPlayhead = new FlxSprite().makeGraphic(2, 2, 0xFFFF0000); + notePreviewPlayhead.scrollFactor.set(0, 0); + notePreviewPlayhead.scale.set(notePreview.width / 2, 0.5); // Setting width does nothing. + notePreviewPlayhead.updateHitbox(); + notePreviewPlayhead.x = notePreview.x; + notePreviewPlayhead.y = notePreview.y; + add(notePreviewPlayhead); + notePreviewPlayhead.zIndex = 31; + setNotePreviewViewportBounds(calculateNotePreviewViewportBounds()); } @@ -2399,6 +2404,13 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState } } + function refreshNotePreviewPlayheadPosition():Void + { + if (notePreviewPlayhead == null) return; + + notePreviewPlayhead.y = notePreview.y + (notePreview.height * ((scrollPositionInPixels + playheadPositionInPixels) / songLengthInPixels)); + } + /** * Builds the group that will hold all the notes. */ @@ -4194,7 +4206,6 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState gridGhostHoldNote.visible = true; gridGhostHoldNote.noteData = gridGhostNote.noteData; gridGhostHoldNote.noteDirection = gridGhostNote.noteData.getDirection(); - gridGhostHoldNote.setHeightDirectly(dragLengthPixels, true); gridGhostHoldNote.updateHoldNotePosition(renderedHoldNotes); @@ -4741,27 +4752,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState // Do nothing. } - // Place notes at the playhead with the gamepad. - if (FlxG.gamepads.firstActive != null) - { - if (FlxG.gamepads.firstActive.justPressed.DPAD_LEFT) placeNoteAtPlayhead(4); - if (FlxG.gamepads.firstActive.justReleased.DPAD_LEFT) finishPlaceNoteAtPlayhead(4); - if (FlxG.gamepads.firstActive.justPressed.DPAD_DOWN) placeNoteAtPlayhead(5); - if (FlxG.gamepads.firstActive.justReleased.DPAD_DOWN) finishPlaceNoteAtPlayhead(5); - if (FlxG.gamepads.firstActive.justPressed.DPAD_UP) placeNoteAtPlayhead(6); - if (FlxG.gamepads.firstActive.justReleased.DPAD_UP) finishPlaceNoteAtPlayhead(6); - if (FlxG.gamepads.firstActive.justPressed.DPAD_RIGHT) placeNoteAtPlayhead(7); - if (FlxG.gamepads.firstActive.justReleased.DPAD_RIGHT) finishPlaceNoteAtPlayhead(7); - - if (FlxG.gamepads.firstActive.justPressed.X) placeNoteAtPlayhead(0); - if (FlxG.gamepads.firstActive.justReleased.X) finishPlaceNoteAtPlayhead(0); - if (FlxG.gamepads.firstActive.justPressed.A) placeNoteAtPlayhead(1); - if (FlxG.gamepads.firstActive.justReleased.A) finishPlaceNoteAtPlayhead(1); - if (FlxG.gamepads.firstActive.justPressed.Y) placeNoteAtPlayhead(2); - if (FlxG.gamepads.firstActive.justReleased.Y) finishPlaceNoteAtPlayhead(2); - if (FlxG.gamepads.firstActive.justPressed.B) placeNoteAtPlayhead(3); - if (FlxG.gamepads.firstActive.justReleased.B) finishPlaceNoteAtPlayhead(3); - } + updatePlayheadGhostHoldNotes(); } function placeNoteAtPlayhead(column:Int):Void @@ -4781,38 +4772,68 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState if (notesAtPos.length == 0 && !removeNoteInstead) { + trace('Placing note. ${column}'); var newNoteData:SongNoteData = new SongNoteData(playheadPosSnappedMs, column, 0, noteKindToPlace); performCommand(new AddNotesCommand([newNoteData], FlxG.keys.pressed.CONTROL)); currentLiveInputPlaceNoteData[column] = newNoteData; - gridPlayheadGhostHoldNotes[column].noteData = newNoteData.clone(); - gridPlayheadGhostHoldNotes[column].noteDirection = newNoteData.getDirection(); } else if (removeNoteInstead) { - trace('Removing existing note at position.'); + trace('Removing existing note at position. ${column}'); performCommand(new RemoveNotesCommand(notesAtPos)); } else { - trace('Already a note there.'); + trace('Already a note there. ${column}'); } } function updatePlayheadGhostHoldNotes():Void { - // Update playhead ghost hold notes. - for (index in 0...gridPlayheadGhostHoldNotes.length) + // Ensure all the ghost hold notes exist. + while (gridPlayheadGhostHoldNotes.length < (STRUMLINE_SIZE * 2)) { - var ghostHold = gridPlayheadGhostHoldNotes[index]; - if (ghostHold == null) continue; + var ghost = new ChartEditorHoldNoteSprite(this); + ghost.alpha = 0.6; + ghost.noteData = null; + ghost.visible = false; + ghost.zIndex = 11; + add(ghost); // Don't add to `renderedHoldNotes` because then it will get killed every frame. + + gridPlayheadGhostHoldNotes.push(ghost); + refresh(); + } + + // Update playhead ghost hold notes. + for (column in 0...gridPlayheadGhostHoldNotes.length) + { + var targetNoteData = currentLiveInputPlaceNoteData[column]; + var ghostHold = gridPlayheadGhostHoldNotes[column]; + + if (targetNoteData == null && ghostHold.noteData != null) + { + // Remove the ghost hold note. + ghostHold.noteData = null; + } + + if (targetNoteData != null && ghostHold.noteData == null) + { + // Readd the new ghost hold note. + ghostHold.noteData = targetNoteData.clone(); + ghostHold.noteDirection = ghostHold.noteData.getDirection(); + ghostHold.visible = true; + ghostHold.alpha = 0.6; + ghostHold.setHeightDirectly(0); + ghostHold.updateHoldNotePosition(renderedHoldNotes); + } if (ghostHold.noteData == null) { ghostHold.visible = false; ghostHold.setHeightDirectly(0); - playheadDragLengthCurrent[index] = 0; + playheadDragLengthCurrent[column] = 0; continue; - }; + } var playheadPos:Float = scrollPositionInPixels + playheadPositionInPixels; var playheadPosFractionalStep:Float = playheadPos / GRID_SIZE / noteSnapRatio; @@ -4829,22 +4850,25 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState var targetNoteLengthStepsInt:Int = Std.int(Math.floor(targetNoteLengthSteps)); var targetNoteLengthPixels:Float = targetNoteLengthSteps * GRID_SIZE; - if (playheadDragLengthCurrent[index] != targetNoteLengthStepsInt) + if (playheadDragLengthCurrent[column] != targetNoteLengthStepsInt) { stretchySounds = !stretchySounds; this.playSound(Paths.sound('chartingSounds/stretch' + (stretchySounds ? '1' : '2') + '_UI')); - playheadDragLengthCurrent[index] = targetNoteLengthStepsInt; + playheadDragLengthCurrent[column] = targetNoteLengthStepsInt; } ghostHold.visible = true; - trace('newHeight: ${targetNoteLengthPixels}'); + ghostHold.alpha = 0.6; ghostHold.setHeightDirectly(targetNoteLengthPixels, true); ghostHold.updateHoldNotePosition(renderedHoldNotes); + trace('lerpLength: ${ghostHold.fullSustainLength}'); + trace('position: ${ghostHold.x}, ${ghostHold.y}'); } else { ghostHold.visible = false; ghostHold.setHeightDirectly(0); - playheadDragLengthCurrent[index] = 0; + playheadDragLengthCurrent[column] = 0; + continue; } } } @@ -4864,14 +4888,14 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState if (newNoteLength < Conductor.instance.stepLengthMs) { // Don't extend the note if it's too short. - trace('Not extending note.'); + trace('Not extending note. ${column}'); currentLiveInputPlaceNoteData[column] = null; gridPlayheadGhostHoldNotes[column].noteData = null; } else { // Extend the note to the playhead position. - trace('Extending note.'); + trace('Extending note. ${column}'); this.playSound(Paths.sound('chartingSounds/stretchSNAP_UI')); performCommand(new ExtendNoteLengthCommand(currentLiveInputPlaceNoteData[column], newNoteLength)); currentLiveInputPlaceNoteData[column] = null; diff --git a/source/funkin/ui/debug/charting/handlers/ChartEditorGamepadHandler.hx b/source/funkin/ui/debug/charting/handlers/ChartEditorGamepadHandler.hx index 896e2df68..70383d3fd 100644 --- a/source/funkin/ui/debug/charting/handlers/ChartEditorGamepadHandler.hx +++ b/source/funkin/ui/debug/charting/handlers/ChartEditorGamepadHandler.hx @@ -1,133 +1,193 @@ package funkin.ui.debug.charting.handlers; +import haxe.ui.focus.FocusManager; +import flixel.input.gamepad.FlxGamepad; +import haxe.ui.actions.ActionManager; +import haxe.ui.actions.IActionInputSource; +import haxe.ui.actions.ActionType; + /** * Yes, we're that crazy. Gamepad support for the chart editor. */ -@:nullSafety +// @:nullSafety + @:access(funkin.ui.debug.charting.ChartEditorState) class ChartEditorGamepadHandler { public static function handleGamepadControls(chartEditorState:ChartEditorState) { - if (FlxG.gamepads.firstActive == null) return; + if (FlxG.gamepads.firstActive != null) handleGamepad(chartEditorState, FlxG.gamepads.firstActive); + } - if (FlxG.gamepads.firstActive.justPressed.A) + /** + * Handle context-generic binds for the gamepad. + * @param chartEditorState The chart editor state. + * @param gamepad The gamepad to handle. + */ + static function handleGamepad(chartEditorState:ChartEditorState, gamepad:FlxGamepad):Void + { + if (chartEditorState.isHaxeUIFocused) { - // trace('Gamepad: A pressed'); + ChartEditorGamepadActionInputSource.instance.handleGamepad(gamepad); } - if (FlxG.gamepads.firstActive.justPressed.B) + else { - // trace('Gamepad: B pressed'); - } - if (FlxG.gamepads.firstActive.justPressed.X) - { - // trace('Gamepad: X pressed'); - } - if (FlxG.gamepads.firstActive.justPressed.Y) - { - // trace('Gamepad: Y pressed'); + handleGamepadLiveInputs(chartEditorState, gamepad); + + if (gamepad.justPressed.RIGHT_SHOULDER) + { + trace('Gamepad: Right shoulder pressed, toggling audio playback.'); + chartEditorState.toggleAudioPlayback(); + } + + if (gamepad.justPressed.START) + { + var minimal = gamepad.pressed.LEFT_SHOULDER; + chartEditorState.hideAllToolboxes(); + trace('Gamepad: Start pressed, opening playtest (minimal: ${minimal})'); + chartEditorState.testSongInPlayState(minimal); + } + + if (gamepad.justPressed.BACK && !gamepad.pressed.LEFT_SHOULDER) + { + trace('Gamepad: Back pressed, focusing on HaxeUI menu.'); + // FocusManager.instance.focus = chartEditorState.menubarMenuFile; + } + else if (gamepad.justPressed.BACK && gamepad.pressed.LEFT_SHOULDER) + { + trace('Gamepad: Back pressed, unfocusing on HaxeUI menu.'); + FocusManager.instance.focus = null; + } } - if (FlxG.gamepads.firstActive.justPressed.LEFT_SHOULDER) + if (gamepad.justPressed.GUIDE) { - // trace('Gamepad: LEFT_SHOULDER pressed'); - } - if (FlxG.gamepads.firstActive.justPressed.RIGHT_SHOULDER) - { - // trace('Gamepad: RIGHT_SHOULDER pressed'); + trace('Gamepad: Guide pressed, quitting chart editor.'); + chartEditorState.quitChartEditor(); } + } - if (FlxG.gamepads.firstActive.justPressed.LEFT_STICK_CLICK) + static function handleGamepadLiveInputs(chartEditorState:ChartEditorState, gamepad:FlxGamepad):Void + { + // Place notes at the playhead with the gamepad. + // Disable when we are interacting with HaxeUI. + if (!(chartEditorState.isHaxeUIFocused || chartEditorState.isHaxeUIDialogOpen)) { - // trace('Gamepad: LEFT_STICK_CLICK pressed'); - } - if (FlxG.gamepads.firstActive.justPressed.RIGHT_STICK_CLICK) - { - // trace('Gamepad: RIGHT_STICK_CLICK pressed'); - } + if (gamepad.justPressed.DPAD_LEFT) chartEditorState.placeNoteAtPlayhead(4); + if (gamepad.justReleased.DPAD_LEFT) chartEditorState.finishPlaceNoteAtPlayhead(4); + if (gamepad.justPressed.DPAD_DOWN) chartEditorState.placeNoteAtPlayhead(5); + if (gamepad.justReleased.DPAD_DOWN) chartEditorState.finishPlaceNoteAtPlayhead(5); + if (gamepad.justPressed.DPAD_UP) chartEditorState.placeNoteAtPlayhead(6); + if (gamepad.justReleased.DPAD_UP) chartEditorState.finishPlaceNoteAtPlayhead(6); + if (gamepad.justPressed.DPAD_RIGHT) chartEditorState.placeNoteAtPlayhead(7); + if (gamepad.justReleased.DPAD_RIGHT) chartEditorState.finishPlaceNoteAtPlayhead(7); - if (FlxG.gamepads.firstActive.justPressed.LEFT_TRIGGER) - { - // trace('Gamepad: LEFT_TRIGGER pressed'); - } - if (FlxG.gamepads.firstActive.justPressed.RIGHT_TRIGGER) - { - // trace('Gamepad: RIGHT_TRIGGER pressed'); - } - - if (FlxG.gamepads.firstActive.justPressed.START) - { - // trace('Gamepad: START pressed'); - } - - if (FlxG.gamepads.firstActive.justPressed.BACK) - { - // trace('Gamepad: BACK pressed'); - } - - if (FlxG.gamepads.firstActive.justPressed.GUIDE) - { - // trace('Gamepad: GUIDE pressed'); - } - - if (FlxG.gamepads.firstActive.justPressed.DPAD_UP) - { - // trace('Gamepad: DPAD_UP pressed'); - } - - if (FlxG.gamepads.firstActive.justPressed.DPAD_DOWN) - { - // trace('Gamepad: DPAD_DOWN pressed'); - } - - if (FlxG.gamepads.firstActive.justPressed.DPAD_LEFT) - { - // trace('Gamepad: DPAD_LEFT pressed'); - } - - if (FlxG.gamepads.firstActive.justPressed.DPAD_RIGHT) - { - // trace('Gamepad: DPAD_RIGHT pressed'); - } - - if (FlxG.gamepads.firstActive.justPressed.LEFT_STICK_DIGITAL_UP) - { - // trace('Gamepad: LEFT_STICK_DIGITAL_UP pressed'); - } - - if (FlxG.gamepads.firstActive.justPressed.LEFT_STICK_DIGITAL_DOWN) - { - // trace('Gamepad: LEFT_STICK_DIGITAL_DOWN pressed'); - } - - if (FlxG.gamepads.firstActive.justPressed.LEFT_STICK_DIGITAL_LEFT) - { - // trace('Gamepad: LEFT_STICK_DIGITAL_LEFT pressed'); - } - - if (FlxG.gamepads.firstActive.justPressed.LEFT_STICK_DIGITAL_RIGHT) - { - // trace('Gamepad: LEFT_STICK_DIGITAL_RIGHT pressed'); - } - - if (FlxG.gamepads.firstActive.justPressed.RIGHT_STICK_DIGITAL_UP) - { - // trace('Gamepad: RIGHT_STICK_DIGITAL_UP pressed'); - } - - if (FlxG.gamepads.firstActive.justPressed.RIGHT_STICK_DIGITAL_DOWN) - { - // trace('Gamepad: RIGHT_STICK_DIGITAL_DOWN pressed'); - } - - if (FlxG.gamepads.firstActive.justPressed.RIGHT_STICK_DIGITAL_LEFT) - { - // trace('Gamepad: RIGHT_STICK_DIGITAL_LEFT pressed'); - } - - if (FlxG.gamepads.firstActive.justPressed.RIGHT_STICK_DIGITAL_RIGHT) - { - // trace('Gamepad: RIGHT_STICK_DIGITAL_RIGHT pressed'); + if (gamepad.justPressed.X) chartEditorState.placeNoteAtPlayhead(0); + if (gamepad.justReleased.X) chartEditorState.finishPlaceNoteAtPlayhead(0); + if (gamepad.justPressed.A) chartEditorState.placeNoteAtPlayhead(1); + if (gamepad.justReleased.A) chartEditorState.finishPlaceNoteAtPlayhead(1); + if (gamepad.justPressed.Y) chartEditorState.placeNoteAtPlayhead(2); + if (gamepad.justReleased.Y) chartEditorState.finishPlaceNoteAtPlayhead(2); + if (gamepad.justPressed.B) chartEditorState.placeNoteAtPlayhead(3); + if (gamepad.justReleased.B) chartEditorState.finishPlaceNoteAtPlayhead(3); + } + } +} + +class ChartEditorGamepadActionInputSource implements IActionInputSource +{ + public static var instance:ChartEditorGamepadActionInputSource = new ChartEditorGamepadActionInputSource(); + + public function new() {} + + public function start():Void {} + + /** + * Handle HaxeUI-specific binds for the gamepad. + * Only called when the HaxeUI menu is focused. + * @param chartEditorState The chart editor state. + * @param gamepad The gamepad to handle. + */ + public function handleGamepad(gamepad:FlxGamepad):Void + { + if (gamepad.justPressed.DPAD_LEFT) + { + trace('Gamepad: DPAD_LEFT pressed, moving left.'); + ActionManager.instance.actionStart(ActionType.LEFT, this); + } + else if (gamepad.justReleased.DPAD_LEFT) + { + ActionManager.instance.actionEnd(ActionType.LEFT, this); + } + + if (gamepad.justPressed.DPAD_RIGHT) + { + trace('Gamepad: DPAD_RIGHT pressed, moving right.'); + ActionManager.instance.actionStart(ActionType.RIGHT, this); + } + else if (gamepad.justReleased.DPAD_RIGHT) + { + ActionManager.instance.actionEnd(ActionType.RIGHT, this); + } + + if (gamepad.justPressed.DPAD_UP) + { + trace('Gamepad: DPAD_UP pressed, moving up.'); + ActionManager.instance.actionStart(ActionType.UP, this); + } + else if (gamepad.justReleased.DPAD_UP) + { + ActionManager.instance.actionEnd(ActionType.UP, this); + } + + if (gamepad.justPressed.DPAD_DOWN) + { + trace('Gamepad: DPAD_DOWN pressed, moving down.'); + ActionManager.instance.actionStart(ActionType.DOWN, this); + } + else if (gamepad.justReleased.DPAD_DOWN) + { + ActionManager.instance.actionEnd(ActionType.DOWN, this); + } + + if (gamepad.justPressed.A) + { + trace('Gamepad: A pressed, confirmingg.'); + ActionManager.instance.actionStart(ActionType.CONFIRM, this); + } + else if (gamepad.justReleased.A) + { + ActionManager.instance.actionEnd(ActionType.CONFIRM, this); + } + + if (gamepad.justPressed.B) + { + trace('Gamepad: B pressed, cancelling.'); + ActionManager.instance.actionStart(ActionType.CANCEL, this); + } + else if (gamepad.justReleased.B) + { + ActionManager.instance.actionEnd(ActionType.CANCEL, this); + } + + if (gamepad.justPressed.LEFT_TRIGGER) + { + trace('Gamepad: LEFT_TRIGGER pressed, moving to previous item.'); + ActionManager.instance.actionStart(ActionType.PREVIOUS, this); + } + else if (gamepad.justReleased.LEFT_TRIGGER) + { + ActionManager.instance.actionEnd(ActionType.PREVIOUS, this); + } + + if (gamepad.justPressed.RIGHT_TRIGGER) + { + trace('Gamepad: RIGHT_TRIGGER pressed, moving to next item.'); + ActionManager.instance.actionStart(ActionType.NEXT, this); + } + else if (gamepad.justReleased.RIGHT_TRIGGER) + { + ActionManager.instance.actionEnd(ActionType.NEXT, this); } } } diff --git a/source/funkin/ui/haxeui/FlxGamepadActionInputSource.hx b/source/funkin/ui/haxeui/FlxGamepadActionInputSource.hx new file mode 100644 index 000000000..9c2901d16 --- /dev/null +++ b/source/funkin/ui/haxeui/FlxGamepadActionInputSource.hx @@ -0,0 +1,53 @@ +package funkin.ui.haxeui; + +import flixel.FlxBasic; +import flixel.input.gamepad.FlxGamepad; +import haxe.ui.actions.IActionInputSource; + +/** + * Receives button presses from the Flixel gamepad and emits HaxeUI events. + */ +class FlxGamepadActionInputSource extends FlxBasic +{ + public static var instance(get, null):FlxGamepadActionInputSource; + + static function get_instance():FlxGamepadActionInputSource + { + if (instance == null) instance = new FlxGamepadActionInputSource(); + return instance; + } + + public function new() + { + super(); + } + + public function start():Void + { + FlxG.plugins.addPlugin(this); + } + + public override function update(elapsed:Float):Void + { + super.update(elapsed); + + if (FlxG.gamepads.firstActive != null) + { + updateGamepad(elapsed, FlxG.gamepads.firstActive); + } + } + + function updateGamepad(elapsed:Float, gamepad:FlxGamepad):Void + { + if (gamepad.justPressed.BACK) + { + // + } + } + + public override function destroy():Void + { + super.destroy(); + FlxG.plugins.remove(this); + } +} From 2dbc0cda6e63a56eccb81f8ad8eb63407dfbc3d7 Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Tue, 13 Feb 2024 03:18:51 -0500 Subject: [PATCH 003/130] Fix a missing import. --- source/funkin/ui/debug/charting/ChartEditorState.hx | 1 + 1 file changed, 1 insertion(+) diff --git a/source/funkin/ui/debug/charting/ChartEditorState.hx b/source/funkin/ui/debug/charting/ChartEditorState.hx index 6d2b47ef4..d0ed095cc 100644 --- a/source/funkin/ui/debug/charting/ChartEditorState.hx +++ b/source/funkin/ui/debug/charting/ChartEditorState.hx @@ -45,6 +45,7 @@ import funkin.graphics.FunkinCamera; import funkin.graphics.FunkinSprite; import funkin.input.Cursor; import funkin.input.TurboActionHandler; +import funkin.input.TurboButtonHandler; import funkin.input.TurboKeyHandler; import funkin.modding.events.ScriptEvent; import funkin.play.character.BaseCharacter.CharacterType; From 8a9a8bb179976b35ee688fcc5fcd6af116f06869 Mon Sep 17 00:00:00 2001 From: Cameron Taylor Date: Thu, 22 Feb 2024 01:50:55 -0500 Subject: [PATCH 004/130] abot bars in probress --- assets | 2 +- hmm.json | 9 ++++++++- source/funkin/audio/visualize/ABotVis.hx | 4 +--- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/assets b/assets index c8f320e89..d9a0b3b0b 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit c8f320e89f65f9e6242354b25f04aac2c07cceeb +Subproject commit d9a0b3b0bcc5b9cac89dde01cccf0b77e9187362 diff --git a/hmm.json b/hmm.json index 26cb0d0b4..1e5bf5f18 100644 --- a/hmm.json +++ b/hmm.json @@ -45,6 +45,13 @@ "type": "haxelib", "version": "3.5.0" }, + { + "name": "funkVis", + "type": "git", + "dir": null, + "ref": "separateDSP", + "url": "https://github.com/FunkinCrew/funkVis" + }, { "name": "hamcrest", "type": "haxelib", @@ -164,4 +171,4 @@ "url": "https://github.com/FunkinCrew/thx.semver" } ] -} +} \ No newline at end of file diff --git a/source/funkin/audio/visualize/ABotVis.hx b/source/funkin/audio/visualize/ABotVis.hx index 89b004df4..16a023474 100644 --- a/source/funkin/audio/visualize/ABotVis.hx +++ b/source/funkin/audio/visualize/ABotVis.hx @@ -35,9 +35,7 @@ class ABotVis extends FlxTypedSpriteGroup viz.frames = visFrms; add(viz); - var visStr = 'VIZ'; - if (lol == 5) visStr = 'viz'; // lol makes it lowercase, accomodates for art that I dont wanna rename! - + var visStr = 'viz'; viz.animation.addByPrefix('VIZ', visStr + lol, 0); viz.animation.play('VIZ', false, false, -1); } From fa8d1186544621d6ba6b63ce90391da1a239fe67 Mon Sep 17 00:00:00 2001 From: Cameron Taylor Date: Thu, 22 Feb 2024 02:49:08 -0500 Subject: [PATCH 005/130] vis positioning --- assets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets b/assets index d9a0b3b0b..a681c9293 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit d9a0b3b0bcc5b9cac89dde01cccf0b77e9187362 +Subproject commit a681c9293fae71fee41aca51266c53ff30564a6f From 40a056078c627be0e78b11bbae4fd6e4cb9a896d Mon Sep 17 00:00:00 2001 From: Cameron Taylor Date: Fri, 23 Feb 2024 02:03:34 -0500 Subject: [PATCH 006/130] vispos --- source/funkin/audio/visualize/ABotVis.hx | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/source/funkin/audio/visualize/ABotVis.hx b/source/funkin/audio/visualize/ABotVis.hx index 16a023474..aa843f6e8 100644 --- a/source/funkin/audio/visualize/ABotVis.hx +++ b/source/funkin/audio/visualize/ABotVis.hx @@ -26,12 +26,17 @@ class ABotVis extends FlxTypedSpriteGroup var visFrms:FlxAtlasFrames = Paths.getSparrowAtlas('aBotViz'); + // these are the differences in X position, from left to right + var positionX:Array = [0, 59, 56, 66, 54, 52, 51]; + for (lol in 1...8) { // pushes initial value volumes.push(0.0); - var viz:FlxSprite = new FlxSprite(50 * lol, 0); + var posX:Float = positionX[lol - 1] + (positionX[lol - 2] ?? 0); + + var viz:FlxSprite = new FlxSprite(posX, 0); viz.frames = visFrms; add(viz); From b261729fa3b895bc07c6d409be0da73b83239781 Mon Sep 17 00:00:00 2001 From: Cameron Taylor Date: Fri, 23 Feb 2024 02:18:50 -0500 Subject: [PATCH 007/130] abot positioning --- assets | 2 +- source/funkin/audio/visualize/ABotVis.hx | 8 +++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/assets b/assets index a681c9293..181e41088 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit a681c9293fae71fee41aca51266c53ff30564a6f +Subproject commit 181e410888e7808ed373e14d539048a4ae17feea diff --git a/source/funkin/audio/visualize/ABotVis.hx b/source/funkin/audio/visualize/ABotVis.hx index aa843f6e8..1bd7d0457 100644 --- a/source/funkin/audio/visualize/ABotVis.hx +++ b/source/funkin/audio/visualize/ABotVis.hx @@ -28,15 +28,17 @@ class ABotVis extends FlxTypedSpriteGroup // these are the differences in X position, from left to right var positionX:Array = [0, 59, 56, 66, 54, 52, 51]; + var positionY:Array = [0, -8, -3.5, -0.4, 0.5, 4.7, 7]; for (lol in 1...8) { // pushes initial value volumes.push(0.0); + var sum = function(num:Float, total:Float) return total += num; + var posX:Float = positionX.slice(0, lol).fold(sum, 0); + var posY:Float = positionY.slice(0, lol).fold(sum, 0); - var posX:Float = positionX[lol - 1] + (positionX[lol - 2] ?? 0); - - var viz:FlxSprite = new FlxSprite(posX, 0); + var viz:FlxSprite = new FlxSprite(posX, posY); viz.frames = visFrms; add(viz); From 6f88865e0bd827b1858e3a7dbcd3ca7b2bdd3d9f Mon Sep 17 00:00:00 2001 From: Cameron Taylor Date: Fri, 23 Feb 2024 04:00:31 -0500 Subject: [PATCH 008/130] viz in progress --- Project.xml | 1 + assets | 2 +- source/funkin/audio/visualize/ABotVis.hx | 214 +++++++++++---------- source/funkin/audio/visualize/AudioClip.hx | 23 +++ source/funkin/play/PlayState.hx | 4 +- 5 files changed, 140 insertions(+), 104 deletions(-) create mode 100644 source/funkin/audio/visualize/AudioClip.hx diff --git a/Project.xml b/Project.xml index c58153575..434ae52c9 100644 --- a/Project.xml +++ b/Project.xml @@ -109,6 +109,7 @@ + diff --git a/assets b/assets index ed3eb91f4..d0dc456b4 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit ed3eb91f4b04fa0473128698e0e079a28998401e +Subproject commit d0dc456b49bd9d62c924b2f87f0205dba338705e diff --git a/source/funkin/audio/visualize/ABotVis.hx b/source/funkin/audio/visualize/ABotVis.hx index 1bd7d0457..2501ca6e6 100644 --- a/source/funkin/audio/visualize/ABotVis.hx +++ b/source/funkin/audio/visualize/ABotVis.hx @@ -8,20 +8,26 @@ import flixel.group.FlxSpriteGroup.FlxTypedSpriteGroup; import flixel.math.FlxMath; import flixel.sound.FlxSound; import funkin.util.MathUtil; +import funkVis.dsp.SpectralAnalyzer; using Lambda; class ABotVis extends FlxTypedSpriteGroup { - public var vis:VisShit; + // public var vis:VisShit; + var analyzer:SpectralAnalyzer; var volumes:Array = []; + public var snd:FlxSound; + public function new(snd:FlxSound) { super(); - vis = new VisShit(snd); + this.snd = snd; + + // vis = new VisShit(snd); // vis.snd = snd; var visFrms:FlxAtlasFrames = Paths.getSparrowAtlas('aBotViz'); @@ -48,118 +54,124 @@ class ABotVis extends FlxTypedSpriteGroup } } + public function initAnalyzer() + { + @:privateAccess + analyzer = new SpectralAnalyzer(7, new AudioClip(cast snd._channel.__source), 0.005, 30); + } + override function update(elapsed:Float) { // updateViz(); - updateFFT(elapsed); + // updateFFT(elapsed); super.update(elapsed); } - function updateFFT(elapsed:Float) + static inline function min(x:Int, y:Int):Int { - if (vis.snd != null) - { - vis.checkAndSetBuffer(); - - if (vis.setBuffer) - { - var remappedShit:Int = 0; - - 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.instance.songPosition, 0, vis.snd.length, 0, vis.numSamples)); - - var fftSamples:Array = []; - - var swagBucks = remappedShit; - - for (i in remappedShit...remappedShit + (Std.int((44100 * (1 / 144))))) - { - var left = vis.audioData[swagBucks] / 32767; - var right = vis.audioData[swagBucks + 1] / 32767; - - var balanced = (left + right) / 2; - - swagBucks += 2; - - fftSamples.push(balanced); - } - - var freqShit = vis.funnyFFT(fftSamples); - - for (i in 0...group.members.length) - { - var getSliceShit = function(s:Int) { - var powShit = FlxMath.remapToRange(s, 0, group.members.length, 0, MathUtil.logBase(10, freqShit[0].length)); - return Math.round(Math.pow(10, powShit)); - }; - - // var powShit:Float = getSliceShit(i); - var hzSliced:Int = getSliceShit(i); - - var sliceLength:Int = Std.int(freqShit[0].length / group.members.length); - - var volSlice = freqShit[0].slice(hzSliced, getSliceShit(i + 1)); - - var avgVel:Float = 0; - - for (slice in volSlice) - { - avgVel += slice; - } - - avgVel /= volSlice.length; - - avgVel *= 10000000; - - volumes[i] += avgVel - (elapsed * (volumes[i] * 50)); - - var animFrame:Int = Std.int(volumes[i]); - - animFrame = Math.floor(Math.min(5, animFrame)); - animFrame = Math.floor(Math.max(0, animFrame)); - - animFrame = Std.int(Math.abs(animFrame - 5)); // shitty dumbass flip, cuz dave got da shit backwards lol! - - group.members[i].animation.curAnim.curFrame = animFrame; - if (FlxG.keys.justPressed.U) - { - trace(avgVel); - trace(group.members[i].animation.curAnim.curFrame); - } - } - - // group.members[0].animation.curAnim.curFrame = - } - } + return x > y ? y : x; } - public function updateViz() + override function draw() { - if (vis.snd != null) + if (analyzer == null) { - var remappedShit:Int = 0; - vis.checkAndSetBuffer(); - - if (vis.setBuffer) - { - // var startingSample:Int = Std.int(FlxMath.remapToRange) - - if (vis.snd.playing) remappedShit = Std.int(FlxMath.remapToRange(vis.snd.time, 0, vis.snd.length, 0, vis.numSamples)); - - for (i in 0...group.members.length) - { - var sampleApprox:Int = Std.int(FlxMath.remapToRange(i, 0, group.members.length, remappedShit, remappedShit + 500)); - - var left = vis.audioData[sampleApprox] / 32767; - - var animFrame:Int = Std.int(FlxMath.remapToRange(left, -1, 1, 0, 6)); - - group.members[i].animation.curAnim.curFrame = animFrame; - } - } + super.draw(); + return; } + + var levels = analyzer.getLevels(false); + + for (i in 0...min(group.members.length, levels.length)) + { + var animFrame:Int = Math.round(levels[i].value * 5); + + animFrame = Math.floor(Math.min(5, animFrame)); + animFrame = Math.floor(Math.max(0, animFrame)); + + animFrame = Std.int(Math.abs(animFrame - 5)); // shitty dumbass flip, cuz dave got da shit backwards lol! + + group.members[i].animation.curAnim.curFrame = animFrame; + } + + super.draw(); } + + // function updateFFT(elapsed:Float) + // { + // if (vis.snd != null) + // { + // vis.checkAndSetBuffer(); + // if (vis.setBuffer) + // { + // var remappedShit:Int = 0; + // 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.instance.songPosition, 0, vis.snd.length, 0, vis.numSamples)); + // var fftSamples:Array = []; + // var swagBucks = remappedShit; + // for (i in remappedShit...remappedShit + (Std.int((44100 * (1 / 144))))) + // { + // var left = vis.audioData[swagBucks] / 32767; + // var right = vis.audioData[swagBucks + 1] / 32767; + // var balanced = (left + right) / 2; + // swagBucks += 2; + // fftSamples.push(balanced); + // } + // var freqShit = vis.funnyFFT(fftSamples); + // for (i in 0...group.members.length) + // { + // var getSliceShit = function(s:Int) { + // var powShit = FlxMath.remapToRange(s, 0, group.members.length, 0, MathUtil.logBase(10, freqShit[0].length)); + // return Math.round(Math.pow(10, powShit)); + // }; + // // var powShit:Float = getSliceShit(i); + // var hzSliced:Int = getSliceShit(i); + // var sliceLength:Int = Std.int(freqShit[0].length / group.members.length); + // var volSlice = freqShit[0].slice(hzSliced, getSliceShit(i + 1)); + // var avgVel:Float = 0; + // for (slice in volSlice) + // { + // avgVel += slice; + // } + // avgVel /= volSlice.length; + // avgVel *= 10000000; + // volumes[i] += avgVel - (elapsed * (volumes[i] * 50)); + // var animFrame:Int = Std.int(volumes[i]); + // animFrame = Math.floor(Math.min(5, animFrame)); + // animFrame = Math.floor(Math.max(0, animFrame)); + // animFrame = Std.int(Math.abs(animFrame - 5)); // shitty dumbass flip, cuz dave got da shit backwards lol! + // group.members[i].animation.curAnim.curFrame = animFrame; + // if (FlxG.keys.justPressed.U) + // { + // trace(avgVel); + // trace(group.members[i].animation.curAnim.curFrame); + // } + // } + // // group.members[0].animation.curAnim.curFrame = + // } + // } + // } + // public function updateViz() + // { + // if (vis.snd != null) + // { + // var remappedShit:Int = 0; + // vis.checkAndSetBuffer(); + // if (vis.setBuffer) + // { + // // var startingSample:Int = Std.int(FlxMath.remapToRange) + // if (vis.snd.playing) remappedShit = Std.int(FlxMath.remapToRange(vis.snd.time, 0, vis.snd.length, 0, vis.numSamples)); + // for (i in 0...group.members.length) + // { + // var sampleApprox:Int = Std.int(FlxMath.remapToRange(i, 0, group.members.length, remappedShit, remappedShit + 500)); + // var left = vis.audioData[sampleApprox] / 32767; + // var animFrame:Int = Std.int(FlxMath.remapToRange(left, -1, 1, 0, 6)); + // group.members[i].animation.curAnim.curFrame = animFrame; + // } + // } + // } + // } } diff --git a/source/funkin/audio/visualize/AudioClip.hx b/source/funkin/audio/visualize/AudioClip.hx new file mode 100644 index 000000000..a8e353799 --- /dev/null +++ b/source/funkin/audio/visualize/AudioClip.hx @@ -0,0 +1,23 @@ +package funkin.audio.visualize; + +import flixel.FlxG; +import flixel.math.FlxMath; +import funkVis.AudioBuffer; +import lime.media.AudioSource; + +class AudioClip implements funkVis.AudioClip +{ + public var audioBuffer(default, null):AudioBuffer; + public var currentFrame(get, never):Int; + + public function new(audioSource:AudioSource) + { + var data:lime.utils.UInt16Array = cast audioSource.buffer.data; + this.audioBuffer = new AudioBuffer(data, audioSource.buffer.sampleRate); + } + + private function get_currentFrame():Int + { + return Std.int(FlxMath.remapToRange(FlxG.sound.music.time, 0, FlxG.sound.music.length, 0, audioBuffer.data.length / 2)); + } +} diff --git a/source/funkin/play/PlayState.hx b/source/funkin/play/PlayState.hx index 1dbba5b54..0112a59e8 100644 --- a/source/funkin/play/PlayState.hx +++ b/source/funkin/play/PlayState.hx @@ -1741,8 +1741,6 @@ class PlayState extends MusicBeatSubState */ function startSong():Void { - dispatchEvent(new ScriptEvent(SONG_START)); - startingSong = false; if (!overrideMusic && !isGamePaused && currentChart != null) @@ -1772,6 +1770,8 @@ class PlayState extends MusicBeatSubState // FlxG.sound.music.time = startTimestamp - Conductor.instance.instrumentalOffset; handleSkippedNotes(); } + + dispatchEvent(new ScriptEvent(SONG_START)); } /** From be348d0f13ad36c15d4cfc5fb881b02eceba261a Mon Sep 17 00:00:00 2001 From: Cameron Taylor Date: Fri, 1 Mar 2024 00:15:51 -0500 Subject: [PATCH 009/130] moved vis code --- source/funkin/audio/visualize/ABotVis.hx | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/source/funkin/audio/visualize/ABotVis.hx b/source/funkin/audio/visualize/ABotVis.hx index 2501ca6e6..13c7eb501 100644 --- a/source/funkin/audio/visualize/ABotVis.hx +++ b/source/funkin/audio/visualize/ABotVis.hx @@ -50,7 +50,7 @@ class ABotVis extends FlxTypedSpriteGroup var visStr = 'viz'; viz.animation.addByPrefix('VIZ', visStr + lol, 0); - viz.animation.play('VIZ', false, false, -1); + viz.animation.play('VIZ', false, false, 2); } } @@ -82,6 +82,16 @@ class ABotVis extends FlxTypedSpriteGroup return; } + // drawFFT(); + + super.draw(); + } + + /** + * TJW funkVis based visualizer! updateFFT() is the old nasty shit that dont worky! + */ + function drawFFT():Void + { var levels = analyzer.getLevels(false); for (i in 0...min(group.members.length, levels.length)) @@ -95,8 +105,6 @@ class ABotVis extends FlxTypedSpriteGroup group.members[i].animation.curAnim.curFrame = animFrame; } - - super.draw(); } // function updateFFT(elapsed:Float) From d6608fe435e8239925b69286cc01082b28b30fad Mon Sep 17 00:00:00 2001 From: Cameron Taylor Date: Thu, 7 Mar 2024 14:19:26 -0500 Subject: [PATCH 010/130] a-bot in progress --- hmm.json | 38 ++++++++++++------------ source/funkin/audio/visualize/ABotVis.hx | 16 +++++----- source/funkin/play/PlayState.hx | 2 +- source/funkin/util/logging/AnsiTrace.hx | 7 ++++- 4 files changed, 33 insertions(+), 30 deletions(-) diff --git a/hmm.json b/hmm.json index b25aae806..021d22070 100644 --- a/hmm.json +++ b/hmm.json @@ -4,21 +4,21 @@ "name": "discord_rpc", "type": "git", "dir": null, - "ref": "2d83fa863ef0c1eace5f1cf67c3ac315d1a3a8a5", + "ref": "2d83fa8", "url": "https://github.com/Aidan63/linc_discord-rpc" }, { "name": "flixel", "type": "git", "dir": null, - "ref": "4d054bd10b05bb1309a0ba3427ffa5378e0b4b99", + "ref": "4d054bd1", "url": "https://github.com/FunkinCrew/flixel" }, { "name": "flixel-addons", "type": "git", "dir": null, - "ref": "a523c3b56622f0640933944171efed46929e360e", + "ref": "a523c3b", "url": "https://github.com/FunkinCrew/flixel-addons" }, { @@ -30,14 +30,14 @@ "name": "flixel-ui", "type": "git", "dir": null, - "ref": "719b4f10d94186ed55f6fef1b6618d32abec8c15", + "ref": "719b4f1", "url": "https://github.com/HaxeFlixel/flixel-ui" }, { "name": "flxanimate", "type": "git", "dir": null, - "ref": "9bacdd6ea39f5e3a33b0f5dfb7bc583fe76060d4", + "ref": "9bacdd6", "url": "https://github.com/FunkinCrew/flxanimate" }, { @@ -49,7 +49,7 @@ "name": "funkVis", "type": "git", "dir": null, - "ref": "separateDSP", + "ref": "7ed1f8fa6d8ca580f2359254482578a128be7ab8", "url": "https://github.com/FunkinCrew/funkVis" }, { @@ -61,14 +61,14 @@ "name": "haxeui-core", "type": "git", "dir": null, - "ref": "0212d8fdfcafeb5f0d5a41e1ddba8ff21d0e183b", + "ref": "0212d8fd", "url": "https://github.com/haxeui/haxeui-core" }, { "name": "haxeui-flixel", "type": "git", "dir": null, - "ref": "63a906a6148958dbfde8c7b48d90b0693767fd95", + "ref": "63a906a", "url": "https://github.com/haxeui/haxeui-flixel" }, { @@ -80,7 +80,7 @@ "name": "hxCodec", "type": "git", "dir": null, - "ref": "387e1665d6feb5762358134f168e6ebfe46acec8", + "ref": "387e166", "url": "https://github.com/FunkinCrew/hxCodec" }, { @@ -92,7 +92,7 @@ "name": "hxcpp-debug-server", "type": "git", "dir": "hxcpp-debug-server", - "ref": "147294123f983e35f50a966741474438069a7a8f", + "ref": "1472941", "url": "https://github.com/FunkinCrew/hxcpp-debugger" }, { @@ -104,56 +104,56 @@ "name": "json2object", "type": "git", "dir": null, - "ref": "a8c26f18463c98da32f744c214fe02273e1823fa", + "ref": "a8c26f1", "url": "https://github.com/FunkinCrew/json2object" }, { "name": "lime", "type": "git", "dir": null, - "ref": "1359fe6ad52e91175dc636a516d460bd54ea22ed", + "ref": "1359fe6a", "url": "https://github.com/FunkinCrew/lime" }, { "name": "mconsole", "type": "git", "dir": null, - "ref": "master", + "ref": "06c0499", "url": "https://github.com/massive-oss/mconsole" }, { "name": "mcover", "type": "git", "dir": "src", - "ref": "master", + "ref": "c3c47cd", "url": "https://github.com/massive-oss/mcover" }, { "name": "mockatoo", "type": "git", "dir": "src", - "ref": "master", + "ref": "13d77a0", "url": "https://github.com/FunkinCrew/mockatoo" }, { "name": "munit", "type": "git", "dir": "src", - "ref": "master", + "ref": "f61be7f", "url": "https://github.com/FunkinCrew/MassiveUnit" }, { "name": "openfl", "type": "git", "dir": null, - "ref": "f229d76361c7e31025a048fe7909847f75bb5d5e", + "ref": "f229d763", "url": "https://github.com/FunkinCrew/openfl" }, { "name": "polymod", "type": "git", "dir": null, - "ref": "d5a3b8995f64d20b95f844454e8c3b38c3d3a9fa", + "ref": "d5a3b89", "url": "https://github.com/larsiusprime/polymod" }, { @@ -171,4 +171,4 @@ "url": "https://github.com/FunkinCrew/thx.semver" } ] -} \ No newline at end of file +} diff --git a/source/funkin/audio/visualize/ABotVis.hx b/source/funkin/audio/visualize/ABotVis.hx index 13c7eb501..05131b795 100644 --- a/source/funkin/audio/visualize/ABotVis.hx +++ b/source/funkin/audio/visualize/ABotVis.hx @@ -57,15 +57,21 @@ class ABotVis extends FlxTypedSpriteGroup public function initAnalyzer() { @:privateAccess - analyzer = new SpectralAnalyzer(7, new AudioClip(cast snd._channel.__source), 0.005, 30); + analyzer = new SpectralAnalyzer(7, new AudioClip(cast snd._channel.__source), 0.06, 30); + analyzer.fftN = 2048; } + var visTimer:Float = -1; + var visTimeMax:Float = 1 / 30; + override function update(elapsed:Float) { // updateViz(); // updateFFT(elapsed); + if (analyzer != null) drawFFT(); + super.update(elapsed); } @@ -76,14 +82,6 @@ class ABotVis extends FlxTypedSpriteGroup override function draw() { - if (analyzer == null) - { - super.draw(); - return; - } - - // drawFFT(); - super.draw(); } diff --git a/source/funkin/play/PlayState.hx b/source/funkin/play/PlayState.hx index 341f1d1b6..3c42834a5 100644 --- a/source/funkin/play/PlayState.hx +++ b/source/funkin/play/PlayState.hx @@ -1784,7 +1784,7 @@ class PlayState extends MusicBeatSubState // I am going insane. FlxG.sound.music.volume = 1.0; - FlxG.sound.music.fadeTween.cancel(); + FlxG.sound.music.fadeTween?.cancel(); trace('Playing vocals...'); add(vocals); diff --git a/source/funkin/util/logging/AnsiTrace.hx b/source/funkin/util/logging/AnsiTrace.hx index c8d27b86f..9fdc19e1b 100644 --- a/source/funkin/util/logging/AnsiTrace.hx +++ b/source/funkin/util/logging/AnsiTrace.hx @@ -52,7 +52,12 @@ class AnsiTrace public static function traceBF() { #if sys - if (colorSupported) Sys.println(ansiBF.join("\n")); + if (colorSupported) + { + for (line in ansiBF) + Sys.stdout().writeString(line + "\n"); + Sys.stdout().flush(); + } #end } From 31ba13630269268b6cf5b6f8c6d5b21194ecf6b9 Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Fri, 8 Mar 2024 20:52:30 -0500 Subject: [PATCH 011/130] Update assets submod --- assets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets b/assets index f550436bf..c8c395450 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit f550436bfed37f2e6efb1b97edd66a5c840bd262 +Subproject commit c8c395450b0cd899224bd4fbfd940ed2b376de44 From ea491e57a058660edf3b79deb65de14e5bf07bc0 Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Fri, 15 Mar 2024 17:16:44 -0400 Subject: [PATCH 012/130] Switch "Skip Cutscene" and "Restart Cutscene" (Dave's request) --- source/funkin/play/PauseSubState.hx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/funkin/play/PauseSubState.hx b/source/funkin/play/PauseSubState.hx index 03681ce13..10df25e90 100644 --- a/source/funkin/play/PauseSubState.hx +++ b/source/funkin/play/PauseSubState.hx @@ -72,8 +72,8 @@ class PauseSubState extends MusicBeatSubState */ static final PAUSE_MENU_ENTRIES_VIDEO_CUTSCENE:Array = [ {text: 'Resume', callback: resume}, - {text: 'Restart Cutscene', callback: restartVideoCutscene}, {text: 'Skip Cutscene', callback: skipVideoCutscene}, + {text: 'Restart Cutscene', callback: restartVideoCutscene}, {text: 'Exit to Menu', callback: quitToMenu}, ]; From e4eb543fa7511180319ccb4b90f9d10a20d1dc67 Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Fri, 15 Mar 2024 21:53:07 -0400 Subject: [PATCH 013/130] Fix a bug where title music starts blaringly loud. --- source/funkin/audio/FunkinSound.hx | 17 ++++++++++++----- source/funkin/ui/title/TitleState.hx | 4 ++-- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/source/funkin/audio/FunkinSound.hx b/source/funkin/audio/FunkinSound.hx index 9efa6ed50..a0bf8c58c 100644 --- a/source/funkin/audio/FunkinSound.hx +++ b/source/funkin/audio/FunkinSound.hx @@ -241,10 +241,16 @@ class FunkinSound extends FlxSound implements ICloneable @:allow(flixel.sound.FlxSoundGroup) override function updateTransform():Void { - _transform.volume = #if FLX_SOUND_SYSTEM ((FlxG.sound.muted || this.muted) ? 0 : 1) * FlxG.sound.volume * #end - (group != null ? group.volume : 1) * _volume * _volumeAdjust; + if (_transform != null) + { + _transform.volume = #if FLX_SOUND_SYSTEM ((FlxG.sound.muted || this.muted) ? 0 : 1) * FlxG.sound.volume * #end + (group != null ? group.volume : 1) * _volume * _volumeAdjust; + } - if (_channel != null) _channel.soundTransform = _transform; + if (_channel != null) + { + _channel.soundTransform = _transform; + } } public function clone():FunkinSound @@ -270,11 +276,12 @@ class FunkinSound extends FlxSound implements ICloneable * Creates a new `FunkinSound` object and loads it as the current music track. * * @param key The key of the music you want to play. Music should be at `music//.ogg`. + * @param startingVolume The volume you want the music to start at. * @param overrideExisting Whether to override music if it is already playing. * @param mapTimeChanges Whether to check for `SongMusicData` to update the Conductor with. * Data should be at `music//-metadata.json`. */ - public static function playMusic(key:String, overrideExisting:Bool = false, mapTimeChanges:Bool = true):Void + public static function playMusic(key:String, startingVolume:Float = 1.0, overrideExisting:Bool = false, mapTimeChanges:Bool = true):Void { if (!overrideExisting && FlxG.sound.music?.playing) return; @@ -292,7 +299,7 @@ class FunkinSound extends FlxSound implements ICloneable } } - FlxG.sound.music = FunkinSound.load(Paths.music('$key/$key')); + FlxG.sound.music = FunkinSound.load(Paths.music('$key/$key'), startingVolume); // Prevent repeat update() and onFocus() calls. FlxG.sound.list.remove(FlxG.sound.music); diff --git a/source/funkin/ui/title/TitleState.hx b/source/funkin/ui/title/TitleState.hx index 1c194d80d..26f6612be 100644 --- a/source/funkin/ui/title/TitleState.hx +++ b/source/funkin/ui/title/TitleState.hx @@ -222,9 +222,9 @@ class TitleState extends MusicBeatState { var shouldFadeIn = (FlxG.sound.music == null); // Load music. Includes logic to handle BPM changes. - FunkinSound.playMusic('freakyMenu', false, true); + FunkinSound.playMusic('freakyMenu', 0.0, false, true); // Fade from 0.0 to 0.7 over 4 seconds - if (shouldFadeIn) FlxG.sound.music.fadeIn(4, 0, 0.7); + if (shouldFadeIn) FlxG.sound.music.fadeIn(4.0, 0.0, 1.0); } function getIntroTextShit():Array> From 5733386519a705e3f119e2e48465cbb93db61331 Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Sat, 16 Mar 2024 00:55:05 -0400 Subject: [PATCH 014/130] Update Polymod to improve error handling in scripts. --- hmm.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hmm.json b/hmm.json index 42d17743f..6a8575eb0 100644 --- a/hmm.json +++ b/hmm.json @@ -146,7 +146,7 @@ "name": "polymod", "type": "git", "dir": null, - "ref": "be712450e5d3ba446008884921bb56873b299a64", + "ref": "682548319a272f6e4c9efa97aca081866426d5c7", "url": "https://github.com/larsiusprime/polymod" }, { From d56c33cd172eecbed8c7788437580588c7e6526e Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Sat, 16 Mar 2024 00:55:57 -0400 Subject: [PATCH 015/130] Fix a dozen tiny issues with 2hot's audio and visuals (and some script crashes!). --- assets | 2 +- source/funkin/Paths.hx | 2 +- source/funkin/audio/FunkinSound.hx | 63 ++++++- source/funkin/audio/SoundGroup.hx | 25 ++- .../modding/events/ScriptEventDispatcher.hx | 7 +- source/funkin/play/GameOverSubState.hx | 165 +++++++++++------- source/funkin/play/PlayState.hx | 14 +- source/funkin/play/PlayStatePlaylist.hx | 8 +- source/funkin/play/stage/Stage.hx | 3 +- .../ui/debug/charting/ChartEditorState.hx | 50 +++--- source/funkin/ui/freeplay/FreeplayState.hx | 20 ++- source/funkin/ui/mainmenu/MainMenuState.hx | 7 +- source/funkin/ui/story/StoryMenuState.hx | 7 +- source/funkin/ui/title/TitleState.hx | 9 +- source/funkin/ui/transition/LoadingState.hx | 94 +++++++--- source/funkin/util/Constants.hx | 6 + 16 files changed, 332 insertions(+), 150 deletions(-) diff --git a/assets b/assets index 0e2c5bf21..82ee26e1f 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit 0e2c5bf2134c7e517b70cf74afd58abe5c7b5e50 +Subproject commit 82ee26e1f733d1b2f30015ae69925e6a39d6526b diff --git a/source/funkin/Paths.hx b/source/funkin/Paths.hx index 6006939be..b00d13def 100644 --- a/source/funkin/Paths.hx +++ b/source/funkin/Paths.hx @@ -9,7 +9,7 @@ import openfl.utils.Assets as OpenFlAssets; */ class Paths { - static var currentLevel:String; + static var currentLevel:Null = null; static public function setCurrentLevel(name:String) { diff --git a/source/funkin/audio/FunkinSound.hx b/source/funkin/audio/FunkinSound.hx index a0bf8c58c..3e521ed0d 100644 --- a/source/funkin/audio/FunkinSound.hx +++ b/source/funkin/audio/FunkinSound.hx @@ -276,16 +276,27 @@ class FunkinSound extends FlxSound implements ICloneable * Creates a new `FunkinSound` object and loads it as the current music track. * * @param key The key of the music you want to play. Music should be at `music//.ogg`. - * @param startingVolume The volume you want the music to start at. - * @param overrideExisting Whether to override music if it is already playing. - * @param mapTimeChanges Whether to check for `SongMusicData` to update the Conductor with. + * @param params A set of additional optional parameters. * Data should be at `music//-metadata.json`. */ - public static function playMusic(key:String, startingVolume:Float = 1.0, overrideExisting:Bool = false, mapTimeChanges:Bool = true):Void + public static function playMusic(key:String, params:FunkinSoundPlayMusicParams):Void { - if (!overrideExisting && FlxG.sound.music?.playing) return; + if (!(params.overrideExisting ?? false) && FlxG.sound.music?.playing) return; - if (mapTimeChanges) + if (!(params.restartTrack ?? false) && FlxG.sound.music?.playing) + { + if (FlxG.sound.music != null && Std.isOfType(FlxG.sound.music, FunkinSound)) + { + var existingSound:FunkinSound = cast FlxG.sound.music; + // Stop here if we would play a matching music track. + if (existingSound._label == Paths.music('$key/$key')) + { + return; + } + } + } + + if (params?.mapTimeChanges ?? true) { var songMusicData:Null = SongRegistry.instance.parseMusicData(key); // Will fall back and return null if the metadata doesn't exist or can't be parsed. @@ -299,7 +310,13 @@ class FunkinSound extends FlxSound implements ICloneable } } - FlxG.sound.music = FunkinSound.load(Paths.music('$key/$key'), startingVolume); + if (FlxG.sound.music != null) + { + FlxG.sound.music.stop(); + FlxG.sound.music.kill(); + } + + FlxG.sound.music = FunkinSound.load(Paths.music('$key/$key'), params?.startingVolume ?? 1.0, true, false, true); // Prevent repeat update() and onFocus() calls. FlxG.sound.list.remove(FlxG.sound.music); @@ -333,10 +350,10 @@ class FunkinSound extends FlxSound implements ICloneable sound._label = embeddedSound; } + if (autoPlay) sound.play(); sound.volume = volume; sound.group = FlxG.sound.defaultSoundGroup; sound.persist = true; - if (autoPlay) sound.play(); // Call onLoad() because the sound already loaded if (onLoad != null && sound._sound != null) onLoad(); @@ -356,3 +373,33 @@ class FunkinSound extends FlxSound implements ICloneable return sound; } } + +/** + * Additional parameters for `FunkinSound.playMusic()` + */ +typedef FunkinSoundPlayMusicParams = +{ + /** + * The volume you want the music to start at. + * @default `1.0` + */ + var ?startingVolume:Float; + + /** + * Whether to override music if a different track is already playing. + * @default `false` + */ + var ?overrideExisting:Bool; + + /** + * Whether to override music if the same track is already playing. + * @default `false` + */ + var ?restartTrack:Bool; + + /** + * Whether to check for `SongMusicData` to update the Conductor with. + * @default `true` + */ + var ?mapTimeChanges:Bool; +} diff --git a/source/funkin/audio/SoundGroup.hx b/source/funkin/audio/SoundGroup.hx index a26537c2a..2c14099bd 100644 --- a/source/funkin/audio/SoundGroup.hx +++ b/source/funkin/audio/SoundGroup.hx @@ -151,14 +151,14 @@ class SoundGroup extends FlxTypedGroup /** * Stop all the sounds in the group. */ - public function stop() + public function stop():Void { forEachAlive(function(sound:FunkinSound) { sound.stop(); }); } - public override function destroy() + public override function destroy():Void { stop(); super.destroy(); @@ -176,9 +176,14 @@ class SoundGroup extends FlxTypedGroup function get_time():Float { - if (getFirstAlive() != null) return getFirstAlive().time; + if (getFirstAlive() != null) + { + return getFirstAlive().time; + } else + { return 0; + } } function set_time(time:Float):Float @@ -193,16 +198,26 @@ class SoundGroup extends FlxTypedGroup function get_playing():Bool { - if (getFirstAlive() != null) return getFirstAlive().playing; + if (getFirstAlive() != null) + { + return getFirstAlive().playing; + } else + { return false; + } } function get_volume():Float { - if (getFirstAlive() != null) return getFirstAlive().volume; + if (getFirstAlive() != null) + { + return getFirstAlive().volume; + } else + { return 1; + } } // in PlayState, adjust the code so that it only mutes the player1 vocal tracks? diff --git a/source/funkin/modding/events/ScriptEventDispatcher.hx b/source/funkin/modding/events/ScriptEventDispatcher.hx index fd58d0fad..c262c311d 100644 --- a/source/funkin/modding/events/ScriptEventDispatcher.hx +++ b/source/funkin/modding/events/ScriptEventDispatcher.hx @@ -8,7 +8,12 @@ import funkin.modding.IScriptedClass; */ class ScriptEventDispatcher { - public static function callEvent(target:IScriptedClass, event:ScriptEvent):Void + /** + * Invoke the given event hook on the given scripted class. + * @param target The target class to call script hooks on. + * @param event The event, which determines the script hook to call and provides parameters for it. + */ + public static function callEvent(target:Null, event:ScriptEvent):Void { if (target == null || event == null) return; diff --git a/source/funkin/play/GameOverSubState.hx b/source/funkin/play/GameOverSubState.hx index 95304d762..f84bc8d7f 100644 --- a/source/funkin/play/GameOverSubState.hx +++ b/source/funkin/play/GameOverSubState.hx @@ -2,20 +2,18 @@ package funkin.play; import flixel.FlxG; import flixel.FlxObject; -import flixel.FlxSprite; -import flixel.sound.FlxSound; -import funkin.audio.FunkinSound; +import flixel.input.touch.FlxTouch; import flixel.util.FlxColor; import flixel.util.FlxTimer; +import funkin.audio.FunkinSound; import funkin.graphics.FunkinSprite; import funkin.modding.events.ScriptEvent; import funkin.modding.events.ScriptEventDispatcher; import funkin.play.character.BaseCharacter; -import funkin.play.PlayState; -import funkin.util.MathUtil; import funkin.ui.freeplay.FreeplayState; import funkin.ui.MusicBeatSubState; import funkin.ui.story.StoryMenuState; +import funkin.util.MathUtil; import openfl.utils.Assets; /** @@ -24,13 +22,14 @@ import openfl.utils.Assets; * * The newest implementation uses a substate, which prevents having to reload the song and stage each reset. */ +@:nullSafety class GameOverSubState extends MusicBeatSubState { /** * The currently active GameOverSubState. * There should be only one GameOverSubState in existance at a time, we can use a singleton. */ - public static var instance:GameOverSubState = null; + public static var instance:Null = null; /** * Which alternate animation on the character to use. @@ -38,7 +37,7 @@ class GameOverSubState extends MusicBeatSubState * For example, playing a different animation when BF dies in Week 4 * or Pico dies in Weekend 1. */ - public static var animationSuffix:String = ""; + public static var animationSuffix:String = ''; /** * Which alternate game over music to use. @@ -46,17 +45,19 @@ class GameOverSubState extends MusicBeatSubState * For example, the bf-pixel script sets this to `-pixel` * and the pico-playable script sets this to `Pico`. */ - public static var musicSuffix:String = ""; + public static var musicSuffix:String = ''; /** * Which alternate "blue ball" sound effect to use. */ - public static var blueBallSuffix:String = ""; + public static var blueBallSuffix:String = ''; + + static var blueballed:Bool = false; /** * The boyfriend character. */ - var boyfriend:BaseCharacter; + var boyfriend:Null = null; /** * The invisible object in the scene which the camera focuses on. @@ -83,7 +84,8 @@ class GameOverSubState extends MusicBeatSubState var transparent:Bool; - final CAMERA_ZOOM_DURATION:Float = 0.5; + static final CAMERA_ZOOM_DURATION:Float = 0.5; + var targetCameraZoom:Float = 1.0; public function new(params:GameOverParams) @@ -92,24 +94,27 @@ class GameOverSubState extends MusicBeatSubState this.isChartingMode = params?.isChartingMode ?? false; transparent = params.transparent; + + cameraFollowPoint = new FlxObject(PlayState.instance.cameraFollowPoint.x, PlayState.instance.cameraFollowPoint.y, 1, 1); } /** * Reset the game over configuration to the default. */ - public static function reset() + public static function reset():Void { - animationSuffix = ""; - musicSuffix = ""; - blueBallSuffix = ""; + animationSuffix = ''; + musicSuffix = ''; + blueBallSuffix = ''; + blueballed = false; } - override public function create() + public override function create():Void { if (instance != null) { // TODO: Do something in this case? IDK. - trace('WARNING: GameOverSubState instance already exists. This should not happen.'); + FlxG.log.warn('WARNING: GameOverSubState instance already exists. This should not happen.'); } instance = this; @@ -120,7 +125,7 @@ class GameOverSubState extends MusicBeatSubState // // Add a black background to the screen. - var bg = new FunkinSprite().makeSolidColor(FlxG.width * 2, FlxG.height * 2, FlxColor.BLACK); + var bg:FunkinSprite = new FunkinSprite().makeSolidColor(FlxG.width * 2, FlxG.height * 2, FlxColor.BLACK); // We make this transparent so that we can see the stage underneath during debugging, // but it's normally opaque. bg.alpha = transparent ? 0.25 : 1.0; @@ -135,18 +140,7 @@ class GameOverSubState extends MusicBeatSubState add(boyfriend); boyfriend.resetCharacter(); - // Assign a camera follow point to the boyfriend's position. - cameraFollowPoint = new FlxObject(PlayState.instance.cameraFollowPoint.x, PlayState.instance.cameraFollowPoint.y, 1, 1); - cameraFollowPoint.x = boyfriend.getGraphicMidpoint().x; - cameraFollowPoint.y = boyfriend.getGraphicMidpoint().y; - var offsets:Array = boyfriend.getDeathCameraOffsets(); - cameraFollowPoint.x += offsets[0]; - cameraFollowPoint.y += offsets[1]; - add(cameraFollowPoint); - - FlxG.camera.target = null; - FlxG.camera.follow(cameraFollowPoint, LOCKON, 0.01); - targetCameraZoom = PlayState?.instance?.currentStage?.camZoom * boyfriend.getDeathCameraZoom(); + setCameraTarget(); // // Set up the audio @@ -156,6 +150,26 @@ class GameOverSubState extends MusicBeatSubState Conductor.instance.update(0); } + @:nullSafety(Off) + function setCameraTarget():Void + { + // Assign a camera follow point to the boyfriend's position. + cameraFollowPoint.x = boyfriend.getGraphicMidpoint().x; + cameraFollowPoint.y = boyfriend.getGraphicMidpoint().y; + var offsets:Array = boyfriend.getDeathCameraOffsets(); + cameraFollowPoint.x += offsets[0]; + cameraFollowPoint.y += offsets[1]; + add(cameraFollowPoint); + + FlxG.camera.target = null; + FlxG.camera.follow(cameraFollowPoint, LOCKON, Constants.DEFAULT_CAMERA_FOLLOW_RATE / 2); + targetCameraZoom = (PlayState?.instance?.currentStage?.camZoom ?? 1.0) * boyfriend.getDeathCameraZoom(); + } + + /** + * Forcibly reset the camera zoom level to that of the current stage. + * This prevents camera zoom events from adversely affecting the game over state. + */ public function resetCameraZoom():Void { // Apply camera zoom level from stage data. @@ -164,21 +178,24 @@ class GameOverSubState extends MusicBeatSubState var hasStartedAnimation:Bool = false; - override function update(elapsed:Float) + override function update(elapsed:Float):Void { if (!hasStartedAnimation) { hasStartedAnimation = true; - if (boyfriend.hasAnimation('fakeoutDeath') && FlxG.random.bool((1 / 4096) * 100)) + if (boyfriend != null) { - boyfriend.playAnimation('fakeoutDeath', true, false); - } - else - { - boyfriend.playAnimation('firstDeath', true, false); // ignoreOther is set to FALSE since you WANT to be able to mash and confirm game over! - // Play the "blue balled" sound. May play a variant if one has been assigned. - playBlueBalledSFX(); + if (boyfriend.hasAnimation('fakeoutDeath') && FlxG.random.bool((1 / 4096) * 100)) + { + boyfriend.playAnimation('fakeoutDeath', true, false); + } + else + { + boyfriend.playAnimation('firstDeath', true, false); // ignoreOther is set to FALSE since you WANT to be able to mash and confirm game over! + // Play the "blue balled" sound. May play a variant if one has been assigned. + playBlueBalledSFX(); + } } } @@ -192,10 +209,10 @@ class GameOverSubState extends MusicBeatSubState // MOBILE ONLY: Restart the level when tapping Boyfriend. if (FlxG.onMobile) { - var touch = FlxG.touches.getFirst(); + var touch:FlxTouch = FlxG.touches.getFirst(); if (touch != null) { - if (touch.overlaps(boyfriend)) + if (boyfriend == null || touch.overlaps(boyfriend)) { confirmDeath(); } @@ -215,7 +232,7 @@ class GameOverSubState extends MusicBeatSubState blueballed = false; PlayState.instance.deathCounter = 0; // PlayState.seenCutscene = false; // old thing... - gameOverMusic.stop(); + if (gameOverMusic != null) gameOverMusic.stop(); if (isChartingMode) { @@ -239,14 +256,14 @@ class GameOverSubState extends MusicBeatSubState // This enables the stepHit and beatHit events. Conductor.instance.update(gameOverMusic.time); } - else + else if (boyfriend != null) { // Music hasn't started yet. switch (PlayStatePlaylist.campaignId) { // TODO: Make the behavior for playing Jeff's voicelines generic or un-hardcoded. - // This will simplify the class and make it easier for mods to add death quotes. - case "week7": + // This will simplify the class and make it easier for mods or future weeks to add death quotes. + case 'week7': if (boyfriend.getCurrentAnimation().startsWith('firstDeath') && boyfriend.isAnimationFinished() && !playingJeffQuote) { playingJeffQuote = true; @@ -279,7 +296,7 @@ class GameOverSubState extends MusicBeatSubState isEnding = true; startDeathMusic(1.0, true); // isEnding changes this function's behavior. - boyfriend.playAnimation('deathConfirm' + animationSuffix, true); + if (boyfriend != null) boyfriend.playAnimation('deathConfirm' + animationSuffix, true); // After the animation finishes... new FlxTimer().start(0.7, function(tmr:FlxTimer) { @@ -290,9 +307,12 @@ class GameOverSubState extends MusicBeatSubState PlayState.instance.needsReset = true; // Readd Boyfriend to the stage. - boyfriend.isDead = false; - remove(boyfriend); - PlayState.instance.currentStage.addCharacter(boyfriend, BF); + if (boyfriend != null) + { + boyfriend.isDead = false; + remove(boyfriend); + PlayState.instance.currentStage.addCharacter(boyfriend, BF); + } // Snap reset the camera which may have changed because of the player character data. resetCameraZoom(); @@ -304,7 +324,7 @@ class GameOverSubState extends MusicBeatSubState } } - public override function dispatchEvent(event:ScriptEvent) + public override function dispatchEvent(event:ScriptEvent):Void { super.dispatchEvent(event); @@ -317,11 +337,11 @@ class GameOverSubState extends MusicBeatSubState */ function resolveMusicPath(suffix:String, starting:Bool = false, ending:Bool = false):Null { - var basePath = 'gameplay/gameover/gameOver'; - if (starting) basePath += 'Start'; - else if (ending) basePath += 'End'; + var basePath:String = 'gameplay/gameover/gameOver'; + if (ending) basePath += 'End'; + else if (starting) basePath += 'Start'; - var musicPath = Paths.music(basePath + suffix); + var musicPath:String = Paths.music(basePath + suffix); while (!Assets.exists(musicPath) && suffix.length > 0) { suffix = suffix.split('-').slice(0, -1).join('-'); @@ -334,23 +354,26 @@ class GameOverSubState extends MusicBeatSubState /** * Starts the death music at the appropriate volume. - * @param startingVolume + * @param startingVolume The initial volume for the music. + * @param force Whether or not to force the music to restart. */ public function startDeathMusic(startingVolume:Float = 1, force:Bool = false):Void { - var musicPath = resolveMusicPath(musicSuffix, isStarting, isEnding); - var onComplete = null; + var musicPath:Null = resolveMusicPath(musicSuffix, isStarting, isEnding); + var onComplete:() -> Void = () -> {}; + if (isStarting) { if (musicPath == null) { + // Looked for starting music and didn't find it. Use middle music instead. isStarting = false; musicPath = resolveMusicPath(musicSuffix, isStarting, isEnding); } else { onComplete = function() { - isStarting = false; + isStarting = true; // We need to force to ensure that the non-starting music plays. startDeathMusic(1.0, true); }; @@ -359,13 +382,16 @@ class GameOverSubState extends MusicBeatSubState if (musicPath == null) { - trace('Could not find game over music!'); + FlxG.log.warn('[GAMEOVER] Could not find game over music at path ($musicPath)!'); return; } else if (gameOverMusic == null || !gameOverMusic.playing || force) { if (gameOverMusic != null) gameOverMusic.stop(); + gameOverMusic = FunkinSound.load(musicPath); + if (gameOverMusic == null) return; + gameOverMusic.volume = startingVolume; gameOverMusic.looped = !(isEnding || isStarting); gameOverMusic.onComplete = onComplete; @@ -378,13 +404,11 @@ class GameOverSubState extends MusicBeatSubState } } - static var blueballed:Bool = false; - /** * Play the sound effect that occurs when * boyfriend's testicles get utterly annihilated. */ - public static function playBlueBalledSFX() + public static function playBlueBalledSFX():Void { blueballed = true; if (Assets.exists(Paths.sound('gameplay/gameover/fnf_loss_sfx' + blueBallSuffix))) @@ -403,7 +427,7 @@ class GameOverSubState extends MusicBeatSubState * Week 7-specific hardcoded behavior, to play a custom death quote. * TODO: Make this a module somehow. */ - function playJeffQuote() + function playJeffQuote():Void { var randomCensor:Array = []; @@ -418,20 +442,27 @@ class GameOverSubState extends MusicBeatSubState }); } - public override function destroy() + public override function destroy():Void { super.destroy(); - if (gameOverMusic != null) gameOverMusic.stop(); - gameOverMusic = null; + if (gameOverMusic != null) + { + gameOverMusic.stop(); + gameOverMusic = null; + } + blueballed = false; instance = null; } public override function toString():String { - return "GameOverSubState"; + return 'GameOverSubState'; } } +/** + * Parameters used to instantiate a GameOverSubState. + */ typedef GameOverParams = { var isChartingMode:Bool; diff --git a/source/funkin/play/PlayState.hx b/source/funkin/play/PlayState.hx index 984f27c26..43a7d1615 100644 --- a/source/funkin/play/PlayState.hx +++ b/source/funkin/play/PlayState.hx @@ -1499,7 +1499,7 @@ class PlayState extends MusicBeatSubState public function resetCameraZoom():Void { // Apply camera zoom level from stage data. - defaultCameraZoom = currentStage.camZoom; + defaultCameraZoom = currentStage?.camZoom ?? 1.0; } /** @@ -2712,7 +2712,12 @@ class PlayState extends MusicBeatSubState if (targetSongId == null) { - FunkinSound.playMusic('freakyMenu'); + FunkinSound.playMusic('freakyMenu', + { + startingVolume: 0.0, + overrideExisting: true, + restartTrack: false + }); // transIn = FlxTransitionableState.defaultTransIn; // transOut = FlxTransitionableState.defaultTransOut; @@ -2993,7 +2998,10 @@ class PlayState extends MusicBeatSubState */ public function resetCamera():Void { - FlxG.camera.follow(cameraFollowPoint, LOCKON, 0.04); + // Apply camera zoom level from stage data. + defaultCameraZoom = currentStage?.camZoom ?? 1.0; + + FlxG.camera.follow(cameraFollowPoint, LOCKON, Constants.DEFAULT_CAMERA_FOLLOW_RATE); FlxG.camera.targetOffset.set(); FlxG.camera.zoom = defaultCameraZoom; // Snap the camera to the follow point immediately. diff --git a/source/funkin/play/PlayStatePlaylist.hx b/source/funkin/play/PlayStatePlaylist.hx index 3b0fb01f6..e47a6288a 100644 --- a/source/funkin/play/PlayStatePlaylist.hx +++ b/source/funkin/play/PlayStatePlaylist.hx @@ -5,12 +5,13 @@ package funkin.play; * * TODO: Add getters/setters for all these properties to validate them. */ +@:nullSafety class PlayStatePlaylist { /** * Whether the game is currently in Story Mode. If false, we are in Free Play Mode. */ - public static var isStoryMode(default, default):Bool = false; + public static var isStoryMode:Bool = false; /** * The loist of upcoming songs to be played. @@ -31,8 +32,9 @@ class PlayStatePlaylist /** * The internal ID of the current playlist, for example `week4` or `weekend-1`. + * @default `null`, used when no playlist is loaded */ - public static var campaignId:String = 'unknown'; + public static var campaignId:Null = null; public static var campaignDifficulty:String = Constants.DEFAULT_DIFFICULTY; @@ -45,7 +47,7 @@ class PlayStatePlaylist playlistSongIds = []; campaignScore = 0; campaignTitle = 'UNKNOWN'; - campaignId = 'unknown'; + campaignId = null; campaignDifficulty = Constants.DEFAULT_DIFFICULTY; } } diff --git a/source/funkin/play/stage/Stage.hx b/source/funkin/play/stage/Stage.hx index 56026469a..e80cbe0ae 100644 --- a/source/funkin/play/stage/Stage.hx +++ b/source/funkin/play/stage/Stage.hx @@ -220,7 +220,8 @@ class Stage extends FlxSpriteGroup implements IPlayStateScriptedClass implements if (propSprite.frames == null || propSprite.frames.numFrames == 0) { - trace(' ERROR: Could not build texture for prop.'); + @:privateAccess + trace(' ERROR: Could not build texture for prop. Check the asset path (${Paths.currentLevel ?? 'default'}, ${dataProp.assetPath}).'); continue; } diff --git a/source/funkin/ui/debug/charting/ChartEditorState.hx b/source/funkin/ui/debug/charting/ChartEditorState.hx index c59a5abdb..64ce14d9d 100644 --- a/source/funkin/ui/debug/charting/ChartEditorState.hx +++ b/source/funkin/ui/debug/charting/ChartEditorState.hx @@ -6,18 +6,15 @@ import flixel.addons.transition.FlxTransitionableState; import flixel.FlxCamera; import flixel.FlxSprite; import flixel.FlxSubState; -import flixel.graphics.FlxGraphic; import flixel.group.FlxGroup.FlxTypedGroup; -import funkin.graphics.FunkinCamera; import flixel.group.FlxSpriteGroup; import flixel.input.keyboard.FlxKey; +import funkin.play.PlayStatePlaylist; import flixel.input.mouse.FlxMouseEvent; import flixel.math.FlxMath; import flixel.math.FlxPoint; import flixel.math.FlxRect; import flixel.sound.FlxSound; -import flixel.system.debug.log.LogStyle; -import flixel.system.FlxAssets.FlxSoundAsset; import flixel.text.FlxText; import flixel.tweens.FlxEase; import flixel.tweens.FlxTween; @@ -27,26 +24,19 @@ import flixel.util.FlxSort; import flixel.util.FlxTimer; import funkin.audio.FunkinSound; import funkin.audio.visualize.PolygonSpectogram; -import funkin.audio.visualize.PolygonSpectogram; import funkin.audio.VoicesGroup; import funkin.audio.waveform.WaveformSprite; import funkin.data.notestyle.NoteStyleRegistry; import funkin.data.song.SongData.SongCharacterData; -import funkin.data.song.SongData.SongCharacterData; -import funkin.data.song.SongData.SongChartData; import funkin.data.song.SongData.SongChartData; import funkin.data.song.SongData.SongEventData; -import funkin.data.song.SongData.SongEventData; import funkin.data.song.SongData.SongMetadata; -import funkin.data.song.SongData.SongMetadata; -import funkin.data.song.SongData.SongNoteData; import funkin.data.song.SongData.SongNoteData; import funkin.data.song.SongData.SongOffsets; import funkin.data.song.SongDataUtils; -import funkin.data.song.SongDataUtils; -import funkin.data.song.SongRegistry; import funkin.data.song.SongRegistry; import funkin.data.stage.StageData; +import funkin.graphics.FunkinCamera; import funkin.graphics.FunkinSprite; import funkin.input.Cursor; import funkin.input.TurboKeyHandler; @@ -62,8 +52,6 @@ import funkin.save.Save; import funkin.ui.debug.charting.commands.AddEventsCommand; import funkin.ui.debug.charting.commands.AddNotesCommand; import funkin.ui.debug.charting.commands.ChartEditorCommand; -import funkin.ui.debug.charting.commands.ChartEditorCommand; -import funkin.ui.debug.charting.commands.ChartEditorCommand; import funkin.ui.debug.charting.commands.CopyItemsCommand; import funkin.ui.debug.charting.commands.CutItemsCommand; import funkin.ui.debug.charting.commands.DeselectAllItemsCommand; @@ -96,6 +84,7 @@ import funkin.ui.debug.charting.toolboxes.ChartEditorOffsetsToolbox; import funkin.ui.haxeui.components.CharacterPlayer; import funkin.ui.haxeui.HaxeUIState; import funkin.ui.mainmenu.MainMenuState; +import funkin.ui.transition.LoadingState; import funkin.util.Constants; import funkin.util.FileUtil; import funkin.util.logging.CrashHandler; @@ -120,7 +109,6 @@ import haxe.ui.containers.Grid; import haxe.ui.containers.HBox; import haxe.ui.containers.menus.Menu; import haxe.ui.containers.menus.MenuBar; -import haxe.ui.containers.menus.MenuBar; import haxe.ui.containers.menus.MenuCheckBox; import haxe.ui.containers.menus.MenuItem; import haxe.ui.containers.ScrollView; @@ -131,7 +119,6 @@ import haxe.ui.core.Screen; import haxe.ui.events.DragEvent; import haxe.ui.events.MouseEvent; import haxe.ui.events.UIEvent; -import haxe.ui.events.UIEvent; import haxe.ui.focus.FocusManager; import haxe.ui.Toolkit; import openfl.display.BitmapData; @@ -5330,30 +5317,31 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState } catch (e) { - this.error("Could Not Playtest", 'Got an error trying to playtest the song.\n${e}'); + this.error('Could Not Playtest', 'Got an error trying to playtest the song.\n${e}'); return; } - // TODO: Rework asset system so we can remove this. + // TODO: Rework asset system so we can remove this jank. switch (currentSongStage) { case 'mainStage': - Paths.setCurrentLevel('week1'); + PlayStatePlaylist.campaignId = 'week1'; case 'spookyMansion': - Paths.setCurrentLevel('week2'); + PlayStatePlaylist.campaignId = 'week2'; case 'phillyTrain': - Paths.setCurrentLevel('week3'); + PlayStatePlaylist.campaignId = 'week3'; case 'limoRide': - Paths.setCurrentLevel('week4'); + PlayStatePlaylist.campaignId = 'week4'; case 'mallXmas' | 'mallEvil': - Paths.setCurrentLevel('week5'); + PlayStatePlaylist.campaignId = 'week5'; case 'school' | 'schoolEvil': - Paths.setCurrentLevel('week6'); + PlayStatePlaylist.campaignId = 'week6'; case 'tankmanBattlefield': - Paths.setCurrentLevel('week7'); + PlayStatePlaylist.campaignId = 'week7'; case 'phillyStreets' | 'phillyBlazin' | 'phillyBlazin2': - Paths.setCurrentLevel('weekend1'); + PlayStatePlaylist.campaignId = 'weekend1'; } + Paths.setCurrentLevel(PlayStatePlaylist.campaignId); subStateClosed.add(reviveUICamera); subStateClosed.add(resetConductorAfterTest); @@ -5361,7 +5349,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState FlxTransitionableState.skipNextTransIn = false; FlxTransitionableState.skipNextTransOut = false; - var targetState = new PlayState( + var targetStateParams = { targetSong: targetSong, targetDifficulty: selectedDifficulty, @@ -5372,14 +5360,13 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState startTimestamp: startTimestamp, playbackRate: playbackRate, overrideMusic: true, - }); + }; // Override music. if (audioInstTrack != null) { FlxG.sound.music = audioInstTrack; } - targetState.vocals = audioVocalTrackGroup; // Kill and replace the UI camera so it doesn't get destroyed during the state transition. uiCamera.kill(); @@ -5389,7 +5376,10 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState this.persistentUpdate = false; this.persistentDraw = false; stopWelcomeMusic(); - openSubState(targetState); + + LoadingState.loadPlayState(targetStateParams, false, true, function(targetState) { + targetState.vocals = audioVocalTrackGroup; + }); } /** diff --git a/source/funkin/ui/freeplay/FreeplayState.hx b/source/funkin/ui/freeplay/FreeplayState.hx index 7ade5a2a6..068b57a9c 100644 --- a/source/funkin/ui/freeplay/FreeplayState.hx +++ b/source/funkin/ui/freeplay/FreeplayState.hx @@ -179,7 +179,7 @@ class FreeplayState extends MusicBeatSubState #if discord_rpc // Updating Discord Rich Presence - DiscordClient.changePresence("In the Menus", null); + DiscordClient.changePresence('In the Menus', null); #end var isDebug:Bool = false; @@ -188,14 +188,19 @@ class FreeplayState extends MusicBeatSubState isDebug = true; #end - FunkinSound.playMusic('freakyMenu'); + FunkinSound.playMusic('freakyMenu', + { + startingVolume: 0.0, + overrideExisting: true, + restartTrack: false + }); // Add a null entry that represents the RANDOM option songs.push(null); // TODO: This makes custom variations disappear from Freeplay. Figure out a better solution later. // Default character (BF) shows default and Erect variations. Pico shows only Pico variations. - displayedVariations = (currentCharacter == "bf") ? [Constants.DEFAULT_VARIATION, "erect"] : [currentCharacter]; + displayedVariations = (currentCharacter == 'bf') ? [Constants.DEFAULT_VARIATION, 'erect'] : [currentCharacter]; // programmatically adds the songs via LevelRegistry and SongRegistry for (levelId in LevelRegistry.instance.listBaseGameLevelIds()) @@ -205,7 +210,7 @@ class FreeplayState extends MusicBeatSubState var song:Song = SongRegistry.instance.fetchEntry(songId); // Only display songs which actually have available charts for the current character. - var availableDifficultiesForSong = song.listDifficulties(displayedVariations); + var availableDifficultiesForSong:Array = song.listDifficulties(displayedVariations); if (availableDifficultiesForSong.length == 0) continue; songs.push(new FreeplaySongData(levelId, songId, song, displayedVariations)); @@ -1226,7 +1231,12 @@ class FreeplayState extends MusicBeatSubState // TODO: Stream the instrumental of the selected song? if (prevSelected == 0) { - FunkinSound.playMusic('freakyMenu'); + FunkinSound.playMusic('freakyMenu', + { + startingVolume: 0.0, + overrideExisting: true, + restartTrack: false + }); FlxG.sound.music.fadeIn(2, 0, 0.8); } } diff --git a/source/funkin/ui/mainmenu/MainMenuState.hx b/source/funkin/ui/mainmenu/MainMenuState.hx index 1892bdec1..38654dcb8 100644 --- a/source/funkin/ui/mainmenu/MainMenuState.hx +++ b/source/funkin/ui/mainmenu/MainMenuState.hx @@ -155,7 +155,12 @@ class MainMenuState extends MusicBeatState function playMenuMusic():Void { - FunkinSound.playMusic('freakyMenu'); + FunkinSound.playMusic('freakyMenu', + { + startingVolume: 0.0, + overrideExisting: true, + restartTrack: false + }); } function resetCamStuff() diff --git a/source/funkin/ui/story/StoryMenuState.hx b/source/funkin/ui/story/StoryMenuState.hx index 1f78eb375..82b419373 100644 --- a/source/funkin/ui/story/StoryMenuState.hx +++ b/source/funkin/ui/story/StoryMenuState.hx @@ -235,7 +235,12 @@ class StoryMenuState extends MusicBeatState function playMenuMusic():Void { - FunkinSound.playMusic('freakyMenu'); + FunkinSound.playMusic('freakyMenu', + { + startingVolume: 0.0, + overrideExisting: true, + restartTrack: false + }); } function updateData():Void diff --git a/source/funkin/ui/title/TitleState.hx b/source/funkin/ui/title/TitleState.hx index 26f6612be..eb4404c78 100644 --- a/source/funkin/ui/title/TitleState.hx +++ b/source/funkin/ui/title/TitleState.hx @@ -220,9 +220,14 @@ class TitleState extends MusicBeatState function playMenuMusic():Void { - var shouldFadeIn = (FlxG.sound.music == null); + var shouldFadeIn:Bool = (FlxG.sound.music == null); // Load music. Includes logic to handle BPM changes. - FunkinSound.playMusic('freakyMenu', 0.0, false, true); + FunkinSound.playMusic('freakyMenu', + { + startingVolume: 0.0, + overrideExisting: true, + restartTrack: true + }); // Fade from 0.0 to 0.7 over 4 seconds if (shouldFadeIn) FlxG.sound.music.fadeIn(4.0, 0.0, 1.0); } diff --git a/source/funkin/ui/transition/LoadingState.hx b/source/funkin/ui/transition/LoadingState.hx index 23b3db6a9..304922988 100644 --- a/source/funkin/ui/transition/LoadingState.hx +++ b/source/funkin/ui/transition/LoadingState.hx @@ -22,10 +22,12 @@ import openfl.filters.ShaderFilter; import openfl.utils.Assets; import flixel.util.typeLimit.NextState; -class LoadingState extends MusicBeatState +class LoadingState extends MusicBeatSubState { inline static var MIN_TIME = 1.0; + var asSubState:Bool = false; + var target:NextState; var playParams:Null; var stopMusic:Bool = false; @@ -173,7 +175,16 @@ class LoadingState extends MusicBeatState { if (stopMusic && FlxG.sound.music != null) FlxG.sound.music.stop(); - FlxG.switchState(target); + if (asSubState) + { + this.close(); + // We will assume the target is a valid substate. + FlxG.state.openSubState(cast target); + } + else + { + FlxG.switchState(target); + } } static function getSongPath():String @@ -185,17 +196,41 @@ class LoadingState extends MusicBeatState * Starts the transition to a new `PlayState` to start a new song. * First switches to the `LoadingState` if assets need to be loaded. * @param params The parameters for the next `PlayState`. + * @param asSubState Whether to open as a substate rather than switching to the `PlayState`. * @param shouldStopMusic Whether to stop the current music while loading. */ - public static function loadPlayState(params:PlayStateParams, shouldStopMusic = false):Void + public static function loadPlayState(params:PlayStateParams, shouldStopMusic = false, asSubState = false, ?onConstruct:PlayState->Void):Void { Paths.setCurrentLevel(PlayStatePlaylist.campaignId); - var playStateCtor:NextState = () -> new PlayState(params); + var playStateCtor:() -> PlayState = function() { + return new PlayState(params); + }; + + if (onConstruct != null) + { + playStateCtor = function() { + var result = new PlayState(params); + onConstruct(result); + return result; + }; + } #if NO_PRELOAD_ALL // Switch to loading state while we load assets (default on HTML5 target). - var loadStateCtor:NextState = () -> new LoadingState(playStateCtor, shouldStopMusic, params); - FlxG.switchState(loadStateCtor); + var loadStateCtor:NextState = function() { + var result = new LoadingState(playStateCtor, shouldStopMusic, params); + @:privateAccess + result.asSubState = asSubState; + return result; + } + if (asSubState) + { + FlxG.state.openSubState(loadStateCtor); + } + else + { + FlxG.switchState(loadStateCtor); + } #else // All assets preloaded, switch directly to play state (defualt on other targets). if (shouldStopMusic && FlxG.sound.music != null) @@ -209,6 +244,34 @@ class LoadingState extends MusicBeatState params.targetSong.cacheCharts(true); } + var shouldPreloadLevelAssets:Bool = !(params?.minimalMode ?? false); + + if (shouldPreloadLevelAssets) preloadLevelAssets(); + + if (asSubState) + { + FlxG.state.openSubState(cast playStateCtor()); + } + else + { + FlxG.switchState(playStateCtor); + } + #end + } + + #if NO_PRELOAD_ALL + static function isSoundLoaded(path:String):Bool + { + return Assets.cache.hasSound(path); + } + + static function isLibraryLoaded(library:String):Bool + { + return Assets.getLibrary(library) != null; + } + #else + static function preloadLevelAssets():Void + { // TODO: This section is a hack! Redo this later when we have a proper asset caching system. FunkinSprite.preparePurgeCache(); FunkinSprite.cacheTexture(Paths.image('combo')); @@ -241,7 +304,10 @@ class LoadingState extends MusicBeatState // List all image assets in the level's library. // This is crude and I want to remove it when we have a proper asset caching system. // TODO: Get rid of this junk! - var library = openfl.utils.Assets.getLibrary(PlayStatePlaylist.campaignId); + var library = PlayStatePlaylist.campaignId != null ? openfl.utils.Assets.getLibrary(PlayStatePlaylist.campaignId) : null; + + if (library == null) return; // We don't need to do anymore precaching. + var assets = library.list(lime.utils.AssetType.IMAGE); trace('Got ${assets.length} assets: ${assets}'); @@ -272,20 +338,6 @@ class LoadingState extends MusicBeatState // FunkinSprite.cacheAllSongTextures(stage) FunkinSprite.purgeCache(); - - FlxG.switchState(playStateCtor); - #end - } - - #if NO_PRELOAD_ALL - static function isSoundLoaded(path:String):Bool - { - return Assets.cache.hasSound(path); - } - - static function isLibraryLoaded(library:String):Bool - { - return Assets.getLibrary(library) != null; } #end diff --git a/source/funkin/util/Constants.hx b/source/funkin/util/Constants.hx index 1005b312e..8d7800c00 100644 --- a/source/funkin/util/Constants.hx +++ b/source/funkin/util/Constants.hx @@ -442,4 +442,10 @@ class Constants * The vertical offset of the strumline from the top edge of the screen. */ public static final STRUMLINE_Y_OFFSET:Float = 24; + + /** + * The rate at which the camera lerps to its target. + * 0.04 = 4% of distance per frame. + */ + public static final DEFAULT_CAMERA_FOLLOW_RATE:Float = 0.04; } From efd0bef89f25467d2d762afada9071435f971617 Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Sat, 16 Mar 2024 01:08:20 -0400 Subject: [PATCH 016/130] Remove checkbox that should have been removed earlier. --- assets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets b/assets index 82ee26e1f..fbfaad0c4 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit 82ee26e1f733d1b2f30015ae69925e6a39d6526b +Subproject commit fbfaad0c4e35fbf48937fb7e28e3888587cf16b1 From 4eea9b76e7393601b857168631bdb1eb5960a0ae Mon Sep 17 00:00:00 2001 From: Cameron Taylor Date: Tue, 19 Mar 2024 13:04:58 -0700 Subject: [PATCH 017/130] idk assets revert this if I busted shit here lol --- hmm.json | 2 +- source/funkin/audio/visualize/ABotVis.hx | 10 ++++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/hmm.json b/hmm.json index 3e5c07c29..04c09e50f 100644 --- a/hmm.json +++ b/hmm.json @@ -49,7 +49,7 @@ "name": "funkVis", "type": "git", "dir": null, - "ref": "7ed1f8fa6d8ca580f2359254482578a128be7ab8", + "ref": "0ac2fffa67fd30563df97c66718551efa92d283e", "url": "https://github.com/FunkinCrew/funkVis" }, { diff --git a/source/funkin/audio/visualize/ABotVis.hx b/source/funkin/audio/visualize/ABotVis.hx index 05131b795..a8b6fb937 100644 --- a/source/funkin/audio/visualize/ABotVis.hx +++ b/source/funkin/audio/visualize/ABotVis.hx @@ -57,8 +57,9 @@ class ABotVis extends FlxTypedSpriteGroup public function initAnalyzer() { @:privateAccess - analyzer = new SpectralAnalyzer(7, new AudioClip(cast snd._channel.__source), 0.06, 30); - analyzer.fftN = 2048; + analyzer = new SpectralAnalyzer(7, new AudioClip(cast snd._channel.__source), 0.01, 30); + analyzer.maxDb = -35; + // analyzer.fftN = 2048; } var visTimer:Float = -1; @@ -70,8 +71,7 @@ class ABotVis extends FlxTypedSpriteGroup // updateFFT(elapsed); - if (analyzer != null) drawFFT(); - + // super.update(elapsed); } @@ -82,6 +82,8 @@ class ABotVis extends FlxTypedSpriteGroup override function draw() { + if (analyzer != null) drawFFT(); + super.draw(); } From 1e888658f75eb859f51b698ddde8a5d3af188e8b Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Tue, 26 Mar 2024 12:33:54 -0400 Subject: [PATCH 018/130] First implementation of credits state. --- Project.xml | 1 + assets | 2 +- source/funkin/data/BaseRegistry.hx | 9 - source/funkin/data/JsonFile.hx | 10 + source/funkin/data/song/SongRegistry.hx | 6 +- source/funkin/ui/credits/CreditsData.hx | 26 +++ .../funkin/ui/credits/CreditsDataHandler.hx | 130 ++++++++++++ source/funkin/ui/credits/CreditsDataMacro.hx | 67 ++++++ source/funkin/ui/credits/CreditsState.hx | 200 ++++++++++++++++++ source/funkin/ui/mainmenu/MainMenuState.hx | 7 + 10 files changed, 445 insertions(+), 13 deletions(-) create mode 100644 source/funkin/data/JsonFile.hx create mode 100644 source/funkin/ui/credits/CreditsData.hx create mode 100644 source/funkin/ui/credits/CreditsDataHandler.hx create mode 100644 source/funkin/ui/credits/CreditsDataMacro.hx create mode 100644 source/funkin/ui/credits/CreditsState.hx diff --git a/Project.xml b/Project.xml index ffc8382a4..5962b9dd8 100644 --- a/Project.xml +++ b/Project.xml @@ -175,6 +175,7 @@ +
diff --git a/assets b/assets index 5f1726f1b..edccf0421 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit 5f1726f1b0c11fc747b7473708cf4e5f28be05f1 +Subproject commit edccf04217c49c730b11c80736e2b2d98a25ee95 diff --git a/source/funkin/data/BaseRegistry.hx b/source/funkin/data/BaseRegistry.hx index 7419d9425..118516bec 100644 --- a/source/funkin/data/BaseRegistry.hx +++ b/source/funkin/data/BaseRegistry.hx @@ -325,12 +325,3 @@ abstract class BaseRegistry & Constructible return ScriptedSong.listScriptClasses(); } - function loadEntryMetadataFile(id:String, ?variation:String):Null + function loadEntryMetadataFile(id:String, ?variation:String):Null { variation = variation == null ? Constants.DEFAULT_VARIATION : variation; var entryFilePath:String = Paths.json('$dataFilePath/$id/$id-metadata${variation == Constants.DEFAULT_VARIATION ? '' : '-$variation'}'); @@ -438,7 +438,7 @@ class SongRegistry extends BaseRegistry return {fileName: entryFilePath, contents: rawJson}; } - function loadMusicDataFile(id:String, ?variation:String):Null + function loadMusicDataFile(id:String, ?variation:String):Null { variation = variation == null ? Constants.DEFAULT_VARIATION : variation; var entryFilePath:String = Paths.file('music/$id/$id-metadata${variation == Constants.DEFAULT_VARIATION ? '' : '-$variation'}.json'); @@ -456,7 +456,7 @@ class SongRegistry extends BaseRegistry return openfl.Assets.exists(entryFilePath); } - function loadEntryChartFile(id:String, ?variation:String):Null + function loadEntryChartFile(id:String, ?variation:String):Null { variation = variation == null ? Constants.DEFAULT_VARIATION : variation; var entryFilePath:String = Paths.json('$dataFilePath/$id/$id-chart${variation == Constants.DEFAULT_VARIATION ? '' : '-$variation'}'); diff --git a/source/funkin/ui/credits/CreditsData.hx b/source/funkin/ui/credits/CreditsData.hx new file mode 100644 index 000000000..0f6ea6bcd --- /dev/null +++ b/source/funkin/ui/credits/CreditsData.hx @@ -0,0 +1,26 @@ +package funkin.ui.credits; + +/** + * The members of the Funkin' Crew, organized by their roles. + */ +typedef CreditsData = +{ + var roles:Array; +} + +/** + * The members of a specific role on the Funkin' Crew. + */ +typedef CreditsDataRole = +{ + var roleName:String; + var members:Array; +} + +/** + * A member of a specific person on the Funkin' Crew. + */ +typedef CreditsDataMember = +{ + var fullName:String; +} diff --git a/source/funkin/ui/credits/CreditsDataHandler.hx b/source/funkin/ui/credits/CreditsDataHandler.hx new file mode 100644 index 000000000..6317dd55d --- /dev/null +++ b/source/funkin/ui/credits/CreditsDataHandler.hx @@ -0,0 +1,130 @@ +package funkin.ui.credits; + +import funkin.data.JsonFile; + +using StringTools; + +@:nullSafety +class CreditsDataHandler +{ + public static final BACKER_PUBLIC_URL:String = 'https://funkin.me/backers'; + + #if HARDCODED_CREDITS + static final CREDITS_DATA_PATH:String = "assets/exclude/data/credits.json"; + #else + static final CREDITS_DATA_PATH:String = "assets/data/credits.json"; + #end + + public static function debugPrint(data:Null):Void + { + if (data == null) + { + trace('CreditsData(NULL)'); + + return; + } + + var roleCount = data.roles.length; + var memberCount = 0; + for (role in data.roles) + { + memberCount += role.members.length; + } + + trace('CreditsData($roleCount roles with $memberCount members)'); + } + + /** + * If for some reason the full credits won't load, + * use this hardcoded data for the original Funkin' Crew. + * + * @return `CreditsData` + */ + public static inline function getFallback():CreditsData + { + return { + roles: [ + { + roleName: 'Founders', + members: [ + {fullName: 'ninjamuffin99'}, + {fullName: 'PhantomArcade'}, + {fullName: 'KawaiSprite'}, + {fullName: 'evilsk8r'}, + ] + } + ] + }; + } + + public static function fetchBackerEntries():Array + { + // TODO: Replace this with a web request. + // We can't just grab the current Kickstarter data and include it in builds, + // because we don't want to deadname people who haven't logged into the portal yet. + // It can be async and paginated for performance! + return ['See the list of backers at $BACKER_PUBLIC_URL.']; + } + + #if HARDCODED_CREDITS + /** + * The data for the credits. + * Hardcoded into game via a macro at compile time. + */ + public static final CREDITS_DATA:Null = #if macro null #else CreditsDataMacro.loadCreditsData() #end; + #else + + /** + * The data for the credits. + * Loaded dynamically from the game folder when needed. + * Nullable because data may fail to parse. + */ + public static var CREDITS_DATA(get, default):Null = null; + + static function get_CREDITS_DATA():Null + { + if (CREDITS_DATA == null) CREDITS_DATA = parseCreditsData(fetchCreditsData()); + + return CREDITS_DATA; + } + + static function fetchCreditsData():funkin.data.JsonFile + { + var rawJson:String = openfl.Assets.getText(CREDITS_DATA_PATH).trim(); + + return { + fileName: CREDITS_DATA_PATH, + contents: rawJson + }; + } + + static function parseCreditsData(file:JsonFile):Null + { + #if !macro + if (file.contents == null) return null; + + var parser = new json2object.JsonParser(); + parser.ignoreUnknownVariables = false; + trace('[CREDITS] Parsing credits data from ${CREDITS_DATA_PATH}'); + parser.fromJson(file.contents, file.fileName); + + if (parser.errors.length > 0) + { + printErrors(parser.errors, file.fileName); + return null; + } + return parser.value; + #else + return null; + #end + } + + static function printErrors(errors:Array, id:String = ''):Void + { + trace('[CREDITS] Failed to parse credits data: ${id}'); + + for (error in errors) + funkin.data.DataError.printError(error); + } + #end +} diff --git a/source/funkin/ui/credits/CreditsDataMacro.hx b/source/funkin/ui/credits/CreditsDataMacro.hx new file mode 100644 index 000000000..c97770eef --- /dev/null +++ b/source/funkin/ui/credits/CreditsDataMacro.hx @@ -0,0 +1,67 @@ +package funkin.ui.credits; + +#if macro +import haxe.macro.Context; +#end + +@:access(funkin.ui.credits.CreditsDataHandler) +class CreditsDataMacro +{ + public static macro function loadCreditsData():haxe.macro.Expr.ExprOf + { + #if !display + trace('Hardcoding credits data...'); + var json = CreditsDataMacro.fetchJSON(); + + if (json == null) + { + Context.info('[WARN] Could not fetch JSON data for credits.', Context.currentPos()); + return macro $v{CreditsDataHandler.getFallback()}; + } + + var creditsData = CreditsDataMacro.parseJSON(json); + + if (creditsData == null) + { + Context.info('[WARN] Could not parse JSON data for credits.', Context.currentPos()); + return macro $v{CreditsDataHandler.getFallback()}; + } + + CreditsDataHandler.debugPrint(creditsData); + return macro $v{creditsData}; + // return macro $v{null}; + #else + // `#if display` is used for code completion. In this case we return + // a minimal value to keep code completion fast. + return macro $v{CreditsDataHandler.getFallback()}; + #end + } + + #if macro + static function fetchJSON():Null + { + return sys.io.File.getContent(CreditsDataHandler.CREDITS_DATA_PATH); + } + + /** + * Parse the JSON data for the credits. + * + * @param json The string data to parse. + * @return The parsed data. + */ + static function parseJSON(json:String):Null + { + try + { + // TODO: Use something with better validation but that still works at macro time. + return haxe.Json.parse(json); + } + catch (e) + { + trace('[ERROR] Failed to parse JSON data for credits.'); + trace(e); + return null; + } + } + #end +} diff --git a/source/funkin/ui/credits/CreditsState.hx b/source/funkin/ui/credits/CreditsState.hx new file mode 100644 index 000000000..1e5965695 --- /dev/null +++ b/source/funkin/ui/credits/CreditsState.hx @@ -0,0 +1,200 @@ +package funkin.ui.credits; + +import flixel.text.FlxText; +import flixel.util.FlxColor; +import funkin.audio.FunkinSound; +import flixel.FlxSprite; +import flixel.group.FlxSpriteGroup; + +/** + * The state used to display the credits scroll. + * AAA studios often fail to credit properly, and we're better than them! + */ +class CreditsState extends MusicBeatState +{ + /** + * The height the credits should start at. + * Make this an instanced variable so it gets set by the constructor. + */ + final STARTING_HEIGHT = FlxG.height; + + /** + * The padding on each side of the screen. + */ + static final SCREEN_PAD = 24; + + /** + * The width of the screen the credits should maximally fill up. + * Make this an instanced variable so it gets set by the constructor. + */ + final FULL_WIDTH = FlxG.width - (SCREEN_PAD * 2); + + /** + * The font to use to display the text. + * To use a font from the `assets` folder, use `Paths.font(...)`. + * Choose something that will render Unicode properly. + */ + static final CREDITS_FONT = 'Arial'; + + /** + * The size of the font. + */ + static final CREDITS_FONT_SIZE = 48; + + static final CREDITS_HEADER_FONT_SIZE = 72; + + /** + * The color of the text itself. + */ + static final CREDITS_FONT_COLOR = FlxColor.WHITE; + + /** + * The color of the text's outline. + */ + static final CREDITS_FONT_STROKE_COLOR = FlxColor.BLACK; + + /** + * The speed the credits scroll at, in pixels per second. + */ + static final CREDITS_SCROLL_BASE_SPEED = 25.0; + + /** + * The speed the credits scroll at while the button is held, in pixels per second. + */ + static final CREDITS_SCROLL_FAST_SPEED = CREDITS_SCROLL_BASE_SPEED * 4.0; + + /** + * The actual sprites and text used to display the credits. + */ + var creditsGroup:FlxSpriteGroup; + + var scrollPaused:Bool = false; + + public function new() + { + super(); + } + + public override function create():Void + { + super.create(); + + // Background + var bg = new FlxSprite(Paths.image('menuDesat')); + bg.scrollFactor.x = 0; + bg.scrollFactor.y = 0; + bg.setGraphicSize(Std.int(FlxG.width)); + bg.updateHitbox(); + bg.x = 0; + bg.y = 0; + bg.visible = true; + bg.color = 0xFFB57EDC; // Lavender + add(bg); + + // TODO: Once we need to display Kickstarter backers, + // make this use a recycled pool so we don't kill peformance. + creditsGroup = new FlxSpriteGroup(); + creditsGroup.x = SCREEN_PAD; + creditsGroup.y = STARTING_HEIGHT; + + buildCreditsGroup(); + + add(creditsGroup); + + // Music + FunkinSound.playMusic('freeplayRandom', + { + startingVolume: 0.0, + overrideExisting: true, + restartTrack: true, + loop: true + }); + FlxG.sound.music.fadeIn(2, 0, 0.8); + } + + function buildCreditsGroup():Void + { + var y = 0; + + for (role in CreditsDataHandler.CREDITS_DATA.roles) + { + creditsGroup.add(buildCreditsLine(role.roleName, y, true, CreditsSide.Center)); + y += CREDITS_HEADER_FONT_SIZE; + + for (member in role.members) + { + creditsGroup.add(buildCreditsLine(member.fullName, y, false, CreditsSide.Center)); + y += CREDITS_FONT_SIZE; + } + + // Padding between each role. + y += CREDITS_FONT_SIZE * 2; + } + } + + function buildCreditsLine(text:String, yPos:Float, header:Bool, side:CreditsSide = CreditsSide.Center):FlxText + { + // CreditsSide.Center: Full screen width + // CreditsSide.Left: Left half of screen + // CreditsSide.Right: Right half of screen + var xPos = (side == CreditsSide.Right) ? (FULL_WIDTH / 2) : 0; + var width = (side == CreditsSide.Center) ? FULL_WIDTH : (FULL_WIDTH / 2); + var size = header ? CREDITS_HEADER_FONT_SIZE : CREDITS_FONT_SIZE; + + var creditsLine:FlxText = new FlxText(xPos, yPos, width, text); + creditsLine.setFormat(CREDITS_FONT, size, CREDITS_FONT_COLOR, FlxTextAlign.CENTER, FlxTextBorderStyle.OUTLINE, CREDITS_FONT_STROKE_COLOR, true); + + return creditsLine; + } + + public override function update(elapsed:Float):Void + { + super.update(elapsed); + + if (!scrollPaused) + { + // TODO: Replace with whatever the special note button is. + if (controls.ACCEPT || FlxG.keys.pressed.SPACE) + { + // Move the whole group. + creditsGroup.y -= CREDITS_SCROLL_FAST_SPEED * elapsed; + } + else + { + // Move the whole group. + creditsGroup.y -= CREDITS_SCROLL_BASE_SPEED * elapsed; + } + } + + if (controls.BACK || hasEnded()) + { + exit(); + } + else if (controls.PAUSE) + { + scrollPaused = !scrollPaused; + } + } + + function hasEnded():Bool + { + return creditsGroup.y < -creditsGroup.height; + } + + function exit():Void + { + FlxG.switchState(new funkin.ui.mainmenu.MainMenuState()); + } + + public override function destroy():Void + { + super.destroy(); + } +} + +enum CreditsSide +{ + Left; + Center; + Right; +} diff --git a/source/funkin/ui/mainmenu/MainMenuState.hx b/source/funkin/ui/mainmenu/MainMenuState.hx index a8c2039ab..e536554d0 100644 --- a/source/funkin/ui/mainmenu/MainMenuState.hx +++ b/source/funkin/ui/mainmenu/MainMenuState.hx @@ -117,6 +117,10 @@ class MainMenuState extends MusicBeatState startExitState(() -> new funkin.ui.options.OptionsState()); }); + createMenuItem('options', 'mainmenu/options', function() { + startExitState(() -> new funkin.ui.credits.CreditsState()); + }); + // Reset position of menu items. var spacing = 160; var top = (FlxG.height - (spacing * (menuItems.length - 1))) / 2; @@ -125,6 +129,9 @@ class MainMenuState extends MusicBeatState var menuItem = menuItems.members[i]; menuItem.x = FlxG.width / 2; menuItem.y = top + spacing * i; + menuItem.scrollFactor.x = 0.0; + // This one affects how much the menu items move when you scroll between them. + menuItem.scrollFactor.y = 0.4; } resetCamStuff(); From 77b65ba68c2279b2868cd91cd80fb78342fe33aa Mon Sep 17 00:00:00 2001 From: Cameron Taylor Date: Wed, 27 Mar 2024 21:32:13 -0400 Subject: [PATCH 019/130] shader var renames for hashlink --- Project.xml | 2 +- assets | 2 +- source/funkin/graphics/shaders/GaussianBlurShader.hx | 2 +- source/funkin/graphics/shaders/Grayscale.hx | 2 +- source/funkin/graphics/shaders/HSVShader.hx | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Project.xml b/Project.xml index ffc8382a4..ab709db17 100644 --- a/Project.xml +++ b/Project.xml @@ -111,7 +111,7 @@ - + diff --git a/assets b/assets index 8013845e3..47a2869c7 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit 8013845e331015b40c4cc35230f6d02bd2148d52 +Subproject commit 47a2869c7fdcd342b15ceaa676710a7239615c01 diff --git a/source/funkin/graphics/shaders/GaussianBlurShader.hx b/source/funkin/graphics/shaders/GaussianBlurShader.hx index 81167655b..cecfdab80 100644 --- a/source/funkin/graphics/shaders/GaussianBlurShader.hx +++ b/source/funkin/graphics/shaders/GaussianBlurShader.hx @@ -20,6 +20,6 @@ class GaussianBlurShader extends FlxRuntimeShader public function setAmount(value:Float):Void { this.amount = value; - this.setFloat("amount", amount); + this.setFloat("_amount", amount); } } diff --git a/source/funkin/graphics/shaders/Grayscale.hx b/source/funkin/graphics/shaders/Grayscale.hx index 6673ace24..fbd0970e5 100644 --- a/source/funkin/graphics/shaders/Grayscale.hx +++ b/source/funkin/graphics/shaders/Grayscale.hx @@ -17,6 +17,6 @@ class Grayscale extends FlxRuntimeShader public function setAmount(value:Float):Void { amount = value; - this.setFloat("amount", amount); + this.setFloat("_amount", amount); } } diff --git a/source/funkin/graphics/shaders/HSVShader.hx b/source/funkin/graphics/shaders/HSVShader.hx index 733bbca7f..2dfdac2c9 100644 --- a/source/funkin/graphics/shaders/HSVShader.hx +++ b/source/funkin/graphics/shaders/HSVShader.hx @@ -20,7 +20,7 @@ class HSVShader extends FlxRuntimeShader function set_hue(value:Float):Float { - this.setFloat('hue', value); + this.setFloat('_hue', value); this.hue = value; return this.hue; From b771b46f1cb0fca132355daa09a685022028ac76 Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Thu, 28 Mar 2024 00:01:18 -0400 Subject: [PATCH 020/130] Fix a build issue. --- source/funkin/audio/FunkinSound.hx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/source/funkin/audio/FunkinSound.hx b/source/funkin/audio/FunkinSound.hx index 92f910335..51533f371 100644 --- a/source/funkin/audio/FunkinSound.hx +++ b/source/funkin/audio/FunkinSound.hx @@ -337,7 +337,11 @@ class FunkinSound extends FlxSound implements ICloneable FlxG.sound.music.kill(); } - FlxG.sound.music = FunkinSound.load(Paths.music('$key/$key'), params?.startingVolume ?? 1.0, true, false, true); + // Apparently HaxeFlixel isn't null safe. + @:nullSafety(Off) + { + FlxG.sound.music = FunkinSound.load(Paths.music('$key/$key'), params?.startingVolume ?? 1.0, true, false, true); + } var music = FunkinSound.load(Paths.music('$key/$key'), params?.startingVolume ?? 1.0, params.loop ?? true, false, true); if (music != null) From 893822532e8897926cf7283043e4131a0066995f Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Thu, 28 Mar 2024 00:01:42 -0400 Subject: [PATCH 021/130] Fix an issue causing the Kickstarter video to not play --- source/funkin/ui/title/AttractState.hx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/source/funkin/ui/title/AttractState.hx b/source/funkin/ui/title/AttractState.hx index 0af97afd9..a42a6c3d9 100644 --- a/source/funkin/ui/title/AttractState.hx +++ b/source/funkin/ui/title/AttractState.hx @@ -17,7 +17,7 @@ import funkin.ui.MusicBeatState; */ class AttractState extends MusicBeatState { - static final ATTRACT_VIDEO_PATH:String = Paths.videos('kickstarterTrailer'); + static final ATTRACT_VIDEO_PATH:String = Paths.stripLibrary(Paths.videos('kickstarterTrailer', 'shared')); public override function create():Void { @@ -29,10 +29,12 @@ class AttractState extends MusicBeatState } #if html5 + trace('Playing web video ${ATTRACT_VIDEO_PATH}'); playVideoHTML5(ATTRACT_VIDEO_PATH); #end #if hxCodec + trace('Playing native video ${ATTRACT_VIDEO_PATH}'); playVideoNative(ATTRACT_VIDEO_PATH); #end } From c1c2621e1d2412994863360e21701e1faf9823b0 Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Thu, 28 Mar 2024 00:18:39 -0400 Subject: [PATCH 022/130] Fix bug where Bad and Shit didn't count at Notes Hit in the results screen. --- source/funkin/play/PlayState.hx | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/source/funkin/play/PlayState.hx b/source/funkin/play/PlayState.hx index 6dc41e3f9..1cf69489d 100644 --- a/source/funkin/play/PlayState.hx +++ b/source/funkin/play/PlayState.hx @@ -2568,32 +2568,38 @@ class PlayState extends MusicBeatSubState */ function popUpScore(daNote:NoteSprite, score:Int, daRating:String, healthChange:Float):Void { - vocals.playerVolume = 1; - if (daRating == 'miss') { // If daRating is 'miss', that means we made a mistake and should not continue. - trace('[WARNING] popUpScore judged a note as a miss!'); + FlxG.log.warn('popUpScore judged a note as a miss!'); // TODO: Remove this. comboPopUps.displayRating('miss'); return; } + vocals.playerVolume = 1; + var isComboBreak = false; switch (daRating) { case 'sick': Highscore.tallies.sick += 1; + Highscore.tallies.totalNotesHit++; isComboBreak = Constants.JUDGEMENT_SICK_COMBO_BREAK; case 'good': Highscore.tallies.good += 1; + Highscore.tallies.totalNotesHit++; isComboBreak = Constants.JUDGEMENT_GOOD_COMBO_BREAK; case 'bad': Highscore.tallies.bad += 1; + Highscore.tallies.totalNotesHit++; isComboBreak = Constants.JUDGEMENT_BAD_COMBO_BREAK; case 'shit': Highscore.tallies.shit += 1; + Highscore.tallies.totalNotesHit++; isComboBreak = Constants.JUDGEMENT_SHIT_COMBO_BREAK; + default: + FlxG.log.error('Wuh? Buh? Guh? Note hit judgement was $daRating!'); } health += healthChange; From 837fcee98386cb150cb6e633054b4bb3b0900519 Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Thu, 28 Mar 2024 00:19:57 -0400 Subject: [PATCH 023/130] Fix a bug where 000 would display any time a Bad or Shit is hit (instead of just when a combo break is hit) --- source/funkin/play/PlayState.hx | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/source/funkin/play/PlayState.hx b/source/funkin/play/PlayState.hx index 1cf69489d..a161c04c5 100644 --- a/source/funkin/play/PlayState.hx +++ b/source/funkin/play/PlayState.hx @@ -2441,7 +2441,8 @@ class PlayState extends MusicBeatSubState if (Highscore.tallies.combo != 0) { // Break the combo. - Highscore.tallies.combo = comboPopUps.displayCombo(0); + if (Highscore.tallies.combo >= 10) comboPopUps.displayCombo(0); + Highscore.tallies.combo = 0; } if (playSound) @@ -2607,18 +2608,18 @@ class PlayState extends MusicBeatSubState if (isComboBreak) { // Break the combo, but don't increment tallies.misses. - Highscore.tallies.combo = comboPopUps.displayCombo(0); + if (Highscore.tallies.combo >= 10) comboPopUps.displayCombo(0); + Highscore.tallies.combo = 0; } else { Highscore.tallies.combo++; - Highscore.tallies.totalNotesHit++; if (Highscore.tallies.combo > Highscore.tallies.maxCombo) Highscore.tallies.maxCombo = Highscore.tallies.combo; } playerStrumline.hitNote(daNote, !isComboBreak); - if (daRating == "sick") + if (daRating == 'sick') { playerStrumline.playNoteSplash(daNote.noteData.getDirection()); } From b13c6563dff894a969a3129faaae8212e5a29f19 Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Thu, 28 Mar 2024 01:46:50 -0400 Subject: [PATCH 024/130] Fix issues with Freeplay OST text and add animations. --- assets | 2 +- source/funkin/data/freeplay/AlbumData.hx | 9 +++++ source/funkin/ui/freeplay/Album.hx | 11 ++++++ source/funkin/ui/freeplay/AlbumRoll.hx | 39 +++++++++++++++++++--- source/funkin/ui/freeplay/FreeplayState.hx | 19 ++++++++--- 5 files changed, 71 insertions(+), 9 deletions(-) diff --git a/assets b/assets index 8013845e3..92bd680af 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit 8013845e331015b40c4cc35230f6d02bd2148d52 +Subproject commit 92bd680af3c627211656205dac85f9de5ae5abee diff --git a/source/funkin/data/freeplay/AlbumData.hx b/source/funkin/data/freeplay/AlbumData.hx index 265a01fce..ca851376d 100644 --- a/source/funkin/data/freeplay/AlbumData.hx +++ b/source/funkin/data/freeplay/AlbumData.hx @@ -1,5 +1,7 @@ package funkin.data.freeplay; +import funkin.data.animation.AnimationData; + /** * A type definition for the data for an album of songs. * It includes things like what graphics to display in Freeplay. @@ -33,4 +35,11 @@ typedef AlbumData = * The album title will be displayed below the album art in Freeplay. */ public var albumTitleAsset:String; + + /** + * An optional array of animations for the album title. + */ + @:optional + @:default([]) + public var albumTitleAnimations:Array; } diff --git a/source/funkin/ui/freeplay/Album.hx b/source/funkin/ui/freeplay/Album.hx index 7291c7357..3060d3eb8 100644 --- a/source/funkin/ui/freeplay/Album.hx +++ b/source/funkin/ui/freeplay/Album.hx @@ -1,6 +1,7 @@ package funkin.ui.freeplay; import funkin.data.freeplay.AlbumData; +import funkin.data.animation.AnimationData; import funkin.data.freeplay.AlbumRegistry; import funkin.data.IRegistryEntry; import flixel.graphics.FlxGraphic; @@ -75,6 +76,16 @@ class Album implements IRegistryEntry return _data.albumTitleAsset; } + public function hasAlbumTitleAnimations() + { + return _data.albumTitleAnimations.length > 0; + } + + public function getAlbumTitleAnimations():Array + { + return _data.albumTitleAnimations; + } + public function toString():String { return 'Album($id)'; diff --git a/source/funkin/ui/freeplay/AlbumRoll.hx b/source/funkin/ui/freeplay/AlbumRoll.hx index a1e63c9a1..bde946e79 100644 --- a/source/funkin/ui/freeplay/AlbumRoll.hx +++ b/source/funkin/ui/freeplay/AlbumRoll.hx @@ -7,6 +7,7 @@ import flixel.tweens.FlxTween; import flixel.util.FlxTimer; import flixel.tweens.FlxEase; import funkin.data.freeplay.AlbumRegistry; +import funkin.util.assets.FlxAnimationUtil; import funkin.graphics.FunkinSprite; import funkin.util.SortUtil; import openfl.utils.Assets; @@ -21,9 +22,9 @@ class AlbumRoll extends FlxSpriteGroup * The ID of the album to display. * Modify this value to automatically update the album art and title. */ - public var albumId(default, set):String; + public var albumId(default, set):Null; - function set_albumId(value:String):String + function set_albumId(value:Null):Null { if (this.albumId != value) { @@ -65,6 +66,17 @@ class AlbumRoll extends FlxSpriteGroup */ function updateAlbum():Void { + if (albumId == null) + { + albumArt.visible = false; + albumTitle.visible = false; + if (titleTimer != null) + { + titleTimer.cancel(); + titleTimer = null; + } + } + albumData = AlbumRegistry.instance.fetchEntry(albumId); if (albumData == null) @@ -94,7 +106,15 @@ class AlbumRoll extends FlxSpriteGroup if (Assets.exists(Paths.image(albumData.getAlbumTitleAssetKey()))) { - albumTitle.loadGraphic(Paths.image(albumData.getAlbumTitleAssetKey())); + if (albumData.hasAlbumTitleAnimations()) + { + albumTitle.loadSparrow(albumData.getAlbumTitleAssetKey()); + FlxAnimationUtil.addAtlasAnimations(albumTitle, albumData.getAlbumTitleAnimations()); + } + else + { + albumTitle.loadGraphic(Paths.image(albumData.getAlbumTitleAssetKey())); + } } else { @@ -155,6 +175,8 @@ class AlbumRoll extends FlxSpriteGroup }); } + var titleTimer:Null = null; + /** * Play the intro animation on the album art. */ @@ -164,7 +186,14 @@ class AlbumRoll extends FlxSpriteGroup FlxTween.tween(albumArt, {x: 950, y: 320, angle: -340}, 0.5, {ease: FlxEase.elasticOut}); albumTitle.visible = false; - new FlxTimer().start(0.75, function(_) { + + if (titleTimer != null) + { + titleTimer.cancel(); + titleTimer = null; + } + + titleTimer = new FlxTimer().start(0.75, function(_) { showTitle(); }); } @@ -179,6 +208,8 @@ class AlbumRoll extends FlxSpriteGroup public function showTitle():Void { albumTitle.visible = true; + albumTitle.animation.play('active'); + albumTitle.animation.finishCallback = (_) -> albumTitle.animation.play('idle'); } /** diff --git a/source/funkin/ui/freeplay/FreeplayState.hx b/source/funkin/ui/freeplay/FreeplayState.hx index f7554197f..6dd96b36d 100644 --- a/source/funkin/ui/freeplay/FreeplayState.hx +++ b/source/funkin/ui/freeplay/FreeplayState.hx @@ -380,7 +380,7 @@ class FreeplayState extends MusicBeatSubState } albumRoll = new AlbumRoll(); - albumRoll.albumId = 'volume1'; + albumRoll.albumId = null; add(albumRoll); albumRoll.applyExitMovers(exitMovers); @@ -881,6 +881,8 @@ class FreeplayState extends MusicBeatSubState for (spr in grpSpr) { + if (spr == null) continue; + var funnyMoveShit:MoveData = moveData; if (moveData.x == null) funnyMoveShit.x = spr.x; @@ -1019,7 +1021,7 @@ class FreeplayState extends MusicBeatSubState albumRoll.setDifficultyStars(daSong?.songRating); // Set the album graphic and play the animation if relevant. - var newAlbumId:String = daSong?.albumId ?? Constants.DEFAULT_ALBUM_ID; + var newAlbumId:String = daSong?.albumId; if (albumRoll.albumId != newAlbumId) { albumRoll.albumId = newAlbumId; @@ -1162,6 +1164,7 @@ class FreeplayState extends MusicBeatSubState intendedCompletion = 0.0; rememberedSongId = null; rememberedDifficulty = null; + albumRoll.albumId = null; } for (index => capsule in grpCapsules.members) @@ -1311,7 +1314,7 @@ class FreeplaySongData public var songName(default, null):String = ''; public var songCharacter(default, null):String = ''; public var songRating(default, null):Int = 0; - public var albumId(default, null):String = ''; + public var albumId(default, null):Null = null; public var currentDifficulty(default, set):String = Constants.DEFAULT_DIFFICULTY; public var displayedVariations(default, null):Array = [Constants.DEFAULT_VARIATION]; @@ -1345,7 +1348,15 @@ class FreeplaySongData this.songName = songDifficulty.songName; this.songCharacter = songDifficulty.characters.opponent; this.songRating = songDifficulty.difficultyRating; - this.albumId = songDifficulty.album; + if (songDifficulty.album == null) + { + FlxG.log.warn('No album for: ${songDifficulty.songName}'); + this.albumId = Constants.DEFAULT_ALBUM_ID; + } + else + { + this.albumId = songDifficulty.album; + } } } From 5311b043ac81b2b38acbc5e57a24590f537b0a4a Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Thu, 28 Mar 2024 02:57:22 -0400 Subject: [PATCH 025/130] Rework credits data structure. --- source/funkin/ui/credits/CreditsData.hx | 16 ++++++++--- .../funkin/ui/credits/CreditsDataHandler.hx | 28 +++++++++++-------- source/funkin/ui/credits/CreditsState.hx | 25 +++++++++++++---- 3 files changed, 47 insertions(+), 22 deletions(-) diff --git a/source/funkin/ui/credits/CreditsData.hx b/source/funkin/ui/credits/CreditsData.hx index 0f6ea6bcd..bf7f13ad5 100644 --- a/source/funkin/ui/credits/CreditsData.hx +++ b/source/funkin/ui/credits/CreditsData.hx @@ -5,7 +5,7 @@ package funkin.ui.credits; */ typedef CreditsData = { - var roles:Array; + var entries:Array; } /** @@ -13,8 +13,16 @@ typedef CreditsData = */ typedef CreditsDataRole = { - var roleName:String; - var members:Array; + @:optional + var header:String; + + @:optional + @:default([]) + var body:Array; + + @:optional + @:default(false) + var appendBackers:Bool; } /** @@ -22,5 +30,5 @@ typedef CreditsDataRole = */ typedef CreditsDataMember = { - var fullName:String; + var line:String; } diff --git a/source/funkin/ui/credits/CreditsDataHandler.hx b/source/funkin/ui/credits/CreditsDataHandler.hx index 6317dd55d..f2722ffbf 100644 --- a/source/funkin/ui/credits/CreditsDataHandler.hx +++ b/source/funkin/ui/credits/CreditsDataHandler.hx @@ -24,14 +24,14 @@ class CreditsDataHandler return; } - var roleCount = data.roles.length; - var memberCount = 0; - for (role in data.roles) + var entryCount = data.entries.length; + var lineCount = 0; + for (entry in data.entries) { - memberCount += role.members.length; + lineCount += entry?.body?.length ?? 0; } - trace('CreditsData($roleCount roles with $memberCount members)'); + trace('CreditsData($entryCount entries containing $lineCount lines)'); } /** @@ -43,15 +43,19 @@ class CreditsDataHandler public static inline function getFallback():CreditsData { return { - roles: [ + entries: [ { - roleName: 'Founders', - members: [ - {fullName: 'ninjamuffin99'}, - {fullName: 'PhantomArcade'}, - {fullName: 'KawaiSprite'}, - {fullName: 'evilsk8r'}, + header: 'Founders', + body: [ + {line: 'ninjamuffin99'}, + {line: 'PhantomArcade'}, + {line: 'KawaiSprite'}, + {line: 'evilsk8r'}, ] + }, + { + header: 'Kickstarter Backers', + appendBackers: true } ] }; diff --git a/source/funkin/ui/credits/CreditsState.hx b/source/funkin/ui/credits/CreditsState.hx index 1e5965695..d43e25114 100644 --- a/source/funkin/ui/credits/CreditsState.hx +++ b/source/funkin/ui/credits/CreditsState.hx @@ -116,17 +116,30 @@ class CreditsState extends MusicBeatState { var y = 0; - for (role in CreditsDataHandler.CREDITS_DATA.roles) + for (entry in CreditsDataHandler.CREDITS_DATA.entries) { - creditsGroup.add(buildCreditsLine(role.roleName, y, true, CreditsSide.Center)); - y += CREDITS_HEADER_FONT_SIZE; - - for (member in role.members) + if (entry.header != null) { - creditsGroup.add(buildCreditsLine(member.fullName, y, false, CreditsSide.Center)); + creditsGroup.add(buildCreditsLine(entry.header, y, true, CreditsSide.Center)); + y += CREDITS_HEADER_FONT_SIZE; + } + + for (line in entry?.body ?? []) + { + creditsGroup.add(buildCreditsLine(line.line, y, false, CreditsSide.Center)); y += CREDITS_FONT_SIZE; } + if (entry.appendBackers) + { + var backers = CreditsDataHandler.fetchBackerEntries(); + for (backer in backers) + { + creditsGroup.add(buildCreditsLine(backer, y, false, CreditsSide.Center)); + y += CREDITS_FONT_SIZE; + } + } + // Padding between each role. y += CREDITS_FONT_SIZE * 2; } From 3a86b47292b88674dae074f22d8b5d37b9671348 Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Thu, 28 Mar 2024 02:57:51 -0400 Subject: [PATCH 026/130] Fix issue where main menu music wouldn't play after credits. --- source/funkin/ui/mainmenu/MainMenuState.hx | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/source/funkin/ui/mainmenu/MainMenuState.hx b/source/funkin/ui/mainmenu/MainMenuState.hx index e536554d0..02632628f 100644 --- a/source/funkin/ui/mainmenu/MainMenuState.hx +++ b/source/funkin/ui/mainmenu/MainMenuState.hx @@ -51,10 +51,7 @@ class MainMenuState extends MusicBeatState transIn = FlxTransitionableState.defaultTransIn; transOut = FlxTransitionableState.defaultTransOut; - if (!(FlxG?.sound?.music?.playing ?? false)) - { - playMenuMusic(); - } + playMenuMusic(); persistentUpdate = persistentDraw = true; @@ -109,15 +106,18 @@ class MainMenuState extends MusicBeatState }); #if CAN_OPEN_LINKS + // In order to prevent popup blockers from triggering, + // we need to open the link as an immediate result of a keypress event, + // so we can't wait for the flicker animation to complete. var hasPopupBlocker = #if web true #else false #end; - createMenuItem('donate', 'mainmenu/donate', selectDonate, hasPopupBlocker); + createMenuItem('merch', 'mainmenu/merch', selectMerch, hasPopupBlocker); #end createMenuItem('options', 'mainmenu/options', function() { startExitState(() -> new funkin.ui.options.OptionsState()); }); - createMenuItem('options', 'mainmenu/options', function() { + createMenuItem('credits', 'mainmenu/credits', function() { startExitState(() -> new funkin.ui.credits.CreditsState()); }); @@ -219,6 +219,11 @@ class MainMenuState extends MusicBeatState { WindowUtil.openURL(Constants.URL_ITCH); } + + function selectMerch() + { + WindowUtil.openURL(Constants.URL_MERCH); + } #end #if newgrounds From 3d14024fd8747d704910570f66a3592a8042e520 Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Thu, 28 Mar 2024 02:58:08 -0400 Subject: [PATCH 027/130] Implement merch link. --- source/funkin/util/Constants.hx | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/source/funkin/util/Constants.hx b/source/funkin/util/Constants.hx index c7bc03139..7ea537935 100644 --- a/source/funkin/util/Constants.hx +++ b/source/funkin/util/Constants.hx @@ -59,6 +59,11 @@ class Constants */ // ============================== + /** + * Link to buy merch for the game. + */ + public static final URL_MERCH:String = 'https://needlejuicerecords.com/pages/friday-night-funkin'; + /** * Link to download the game on Itch.io. */ From e5eca37dc067e82d3a75f849fd62a8c24fe67dca Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Thu, 28 Mar 2024 02:58:46 -0400 Subject: [PATCH 028/130] Update assets submodule. --- assets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets b/assets index edccf0421..289810289 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit edccf04217c49c730b11c80736e2b2d98a25ee95 +Subproject commit 289810289d66cbaf5d55494e396e71bdf9085b1e From c7d67b46e0089a1a1ddfb81bbb470f3100a1b88a Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Thu, 28 Mar 2024 20:29:32 -0400 Subject: [PATCH 029/130] Update art submodule --- art | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/art b/art index 00463685f..03e7c2a23 160000 --- a/art +++ b/art @@ -1 +1 @@ -Subproject commit 00463685fa570f0c853d08e250b46ef80f30bc48 +Subproject commit 03e7c2a2353b184e45955c96d763b7cdf1acbc34 From 1c9b087f2ff6a597255311064f0e576565491d18 Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Thu, 28 Mar 2024 21:20:08 -0400 Subject: [PATCH 030/130] Update assets submodule --- assets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets b/assets index 485243fdd..65e6ff18c 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit 485243fdd44acbc4db6a97ec7bf10a8b18350be9 +Subproject commit 65e6ff18c7fcbd646ac7a3676ca5c2baa95b5fea From 8020624366a48b1563945722744cca20702e078b Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Thu, 28 Mar 2024 21:40:16 -0400 Subject: [PATCH 031/130] Fix a crash I found. --- source/funkin/audio/VoicesGroup.hx | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/source/funkin/audio/VoicesGroup.hx b/source/funkin/audio/VoicesGroup.hx index 91054cfb0..5037ee1d0 100644 --- a/source/funkin/audio/VoicesGroup.hx +++ b/source/funkin/audio/VoicesGroup.hx @@ -159,10 +159,18 @@ class VoicesGroup extends SoundGroup public override function destroy():Void { - playerVoices.destroy(); - playerVoices = null; - opponentVoices.destroy(); - opponentVoices = null; + if (playerVoices != null) + { + playerVoices.destroy(); + playerVoices = null; + } + + if (opponentVoices != null) + { + opponentVoices.destroy(); + opponentVoices = null; + } + super.destroy(); } } From aa7ff6fbc45a0820dc2da581ea5b84e44d5df7c7 Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Thu, 28 Mar 2024 21:40:47 -0400 Subject: [PATCH 032/130] Update assets submodule --- assets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets b/assets index 485243fdd..15c3f16c7 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit 485243fdd44acbc4db6a97ec7bf10a8b18350be9 +Subproject commit 15c3f16c7ec162b7c8d86421b624d74501b9616f From 342782c3d379d67127d1ef8acc5662fdfc370ae6 Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Thu, 28 Mar 2024 22:33:50 -0400 Subject: [PATCH 033/130] Fix issue with pink screen when moving from PlayState->Freeplay->Main Menu --- source/funkin/play/GameOverSubState.hx | 4 ++-- source/funkin/play/PauseSubState.hx | 3 ++- source/funkin/play/PlayState.hx | 17 ++++------------- source/funkin/play/ResultState.hx | 2 +- source/funkin/ui/freeplay/FreeplayState.hx | 19 +++++++++++++++++-- source/funkin/ui/mainmenu/MainMenuState.hx | 5 ++--- source/funkin/ui/title/TitleState.hx | 12 ------------ 7 files changed, 28 insertions(+), 34 deletions(-) diff --git a/source/funkin/play/GameOverSubState.hx b/source/funkin/play/GameOverSubState.hx index a1796e912..652ba1484 100644 --- a/source/funkin/play/GameOverSubState.hx +++ b/source/funkin/play/GameOverSubState.hx @@ -238,11 +238,11 @@ class GameOverSubState extends MusicBeatSubState } else if (PlayStatePlaylist.isStoryMode) { - FlxG.switchState(() -> new StoryMenuState()); + openSubState(new funkin.ui.transition.StickerSubState(null, (sticker) -> new StoryMenuState(sticker))); } else { - FlxG.switchState(() -> new FreeplayState()); + openSubState(new funkin.ui.transition.StickerSubState(null, (sticker) -> FreeplayState.build(sticker))); } } diff --git a/source/funkin/play/PauseSubState.hx b/source/funkin/play/PauseSubState.hx index f16aa00d8..471f8cf02 100644 --- a/source/funkin/play/PauseSubState.hx +++ b/source/funkin/play/PauseSubState.hx @@ -12,6 +12,7 @@ import flixel.tweens.FlxTween; import flixel.util.FlxColor; import funkin.audio.FunkinSound; import funkin.data.song.SongRegistry; +import funkin.ui.freeplay.FreeplayState; import funkin.graphics.FunkinSprite; import funkin.play.cutscene.VideoCutscene; import funkin.play.PlayState; @@ -658,7 +659,7 @@ class PauseSubState extends MusicBeatSubState } else { - state.openSubState(new funkin.ui.transition.StickerSubState(null, (sticker) -> new funkin.ui.freeplay.FreeplayState(null, sticker))); + state.openSubState(new funkin.ui.transition.StickerSubState(null, (sticker) -> FreeplayState.build(null, sticker))); } } diff --git a/source/funkin/play/PlayState.hx b/source/funkin/play/PlayState.hx index fd6463bb1..678f2430e 100644 --- a/source/funkin/play/PlayState.hx +++ b/source/funkin/play/PlayState.hx @@ -2785,18 +2785,6 @@ class PlayState extends MusicBeatSubState if (targetSongId == null) { - FunkinSound.playMusic('freakyMenu', - { - overrideExisting: true, - restartTrack: false - }); - - // transIn = FlxTransitionableState.defaultTransIn; - // transOut = FlxTransitionableState.defaultTransOut; - - // TODO: Rework week unlock logic. - // StoryMenuState.weekUnlocked[Std.int(Math.min(storyWeek + 1, StoryMenuState.weekUnlocked.length - 1))] = true; - if (currentSong.validScore) { NGio.unlockMedal(60961); @@ -3205,7 +3193,10 @@ class PlayState extends MusicBeatSubState // Don't go back in time to before the song started. targetTimeMs = Math.max(0, targetTimeMs); - FlxG.sound.music.time = targetTimeMs; + if (FlxG.sound.music != null) + { + FlxG.sound.music.time = targetTimeMs; + } handleSkippedNotes(); SongEventRegistry.handleSkippedEvents(songEvents, Conductor.instance.songPosition); diff --git a/source/funkin/play/ResultState.hx b/source/funkin/play/ResultState.hx index 821f4ba3c..12f395d0f 100644 --- a/source/funkin/play/ResultState.hx +++ b/source/funkin/play/ResultState.hx @@ -365,7 +365,7 @@ class ResultState extends MusicBeatSubState } else { - openSubState(new funkin.ui.transition.StickerSubState(null, (sticker) -> new FreeplayState(null, sticker))); + openSubState(new funkin.ui.transition.StickerSubState(null, (sticker) -> FreeplayState.build(null, sticker))); } } diff --git a/source/funkin/ui/freeplay/FreeplayState.hx b/source/funkin/ui/freeplay/FreeplayState.hx index 6cb0d1d9a..40081b2ec 100644 --- a/source/funkin/ui/freeplay/FreeplayState.hx +++ b/source/funkin/ui/freeplay/FreeplayState.hx @@ -145,7 +145,7 @@ class FreeplayState extends MusicBeatSubState stickerSubState = stickers; } - super(); + super(FlxColor.TRANSPARENT); } override function create():Void @@ -899,7 +899,7 @@ class FreeplayState extends MusicBeatSubState if (Type.getClass(FlxG.state) == MainMenuState) { - FlxG.state.persistentUpdate = true; + FlxG.state.persistentUpdate = false; FlxG.state.persistentDraw = true; } @@ -1201,6 +1201,21 @@ class FreeplayState extends MusicBeatSubState grpCapsules.members[curSelected].selected = true; } } + + /** + * Build an instance of `FreeplayState` that is above the `MainMenuState`. + * @return The MainMenuState with the FreeplayState as a substate. + */ + public static function build(?params:FreeplayStateParams, ?stickers:StickerSubState):MusicBeatState + { + var result = new MainMenuState(); + result.persistentUpdate = false; + result.persistentDraw = true; + + result.openSubState(new FreeplayState(params, stickers)); + + return result; + } } /** diff --git a/source/funkin/ui/mainmenu/MainMenuState.hx b/source/funkin/ui/mainmenu/MainMenuState.hx index a8c2039ab..df81cf6f2 100644 --- a/source/funkin/ui/mainmenu/MainMenuState.hx +++ b/source/funkin/ui/mainmenu/MainMenuState.hx @@ -56,7 +56,8 @@ class MainMenuState extends MusicBeatState playMenuMusic(); } - persistentUpdate = persistentDraw = true; + persistentUpdate = false; + persistentDraw = true; var bg:FlxSprite = new FlxSprite(Paths.image('menuBG')); bg.scrollFactor.x = 0; @@ -311,8 +312,6 @@ class MainMenuState extends MusicBeatState // Open the debug menu, defaults to ` / ~ if (controls.DEBUG_MENU) { - this.persistentUpdate = false; - this.persistentDraw = false; FlxG.state.openSubState(new DebugMenuSubState()); } diff --git a/source/funkin/ui/title/TitleState.hx b/source/funkin/ui/title/TitleState.hx index 1a4e13ab1..7bd4a84af 100644 --- a/source/funkin/ui/title/TitleState.hx +++ b/source/funkin/ui/title/TitleState.hx @@ -290,18 +290,6 @@ class TitleState extends MusicBeatState // do controls.PAUSE | controls.ACCEPT instead? var pressedEnter:Bool = FlxG.keys.justPressed.ENTER; - if (FlxG.onMobile) - { - for (touch in FlxG.touches.list) - { - if (touch.justPressed) - { - FlxG.switchState(() -> new FreeplayState()); - pressedEnter = true; - } - } - } - var gamepad:FlxGamepad = FlxG.gamepads.lastActive; if (gamepad != null) From b75c7c23614785fd31af2bdd2c6b059fd6c4f1b9 Mon Sep 17 00:00:00 2001 From: Cameron Taylor Date: Thu, 28 Mar 2024 23:08:50 -0400 Subject: [PATCH 034/130] funkVis html5 --- hmm.json | 2 +- source/funkin/audio/visualize/ABotVis.hx | 3 ++- source/funkin/audio/visualize/AudioClip.hx | 23 ---------------------- 3 files changed, 3 insertions(+), 25 deletions(-) delete mode 100644 source/funkin/audio/visualize/AudioClip.hx diff --git a/hmm.json b/hmm.json index 81624a08a..430f33f0d 100644 --- a/hmm.json +++ b/hmm.json @@ -49,7 +49,7 @@ "name": "funkVis", "type": "git", "dir": null, - "ref": "0ac2fffa67fd30563df97c66718551efa92d283e", + "ref": "backend-rework", "url": "https://github.com/FunkinCrew/funkVis" }, { diff --git a/source/funkin/audio/visualize/ABotVis.hx b/source/funkin/audio/visualize/ABotVis.hx index a8b6fb937..1188d389f 100644 --- a/source/funkin/audio/visualize/ABotVis.hx +++ b/source/funkin/audio/visualize/ABotVis.hx @@ -9,6 +9,7 @@ import flixel.math.FlxMath; import flixel.sound.FlxSound; import funkin.util.MathUtil; import funkVis.dsp.SpectralAnalyzer; +import funkVis.audioclip.frontends.LimeAudioClip; using Lambda; @@ -57,7 +58,7 @@ class ABotVis extends FlxTypedSpriteGroup public function initAnalyzer() { @:privateAccess - analyzer = new SpectralAnalyzer(7, new AudioClip(cast snd._channel.__source), 0.01, 30); + analyzer = new SpectralAnalyzer(7, new LimeAudioClip(cast snd._channel.__source), 0.01, 30); analyzer.maxDb = -35; // analyzer.fftN = 2048; } diff --git a/source/funkin/audio/visualize/AudioClip.hx b/source/funkin/audio/visualize/AudioClip.hx deleted file mode 100644 index a8e353799..000000000 --- a/source/funkin/audio/visualize/AudioClip.hx +++ /dev/null @@ -1,23 +0,0 @@ -package funkin.audio.visualize; - -import flixel.FlxG; -import flixel.math.FlxMath; -import funkVis.AudioBuffer; -import lime.media.AudioSource; - -class AudioClip implements funkVis.AudioClip -{ - public var audioBuffer(default, null):AudioBuffer; - public var currentFrame(get, never):Int; - - public function new(audioSource:AudioSource) - { - var data:lime.utils.UInt16Array = cast audioSource.buffer.data; - this.audioBuffer = new AudioBuffer(data, audioSource.buffer.sampleRate); - } - - private function get_currentFrame():Int - { - return Std.int(FlxMath.remapToRange(FlxG.sound.music.time, 0, FlxG.sound.music.length, 0, audioBuffer.data.length / 2)); - } -} From ddb41c9ef7d8c08e5100253216979dfdc6c14ef7 Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Thu, 28 Mar 2024 23:13:47 -0400 Subject: [PATCH 035/130] Increase AFK timer, and add SFX over it --- assets | 2 +- source/funkin/ui/freeplay/DJBoyfriend.hx | 29 ++++++++++++++---------- 2 files changed, 18 insertions(+), 13 deletions(-) diff --git a/assets b/assets index 15c3f16c7..04605b7e3 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit 15c3f16c7ec162b7c8d86421b624d74501b9616f +Subproject commit 04605b7e3ab7556b395476aa31b8853ff5243c6f diff --git a/source/funkin/ui/freeplay/DJBoyfriend.hx b/source/funkin/ui/freeplay/DJBoyfriend.hx index 33f264301..5f1144fab 100644 --- a/source/funkin/ui/freeplay/DJBoyfriend.hx +++ b/source/funkin/ui/freeplay/DJBoyfriend.hx @@ -27,8 +27,8 @@ class DJBoyfriend extends FlxAtlasSprite var gotSpooked:Bool = false; - static final SPOOK_PERIOD:Float = 10.0; - static final TV_PERIOD:Float = 10.0; + static final SPOOK_PERIOD:Float = 120.0; + static final TV_PERIOD:Float = 180.0; // Time since dad last SPOOKED you. var timeSinceSpook:Float = 0; @@ -43,7 +43,14 @@ class DJBoyfriend extends FlxAtlasSprite switch (name) { case "Boyfriend DJ watchin tv OG": - if (number == 85) runTvLogic(); + if (number == 80) + { + FunkinSound.playOnce(Paths.sound('remote_click')); + } + if (number == 85) + { + runTvLogic(); + } default: } }; @@ -219,19 +226,17 @@ class DJBoyfriend extends FlxAtlasSprite if (cartoonSnd == null) { // tv is OFF, but getting turned on - // Eric got FUCKING TROLLED there is no `tv_on` or `channel_switch` sound! - // FunkinSound.playOnce(Paths.sound('tv_on'), 1.0, function() { - // }); - loadCartoon(); + FunkinSound.playOnce(Paths.sound('tv_on'), 1.0, function() { + loadCartoon(); + }); } else { // plays it smidge after the click - // new FlxTimer().start(0.1, function(_) { - // // FunkinSound.playOnce(Paths.sound('channel_switch')); - // }); - cartoonSnd.destroy(); - loadCartoon(); + FunkinSound.playOnce(Paths.sound('channel_switch'), 1.0, function() { + cartoonSnd.destroy(); + loadCartoon(); + }); } // loadCartoon(); From c97227b1300a40d2f6153940d86a04882ca8bdca Mon Sep 17 00:00:00 2001 From: Cameron Taylor Date: Fri, 29 Mar 2024 00:39:32 -0400 Subject: [PATCH 036/130] assets submod --- assets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets b/assets index 69ac1b5f1..8a48607c8 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit 69ac1b5f10ee8722ac0586a0e0282f04dccc07eb +Subproject commit 8a48607c800e096bbe6e67395adbbd48639a72ed From 7c04630bb775161e9878e6554146a313aaab5c2a Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Fri, 29 Mar 2024 00:49:02 -0400 Subject: [PATCH 037/130] Fix a bug where duplicate notes would get placed at the beginning --- source/funkin/play/notes/Strumline.hx | 5 +++++ source/funkin/ui/transition/LoadingState.hx | 3 ++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/source/funkin/play/notes/Strumline.hx b/source/funkin/play/notes/Strumline.hx index 9a6699c43..a3b5dafc5 100644 --- a/source/funkin/play/notes/Strumline.hx +++ b/source/funkin/play/notes/Strumline.hx @@ -295,6 +295,11 @@ class Strumline extends FlxSpriteGroup { if (noteData.length == 0) return; + // Ensure note data gets reset if the song happens to loop. + // NOTE: I had to remove this line because it was causing notes visible during the countdown to be placed multiple times. + // I don't remember what bug I was trying to fix by adding this. + // if (conductorInUse.currentStep == 0) nextNoteIndex = 0; + var songStart:Float = PlayState.instance?.startTimestamp ?? 0.0; var hitWindowStart:Float = Conductor.instance.songPosition - Constants.HIT_WINDOW_MS; var renderWindowStart:Float = Conductor.instance.songPosition + RENDER_DISTANCE_MS; diff --git a/source/funkin/ui/transition/LoadingState.hx b/source/funkin/ui/transition/LoadingState.hx index 980c264e3..d913b8099 100644 --- a/source/funkin/ui/transition/LoadingState.hx +++ b/source/funkin/ui/transition/LoadingState.hx @@ -210,7 +210,8 @@ class LoadingState extends MusicBeatState } // Load and cache the song's charts. - if (params?.targetSong != null) + // Don't do this if we already provided the music and charts. + if (params?.targetSong != null && !params.overrideMusic) { params.targetSong.cacheCharts(true); } From 28462681b2af4a55c82fb60aa55b51ac4ab29966 Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Fri, 29 Mar 2024 00:52:20 -0400 Subject: [PATCH 038/130] Fix bug where 100ms sustains wouldn't update their rendering. --- source/funkin/play/notes/Strumline.hx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/funkin/play/notes/Strumline.hx b/source/funkin/play/notes/Strumline.hx index a3b5dafc5..2b10c05ee 100644 --- a/source/funkin/play/notes/Strumline.hx +++ b/source/funkin/play/notes/Strumline.hx @@ -827,7 +827,7 @@ class Strumline extends FlxSpriteGroup { // The note sprite pool is full and all note splashes are active. // We have to create a new note. - result = new SustainTrail(0, 100, noteStyle); + result = new SustainTrail(0, 0, noteStyle); this.holdNotes.add(result); } From 9b7bfff817cdd9d50468a263053d9837fa9c3f6d Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Fri, 29 Mar 2024 01:23:36 -0400 Subject: [PATCH 039/130] Update assets submodule --- assets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets b/assets index 485243fdd..44d74c089 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit 485243fdd44acbc4db6a97ec7bf10a8b18350be9 +Subproject commit 44d74c0898b630a98344ef22987be73140e932c3 From f50c1ce86fb38d5f5b95a864ed7e0de684414b70 Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Fri, 29 Mar 2024 10:17:16 -0400 Subject: [PATCH 040/130] Update assets submodule --- assets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets b/assets index 65e6ff18c..0965a86e2 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit 65e6ff18c7fcbd646ac7a3676ca5c2baa95b5fea +Subproject commit 0965a86e2248bd9b8b2387f8b4f6b16385499db0 From 5be47e6619aa13ca6251c1c580d9dbc4ef330818 Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Fri, 29 Mar 2024 10:34:59 -0400 Subject: [PATCH 041/130] Fix limo ride too --- assets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets b/assets index 0965a86e2..5d78b0705 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit 0965a86e2248bd9b8b2387f8b4f6b16385499db0 +Subproject commit 5d78b070535d6a1d88c5b450fc092eb6cd331f78 From 32ed26ffa6e786003786bab7bac0d7c8365871be Mon Sep 17 00:00:00 2001 From: Cameron Taylor Date: Fri, 29 Mar 2024 17:54:20 -0400 Subject: [PATCH 042/130] stereo preloader in progress --- assets | 2 +- .../ui/transition/preload/FunkinPreloader.hx | 187 +++++++++++++++--- .../ui/transition/preload/VFDOverlay.hx | 70 +++++++ source/funkin/util/Constants.hx | 2 +- 4 files changed, 230 insertions(+), 31 deletions(-) create mode 100644 source/funkin/ui/transition/preload/VFDOverlay.hx diff --git a/assets b/assets index 65e6ff18c..f462b181f 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit 65e6ff18c7fcbd646ac7a3676ca5c2baa95b5fea +Subproject commit f462b181f13c016f79e022d08b4d23f61d4a7e8b diff --git a/source/funkin/ui/transition/preload/FunkinPreloader.hx b/source/funkin/ui/transition/preload/FunkinPreloader.hx index 89a8c1140..2e8e0c319 100644 --- a/source/funkin/ui/transition/preload/FunkinPreloader.hx +++ b/source/funkin/ui/transition/preload/FunkinPreloader.hx @@ -1,5 +1,10 @@ package funkin.ui.transition.preload; +import openfl.filters.GlowFilter; +import openfl.display.SpreadMethod; +import openfl.display.GradientType; +import openfl.geom.Matrix; +import openfl.filters.BlurFilter; import openfl.events.MouseEvent; import flash.display.Bitmap; import flash.display.BitmapData; @@ -46,7 +51,7 @@ class FunkinPreloader extends FlxBasePreloader */ static final BAR_PADDING:Float = 20; - static final BAR_HEIGHT:Int = 20; + static final BAR_HEIGHT:Int = 12; /** * Logo takes this long (in seconds) to fade in. @@ -108,10 +113,19 @@ class FunkinPreloader extends FlxBasePreloader #if TOUCH_HERE_TO_PLAY var touchHereToPlay:Bitmap; #end + var progressBarPieces:Array; var progressBar:Bitmap; var progressLeftText:TextField; var progressRightText:TextField; + var dspText:TextField; + var enhancedText:TextField; + var stereoText:TextField; + + var vfdShader:VFDOverlay; + var box:Sprite; + var progressLines:Sprite; + public function new() { super(Constants.PRELOADER_MIN_STAGE_TIME, Constants.SITE_LOCK); @@ -146,7 +160,7 @@ class FunkinPreloader extends FlxBasePreloader bmp.x = (this._width - bmp.width) / 2; bmp.y = (this._height - bmp.height) / 2; }); - addChild(logo); + // addChild(logo); #if TOUCH_HERE_TO_PLAY touchHereToPlay = createBitmap(TouchHereToPlayImage, function(bmp:Bitmap) { @@ -160,16 +174,48 @@ class FunkinPreloader extends FlxBasePreloader addChild(touchHereToPlay); #end + var amountOfPieces:Int = 16; + progressBarPieces = []; + var maxBarWidth = this._width - BAR_PADDING * 2; + var pieceWidth = maxBarWidth / amountOfPieces; + var pieceGap:Int = 8; + + progressLines = new openfl.display.Sprite(); + progressLines.graphics.lineStyle(2, Constants.COLOR_PRELOADER_BAR); + progressLines.graphics.drawRect(-2, 480, this._width + 4, 30); + addChild(progressLines); + + var progressBarPiece = new Sprite(); + progressBarPiece.graphics.beginFill(Constants.COLOR_PRELOADER_BAR); + progressBarPiece.graphics.drawRoundRect(0, 0, pieceWidth - pieceGap, BAR_HEIGHT, 4, 4); + progressBarPiece.graphics.endFill(); + + for (i in 0...amountOfPieces) + { + var piece = new Sprite(); + piece.graphics.beginFill(Constants.COLOR_PRELOADER_BAR); + piece.graphics.drawRoundRect(0, 0, pieceWidth - pieceGap, BAR_HEIGHT, 4, 4); + piece.graphics.endFill(); + + piece.x = i * (piece.width + pieceGap); + piece.y = this._height - BAR_PADDING - BAR_HEIGHT - 200; + addChild(piece); + progressBarPieces.push(piece); + } + // Create the progress bar. - progressBar = new Bitmap(new BitmapData(1, BAR_HEIGHT, true, Constants.COLOR_PRELOADER_BAR)); - progressBar.x = BAR_PADDING; - progressBar.y = this._height - BAR_PADDING - BAR_HEIGHT; - addChild(progressBar); + // progressBar = new Bitmap(new BitmapData(1, BAR_HEIGHT, true, Constants.COLOR_PRELOADER_BAR)); + // progressBar.x = BAR_PADDING; + // progressBar.y = this._height - BAR_PADDING - BAR_HEIGHT; + // addChild(progressBar); // Create the progress message. progressLeftText = new TextField(); + dspText = new TextField(); + enhancedText = new TextField(); + stereoText = new TextField(); - var progressLeftTextFormat = new TextFormat("VCR OSD Mono", 16, Constants.COLOR_PRELOADER_BAR, true); + var progressLeftTextFormat = new TextFormat("DS-Digital", 32, Constants.COLOR_PRELOADER_BAR, true); progressLeftTextFormat.align = TextFormatAlign.LEFT; progressLeftText.defaultTextFormat = progressLeftTextFormat; @@ -177,13 +223,14 @@ class FunkinPreloader extends FlxBasePreloader progressLeftText.width = this._width - BAR_PADDING * 2; progressLeftText.text = 'Downloading assets...'; progressLeftText.x = BAR_PADDING; - progressLeftText.y = this._height - BAR_PADDING - BAR_HEIGHT - 16 - 4; + progressLeftText.y = this._height - BAR_PADDING - BAR_HEIGHT - 290; + // progressLeftText.shader = new VFDOverlay(); addChild(progressLeftText); // Create the progress %. progressRightText = new TextField(); - var progressRightTextFormat = new TextFormat("VCR OSD Mono", 16, Constants.COLOR_PRELOADER_BAR, true); + var progressRightTextFormat = new TextFormat("DS-Digital", 16, Constants.COLOR_PRELOADER_BAR, true); progressRightTextFormat.align = TextFormatAlign.RIGHT; progressRightText.defaultTextFormat = progressRightTextFormat; @@ -193,6 +240,60 @@ class FunkinPreloader extends FlxBasePreloader progressRightText.x = BAR_PADDING; progressRightText.y = this._height - BAR_PADDING - BAR_HEIGHT - 16 - 4; addChild(progressRightText); + + box = new Sprite(); + box.graphics.beginFill(Constants.COLOR_PRELOADER_BAR, 1); + box.graphics.drawRoundRect(0, 0, 64, 20, 5, 5); + box.graphics.drawRoundRect(70, 0, 58, 20, 5, 5); + box.graphics.endFill(); + box.graphics.beginFill(Constants.COLOR_PRELOADER_BAR, 0.1); + box.graphics.drawRoundRect(0, 0, 128, 20, 5, 5); + box.graphics.endFill(); + box.x = 880; + box.y = 440; + addChild(box); + + dspText.selectable = false; + dspText.textColor = 0x000000; + dspText.width = this._width; + dspText.height = 20; + dspText.text = 'DSP'; + dspText.x = 10; + dspText.y = -5; + box.addChild(dspText); + + enhancedText.selectable = false; + enhancedText.textColor = Constants.COLOR_PRELOADER_BAR; + enhancedText.width = this._width; + enhancedText.height = 100; + enhancedText.text = 'ENHANCED'; + enhancedText.x = -100; + enhancedText.y = 0; + box.addChild(enhancedText); + + stereoText.selectable = false; + stereoText.textColor = Constants.COLOR_PRELOADER_BAR; + stereoText.width = this._width; + stereoText.height = 100; + stereoText.text = 'STEREO'; + stereoText.x = 0; + stereoText.y = -40; + box.addChild(stereoText); + + // var dummyMatrix:openfl.geom.Matrix = new Matrix(); + // dummyMatrix.createGradientBox(this._width, this._height * 0.1, 90 * Math.PI / 180); + + // var gradient:Sprite = new Sprite(); + // gradient.graphics.beginGradientFill(GradientType.LINEAR, [0xFFFFFF, 0x000000], [1, 1], [0, 255], dummyMatrix, SpreadMethod.REFLECT); + // gradient.graphics.drawRect(0, 0, this._width, this._height); + // gradient.graphics.endFill(); + // addChild(gradient); + + var vfdBitmap:Bitmap = new Bitmap(new BitmapData(this._width, this._height, true, 0xFFFFFFFF)); + addChild(vfdBitmap); + + vfdShader = new VFDOverlay(); + vfdBitmap.shader = vfdShader; } var lastElapsed:Float = 0.0; @@ -200,6 +301,8 @@ class FunkinPreloader extends FlxBasePreloader override function update(percent:Float):Void { var elapsed:Float = (Date.now().getTime() - this._startTime) / 1000.0; + + vfdShader.update(elapsed * 100); // trace('Time since last frame: ' + (lastElapsed - elapsed)); downloadingAssetsPercent = percent; @@ -748,12 +851,19 @@ class FunkinPreloader extends FlxBasePreloader else { renderLogoFadeIn(elapsed); + + // Render progress bar + var maxWidth = this._width - BAR_PADDING * 2; + var barWidth = maxWidth * percent; + var piecesToRender:Int = Std.int(percent * progressBarPieces.length); + + for (i => piece in progressBarPieces) + { + piece.alpha = i <= piecesToRender ? 0.9 : 0.1; + } } - // Render progress bar - var maxWidth = this._width - BAR_PADDING * 2; - var barWidth = maxWidth * percent; - progressBar.width = barWidth; + // progressBar.width = barWidth; // Cycle ellipsis count to show loading var ellipsisCount:Int = Std.int(elapsed / ELLIPSIS_TIME) % 3 + 1; @@ -766,29 +876,29 @@ class FunkinPreloader extends FlxBasePreloader { // case FunkinPreloaderState.NotStarted: default: - updateProgressLeftText('Loading (0/$TOTAL_STEPS)$ellipsis'); + updateProgressLeftText('Loading \n0/$TOTAL_STEPS $ellipsis'); case FunkinPreloaderState.DownloadingAssets: - updateProgressLeftText('Downloading assets (1/$TOTAL_STEPS)$ellipsis'); + updateProgressLeftText('Downloading assets \n1/$TOTAL_STEPS $ellipsis'); case FunkinPreloaderState.PreloadingPlayAssets: - updateProgressLeftText('Preloading assets (2/$TOTAL_STEPS)$ellipsis'); + updateProgressLeftText('Preloading assets \n2/$TOTAL_STEPS $ellipsis'); case FunkinPreloaderState.InitializingScripts: - updateProgressLeftText('Initializing scripts (3/$TOTAL_STEPS)$ellipsis'); + updateProgressLeftText('Initializing scripts \n3/$TOTAL_STEPS $ellipsis'); case FunkinPreloaderState.CachingGraphics: - updateProgressLeftText('Caching graphics (4/$TOTAL_STEPS)$ellipsis'); + updateProgressLeftText('Caching graphics \n4/$TOTAL_STEPS $ellipsis'); case FunkinPreloaderState.CachingAudio: - updateProgressLeftText('Caching audio (5/$TOTAL_STEPS)$ellipsis'); + updateProgressLeftText('Caching audio \n5/$TOTAL_STEPS $ellipsis'); case FunkinPreloaderState.CachingData: - updateProgressLeftText('Caching data (6/$TOTAL_STEPS)$ellipsis'); + updateProgressLeftText('Caching data \n6/$TOTAL_STEPS $ellipsis'); case FunkinPreloaderState.ParsingSpritesheets: - updateProgressLeftText('Parsing spritesheets (7/$TOTAL_STEPS)$ellipsis'); + updateProgressLeftText('Parsing spritesheets \n7/$TOTAL_STEPS $ellipsis'); case FunkinPreloaderState.ParsingStages: - updateProgressLeftText('Parsing stages (8/$TOTAL_STEPS)$ellipsis'); + updateProgressLeftText('Parsing stages \n8/$TOTAL_STEPS $ellipsis'); case FunkinPreloaderState.ParsingCharacters: - updateProgressLeftText('Parsing characters (9/$TOTAL_STEPS)$ellipsis'); + updateProgressLeftText('Parsing characters \n9/$TOTAL_STEPS $ellipsis'); case FunkinPreloaderState.ParsingSongs: - updateProgressLeftText('Parsing songs (10/$TOTAL_STEPS)$ellipsis'); + updateProgressLeftText('Parsing songs \n10/$TOTAL_STEPS $ellipsis'); case FunkinPreloaderState.Complete: - updateProgressLeftText('Finishing up ($TOTAL_STEPS/$TOTAL_STEPS)$ellipsis'); + updateProgressLeftText('Finishing up \n$TOTAL_STEPS/$TOTAL_STEPS $ellipsis'); #if TOUCH_HERE_TO_PLAY case FunkinPreloaderState.TouchHereToPlay: updateProgressLeftText(null); @@ -815,10 +925,21 @@ class FunkinPreloader extends FlxBasePreloader else if (progressLeftText.text != text) { // We have to keep updating the text format, because the font can take a frame or two to load. - var progressLeftTextFormat = new TextFormat("VCR OSD Mono", 16, Constants.COLOR_PRELOADER_BAR, true); + var progressLeftTextFormat = new TextFormat("DS-Digital", 32, Constants.COLOR_PRELOADER_BAR, true); progressLeftTextFormat.align = TextFormatAlign.LEFT; progressLeftText.defaultTextFormat = progressLeftTextFormat; progressLeftText.text = text; + + dspText.defaultTextFormat = new TextFormat("Quantico", 20, 0x000000, false); + dspText.text = 'DSP\t\t\t\t\tFNF'; // fukin dum.... + dspText.textColor = 0x000000; + + enhancedText.defaultTextFormat = new TextFormat("Inconsolata Black", 16, Constants.COLOR_PRELOADER_BAR, false); + enhancedText.text = 'ENHANCED'; + enhancedText.textColor = Constants.COLOR_PRELOADER_BAR; + + stereoText.defaultTextFormat = new TextFormat("Inconsolata Bold", 36, Constants.COLOR_PRELOADER_BAR, false); + stereoText.text = 'NATURAL STEREO'; } } } @@ -845,9 +966,17 @@ class FunkinPreloader extends FlxBasePreloader logo.y = (this._height - logo.height) / 2; // Fade out progress bar too. - progressBar.alpha = logo.alpha; + // progressBar.alpha = logo.alpha; progressLeftText.alpha = logo.alpha; progressRightText.alpha = logo.alpha; + box.alpha = logo.alpha; + dspText.alpha = logo.alpha; + enhancedText.alpha = logo.alpha; + stereoText.alpha = logo.alpha; + progressLines.alpha = logo.alpha; + + for (piece in progressBarPieces) + piece.alpha = logo.alpha; return elapsedFinished; } @@ -901,8 +1030,8 @@ class FunkinPreloader extends FlxBasePreloader { // Ensure the graphics are properly destroyed and GC'd. removeChild(logo); - removeChild(progressBar); - logo = progressBar = null; + // removeChild(progressBar); + logo = null; super.destroy(); } diff --git a/source/funkin/ui/transition/preload/VFDOverlay.hx b/source/funkin/ui/transition/preload/VFDOverlay.hx new file mode 100644 index 000000000..1792c56ec --- /dev/null +++ b/source/funkin/ui/transition/preload/VFDOverlay.hx @@ -0,0 +1,70 @@ +package funkin.ui.transition.preload; + +import flixel.tweens.FlxEase; +import flixel.tweens.FlxTween; +import openfl.display.GraphicsShader; + +class VFDOverlay extends GraphicsShader +{ + public var elapsedTime(default, set):Float = 0; + + function set_elapsedTime(value:Float):Float + { + u_time.value = [value]; + return value; + } + + @:glFragmentSource('#pragma header + const vec2 s = vec2(1, 1.7320508); + + uniform float u_time; + + float rand(float co) { return fract(sin(co*(91.3458)) * 47453.5453); } + float rand(vec2 co){ return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453); } + + void main(void) { + vec4 col = texture2D (bitmap, openfl_TextureCoordv); + vec2 game_res = vec2(1280.0, 720.0); + const float tileAmount = 10.; + + vec2 uv = (2. * openfl_TextureCoordv.xy * -1.); + uv *= 50.; + + vec4 hexCenter = floor(vec4(uv, uv - vec2(0.5, 1.0)) / s.xyxy) + 0.5; + vec4 offset = vec4(uv - hexCenter.xy * s, uv - (hexCenter.zw + 0.5) * s) + 0.0; + vec4 hexInfo = dot(offset.xy, offset.xy) < dot(offset.zw, offset.zw) ? vec4(offset.xy, hexCenter.xy) : vec4(offset.zw, hexCenter.zw); + + // Distance to the nearest edge of a hexagon + vec2 p = abs(hexInfo.xy) ; + float edgeDist = max(dot(p, normalize(vec2(1.0, sqrt(3.0)))), p.x); + float edgeWidth = 0.05 * tileAmount; // Adjust edge width based on tile amount + float edgeSharpness = 0.011 * tileAmount; + + float outline = smoothstep(edgeWidth - edgeSharpness, edgeWidth, edgeDist); + float color_mix = mix(0.0, 0.3, outline); // Mix black outline with white fill + + float flicker = (sin(u_time) * 0.05) + 1.0; + float sinshit = smoothstep(-3.0, 1.0, sin(uv.y * 3.)); + + col = vec4(vec3(0.0), color_mix); + col = mix(col, vec4(0., 0., 0., sinshit), 0.5 * flicker); + + float specs = rand(uv.xy); + vec4 noise = vec4(0., 0., 0., specs); + col = mix(col, noise, 0.1); + + gl_FragColor = col; + } + ') + public function new() + { + super(); + + this.elapsedTime = 0; + } + + public function update(elapsed:Float):Void + { + this.elapsedTime += elapsed; + } +} diff --git a/source/funkin/util/Constants.hx b/source/funkin/util/Constants.hx index 5d355f2da..33525a7e2 100644 --- a/source/funkin/util/Constants.hx +++ b/source/funkin/util/Constants.hx @@ -135,7 +135,7 @@ class Constants /** * Color for the preloader progress bar */ - public static final COLOR_PRELOADER_BAR:FlxColor = 0xFF00FF00; + public static final COLOR_PRELOADER_BAR:FlxColor = 0xFF9DDF35; /** * Color for the preloader site lock background From f19507bd957a45c784883f4beef37017aa57e1ca Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Fri, 29 Mar 2024 23:00:42 -0400 Subject: [PATCH 043/130] Add a bunch of erect songs --- assets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets b/assets index 65e6ff18c..208d1ab80 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit 65e6ff18c7fcbd646ac7a3676ca5c2baa95b5fea +Subproject commit 208d1ab80739cb728de3a64535ef3e3bee0843b0 From 846df8de6fa3f207cc4a12cfa175215679c833ea Mon Sep 17 00:00:00 2001 From: Cameron Taylor Date: Sat, 30 Mar 2024 03:06:39 -0400 Subject: [PATCH 044/130] assets submod --- assets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets b/assets index 5d78b0705..3b168f7ca 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit 5d78b070535d6a1d88c5b450fc092eb6cd331f78 +Subproject commit 3b168f7cac41e1843de9a223453d0ff4c04b0283 From 3637e3594ba85e1e0344ab33053b8960edd86b3b Mon Sep 17 00:00:00 2001 From: Cameron Taylor Date: Sat, 30 Mar 2024 03:24:30 -0400 Subject: [PATCH 045/130] assets submod --- assets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets b/assets index 15c3f16c7..200658724 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit 15c3f16c7ec162b7c8d86421b624d74501b9616f +Subproject commit 200658724592b298f49b13016f2c706c54ad538f From fe498b38e51babb076a1a94003be002dc17ac2fe Mon Sep 17 00:00:00 2001 From: Cameron Taylor Date: Sat, 30 Mar 2024 03:32:17 -0400 Subject: [PATCH 046/130] assets submod --- assets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets b/assets index 2a0afcd76..763c833cb 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit 2a0afcd76a26251dbbebb6901df4651f25a92c23 +Subproject commit 763c833cbcde724d50ff31f5bac9f2ac3d5e61a7 From 1df4a354cb3ac7663f2c43da96e555edec7c6724 Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Mon, 1 Apr 2024 18:34:26 -0400 Subject: [PATCH 047/130] Freeplay menu now filters to supported songs when you change difficulty --- source/funkin/ui/freeplay/FreeplayState.hx | 70 +++++++++++++++++----- source/funkin/util/Constants.hx | 6 ++ 2 files changed, 60 insertions(+), 16 deletions(-) diff --git a/source/funkin/ui/freeplay/FreeplayState.hx b/source/funkin/ui/freeplay/FreeplayState.hx index 6cb0d1d9a..471fe7e28 100644 --- a/source/funkin/ui/freeplay/FreeplayState.hx +++ b/source/funkin/ui/freeplay/FreeplayState.hx @@ -536,21 +536,18 @@ class FreeplayState extends MusicBeatSubState }); } + var currentFilter:SongFilter = null; + var currentFilteredSongs:Array = []; + /** * Given the current filter, rebuild the current song list. * * @param filterStuff A filter to apply to the song list (regex, startswith, all, favorite) * @param force + * @param onlyIfChanged Only apply the filter if the song list has changed */ - public function generateSongList(?filterStuff:SongFilter, force:Bool = false):Void + public function generateSongList(filterStuff:Null, force:Bool = false, onlyIfChanged:Bool = true):Void { - curSelected = 1; - - for (cap in grpCapsules.members) - { - cap.kill(); - } - var tempSongs:Array = songs; if (filterStuff != null) @@ -582,6 +579,35 @@ class FreeplayState extends MusicBeatSubState } } + // Filter further by current selected difficulty. + if (currentDifficulty != null) + { + tempSongs = tempSongs.filter(song -> { + if (song == null) return true; // Random + return song.songDifficulties.contains(currentDifficulty); + }); + } + + if (onlyIfChanged) + { + // == performs equality by reference + if (tempSongs.isEqualUnordered(currentFilteredSongs)) return; + } + + // Only now do we know that the filter is actually changing. + + rememberedSongId = grpCapsules.members[curSelected]?.songData?.songId; + + for (cap in grpCapsules.members) + { + cap.kill(); + } + + currentFilter = filterStuff; + + currentFilteredSongs = tempSongs; + curSelected = 0; + var hsvShader:HSVShader = new HSVShader(); var randomCapsule:SongMenuItem = grpCapsules.recycle(SongMenuItem); @@ -658,11 +684,12 @@ class FreeplayState extends MusicBeatSubState if (FlxG.keys.justPressed.F) { - if (songs[curSelected] != null) + var targetSong = grpCapsules.members[curSelected]?.songData; + if (targetSong != null) { var realShit:Int = curSelected; - songs[curSelected].isFav = !songs[curSelected].isFav; - if (songs[curSelected].isFav) + targetSong.isFav = !targetSong.isFav; + if (targetSong.isFav) { FlxTween.tween(grpCapsules.members[realShit], {angle: 360}, 0.4, { @@ -854,11 +881,13 @@ class FreeplayState extends MusicBeatSubState { dj.resetAFKTimer(); changeDiff(-1); + generateSongList(currentFilter, true); } if (controls.UI_RIGHT_P && !FlxG.keys.pressed.CONTROL) { dj.resetAFKTimer(); changeDiff(1); + generateSongList(currentFilter, true); } if (controls.BACK && !typing.hasFocus) @@ -926,7 +955,7 @@ class FreeplayState extends MusicBeatSubState public override function destroy():Void { super.destroy(); - var daSong:Null = songs[curSelected]; + var daSong:Null = grpCapsules.members[curSelected]?.songData; if (daSong != null) { clearDaCache(daSong.songName); @@ -948,10 +977,10 @@ class FreeplayState extends MusicBeatSubState currentDifficulty = diffIdsCurrent[currentDifficultyIndex]; - var daSong:Null = songs[curSelected]; + var daSong:Null = grpCapsules.members[curSelected].songData; if (daSong != null) { - var songScore:SaveScoreData = Save.instance.getSongScore(songs[curSelected].songId, currentDifficulty); + var songScore:SaveScoreData = Save.instance.getSongScore(grpCapsules.members[curSelected].songData.songId, currentDifficulty); intendedScore = songScore?.score ?? 0; intendedCompletion = songScore?.accuracy ?? 0.0; rememberedDifficulty = currentDifficulty; @@ -1103,6 +1132,12 @@ class FreeplayState extends MusicBeatSubState targetVariation: targetVariation, practiceMode: false, minimalMode: false, + + #if (debug || FORCE_DEBUG_VERSION) + botPlayMode: FlxG.keys.pressed.SHIFT, + #else + botPlayMode: false, + #end // TODO: Make these an option! It's currently only accessible via chart editor. // startTimestamp: 0.0, // playbackRate: 0.5, @@ -1115,10 +1150,12 @@ class FreeplayState extends MusicBeatSubState { if (rememberedSongId != null) { - curSelected = songs.findIndex(function(song) { + curSelected = currentFilteredSongs.findIndex(function(song) { if (song == null) return false; return song.songId == rememberedSongId; }); + + if (curSelected == -1) curSelected = 0; } if (rememberedDifficulty != null) @@ -1127,7 +1164,7 @@ class FreeplayState extends MusicBeatSubState } // Set the difficulty star count on the right. - var daSong:Null = songs[curSelected]; + var daSong:Null = grpCapsules.members[curSelected]?.songData; albumRoll.setDifficultyStars(daSong?.songRating ?? 0); } @@ -1156,6 +1193,7 @@ class FreeplayState extends MusicBeatSubState { intendedScore = 0; intendedCompletion = 0.0; + diffIdsCurrent = diffIdsTotal; rememberedSongId = null; rememberedDifficulty = null; } diff --git a/source/funkin/util/Constants.hx b/source/funkin/util/Constants.hx index 5d355f2da..13a6f65b5 100644 --- a/source/funkin/util/Constants.hx +++ b/source/funkin/util/Constants.hx @@ -181,6 +181,12 @@ class Constants */ public static final DEFAULT_DIFFICULTY_LIST:Array = ['easy', 'normal', 'hard']; + /** + * List of all difficulties used by the base game. + * Includes Erect and Nightmare. + */ + public static final DEFAULT_DIFFICULTY_LIST_FULL:Array = ['easy', 'normal', 'hard', 'erect', 'nightmare']; + /** * Default player character for charts. */ From 927b2a7cfc5ef956e77aae1a7dd7660f8d9a738a Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Mon, 1 Apr 2024 13:05:16 -0400 Subject: [PATCH 048/130] Put judgements below the notes, and remove COMBO word. --- source/funkin/play/PlayState.hx | 6 ++++-- source/funkin/play/components/PopUpStuff.hx | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/source/funkin/play/PlayState.hx b/source/funkin/play/PlayState.hx index 274ee4fe8..97dd96016 100644 --- a/source/funkin/play/PlayState.hx +++ b/source/funkin/play/PlayState.hx @@ -728,6 +728,10 @@ class PlayState extends MusicBeatSubState #end initialized = true; + + // This step ensures z-indexes are applied properly, + // and it's important to call it last so all elements get affected. + refresh(); } public override function draw():Void @@ -1720,8 +1724,6 @@ class PlayState extends MusicBeatSubState playerStrumline.fadeInArrows(); opponentStrumline.fadeInArrows(); } - - this.refresh(); } /** diff --git a/source/funkin/play/components/PopUpStuff.hx b/source/funkin/play/components/PopUpStuff.hx index 39fc192a0..724bf0cb9 100644 --- a/source/funkin/play/components/PopUpStuff.hx +++ b/source/funkin/play/components/PopUpStuff.hx @@ -85,7 +85,7 @@ class PopUpStuff extends FlxTypedGroup comboSpr.velocity.y -= 150; comboSpr.velocity.x += FlxG.random.int(1, 10); - add(comboSpr); + // add(comboSpr); if (PlayState.instance.currentStageId.startsWith('school')) { From 67e096e4430a84bac3e04da02fe249240866c7e0 Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Mon, 1 Apr 2024 21:59:53 -0400 Subject: [PATCH 049/130] Bunch of results screen fixes --- source/funkin/Highscore.hx | 4 ++ source/funkin/play/PauseSubState.hx | 2 + source/funkin/play/PlayState.hx | 43 +++++++++--- source/funkin/play/ResultState.hx | 68 +++++++++++++------ source/funkin/play/components/TallyCounter.hx | 23 +++++-- source/funkin/ui/freeplay/FreeplayState.hx | 4 +- 6 files changed, 106 insertions(+), 38 deletions(-) diff --git a/source/funkin/Highscore.hx b/source/funkin/Highscore.hx index 996e2367e..94f41cea4 100644 --- a/source/funkin/Highscore.hx +++ b/source/funkin/Highscore.hx @@ -59,6 +59,7 @@ abstract Tallies(RawTallies) totalNotes: 0, totalNotesHit: 0, maxCombo: 0, + score: 0, isNewHighscore: false } } @@ -81,6 +82,9 @@ typedef RawTallies = var good:Int; var sick:Int; var maxCombo:Int; + + var score:Int; + var isNewHighscore:Bool; /** diff --git a/source/funkin/play/PauseSubState.hx b/source/funkin/play/PauseSubState.hx index ed847402a..2af04749f 100644 --- a/source/funkin/play/PauseSubState.hx +++ b/source/funkin/play/PauseSubState.hx @@ -567,6 +567,8 @@ class PauseSubState extends MusicBeatSubState PlayStatePlaylist.campaignDifficulty = difficulty; PlayState.instance.currentDifficulty = PlayStatePlaylist.campaignDifficulty; + FreeplayState.rememberedDifficulty = difficulty; + PlayState.instance.needsReset = true; state.close(); diff --git a/source/funkin/play/PlayState.hx b/source/funkin/play/PlayState.hx index 274ee4fe8..438941f90 100644 --- a/source/funkin/play/PlayState.hx +++ b/source/funkin/play/PlayState.hx @@ -2731,7 +2731,7 @@ class PlayState extends MusicBeatSubState */ public function endSong(rightGoddamnNow:Bool = false):Void { - FlxG.sound.music.volume = 0; + if (FlxG.sound.music != null) FlxG.sound.music.volume = 0; vocals.volume = 0; mayPauseGame = false; @@ -2749,6 +2749,8 @@ class PlayState extends MusicBeatSubState deathCounter = 0; + var isNewHighscore = false; + if (currentSong != null && currentSong.validScore) { // crackhead double thingie, sets whether was new highscore, AND saves the song! @@ -2779,11 +2781,14 @@ class PlayState extends MusicBeatSubState #if newgrounds NGio.postScore(score, currentSong.id); #end + isNewHighscore = true; } } if (PlayStatePlaylist.isStoryMode) { + isNewHighscore = false; + PlayStatePlaylist.campaignScore += songScore; // Pop the next song ID from the list. @@ -2833,6 +2838,7 @@ class PlayState extends MusicBeatSubState #if newgrounds NGio.postScore(score, 'Level ${PlayStatePlaylist.campaignId}'); #end + isNewHighscore = true; } } @@ -2844,11 +2850,11 @@ class PlayState extends MusicBeatSubState { if (rightGoddamnNow) { - moveToResultsScreen(); + moveToResultsScreen(isNewHighscore); } else { - zoomIntoResultsScreen(); + zoomIntoResultsScreen(isNewHighscore); } } } @@ -2909,11 +2915,11 @@ class PlayState extends MusicBeatSubState { if (rightGoddamnNow) { - moveToResultsScreen(); + moveToResultsScreen(isNewHighscore); } else { - zoomIntoResultsScreen(); + zoomIntoResultsScreen(isNewHighscore); } } } @@ -2987,7 +2993,7 @@ class PlayState extends MusicBeatSubState /** * Play the camera zoom animation and then move to the results screen once it's done. */ - function zoomIntoResultsScreen():Void + function zoomIntoResultsScreen(isNewHighscore:Bool):Void { trace('WENT TO RESULTS SCREEN!'); @@ -3044,7 +3050,7 @@ class PlayState extends MusicBeatSubState { ease: FlxEase.expoIn, onComplete: function(_) { - moveToResultsScreen(); + moveToResultsScreen(isNewHighscore); } }); }); @@ -3053,7 +3059,7 @@ class PlayState extends MusicBeatSubState /** * Move to the results screen right goddamn now. */ - function moveToResultsScreen():Void + function moveToResultsScreen(isNewHighscore:Bool):Void { persistentUpdate = false; vocals.stop(); @@ -3065,7 +3071,24 @@ class PlayState extends MusicBeatSubState { storyMode: PlayStatePlaylist.isStoryMode, title: PlayStatePlaylist.isStoryMode ? ('${PlayStatePlaylist.campaignTitle}') : ('${currentChart.songName} by ${currentChart.songArtist}'), - tallies: talliesToUse, + scoreData: + { + score: songScore, + tallies: + { + sick: Highscore.tallies.sick, + good: Highscore.tallies.good, + bad: Highscore.tallies.bad, + shit: Highscore.tallies.shit, + missed: Highscore.tallies.missed, + combo: Highscore.tallies.combo, + maxCombo: Highscore.tallies.maxCombo, + totalNotesHit: Highscore.tallies.totalNotesHit, + totalNotes: Highscore.tallies.totalNotes, + }, + accuracy: Highscore.tallies.totalNotesHit / Highscore.tallies.totalNotes, + }, + isNewHighscore: isNewHighscore }); res.camera = camHUD; openSubState(res); @@ -3212,7 +3235,7 @@ class PlayState extends MusicBeatSubState // Don't go back in time to before the song started. targetTimeMs = Math.max(0, targetTimeMs); - FlxG.sound.music.time = targetTimeMs; + if (FlxG.sound.music != null) FlxG.sound.music.time = targetTimeMs; handleSkippedNotes(); SongEventRegistry.handleSkippedEvents(songEvents, Conductor.instance.songPosition); diff --git a/source/funkin/play/ResultState.hx b/source/funkin/play/ResultState.hx index 821f4ba3c..7dbaf087f 100644 --- a/source/funkin/play/ResultState.hx +++ b/source/funkin/play/ResultState.hx @@ -1,5 +1,6 @@ package funkin.play; +import funkin.util.MathUtil; import funkin.ui.story.StoryMenuState; import funkin.graphics.adobeanimate.FlxAtlasSprite; import flixel.FlxSprite; @@ -16,6 +17,8 @@ import flixel.tweens.FlxTween; import funkin.audio.FunkinSound; import flixel.util.FlxGradient; import flixel.util.FlxTimer; +import funkin.save.Save; +import funkin.save.Save.SaveScoreData; import funkin.graphics.shaders.LeftMaskShader; import funkin.play.components.TallyCounter; @@ -42,12 +45,15 @@ class ResultState extends MusicBeatSubState override function create():Void { - if (params.tallies.sick == params.tallies.totalNotesHit - && params.tallies.maxCombo == params.tallies.totalNotesHit) resultsVariation = PERFECT; - else if (params.tallies.missed + params.tallies.bad + params.tallies.shit >= params.tallies.totalNotes * 0.50) - resultsVariation = SHIT; // if more than half of your song was missed, bad, or shit notes, you get shit ending! - else - resultsVariation = NORMAL; + /* + if (params.scoreData.sick == params.scoreData.totalNotesHit + && params.scoreData.maxCombo == params.scoreData.totalNotesHit) resultsVariation = PERFECT; + else if (params.scoreData.missed + params.scoreData.bad + params.scoreData.shit >= params.scoreData.totalNotes * 0.50) + resultsVariation = SHIT; // if more than half of your song was missed, bad, or shit notes, you get shit ending! + else + resultsVariation = NORMAL; + */ + resultsVariation = NORMAL; FunkinSound.playMusic('results$resultsVariation', { @@ -130,12 +136,16 @@ class ResultState extends MusicBeatSubState var diffSpr:String = switch (PlayState.instance.currentDifficulty) { - case 'EASY': + case 'easy': 'difEasy'; - case 'NORMAL': + case 'normal': 'difNormal'; - case 'HARD': + case 'hard': 'difHard'; + case 'erect': + 'difErect'; + case 'nightmare': + 'difNightmare'; case _: 'difNormal'; } @@ -195,29 +205,33 @@ class ResultState extends MusicBeatSubState * NOTE: We display how many notes were HIT, not how many notes there were in total. * */ - var totalHit:TallyCounter = new TallyCounter(375, hStuf * 3, params.tallies.totalNotesHit); + var totalHit:TallyCounter = new TallyCounter(375, hStuf * 3, params.scoreData.tallies.totalNotesHit); ratingGrp.add(totalHit); - var maxCombo:TallyCounter = new TallyCounter(375, hStuf * 4, params.tallies.maxCombo); + var maxCombo:TallyCounter = new TallyCounter(375, hStuf * 4, params.scoreData.tallies.maxCombo); ratingGrp.add(maxCombo); hStuf += 2; var extraYOffset:Float = 5; - var tallySick:TallyCounter = new TallyCounter(230, (hStuf * 5) + extraYOffset, params.tallies.sick, 0xFF89E59E); + var tallySick:TallyCounter = new TallyCounter(230, (hStuf * 5) + extraYOffset, params.scoreData.tallies.sick, 0xFF89E59E); ratingGrp.add(tallySick); - var tallyGood:TallyCounter = new TallyCounter(210, (hStuf * 6) + extraYOffset, params.tallies.good, 0xFF89C9E5); + var tallyGood:TallyCounter = new TallyCounter(210, (hStuf * 6) + extraYOffset, params.scoreData.tallies.good, 0xFF89C9E5); ratingGrp.add(tallyGood); - var tallyBad:TallyCounter = new TallyCounter(190, (hStuf * 7) + extraYOffset, params.tallies.bad, 0xFFE6CF8A); + var tallyBad:TallyCounter = new TallyCounter(190, (hStuf * 7) + extraYOffset, params.scoreData.tallies.bad, 0xFFE6CF8A); ratingGrp.add(tallyBad); - var tallyShit:TallyCounter = new TallyCounter(220, (hStuf * 8) + extraYOffset, params.tallies.shit, 0xFFE68C8A); + var tallyShit:TallyCounter = new TallyCounter(220, (hStuf * 8) + extraYOffset, params.scoreData.tallies.shit, 0xFFE68C8A); ratingGrp.add(tallyShit); - var tallyMissed:TallyCounter = new TallyCounter(260, (hStuf * 9) + extraYOffset, params.tallies.missed, 0xFFC68AE6); + var tallyMissed:TallyCounter = new TallyCounter(260, (hStuf * 9) + extraYOffset, params.scoreData.tallies.missed, 0xFFC68AE6); ratingGrp.add(tallyMissed); + var score:TallyCounter = new TallyCounter(825, 630, params.scoreData.score, RIGHT); + score.scale.set(2, 2); + ratingGrp.add(score); + for (ind => rating in ratingGrp.members) { rating.visible = false; @@ -235,9 +249,16 @@ class ResultState extends MusicBeatSubState scorePopin.animation.play("score"); scorePopin.visible = true; - highscoreNew.visible = true; - highscoreNew.animation.play("new"); - FlxTween.tween(highscoreNew, {y: highscoreNew.y + 10}, 0.8, {ease: FlxEase.quartOut}); + if (params.isNewHighscore) + { + highscoreNew.visible = true; + highscoreNew.animation.play("new"); + FlxTween.tween(highscoreNew, {y: highscoreNew.y + 10}, 0.8, {ease: FlxEase.quartOut}); + } + else + { + highscoreNew.visible = false; + } }; switch (resultsVariation) @@ -276,8 +297,6 @@ class ResultState extends MusicBeatSubState } }); - if (params.tallies.isNewHighscore) trace("ITS A NEW HIGHSCORE!!!"); - super.create(); } @@ -393,8 +412,13 @@ typedef ResultsStateParams = */ var title:String; + /** + * Whether the displayed score is a new highscore + */ + var isNewHighscore:Bool; + /** * The score, accuracy, and judgements. */ - var tallies:Highscore.Tallies; + var scoreData:SaveScoreData; }; diff --git a/source/funkin/play/components/TallyCounter.hx b/source/funkin/play/components/TallyCounter.hx index 77e6ef4ec..35a8f3f51 100644 --- a/source/funkin/play/components/TallyCounter.hx +++ b/source/funkin/play/components/TallyCounter.hx @@ -6,6 +6,8 @@ import flixel.group.FlxSpriteGroup.FlxTypedSpriteGroup; import flixel.math.FlxMath; import flixel.tweens.FlxEase; import flixel.tweens.FlxTween; +import flixel.text.FlxText.FlxTextAlign; +import funkin.util.MathUtil; /** * Numerical counters used next to each judgement in the Results screen. @@ -13,18 +15,23 @@ import flixel.tweens.FlxTween; class TallyCounter extends FlxTypedSpriteGroup { public var curNumber:Float = 0; - public var neededNumber:Int = 0; + public var flavour:Int = 0xFFFFFFFF; - public function new(x:Float, y:Float, neededNumber:Int = 0, ?flavour:Int = 0xFFFFFFFF) + public var align:FlxTextAlign = FlxTextAlign.LEFT; + + public function new(x:Float, y:Float, neededNumber:Int = 0, ?flavour:Int = 0xFFFFFFFF, align:FlxTextAlign = FlxTextAlign.LEFT) { super(x, y); + this.align = align; + this.flavour = flavour; this.neededNumber = neededNumber; - drawNumbers(); + + if (curNumber == neededNumber) drawNumbers(); } var tmr:Float = 0; @@ -41,6 +48,8 @@ class TallyCounter extends FlxTypedSpriteGroup var seperatedScore:Array = []; var tempCombo:Int = Math.round(curNumber); + var fullNumberDigits:Int = Std.int(Math.max(1, Math.ceil(MathUtil.logBase(10, neededNumber)))); + while (tempCombo != 0) { seperatedScore.push(tempCombo % 10); @@ -55,7 +64,13 @@ class TallyCounter extends FlxTypedSpriteGroup { if (ind >= members.length) { - var numb:TallyNumber = new TallyNumber(ind * 43, 0, num); + var xPos = ind * (43 * this.scale.x); + if (this.align == FlxTextAlign.RIGHT) + { + xPos -= (fullNumberDigits * (43 * this.scale.x)); + } + var numb:TallyNumber = new TallyNumber(xPos, 0, num); + numb.scale.set(this.scale.x, this.scale.y); add(numb); numb.color = flavour; } diff --git a/source/funkin/ui/freeplay/FreeplayState.hx b/source/funkin/ui/freeplay/FreeplayState.hx index 6cb0d1d9a..058f61a5b 100644 --- a/source/funkin/ui/freeplay/FreeplayState.hx +++ b/source/funkin/ui/freeplay/FreeplayState.hx @@ -133,8 +133,8 @@ class FreeplayState extends MusicBeatSubState var stickerSubState:StickerSubState; - static var rememberedDifficulty:Null = Constants.DEFAULT_DIFFICULTY; - static var rememberedSongId:Null = null; + public static var rememberedDifficulty:Null = Constants.DEFAULT_DIFFICULTY; + public static var rememberedSongId:Null = null; public function new(?params:FreeplayStateParams, ?stickers:StickerSubState) { From 626cc5cc78d6543fae7b1095049e97609c2e9f59 Mon Sep 17 00:00:00 2001 From: Cameron Taylor Date: Mon, 1 Apr 2024 22:06:44 -0400 Subject: [PATCH 050/130] assets submod --- assets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets b/assets index b2144938c..d7e85ef60 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit b2144938c899e4a5d2d05466f710aa75ff4e1d1c +Subproject commit d7e85ef60933ca93d47e1db6295aba8aa64fcbdf From 02b8aa0f1246f4e5c710759668e5f8b9a7fa9d19 Mon Sep 17 00:00:00 2001 From: Cameron Taylor Date: Mon, 1 Apr 2024 22:13:38 -0400 Subject: [PATCH 051/130] assets submod --- assets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets b/assets index 04605b7e3..d7e85ef60 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit 04605b7e3ab7556b395476aa31b8853ff5243c6f +Subproject commit d7e85ef60933ca93d47e1db6295aba8aa64fcbdf From d4117c2e6a263152a0a8bc278b3fb5318497d3d1 Mon Sep 17 00:00:00 2001 From: Cameron Taylor Date: Mon, 1 Apr 2024 22:21:10 -0400 Subject: [PATCH 052/130] assets submod --- assets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets b/assets index 349b3e018..346da48a8 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit 349b3e01813ce7174cd4406be3fbefe94c61946e +Subproject commit 346da48a86f07a9c6372bf92c64d68802ae75078 From 5ecedef88aac329c8e1262fc0702f26f275fee3d Mon Sep 17 00:00:00 2001 From: Cameron Taylor Date: Mon, 1 Apr 2024 22:30:54 -0400 Subject: [PATCH 053/130] assets submod --- assets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets b/assets index 208d1ab80..dfa5ca25a 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit 208d1ab80739cb728de3a64535ef3e3bee0843b0 +Subproject commit dfa5ca25a32c834c1f21c39b0c4d6e4830d6f799 From 8cb11d081d2f6ab40175a4ca0901d59b297dadc9 Mon Sep 17 00:00:00 2001 From: Cameron Taylor Date: Mon, 1 Apr 2024 22:31:19 -0400 Subject: [PATCH 054/130] art submod --- art | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/art b/art index 03e7c2a23..00463685f 160000 --- a/art +++ b/art @@ -1 +1 @@ -Subproject commit 03e7c2a2353b184e45955c96d763b7cdf1acbc34 +Subproject commit 00463685fa570f0c853d08e250b46ef80f30bc48 From ddda7f6a01f83f52bbfe6122161cda906aea32cf Mon Sep 17 00:00:00 2001 From: Cameron Taylor Date: Mon, 1 Apr 2024 22:35:56 -0400 Subject: [PATCH 055/130] assets submod --- assets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets b/assets index 44d74c089..cb862903e 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit 44d74c0898b630a98344ef22987be73140e932c3 +Subproject commit cb862903ec0975364c13080297ccbfb13f26f5cb From 7ae44c56201ed1c5e9bd58c61cd13eb7d76b8a9c Mon Sep 17 00:00:00 2001 From: Cameron Taylor Date: Mon, 1 Apr 2024 22:39:48 -0400 Subject: [PATCH 056/130] assets submod --- assets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets b/assets index 77e64da9e..a54eb8517 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit 77e64da9e9836c0272ff7351444881aa90f60eb6 +Subproject commit a54eb8517914e2a90b77e122ecd81cf73d60adaa From 90cf53b959ed014946a7d0d87841f5924d5b74ad Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Tue, 2 Apr 2024 17:27:29 -0400 Subject: [PATCH 057/130] Someone forgot to merge assets from the credits branch. --- assets | 2 +- source/funkin/ui/credits/CreditsDataHandler.hx | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/assets b/assets index a54eb8517..3ccfe33ac 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit a54eb8517914e2a90b77e122ecd81cf73d60adaa +Subproject commit 3ccfe33acef6e62c40317af583af764838544a24 diff --git a/source/funkin/ui/credits/CreditsDataHandler.hx b/source/funkin/ui/credits/CreditsDataHandler.hx index f2722ffbf..86afdafd1 100644 --- a/source/funkin/ui/credits/CreditsDataHandler.hx +++ b/source/funkin/ui/credits/CreditsDataHandler.hx @@ -20,7 +20,12 @@ class CreditsDataHandler if (data == null) { trace('CreditsData(NULL)'); + return; + } + if (data.entries == null || data.entries.length == 0) + { + trace('CreditsData(EMPTY)'); return; } From f7ff381bc7d526977d55a61f059fc60de747ef4a Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Tue, 2 Apr 2024 23:33:10 -0400 Subject: [PATCH 058/130] Fix some build issues with HTML5. --- source/funkin/ui/debug/latency/LatencyState.hx | 5 +---- source/funkin/ui/transition/LoadingState.hx | 4 ++-- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/source/funkin/ui/debug/latency/LatencyState.hx b/source/funkin/ui/debug/latency/LatencyState.hx index 7b2eabb1c..875a956e0 100644 --- a/source/funkin/ui/debug/latency/LatencyState.hx +++ b/source/funkin/ui/debug/latency/LatencyState.hx @@ -171,10 +171,7 @@ class LatencyState extends MusicBeatSubState trace(FlxG.sound.music._channel.position); */ - #if FLX_DEBUG - funnyStatsGraph.update(FlxG.sound.music.time % 500); - realStats.update(swagSong.getTimeWithDiff() % 500); - #end + localConductor.update(swagSong.time, false); if (FlxG.keys.justPressed.S) { diff --git a/source/funkin/ui/transition/LoadingState.hx b/source/funkin/ui/transition/LoadingState.hx index e4f4bf004..af8798ae2 100644 --- a/source/funkin/ui/transition/LoadingState.hx +++ b/source/funkin/ui/transition/LoadingState.hx @@ -222,7 +222,7 @@ class LoadingState extends MusicBeatSubState #if NO_PRELOAD_ALL // Switch to loading state while we load assets (default on HTML5 target). - var loadStateCtor:NextState = function() { + var loadStateCtor = function() { var result = new LoadingState(playStateCtor, shouldStopMusic, params); @:privateAccess result.asSubState = asSubState; @@ -230,7 +230,7 @@ class LoadingState extends MusicBeatSubState } if (asSubState) { - FlxG.state.openSubState(loadStateCtor); + FlxG.state.openSubState(cast loadStateCtor()); } else { From 2b4bf42ac4c55ec3524be7d0109e6814e241bf6a Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Wed, 3 Apr 2024 01:40:08 -0400 Subject: [PATCH 059/130] Fix multiple music, and crashes in freeplay --- source/funkin/audio/FunkinSound.hx | 20 +++++++------------- source/funkin/ui/freeplay/FreeplayState.hx | 9 +++++++-- 2 files changed, 14 insertions(+), 15 deletions(-) diff --git a/source/funkin/audio/FunkinSound.hx b/source/funkin/audio/FunkinSound.hx index 100cee262..8c1bf3b41 100644 --- a/source/funkin/audio/FunkinSound.hx +++ b/source/funkin/audio/FunkinSound.hx @@ -321,6 +321,13 @@ class FunkinSound extends FlxSound implements ICloneable } } + if (FlxG.sound.music != null) + { + FlxG.sound.music.fadeTween?.cancel(); + FlxG.sound.music.stop(); + FlxG.sound.music.kill(); + } + if (params?.mapTimeChanges ?? true) { var songMusicData:Null = SongRegistry.instance.parseMusicData(key); @@ -335,19 +342,6 @@ class FunkinSound extends FlxSound implements ICloneable } } - if (FlxG.sound.music != null) - { - FlxG.sound.music.fadeTween?.cancel(); - FlxG.sound.music.stop(); - FlxG.sound.music.kill(); - } - - // Apparently HaxeFlixel isn't null safe. - @:nullSafety(Off) - { - FlxG.sound.music = FunkinSound.load(Paths.music('$key/$key'), params?.startingVolume ?? 1.0, true, false, true); - } - var music = FunkinSound.load(Paths.music('$key/$key'), params?.startingVolume ?? 1.0, params.loop ?? true, false, true); if (music != null) { diff --git a/source/funkin/ui/freeplay/FreeplayState.hx b/source/funkin/ui/freeplay/FreeplayState.hx index 531167a95..455805479 100644 --- a/source/funkin/ui/freeplay/FreeplayState.hx +++ b/source/funkin/ui/freeplay/FreeplayState.hx @@ -134,7 +134,7 @@ class FreeplayState extends MusicBeatSubState var stickerSubState:StickerSubState; public static var rememberedDifficulty:Null = Constants.DEFAULT_DIFFICULTY; - public static var rememberedSongId:Null = null; + public static var rememberedSongId:Null = 'tutorial'; public function new(?params:FreeplayStateParams, ?stickers:StickerSubState) { @@ -596,7 +596,7 @@ class FreeplayState extends MusicBeatSubState // Only now do we know that the filter is actually changing. - rememberedSongId = grpCapsules.members[curSelected]?.songData?.songId; + rememberedSongId = grpCapsules.members[curSelected]?.songData?.songId ?? rememberedSongId; for (cap in grpCapsules.members) { @@ -939,6 +939,11 @@ class FreeplayState extends MusicBeatSubState FlxTransitionableState.skipNextTransOut = true; if (Type.getClass(FlxG.state) == MainMenuState) { + FunkinSound.playMusic('freakyMenu', + { + overrideExisting: true, + restartTrack: false + }); close(); } else From f7141e7096f25a4a3a9986afe6c26357376ae49e Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Wed, 3 Apr 2024 01:01:58 -0400 Subject: [PATCH 060/130] Fixed an issue with save data not loading defaults properly. --- source/funkin/save/Save.hx | 8 +-- .../funkin/save/migrator/SaveDataMigrator.hx | 3 +- source/funkin/ui/freeplay/FreeplayState.hx | 2 +- source/funkin/util/StructureUtil.hx | 61 +++++++++++++++++++ 4 files changed, 68 insertions(+), 6 deletions(-) create mode 100644 source/funkin/util/StructureUtil.hx diff --git a/source/funkin/save/Save.hx b/source/funkin/save/Save.hx index 73ba8efa0..dc7c5f989 100644 --- a/source/funkin/save/Save.hx +++ b/source/funkin/save/Save.hx @@ -14,7 +14,7 @@ import thx.semver.Version; class Save { // Version 2.0.2 adds attributes to `optionsChartEditor`, that should return default values if they are null. - public static final SAVE_DATA_VERSION:thx.semver.Version = "2.0.2"; + public static final SAVE_DATA_VERSION:thx.semver.Version = "2.0.3"; public static final SAVE_DATA_VERSION_RULE:thx.semver.VersionRule = "2.0.x"; // We load this version's saves from a new save path, to maintain SOME level of backwards compatibility. @@ -650,9 +650,9 @@ class Save if (legacySaveData != null) { trace('[SAVE] Found legacy save data, converting...'); - var gameSave = SaveDataMigrator.migrate(legacySaveData); + var gameSave = SaveDataMigrator.migrateFromLegacy(legacySaveData); @:privateAccess - FlxG.save.mergeData(gameSave.data); + FlxG.save.mergeData(gameSave.data, true); } else { @@ -664,7 +664,7 @@ class Save trace('[SAVE] Loaded save data.'); @:privateAccess var gameSave = SaveDataMigrator.migrate(FlxG.save.data); - FlxG.save.mergeData(gameSave.data); + FlxG.save.mergeData(gameSave.data, true); } } diff --git a/source/funkin/save/migrator/SaveDataMigrator.hx b/source/funkin/save/migrator/SaveDataMigrator.hx index 00637d52a..3ed59e726 100644 --- a/source/funkin/save/migrator/SaveDataMigrator.hx +++ b/source/funkin/save/migrator/SaveDataMigrator.hx @@ -3,6 +3,7 @@ package funkin.save.migrator; import funkin.save.Save; import funkin.save.migrator.RawSaveData_v1_0_0; import thx.semver.Version; +import funkin.util.StructureUtil; import funkin.util.VersionUtil; @:nullSafety @@ -26,7 +27,7 @@ class SaveDataMigrator if (VersionUtil.validateVersion(version, Save.SAVE_DATA_VERSION_RULE)) { // Simply import the structured data. - var save:Save = new Save(inputData); + var save:Save = new Save(StructureUtil.deepMerge(Save.getDefault(), inputData)); return save; } else diff --git a/source/funkin/ui/freeplay/FreeplayState.hx b/source/funkin/ui/freeplay/FreeplayState.hx index 455805479..66c829e11 100644 --- a/source/funkin/ui/freeplay/FreeplayState.hx +++ b/source/funkin/ui/freeplay/FreeplayState.hx @@ -962,7 +962,7 @@ class FreeplayState extends MusicBeatSubState public override function destroy():Void { super.destroy(); - var daSong:Null = grpCapsules.members[curSelected]?.songData; + var daSong:Null = currentFilteredSongs[curSelected]; if (daSong != null) { clearDaCache(daSong.songName); diff --git a/source/funkin/util/StructureUtil.hx b/source/funkin/util/StructureUtil.hx new file mode 100644 index 000000000..351d0e0a8 --- /dev/null +++ b/source/funkin/util/StructureUtil.hx @@ -0,0 +1,61 @@ +package funkin.util; + +import haxe.DynamicAccess; + +/** + * Utilities for working with anonymous structures. + */ +class StructureUtil +{ + /** + * Merge two structures, with the second overwriting the first. + * Performs a SHALLOW clone, where child structures are not merged. + * @param a The base structure. + * @param b The new structure. + * @return The merged structure. + */ + public static function merge(a:Dynamic, b:Dynamic):Dynamic + { + var result:DynamicAccess = Reflect.copy(a); + + for (field in Reflect.fields(b)) + { + result.set(field, Reflect.field(b, field)); + } + + return result; + } + + /** + * Merge two structures, with the second overwriting the first. + * Performs a DEEP clone, where child structures are also merged recursively. + * @param a The base structure. + * @param b The new structure. + * @return The merged structure. + */ + public static function deepMerge(a:Dynamic, b:Dynamic):Dynamic + { + if (a == null) return b; + if (b == null) return null; + if (!Reflect.isObject(a) || !Reflect.isObject(b)) return b; + + var result:DynamicAccess = Reflect.copy(a); + + for (field in Reflect.fields(b)) + { + if (Reflect.isObject(b)) + { + // Note that isObject also returns true for class instances, + // but we just assume that's not a problem here. + result.set(field, deepMerge(Reflect.field(result, field), Reflect.field(b, field))); + } + else + { + // If we're here, b[field] is a primitive. + result.set(field, Reflect.field(b, field)); + } + } + + return result; + } +} From e9b0af6ea246ea567d21fc719111b53f50fa35cd Mon Sep 17 00:00:00 2001 From: Cameron Taylor Date: Wed, 3 Apr 2024 03:40:10 -0400 Subject: [PATCH 061/130] assets submod --- assets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets b/assets index 503b73d20..15cf800ac 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit 503b73d20be0b55f881da6182b70432b0810fd17 +Subproject commit 15cf800ac9cc4e55210dafb8f2c64838360f9fd0 From ad39ce3c2154ac7cb48723f570226c3462b2c606 Mon Sep 17 00:00:00 2001 From: Cameron Taylor Date: Wed, 3 Apr 2024 04:43:12 -0400 Subject: [PATCH 062/130] local conductor got removed somewhere? --- source/funkin/ui/debug/latency/LatencyState.hx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/funkin/ui/debug/latency/LatencyState.hx b/source/funkin/ui/debug/latency/LatencyState.hx index 875a956e0..620f0edd7 100644 --- a/source/funkin/ui/debug/latency/LatencyState.hx +++ b/source/funkin/ui/debug/latency/LatencyState.hx @@ -171,7 +171,7 @@ class LatencyState extends MusicBeatSubState trace(FlxG.sound.music._channel.position); */ - localConductor.update(swagSong.time, false); + // localConductor.update(swagSong.time, false); if (FlxG.keys.justPressed.S) { From e9d854673729a20cc25dc42fbe8e4cc25ae09b6f Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Wed, 3 Apr 2024 04:52:12 -0400 Subject: [PATCH 063/130] More results screen changes --- source/funkin/play/ResultState.hx | 10 ++++----- source/funkin/ui/freeplay/FreeplayScore.hx | 4 ++-- source/funkin/ui/freeplay/FreeplayState.hx | 2 +- source/funkin/util/StructureUtil.hx | 24 ++++++++++++++++++++++ source/funkin/util/tools/MapTools.hx | 12 +++++++++++ 5 files changed, 44 insertions(+), 8 deletions(-) diff --git a/source/funkin/play/ResultState.hx b/source/funkin/play/ResultState.hx index 3ae8ad138..1dfc09114 100644 --- a/source/funkin/play/ResultState.hx +++ b/source/funkin/play/ResultState.hx @@ -11,6 +11,7 @@ import flixel.math.FlxPoint; import funkin.ui.MusicBeatSubState; import flixel.math.FlxRect; import flixel.text.FlxBitmapText; +import funkin.ui.freeplay.FreeplayScore; import flixel.tweens.FlxEase; import funkin.ui.freeplay.FreeplayState; import flixel.tweens.FlxTween; @@ -188,7 +189,7 @@ class ResultState extends MusicBeatSubState scorePopin.visible = false; add(scorePopin); - var highscoreNew:FlxSprite = new FlxSprite(280, 580); + var highscoreNew:FlxSprite = new FlxSprite(310, 570); highscoreNew.frames = Paths.getSparrowAtlas("resultScreen/highscoreNew"); highscoreNew.animation.addByPrefix("new", "NEW HIGHSCORE", 24); highscoreNew.visible = false; @@ -228,9 +229,8 @@ class ResultState extends MusicBeatSubState var tallyMissed:TallyCounter = new TallyCounter(260, (hStuf * 9) + extraYOffset, params.scoreData.tallies.missed, 0xFFC68AE6); ratingGrp.add(tallyMissed); - var score:TallyCounter = new TallyCounter(825, 630, params.scoreData.score, RIGHT); - score.scale.set(2, 2); - ratingGrp.add(score); + var score:FreeplayScore = new FreeplayScore(825, 630, 10, params.scoreData.score); + add(score); for (ind => rating in ratingGrp.members) { @@ -249,7 +249,7 @@ class ResultState extends MusicBeatSubState scorePopin.animation.play("score"); scorePopin.visible = true; - if (params.isNewHighscore) + if (params.isNewHighscore || true) { highscoreNew.visible = true; highscoreNew.animation.play("new"); diff --git a/source/funkin/ui/freeplay/FreeplayScore.hx b/source/funkin/ui/freeplay/FreeplayScore.hx index 413b182e0..da4c9f5d4 100644 --- a/source/funkin/ui/freeplay/FreeplayScore.hx +++ b/source/funkin/ui/freeplay/FreeplayScore.hx @@ -42,11 +42,11 @@ class FreeplayScore extends FlxTypedSpriteGroup return val; } - public function new(x:Float, y:Float, scoreShit:Int = 100) + public function new(x:Float, y:Float, digitCount:Int, scoreShit:Int = 100) { super(x, y); - for (i in 0...7) + for (i in 0...digitCount) { add(new ScoreNum(x + (45 * i), y, 0)); } diff --git a/source/funkin/ui/freeplay/FreeplayState.hx b/source/funkin/ui/freeplay/FreeplayState.hx index 66c829e11..10a582728 100644 --- a/source/funkin/ui/freeplay/FreeplayState.hx +++ b/source/funkin/ui/freeplay/FreeplayState.hx @@ -425,7 +425,7 @@ class FreeplayState extends MusicBeatSubState tmr.time = FlxG.random.float(20, 60); }, 0); - fp = new FreeplayScore(460, 60, 100); + fp = new FreeplayScore(460, 60, 7, 100); fp.visible = false; add(fp); diff --git a/source/funkin/util/StructureUtil.hx b/source/funkin/util/StructureUtil.hx index 351d0e0a8..92d4e61fb 100644 --- a/source/funkin/util/StructureUtil.hx +++ b/source/funkin/util/StructureUtil.hx @@ -1,5 +1,6 @@ package funkin.util; +import funkin.util.tools.MapTools; import haxe.DynamicAccess; /** @@ -26,6 +27,18 @@ class StructureUtil return result; } + public static function toMap(a:Dynamic):haxe.ds.Map + { + var result:haxe.ds.Map = []; + + for (field in Reflect.fields(a)) + { + result.set(field, Reflect.field(a, field)); + } + + return result; + } + /** * Merge two structures, with the second overwriting the first. * Performs a DEEP clone, where child structures are also merged recursively. @@ -38,6 +51,17 @@ class StructureUtil if (a == null) return b; if (b == null) return null; if (!Reflect.isObject(a) || !Reflect.isObject(b)) return b; + if (Std.isOfType(b, haxe.ds.StringMap)) + { + if (Std.isOfType(a, haxe.ds.StringMap)) + { + return MapTools.merge(a, b); + } + else + { + return StructureUtil.toMap(a).merge(b); + } + } var result:DynamicAccess = Reflect.copy(a); diff --git a/source/funkin/util/tools/MapTools.hx b/source/funkin/util/tools/MapTools.hx index 1399fb791..029ea4978 100644 --- a/source/funkin/util/tools/MapTools.hx +++ b/source/funkin/util/tools/MapTools.hx @@ -33,6 +33,18 @@ class MapTools return map.copy(); } + public static function merge(a:Map, b:Map):Map + { + var result = a.copy(); + + for (pair in b.keyValueIterator()) + { + result.set(pair.key, pair.value); + } + + return result; + } + /** * Create a new array with clones of all elements of the given array, to prevent modifying the original. */ From 1759f5c3883b572db0050478bfec5ad8b33585ec Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Wed, 3 Apr 2024 04:52:28 -0400 Subject: [PATCH 064/130] Note cover now only plays splash on player --- source/funkin/play/PlayState.hx | 4 ++-- source/funkin/play/notes/NoteHoldCover.hx | 7 ------- source/funkin/play/notes/Strumline.hx | 17 ++++++++++++++--- 3 files changed, 16 insertions(+), 12 deletions(-) diff --git a/source/funkin/play/PlayState.hx b/source/funkin/play/PlayState.hx index 52bfedd8d..e3e1f974d 100644 --- a/source/funkin/play/PlayState.hx +++ b/source/funkin/play/PlayState.hx @@ -2224,8 +2224,8 @@ class PlayState extends MusicBeatSubState holdNote.handledMiss = true; // Mute vocals and play miss animation, but don't penalize. - vocals.playerVolume = 0; - if (currentStage != null && currentStage.getBoyfriend() != null) currentStage.getBoyfriend().playSingAnimation(holdNote.noteData.getDirection(), true); + // vocals.playerVolume = 0; + // if (currentStage != null && currentStage.getBoyfriend() != null) currentStage.getBoyfriend().playSingAnimation(holdNote.noteData.getDirection(), true); } } } diff --git a/source/funkin/play/notes/NoteHoldCover.hx b/source/funkin/play/notes/NoteHoldCover.hx index 52ae97d4f..7bed8a08c 100644 --- a/source/funkin/play/notes/NoteHoldCover.hx +++ b/source/funkin/play/notes/NoteHoldCover.hx @@ -77,13 +77,6 @@ class NoteHoldCover extends FlxTypedSpriteGroup public override function update(elapsed):Void { super.update(elapsed); - if ((!holdNote.alive || holdNote.missedNote) && !glow.animation.curAnim.name.startsWith('holdCoverEnd')) - { - // If alive is false, the hold note was held to completion. - // If missedNote is true, the hold note was "dropped". - - playEnd(); - } } public function playStart():Void diff --git a/source/funkin/play/notes/Strumline.hx b/source/funkin/play/notes/Strumline.hx index 2b10c05ee..2b4e09370 100644 --- a/source/funkin/play/notes/Strumline.hx +++ b/source/funkin/play/notes/Strumline.hx @@ -370,8 +370,6 @@ class Strumline extends FlxSpriteGroup // Hold note is offscreen, kill it. holdNote.visible = false; holdNote.kill(); // Do not destroy! Recycling is faster. - - // The cover will see this and clean itself up. } else if (holdNote.hitNote && holdNote.sustainLength <= 0) { @@ -385,10 +383,16 @@ class Strumline extends FlxSpriteGroup playStatic(holdNote.noteDirection); } - if (holdNote.cover != null) + if (holdNote.cover != null && isPlayer) { holdNote.cover.playEnd(); } + else if (holdNote.cover != null) + { + // *lightning* *zap* *crackle* + holdNote.cover.visible = false; + holdNote.cover.kill(); + } holdNote.visible = false; holdNote.kill(); @@ -410,6 +414,13 @@ class Strumline extends FlxSpriteGroup { holdNote.y = this.y - INITIAL_OFFSET + calculateNoteYPos(holdNote.strumTime, vwoosh) + yOffset + STRUMLINE_SIZE / 2; } + + // Clean up the cover. + if (holdNote.cover != null) + { + holdNote.cover.visible = false; + holdNote.cover.kill(); + } } else if (Conductor.instance.songPosition > holdNote.strumTime && holdNote.hitNote) { From d911c46d2fd15b54dc8abde12268376125e361b9 Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Wed, 3 Apr 2024 06:24:20 -0400 Subject: [PATCH 065/130] Better scoring numbers and improved anims. --- assets | 2 +- source/funkin/play/ResultScore.hx | 140 ++++++++++++++++++++++++++++++ source/funkin/play/ResultState.hx | 9 +- 3 files changed, 148 insertions(+), 3 deletions(-) create mode 100644 source/funkin/play/ResultScore.hx diff --git a/assets b/assets index 3ccfe33ac..4ee903339 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit 3ccfe33acef6e62c40317af583af764838544a24 +Subproject commit 4ee903339e3a34ae8d612125b0bf9c17fbb667b2 diff --git a/source/funkin/play/ResultScore.hx b/source/funkin/play/ResultScore.hx new file mode 100644 index 000000000..d5d5a6567 --- /dev/null +++ b/source/funkin/play/ResultScore.hx @@ -0,0 +1,140 @@ +package funkin.play; + +import flixel.FlxSprite; +import flixel.group.FlxSpriteGroup.FlxTypedSpriteGroup; + +class ResultScore extends FlxTypedSpriteGroup +{ + public var scoreShit(default, set):Int = 0; + + function set_scoreShit(val):Int + { + if (group == null || group.members == null) return val; + var loopNum:Int = group.members.length - 1; + var dumbNumb = Std.parseInt(Std.string(val)); + var prevNum:ScoreNum; + + while (dumbNumb > 0) + { + group.members[loopNum].digit = dumbNumb % 10; + + // var funnyNum = group.members[loopNum]; + // prevNum = group.members[loopNum + 1]; + + // if (prevNum != null) + // { + // funnyNum.x = prevNum.x - (funnyNum.width * 0.7); + // } + + // funnyNum.y = (funnyNum.baseY - (funnyNum.height / 2)) + 73; + // funnyNum.x = (funnyNum.baseX - (funnyNum.width / 2)) + 450; // this plus value is hand picked lol! + + dumbNumb = Math.floor(dumbNumb / 10); + loopNum--; + } + + while (loopNum > 0) + { + group.members[loopNum].digit = 10; + loopNum--; + } + + return val; + } + + public function animateNumbers():Void + { + for (i in group.members) + { + i.playAnim(); + } + } + + public function new(x:Float, y:Float, digitCount:Int, scoreShit:Int = 100) + { + super(x, y); + + for (i in 0...digitCount) + { + add(new ScoreNum(x + (65 * i), y)); + } + + this.scoreShit = scoreShit; + } + + public function updateScore(scoreNew:Int) + { + scoreShit = scoreNew; + } +} + +class ScoreNum extends FlxSprite +{ + public var digit(default, set):Int = 10; + + function set_digit(val):Int + { + if (val >= 0 && animation.curAnim != null && animation.curAnim.name != numToString[val]) + { + animation.play(numToString[val], true, false, 0); + updateHitbox(); + + switch (val) + { + case 1: + // offset.x -= 15; + case 5: + // set offsets + // offset.x += 0; + // offset.y += 10; + + case 7: + // offset.y += 6; + case 4: + // offset.y += 5; + case 9: + // offset.y += 5; + default: + centerOffsets(false); + } + } + + return digit = val; + } + + public function playAnim():Void + { + animation.play(numToString[digit], true, false, 0); + } + + public var baseY:Float = 0; + public var baseX:Float = 0; + + var numToString:Array = [ + "ZERO", "ONE", "TWO", "THREE", "FOUR", "FIVE", "SIX", "SEVEN", "EIGHT", "NINE", "DISABLED" + ]; + + public function new(x:Float, y:Float) + { + super(x, y); + + baseY = y; + baseX = x; + + frames = Paths.getSparrowAtlas('resultScreen/score-digital-numbers'); + + for (i in 0...10) + { + var stringNum:String = numToString[i]; + animation.addByPrefix(stringNum, '$stringNum DIGITAL', 24, false); + } + + animation.addByPrefix('DISABLED', 'DISABLED', 24, false); + + this.digit = 10; + + animation.play(numToString[digit], true); + + updateHitbox(); + } +} diff --git a/source/funkin/play/ResultState.hx b/source/funkin/play/ResultState.hx index 1dfc09114..c05257338 100644 --- a/source/funkin/play/ResultState.hx +++ b/source/funkin/play/ResultState.hx @@ -229,7 +229,8 @@ class ResultState extends MusicBeatSubState var tallyMissed:TallyCounter = new TallyCounter(260, (hStuf * 9) + extraYOffset, params.scoreData.tallies.missed, 0xFFC68AE6); ratingGrp.add(tallyMissed); - var score:FreeplayScore = new FreeplayScore(825, 630, 10, params.scoreData.score); + var score:ResultScore = new ResultScore(35, 305, 10, params.scoreData.score); + score.visible = false; add(score); for (ind => rating in ratingGrp.members) @@ -247,9 +248,13 @@ class ResultState extends MusicBeatSubState ratingsPopin.animation.finishCallback = anim -> { scorePopin.animation.play("score"); + scorePopin.animation.finishCallback = anim -> { + score.visible = true; + score.animateNumbers(); + }; scorePopin.visible = true; - if (params.isNewHighscore || true) + if (params.isNewHighscore) { highscoreNew.visible = true; highscoreNew.animation.play("new"); From 4f2f28cb317f38ee506548061a3ef9d211fbdf02 Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Wed, 3 Apr 2024 15:05:54 -0400 Subject: [PATCH 066/130] Fix issue with deepMerge() caused by handling maps incorrectly, causing an unhandleable crash. --- source/funkin/util/StructureUtil.hx | 64 +++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/source/funkin/util/StructureUtil.hx b/source/funkin/util/StructureUtil.hx index 351d0e0a8..f94de4652 100644 --- a/source/funkin/util/StructureUtil.hx +++ b/source/funkin/util/StructureUtil.hx @@ -1,5 +1,6 @@ package funkin.util; +import funkin.util.tools.MapTools; import haxe.DynamicAccess; /** @@ -26,6 +27,57 @@ class StructureUtil return result; } + public static function toMap(a:Dynamic):haxe.ds.Map + { + var result:haxe.ds.Map = []; + + for (field in Reflect.fields(a)) + { + result.set(field, Reflect.field(a, field)); + } + + return result; + } + + public static function isMap(a:Dynamic):Bool + { + return Std.isOfType(a, haxe.Constraints.IMap); + } + + public static function isObject(a:Dynamic):Bool + { + switch (Type.typeof(a)) + { + case TObject: + return true; + default: + return false; + } + } + + public static function isPrimitive(a:Dynamic):Bool + { + switch (Type.typeof(a)) + { + case TInt | TFloat | TBool: + return true; + case TClass(c): + return false; + case TEnum(e): + return false; + case TObject: + return false; + case TFunction: + return false; + case TNull: + return true; + case TUnknown: + return false; + default: + return false; + } + } + /** * Merge two structures, with the second overwriting the first. * Performs a DEEP clone, where child structures are also merged recursively. @@ -37,6 +89,18 @@ class StructureUtil { if (a == null) return b; if (b == null) return null; + if (isPrimitive(a) && isPrimitive(b)) return b; + if (isMap(b)) + { + if (isMap(a)) + { + return MapTools.merge(a, b); + } + else + { + return StructureUtil.toMap(a).merge(b); + } + } if (!Reflect.isObject(a) || !Reflect.isObject(b)) return b; var result:DynamicAccess = Reflect.copy(a); From b39712d33f6d36ddcf14c8fb050572abb9562549 Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Wed, 3 Apr 2024 20:31:34 -0400 Subject: [PATCH 067/130] Prevent crashes when the game attempts to load bad save data. --- hmm.json | 2 +- source/funkin/save/Save.hx | 4 +++ source/funkin/util/SerializerUtil.hx | 48 ++++++++++++++++++++++++++++ 3 files changed, 53 insertions(+), 1 deletion(-) diff --git a/hmm.json b/hmm.json index 0dfe88ded..641ef1bbd 100644 --- a/hmm.json +++ b/hmm.json @@ -139,7 +139,7 @@ "name": "openfl", "type": "git", "dir": null, - "ref": "f229d76361c7e31025a048fe7909847f75bb5d5e", + "ref": "228c1b5063911e2ad75cef6e3168ef0a4b9f9134", "url": "https://github.com/FunkinCrew/openfl" }, { diff --git a/source/funkin/save/Save.hx b/source/funkin/save/Save.hx index dc7c5f989..6f2146a7a 100644 --- a/source/funkin/save/Save.hx +++ b/source/funkin/save/Save.hx @@ -9,6 +9,7 @@ import funkin.save.migrator.SaveDataMigrator; import funkin.ui.debug.charting.ChartEditorState.ChartEditorLiveInputStyle; import funkin.ui.debug.charting.ChartEditorState.ChartEditorTheme; import thx.semver.Version; +import funkin.util.SerializerUtil; @:nullSafety class Save @@ -641,6 +642,9 @@ class Save { trace("[SAVE] Loading save from slot " + slot + "..."); + // Prevent crashes if the save data is corrupted. + SerializerUtil.initSerializer(); + FlxG.save.bind('$SAVE_NAME${slot}', SAVE_PATH); if (FlxG.save.isEmpty()) diff --git a/source/funkin/util/SerializerUtil.hx b/source/funkin/util/SerializerUtil.hx index c87d3f6c0..fa602cc73 100644 --- a/source/funkin/util/SerializerUtil.hx +++ b/source/funkin/util/SerializerUtil.hx @@ -63,6 +63,31 @@ class SerializerUtil } } + public static function initSerializer():Void + { + haxe.Unserializer.DEFAULT_RESOLVER = new FunkinTypeResolver(); + } + + /** + * Serialize a Haxe object using the built-in Serializer. + * @param input The object to serialize + * @return The serialized object as a string + */ + public static function fromHaxeObject(input:Dynamic):String + { + return haxe.Serializer.run(input); + } + + /** + * Convert a serialized Haxe object back into a Haxe object. + * @param input The serialized object as a string + * @return The deserialized object + */ + public static function toHaxeObject(input:String):Dynamic + { + return haxe.Unserializer.run(input); + } + /** * Customize how certain types are serialized when converting to JSON. */ @@ -90,3 +115,26 @@ class SerializerUtil return result; } } + +class FunkinTypeResolver +{ + public function new() + { + // Blank constructor. + } + + public function resolveClass(name:String):Class + { + if (name == 'Dynamic') + { + FlxG.log.warn('Found invalid class type in save data, indicates partial save corruption.'); + return null; + } + return Type.resolveClass(name); + }; + + public function resolveEnum(name:String):Enum + { + return Type.resolveEnum(name); + }; +} From 58427363d16dd68c97f89fdfe79713d4f939a170 Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Wed, 3 Apr 2024 20:33:51 -0400 Subject: [PATCH 068/130] Prevent a crash trying to open a non-existant debugger checkbox. --- .../charting/handlers/ChartEditorToolboxHandler.hx | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/source/funkin/ui/debug/charting/handlers/ChartEditorToolboxHandler.hx b/source/funkin/ui/debug/charting/handlers/ChartEditorToolboxHandler.hx index 8c7b1a8c1..f82bc3c1f 100644 --- a/source/funkin/ui/debug/charting/handlers/ChartEditorToolboxHandler.hx +++ b/source/funkin/ui/debug/charting/handlers/ChartEditorToolboxHandler.hx @@ -308,16 +308,6 @@ class ChartEditorToolboxHandler state.playtestBotPlayMode = checkboxBotPlay.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; - }; - var checkboxSongScripts:Null = toolbox.findComponent('playtestSongScriptsCheckbox', CheckBox); if (checkboxSongScripts == null) From d8903f138f0a3f9c3c8b65f7dcb26630e2453bac Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Wed, 3 Apr 2024 20:50:51 -0400 Subject: [PATCH 069/130] Additional save fix --- source/funkin/save/Save.hx | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/source/funkin/save/Save.hx b/source/funkin/save/Save.hx index 6f2146a7a..af2730ddd 100644 --- a/source/funkin/save/Save.hx +++ b/source/funkin/save/Save.hx @@ -392,6 +392,22 @@ class Save */ public function getLevelScore(levelId:String, difficultyId:String = 'normal'):Null { + if (data.scores?.levels == null) + { + if (data.scores == null) + { + data.scores = + { + songs: [], + levels: [] + }; + } + else + { + data.scores.levels = []; + } + } + var level = data.scores.levels.get(levelId); if (level == null) { From fbba04bbe7f07dab2709319638ddff980acde0d5 Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Wed, 3 Apr 2024 21:57:13 -0400 Subject: [PATCH 070/130] Update 2hot/blazin charts to new drafts --- assets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets b/assets index 3ccfe33ac..56d7fbf61 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit 3ccfe33acef6e62c40317af583af764838544a24 +Subproject commit 56d7fbf618994199ccdfae83d940a1302b6cd520 From f129cb79973f820742fdc2075198c322ffda763c Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Wed, 3 Apr 2024 21:57:29 -0400 Subject: [PATCH 071/130] Fix a bug where if Weekend 1 wasn't cleared, you can't chart those songs --- source/funkin/play/song/Song.hx | 3 ++- .../debug/charting/handlers/ChartEditorImportExportHandler.hx | 2 +- source/funkin/ui/freeplay/FreeplayState.hx | 4 ++-- source/funkin/ui/story/Level.hx | 2 +- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/source/funkin/play/song/Song.hx b/source/funkin/play/song/Song.hx index 0248e09ee..d219dc2f6 100644 --- a/source/funkin/play/song/Song.hx +++ b/source/funkin/play/song/Song.hx @@ -404,11 +404,12 @@ class Song implements IPlayStateScriptedClass implements IRegistryEntry, showHidden:Bool = false):Array + public function listDifficulties(?variationId:String, ?variationIds:Array, showLocked:Bool = false, showHidden:Bool = false):Array { if (variationIds == null) variationIds = []; if (variationId != null) variationIds.push(variationId); diff --git a/source/funkin/ui/debug/charting/handlers/ChartEditorImportExportHandler.hx b/source/funkin/ui/debug/charting/handlers/ChartEditorImportExportHandler.hx index 557875596..0308cd871 100644 --- a/source/funkin/ui/debug/charting/handlers/ChartEditorImportExportHandler.hx +++ b/source/funkin/ui/debug/charting/handlers/ChartEditorImportExportHandler.hx @@ -73,7 +73,7 @@ class ChartEditorImportExportHandler state.loadInstFromAsset(Paths.inst(songId, '-$variation'), variation); } - for (difficultyId in song.listDifficulties(variation)) + for (difficultyId in song.listDifficulties(variation, true, true)) { var diff:Null = song.getDifficulty(difficultyId, variation); if (diff == null) continue; diff --git a/source/funkin/ui/freeplay/FreeplayState.hx b/source/funkin/ui/freeplay/FreeplayState.hx index 66c829e11..7264124c4 100644 --- a/source/funkin/ui/freeplay/FreeplayState.hx +++ b/source/funkin/ui/freeplay/FreeplayState.hx @@ -195,7 +195,7 @@ class FreeplayState extends MusicBeatSubState var song:Song = SongRegistry.instance.fetchEntry(songId); // Only display songs which actually have available charts for the current character. - var availableDifficultiesForSong:Array = song.listDifficulties(displayedVariations); + var availableDifficultiesForSong:Array = song.listDifficulties(displayedVariations, false); if (availableDifficultiesForSong.length == 0) continue; songs.push(new FreeplaySongData(levelId, songId, song, displayedVariations)); @@ -1400,7 +1400,7 @@ class FreeplaySongData function updateValues(variations:Array):Void { - this.songDifficulties = song.listDifficulties(variations); + this.songDifficulties = song.listDifficulties(variations, false, false); if (!this.songDifficulties.contains(currentDifficulty)) currentDifficulty = Constants.DEFAULT_DIFFICULTY; var songDifficulty:SongDifficulty = song.getDifficulty(currentDifficulty, variations); diff --git a/source/funkin/ui/story/Level.hx b/source/funkin/ui/story/Level.hx index 626fb8e52..8f454aa1a 100644 --- a/source/funkin/ui/story/Level.hx +++ b/source/funkin/ui/story/Level.hx @@ -169,7 +169,7 @@ class Level implements IRegistryEntry if (firstSong != null) { // Don't display alternate characters in Story Mode. Only show `default` and `erect` variations. - for (difficulty in firstSong.listDifficulties([Constants.DEFAULT_VARIATION, 'erect'])) + for (difficulty in firstSong.listDifficulties([Constants.DEFAULT_VARIATION, 'erect'], false, false)) { difficulties.push(difficulty); } From ae7a6805d4b55524f4ecbab8cc9e77bd4ffce3dd Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Thu, 4 Apr 2024 03:28:37 -0400 Subject: [PATCH 072/130] Fix Polymod errors in Week 6. --- assets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets b/assets index 3ccfe33ac..ddeed8863 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit 3ccfe33acef6e62c40317af583af764838544a24 +Subproject commit ddeed88638a6a36aca4d2a91633f48cff50dd6c7 From 57d6ed118d9a5d4f3d6eeddec8076ea563501326 Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Thu, 4 Apr 2024 03:31:03 -0400 Subject: [PATCH 073/130] Hide Rating on the right side of the items in Freeplay --- source/funkin/ui/freeplay/SongMenuItem.hx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/funkin/ui/freeplay/SongMenuItem.hx b/source/funkin/ui/freeplay/SongMenuItem.hx index bffa821b3..f8b3d7ac3 100644 --- a/source/funkin/ui/freeplay/SongMenuItem.hx +++ b/source/funkin/ui/freeplay/SongMenuItem.hx @@ -83,10 +83,10 @@ class SongMenuItem extends FlxSpriteGroup diffRatingSprite = new FlxSprite(145, 90).loadGraphic(Paths.image('freeplay/diffRatings/diff00')); diffRatingSprite.shader = grayscaleShader; + diffRatingSprite.origin.set(capsule.origin.x - diffRatingSprite.x, capsule.origin.y - diffRatingSprite.y); // TODO: Readd once ratings are fully implemented // add(diffRatingSprite); - diffRatingSprite.origin.set(capsule.origin.x - diffRatingSprite.x, capsule.origin.y - diffRatingSprite.y); - grpHide.add(diffRatingSprite); + // grpHide.add(diffRatingSprite); songText = new CapsuleText(capsule.width * 0.26, 45, 'Random', Std.int(40 * realScaled)); add(songText); From 8826d0741b14ba4e18922f7ee3d3ebc9c9a09af4 Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Thu, 4 Apr 2024 03:31:44 -0400 Subject: [PATCH 074/130] Hide miss popups when hitting ~160ms --- source/funkin/play/PlayState.hx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/funkin/play/PlayState.hx b/source/funkin/play/PlayState.hx index 52bfedd8d..91c3f3af9 100644 --- a/source/funkin/play/PlayState.hx +++ b/source/funkin/play/PlayState.hx @@ -2576,7 +2576,7 @@ class PlayState extends MusicBeatSubState // If daRating is 'miss', that means we made a mistake and should not continue. FlxG.log.warn('popUpScore judged a note as a miss!'); // TODO: Remove this. - comboPopUps.displayRating('miss'); + // comboPopUps.displayRating('miss'); return; } @@ -2857,7 +2857,7 @@ class PlayState extends MusicBeatSubState FlxTransitionableState.skipNextTransIn = true; FlxTransitionableState.skipNextTransOut = true; - FlxG.sound.music.stop(); + if (FlxG.sound.music != null) FlxG.sound.music.stop(); vocals.stop(); // TODO: Softcode this cutscene. From 3ac466aa5ea866573e4e9181630b566e1416e444 Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Thu, 4 Apr 2024 03:35:36 -0400 Subject: [PATCH 075/130] Add missing MapTools function from #459 --- source/funkin/util/tools/MapTools.hx | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/source/funkin/util/tools/MapTools.hx b/source/funkin/util/tools/MapTools.hx index 1399fb791..b98cb0adf 100644 --- a/source/funkin/util/tools/MapTools.hx +++ b/source/funkin/util/tools/MapTools.hx @@ -33,6 +33,24 @@ class MapTools return map.copy(); } + /** + * Create a new map which is a combination of the two given maps. + * @param a The base map. + * @param b The other map. The values from this take precedence. + * @return The combined map. + */ + public static function merge(a:Map, b:Map):Map + { + var result = a.copy(); + + for (pair in b.keyValueIterator()) + { + result.set(pair.key, pair.value); + } + + return result; + } + /** * Create a new array with clones of all elements of the given array, to prevent modifying the original. */ From 33685b2bcd42703b9f62abf622bc00395afd73ed Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Thu, 4 Apr 2024 04:08:07 -0400 Subject: [PATCH 076/130] Fix an issue where player could not switch difficulties from Pause menu until they beat Weekend 1. --- assets | 2 +- source/funkin/play/PauseSubState.hx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/assets b/assets index 56d7fbf61..332a15c92 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit 56d7fbf618994199ccdfae83d940a1302b6cd520 +Subproject commit 332a15c9282cea938dfdeb4a42785418d211fff0 diff --git a/source/funkin/play/PauseSubState.hx b/source/funkin/play/PauseSubState.hx index f1375cc63..fc1d01377 100644 --- a/source/funkin/play/PauseSubState.hx +++ b/source/funkin/play/PauseSubState.hx @@ -441,7 +441,7 @@ class PauseSubState extends MusicBeatSubState var entries:Array = []; if (PlayState.instance.currentChart != null) { - var difficultiesInVariation = PlayState.instance.currentSong.listDifficulties(PlayState.instance.currentChart.variation); + var difficultiesInVariation = PlayState.instance.currentSong.listDifficulties(PlayState.instance.currentChart.variation, true); trace('DIFFICULTIES: ${difficultiesInVariation}'); for (difficulty in difficultiesInVariation) { From 99cdb62175d89b7f981cf44edfc25d101a834406 Mon Sep 17 00:00:00 2001 From: Cameron Taylor Date: Thu, 4 Apr 2024 04:46:38 -0400 Subject: [PATCH 077/130] updated color --- source/funkin/util/Constants.hx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/funkin/util/Constants.hx b/source/funkin/util/Constants.hx index e04af0097..d787b30f5 100644 --- a/source/funkin/util/Constants.hx +++ b/source/funkin/util/Constants.hx @@ -140,7 +140,7 @@ class Constants /** * Color for the preloader progress bar */ - public static final COLOR_PRELOADER_BAR:FlxColor = 0xFF9DDF35; + public static final COLOR_PRELOADER_BAR:FlxColor = 0xFFA4FF11; /** * Color for the preloader site lock background From 39d92eb09dd26a24d495f4c5d8ae6c44c6bdb141 Mon Sep 17 00:00:00 2001 From: Cameron Taylor Date: Thu, 4 Apr 2024 04:55:27 -0400 Subject: [PATCH 078/130] fast loading on preloader --- source/funkin/util/Constants.hx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/funkin/util/Constants.hx b/source/funkin/util/Constants.hx index d787b30f5..47410b9c5 100644 --- a/source/funkin/util/Constants.hx +++ b/source/funkin/util/Constants.hx @@ -357,7 +357,7 @@ class Constants * The progress bare is automatically rescaled to match. */ #if debug - public static final PRELOADER_MIN_STAGE_TIME:Float = 1.0; + public static final PRELOADER_MIN_STAGE_TIME:Float = 0.0; #else public static final PRELOADER_MIN_STAGE_TIME:Float = 0.1; #end From 57a5973c2ceed56952dd1c283228bf8129bbe5f6 Mon Sep 17 00:00:00 2001 From: Cameron Taylor Date: Thu, 4 Apr 2024 05:22:44 -0400 Subject: [PATCH 079/130] small fade polish for week 8 convos --- .../play/cutscene/dialogue/Conversation.hx | 4 +++- source/funkin/util/EaseUtil.hx | 17 +++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) create mode 100644 source/funkin/util/EaseUtil.hx diff --git a/source/funkin/play/cutscene/dialogue/Conversation.hx b/source/funkin/play/cutscene/dialogue/Conversation.hx index c520c3e25..2c59eaba0 100644 --- a/source/funkin/play/cutscene/dialogue/Conversation.hx +++ b/source/funkin/play/cutscene/dialogue/Conversation.hx @@ -23,6 +23,7 @@ import funkin.modding.IScriptedClass.IDialogueScriptedClass; import funkin.modding.IScriptedClass.IEventHandler; import funkin.play.cutscene.dialogue.DialogueBox; import funkin.util.SortUtil; +import funkin.util.EaseUtil; /** * A high-level handler for dialogue. @@ -179,7 +180,7 @@ class Conversation extends FlxSpriteGroup implements IDialogueScriptedClass impl if (backdropData.fadeTime > 0.0) { backdrop.alpha = 0.0; - FlxTween.tween(backdrop, {alpha: 1.0}, backdropData.fadeTime, {ease: FlxEase.linear}); + FlxTween.tween(backdrop, {alpha: 1.0}, backdropData.fadeTime, {ease: EaseUtil.stepped(10)}); } else { @@ -403,6 +404,7 @@ class Conversation extends FlxSpriteGroup implements IDialogueScriptedClass impl type: ONESHOT, // holy shit like the game no way startDelay: 0, onComplete: (_) -> endOutro(), + ease: EaseUtil.stepped(8) }); FlxTween.tween(this.music, {volume: 0.0}, outroData.fadeTime); diff --git a/source/funkin/util/EaseUtil.hx b/source/funkin/util/EaseUtil.hx new file mode 100644 index 000000000..200e74d07 --- /dev/null +++ b/source/funkin/util/EaseUtil.hx @@ -0,0 +1,17 @@ +package funkin.util; + +class EaseUtil +{ + /** + * Returns an ease function that eases via steps. + * Useful for "retro" style fades (week 6!) + * @param steps how many steps to ease over + * @return Float->Float + */ + public static inline function stepped(steps:Int):Float->Float + { + return function(t:Float):Float { + return Math.floor(t * steps) / steps; + } + } +} From cdf15b3431400eb3b66a59ae75e3cfb836e65b62 Mon Sep 17 00:00:00 2001 From: Cameron Taylor Date: Thu, 4 Apr 2024 05:32:21 -0400 Subject: [PATCH 080/130] assets submod --- assets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets b/assets index 332a15c92..a1d24709d 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit 332a15c9282cea938dfdeb4a42785418d211fff0 +Subproject commit a1d24709d4a89f188beac95b55da9594b2db28cd From 894ca987559ecc68282d291c080b7a0a8eb32eed Mon Sep 17 00:00:00 2001 From: Cameron Taylor Date: Thu, 4 Apr 2024 05:33:58 -0400 Subject: [PATCH 081/130] assets submod --- assets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets b/assets index 4ee903339..fe0570d4c 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit 4ee903339e3a34ae8d612125b0bf9c17fbb667b2 +Subproject commit fe0570d4cfe20d232bad062f3140787faad1baeb From 64cab4d1377193794abfa1a7a37b5f5913d060c4 Mon Sep 17 00:00:00 2001 From: Cameron Taylor Date: Thu, 4 Apr 2024 05:37:48 -0400 Subject: [PATCH 082/130] removed duplicate merge --- source/funkin/util/tools/MapTools.hx | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/source/funkin/util/tools/MapTools.hx b/source/funkin/util/tools/MapTools.hx index beee1219b..b98cb0adf 100644 --- a/source/funkin/util/tools/MapTools.hx +++ b/source/funkin/util/tools/MapTools.hx @@ -33,18 +33,6 @@ class MapTools return map.copy(); } - public static function merge(a:Map, b:Map):Map - { - var result = a.copy(); - - for (pair in b.keyValueIterator()) - { - result.set(pair.key, pair.value); - } - - return result; - } - /** * Create a new map which is a combination of the two given maps. * @param a The base map. From acb58a6b49672ff332c8dd725151742080eae084 Mon Sep 17 00:00:00 2001 From: Cameron Taylor Date: Thu, 4 Apr 2024 05:41:44 -0400 Subject: [PATCH 083/130] remove sitelock --- source/funkin/ui/transition/preload/FunkinPreloader.hx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/funkin/ui/transition/preload/FunkinPreloader.hx b/source/funkin/ui/transition/preload/FunkinPreloader.hx index 2e8e0c319..9f509df9c 100644 --- a/source/funkin/ui/transition/preload/FunkinPreloader.hx +++ b/source/funkin/ui/transition/preload/FunkinPreloader.hx @@ -128,7 +128,7 @@ class FunkinPreloader extends FlxBasePreloader public function new() { - super(Constants.PRELOADER_MIN_STAGE_TIME, Constants.SITE_LOCK); + super(Constants.PRELOADER_MIN_STAGE_TIME); // We can't even call trace() yet, until Flixel loads. trace('Initializing custom preloader...'); From 823baa3326fb9b6268610e095f9173c261a3363b Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Sat, 30 Mar 2024 00:54:07 -0400 Subject: [PATCH 084/130] Add new album roll animation (again) --- assets | 2 +- .../graphics/adobeanimate/FlxAtlasSprite.hx | 3 +- source/funkin/ui/freeplay/AlbumRoll.hx | 129 ++++++------------ source/funkin/ui/freeplay/FreeplayState.hx | 10 +- 4 files changed, 47 insertions(+), 97 deletions(-) diff --git a/assets b/assets index fe0570d4c..36f0d2944 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit fe0570d4cfe20d232bad062f3140787faad1baeb +Subproject commit 36f0d29445579402cb42750c746bb07d2565fe81 diff --git a/source/funkin/graphics/adobeanimate/FlxAtlasSprite.hx b/source/funkin/graphics/adobeanimate/FlxAtlasSprite.hx index 5394bce1a..5ab2df837 100644 --- a/source/funkin/graphics/adobeanimate/FlxAtlasSprite.hx +++ b/source/funkin/graphics/adobeanimate/FlxAtlasSprite.hx @@ -137,7 +137,8 @@ class FlxAtlasSprite extends FlxAnimate anim.callback = function(_, frame:Int) { var offset = loop ? 0 : -1; - if (frame == (anim.getFrameLabel(id).duration + offset) + anim.getFrameLabel(id).index) + var frameLabel = anim.getFrameLabel(id); + if (frame == (frameLabel.duration + offset) + frameLabel.index) { if (loop) { diff --git a/source/funkin/ui/freeplay/AlbumRoll.hx b/source/funkin/ui/freeplay/AlbumRoll.hx index bde946e79..189e04973 100644 --- a/source/funkin/ui/freeplay/AlbumRoll.hx +++ b/source/funkin/ui/freeplay/AlbumRoll.hx @@ -1,5 +1,6 @@ package funkin.ui.freeplay; +import funkin.graphics.adobeanimate.FlxAtlasSprite; import flixel.FlxSprite; import flixel.group.FlxSpriteGroup; import flixel.util.FlxSort; @@ -35,30 +36,47 @@ class AlbumRoll extends FlxSpriteGroup return value; } - var albumArt:FunkinSprite; - var albumTitle:FunkinSprite; + var newAlbumArt:FlxAtlasSprite; var difficultyStars:DifficultyStars; var _exitMovers:Null; var albumData:Album; + final animNames:Map = [ + "volume1-active" => "ENTRANCE", + "volume2-active" => "ENTRANCE VOL2", + "volume3-active" => "ENTRANCE VOL3", + "volume1-trans" => "VOL1 TRANS", + "volume2-trans" => "VOL2 TRANS", + "volume3-trans" => "VOL3 TRANS", + "volume1-idle" => "VOL1 STILL", + "volume2-idle" => "VOL2 STILL", + "volume3-idle" => "VOL3 STILL", + ]; + public function new() { super(); - albumTitle = new FunkinSprite(947, 491); - albumTitle.visible = true; - albumTitle.zIndex = 200; - add(albumTitle); + newAlbumArt = new FlxAtlasSprite(0, 0, Paths.animateAtlas("freeplay/albumRoll/freeplayAlbum")); + newAlbumArt.visible = false; + newAlbumArt.onAnimationFinish.add(onAlbumFinish); + + add(newAlbumArt); difficultyStars = new DifficultyStars(140, 39); + difficultyStars.stars.visible = false; + add(difficultyStars); + } - difficultyStars.stars.visible = true; - albumTitle.visible = false; - // albumArtist.visible = false; + function onAlbumFinish(animName:String):Void + { + // Play the idle animation for the current album. + newAlbumArt.playAnimation(animNames.get('$albumId-idle'), false, false, true); - // var albumArtist:FlxSprite = new FlxSprite(1010, 607).loadGraphic(Paths.image('freeplay/albumArtist-kawaisprite')); + // End on the last frame and don't continue until playAnimation is called again. + // newAlbumArt.anim.pause(); } /** @@ -68,13 +86,8 @@ class AlbumRoll extends FlxSpriteGroup { if (albumId == null) { - albumArt.visible = false; - albumTitle.visible = false; - if (titleTimer != null) - { - titleTimer.cancel(); - titleTimer = null; - } + difficultyStars.stars.visible = false; + return; } albumData = AlbumRegistry.instance.fetchEntry(albumId); @@ -86,41 +99,8 @@ class AlbumRoll extends FlxSpriteGroup return; }; - if (albumArt != null) - { - FlxTween.cancelTweensOf(albumArt); - albumArt.visible = false; - albumArt.destroy(); - remove(albumArt); - } - - // Paths.animateAtlas('freeplay/albumRoll'), - albumArt = FunkinSprite.create(1500, 360, albumData.getAlbumArtAssetKey()); - albumArt.setGraphicSize(262, 262); // Magic number for size IG - albumArt.zIndex = 100; - - // playIntro(); - add(albumArt); - applyExitMovers(); - if (Assets.exists(Paths.image(albumData.getAlbumTitleAssetKey()))) - { - if (albumData.hasAlbumTitleAnimations()) - { - albumTitle.loadSparrow(albumData.getAlbumTitleAssetKey()); - FlxAnimationUtil.addAtlasAnimations(albumTitle, albumData.getAlbumTitleAnimations()); - } - else - { - albumTitle.loadGraphic(Paths.image(albumData.getAlbumTitleAssetKey())); - } - } - else - { - albumTitle.visible = false; - } - refresh(); } @@ -146,27 +126,13 @@ class AlbumRoll extends FlxSpriteGroup if (exitMovers == null) return; - exitMovers.set([albumArt], + exitMovers.set([newAlbumArt], { x: FlxG.width, speed: 0.4, wait: 0 }); - exitMovers.set([albumTitle], - { - x: FlxG.width, - speed: 0.2, - wait: 0.1 - }); - /* - exitMovers.set([albumArtist], - { - x: FlxG.width * 1.1, - speed: 0.2, - wait: 0.2 - }); - */ exitMovers.set([difficultyStars], { x: FlxG.width * 1.2, @@ -182,22 +148,21 @@ class AlbumRoll extends FlxSpriteGroup */ public function playIntro():Void { - albumArt.visible = true; - FlxTween.tween(albumArt, {x: 950, y: 320, angle: -340}, 0.5, {ease: FlxEase.elasticOut}); + newAlbumArt.visible = true; + newAlbumArt.playAnimation(animNames.get('$albumId-active'), false, false, false); - albumTitle.visible = false; - - if (titleTimer != null) - { - titleTimer.cancel(); - titleTimer = null; - } - - titleTimer = new FlxTimer().start(0.75, function(_) { - showTitle(); + difficultyStars.stars.visible = false; + new FlxTimer().start(0.75, function(_) { + // showTitle(); + showStars(); }); } + public function skipIntro():Void + { + newAlbumArt.playAnimation(animNames.get('$albumId-trans'), false, false, false); + } + public function setDifficultyStars(?difficulty:Int):Void { if (difficulty == null) return; @@ -205,19 +170,11 @@ class AlbumRoll extends FlxSpriteGroup difficultyStars.difficulty = difficulty; } - public function showTitle():Void - { - albumTitle.visible = true; - albumTitle.animation.play('active'); - albumTitle.animation.finishCallback = (_) -> albumTitle.animation.play('idle'); - } - /** * Make the album stars visible. */ public function showStars():Void { - // albumArtist.visible = false; - difficultyStars.stars.visible = false; + difficultyStars.stars.visible = false; // true; } } diff --git a/source/funkin/ui/freeplay/FreeplayState.hx b/source/funkin/ui/freeplay/FreeplayState.hx index 0724ad022..dc1f164ea 100644 --- a/source/funkin/ui/freeplay/FreeplayState.hx +++ b/source/funkin/ui/freeplay/FreeplayState.hx @@ -469,14 +469,6 @@ class FreeplayState extends MusicBeatSubState albumRoll.playIntro(); - new FlxTimer().start(0.75, function(_) { - albumRoll.showTitle(); - }); - - new FlxTimer().start(35 / 24, function(_) { - albumRoll.showStars(); - }); - FlxTween.tween(grpDifficulties, {x: 90}, 0.6, {ease: FlxEase.quartOut}); var diffSelLeft:DifficultySelector = new DifficultySelector(20, grpDifficulties.y - 10, false, controls); @@ -1055,7 +1047,7 @@ class FreeplayState extends MusicBeatSubState if (albumRoll.albumId != newAlbumId) { albumRoll.albumId = newAlbumId; - albumRoll.playIntro(); + albumRoll.skipIntro(); } } From a764112bd40b9458f4925f5b6a4998f760a9b3e1 Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Fri, 5 Apr 2024 01:24:03 -0400 Subject: [PATCH 085/130] Removed many unused assets to optimize bandwidth usage. --- Project.xml | 4 + assets | 2 +- source/funkin/Paths.hx | 2 +- source/funkin/modding/PolymodHandler.hx | 4 +- source/funkin/play/cutscene/VideoCutscene.hx | 9 +- .../funkin/ui/credits/CreditsDataHandler.hx | 7 ++ .../components/ChartEditorNoteSprite.hx | 6 - source/funkin/ui/freeplay/AlbumRoll.hx | 35 ------ source/funkin/ui/freeplay/DifficultyStars.hx | 106 ------------------ source/funkin/ui/freeplay/FreeplayState.hx | 11 -- source/funkin/ui/mainmenu/MainMenuState.hx | 4 +- 11 files changed, 25 insertions(+), 165 deletions(-) delete mode 100644 source/funkin/ui/freeplay/DifficultyStars.hx diff --git a/Project.xml b/Project.xml index 8ba14e7dc..db338d32a 100644 --- a/Project.xml +++ b/Project.xml @@ -45,6 +45,7 @@ +
@@ -58,10 +59,13 @@ +
+ + diff --git a/assets b/assets index 5027bc656..a11c558e4 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit 5027bc656c9df5ec208ab256f9494bd7da425111 +Subproject commit a11c558e4c0ed796c34246b43abc9c2d024d0a42 diff --git a/source/funkin/Paths.hx b/source/funkin/Paths.hx index fd4ef76fa..54a4b7acf 100644 --- a/source/funkin/Paths.hx +++ b/source/funkin/Paths.hx @@ -113,7 +113,7 @@ class Paths public static function videos(key:String, ?library:String):String { - return getPath('videos/$key.${Constants.EXT_VIDEO}', BINARY, library); + return getPath('videos/$key.${Constants.EXT_VIDEO}', BINARY, library ?? 'videos'); } public static function voices(song:String, ?suffix:String = ''):String diff --git a/source/funkin/modding/PolymodHandler.hx b/source/funkin/modding/PolymodHandler.hx index 78f660d3f..62860ee0f 100644 --- a/source/funkin/modding/PolymodHandler.hx +++ b/source/funkin/modding/PolymodHandler.hx @@ -240,8 +240,8 @@ class PolymodHandler { return { assetLibraryPaths: [ - 'default' => 'preload', 'shared' => 'shared', 'songs' => 'songs', 'tutorial' => 'tutorial', 'week1' => 'week1', 'week2' => 'week2', - 'week3' => 'week3', 'week4' => 'week4', 'week5' => 'week5', 'week6' => 'week6', 'week7' => 'week7', 'weekend1' => 'weekend1', + 'default' => 'preload', 'shared' => 'shared', 'songs' => 'songs', 'videos' => 'videos', 'tutorial' => 'tutorial', 'week1' => 'week1', + 'week2' => 'week2', 'week3' => 'week3', 'week4' => 'week4', 'week5' => 'week5', 'week6' => 'week6', 'week7' => 'week7', 'weekend1' => 'weekend1', ], coreAssetRedirect: CORE_FOLDER, } diff --git a/source/funkin/play/cutscene/VideoCutscene.hx b/source/funkin/play/cutscene/VideoCutscene.hx index 3da51185f..6983fbcad 100644 --- a/source/funkin/play/cutscene/VideoCutscene.hx +++ b/source/funkin/play/cutscene/VideoCutscene.hx @@ -67,8 +67,13 @@ class VideoCutscene if (!openfl.Assets.exists(filePath)) { // Display a popup. - lime.app.Application.current.window.alert('Video file does not exist: ${filePath}', 'Error playing video'); - return; + // lime.app.Application.current.window.alert('Video file does not exist: ${filePath}', 'Error playing video'); + // return; + + // TODO: After moving videos to their own library, + // this function ALWAYS FAILS on web, but the video still plays. + // I think that's due to a weird quirk with how OpenFL libraries work. + trace('Video file does not exist: ${filePath}'); } var rawFilePath = Paths.stripLibrary(filePath); diff --git a/source/funkin/ui/credits/CreditsDataHandler.hx b/source/funkin/ui/credits/CreditsDataHandler.hx index 86afdafd1..628a9f893 100644 --- a/source/funkin/ui/credits/CreditsDataHandler.hx +++ b/source/funkin/ui/credits/CreditsDataHandler.hx @@ -99,12 +99,19 @@ class CreditsDataHandler static function fetchCreditsData():funkin.data.JsonFile { + #if !macro var rawJson:String = openfl.Assets.getText(CREDITS_DATA_PATH).trim(); return { fileName: CREDITS_DATA_PATH, contents: rawJson }; + #else + return { + fileName: CREDITS_DATA_PATH, + contents: null + }; + #end } static function parseCreditsData(file:JsonFile):Null diff --git a/source/funkin/ui/debug/charting/components/ChartEditorNoteSprite.hx b/source/funkin/ui/debug/charting/components/ChartEditorNoteSprite.hx index cd403c6f8..98f5a47aa 100644 --- a/source/funkin/ui/debug/charting/components/ChartEditorNoteSprite.hx +++ b/source/funkin/ui/debug/charting/components/ChartEditorNoteSprite.hx @@ -117,12 +117,6 @@ class ChartEditorNoteSprite extends FlxSprite { noteFrameCollection.pushFrame(frame); } - var frameCollectionNormal2:FlxAtlasFrames = Paths.getSparrowAtlas('NoteHoldNormal'); - - for (frame in frameCollectionNormal2.frames) - { - noteFrameCollection.pushFrame(frame); - } // Pixel notes var graphicPixel = FlxG.bitmap.add(Paths.image('weeb/pixelUI/arrows-pixels', 'week6'), false, null); diff --git a/source/funkin/ui/freeplay/AlbumRoll.hx b/source/funkin/ui/freeplay/AlbumRoll.hx index bde946e79..c1263fed6 100644 --- a/source/funkin/ui/freeplay/AlbumRoll.hx +++ b/source/funkin/ui/freeplay/AlbumRoll.hx @@ -37,7 +37,6 @@ class AlbumRoll extends FlxSpriteGroup var albumArt:FunkinSprite; var albumTitle:FunkinSprite; - var difficultyStars:DifficultyStars; var _exitMovers:Null; @@ -52,9 +51,6 @@ class AlbumRoll extends FlxSpriteGroup albumTitle.zIndex = 200; add(albumTitle); - difficultyStars = new DifficultyStars(140, 39); - - difficultyStars.stars.visible = true; albumTitle.visible = false; // albumArtist.visible = false; @@ -158,21 +154,6 @@ class AlbumRoll extends FlxSpriteGroup speed: 0.2, wait: 0.1 }); - - /* - exitMovers.set([albumArtist], - { - x: FlxG.width * 1.1, - speed: 0.2, - wait: 0.2 - }); - */ - exitMovers.set([difficultyStars], - { - x: FlxG.width * 1.2, - speed: 0.2, - wait: 0.3 - }); } var titleTimer:Null = null; @@ -198,26 +179,10 @@ class AlbumRoll extends FlxSpriteGroup }); } - public function setDifficultyStars(?difficulty:Int):Void - { - if (difficulty == null) return; - - difficultyStars.difficulty = difficulty; - } - public function showTitle():Void { albumTitle.visible = true; albumTitle.animation.play('active'); albumTitle.animation.finishCallback = (_) -> albumTitle.animation.play('idle'); } - - /** - * Make the album stars visible. - */ - public function showStars():Void - { - // albumArtist.visible = false; - difficultyStars.stars.visible = false; - } } diff --git a/source/funkin/ui/freeplay/DifficultyStars.hx b/source/funkin/ui/freeplay/DifficultyStars.hx deleted file mode 100644 index 51526bcbe..000000000 --- a/source/funkin/ui/freeplay/DifficultyStars.hx +++ /dev/null @@ -1,106 +0,0 @@ -package funkin.ui.freeplay; - -import flixel.group.FlxSpriteGroup; -import funkin.graphics.adobeanimate.FlxAtlasSprite; -import funkin.graphics.shaders.HSVShader; - -class DifficultyStars extends FlxSpriteGroup -{ - /** - * Internal handler var for difficulty... ranges from 0... to 15 - * 0 is 1 star... 15 is 0 stars! - */ - var curDifficulty(default, set):Int = 0; - - /** - * Range between 0 and 15 - */ - public var difficulty(default, set):Int = 1; - - public var stars:FlxAtlasSprite; - - var flames:FreeplayFlames; - - var hsvShader:HSVShader; - - public function new(x:Float, y:Float) - { - super(x, y); - - hsvShader = new HSVShader(); - - flames = new FreeplayFlames(0, 0); - add(flames); - - stars = new FlxAtlasSprite(0, 0, Paths.animateAtlas("freeplay/freeplayStars")); - stars.anim.play("diff stars"); - add(stars); - - stars.shader = hsvShader; - - for (memb in flames.members) - memb.shader = hsvShader; - } - - override function update(elapsed:Float):Void - { - super.update(elapsed); - - // "loops" the current animation - // for clarity, the animation file looks like - // frame : stars - // 0-99: 1 star - // 100-199: 2 stars - // ...... - // 1300-1499: 15 stars - // 1500 : 0 stars - if (curDifficulty < 15 && stars.anim.curFrame >= (curDifficulty + 1) * 100) - { - stars.anim.play("diff stars", true, false, curDifficulty * 100); - } - } - - function set_difficulty(value:Int):Int - { - difficulty = value; - - if (difficulty <= 0) - { - difficulty = 0; - curDifficulty = 15; - } - else if (difficulty <= 15) - { - difficulty = value; - curDifficulty = difficulty - 1; - } - else - { - difficulty = 15; - curDifficulty = difficulty - 1; - } - - if (difficulty > 10) flames.flameCount = difficulty - 10; - else - flames.flameCount = 0; - - return difficulty; - } - - function set_curDifficulty(value:Int):Int - { - curDifficulty = value; - if (curDifficulty == 15) - { - stars.anim.play("diff stars", true, false, 1500); - stars.anim.pause(); - } - else - { - stars.anim.curFrame = Std.int(curDifficulty * 100); - stars.anim.play("diff stars", true, false, curDifficulty * 100); - } - - return curDifficulty; - } -} diff --git a/source/funkin/ui/freeplay/FreeplayState.hx b/source/funkin/ui/freeplay/FreeplayState.hx index 0724ad022..af76a42ce 100644 --- a/source/funkin/ui/freeplay/FreeplayState.hx +++ b/source/funkin/ui/freeplay/FreeplayState.hx @@ -473,10 +473,6 @@ class FreeplayState extends MusicBeatSubState albumRoll.showTitle(); }); - new FlxTimer().start(35 / 24, function(_) { - albumRoll.showStars(); - }); - FlxTween.tween(grpDifficulties, {x: 90}, 0.6, {ease: FlxEase.quartOut}); var diffSelLeft:DifficultySelector = new DifficultySelector(20, grpDifficulties.y - 10, false, controls); @@ -1047,9 +1043,6 @@ class FreeplayState extends MusicBeatSubState } } - // Set the difficulty star count on the right. - albumRoll.setDifficultyStars(daSong?.songRating); - // Set the album graphic and play the animation if relevant. var newAlbumId:String = daSong?.albumId; if (albumRoll.albumId != newAlbumId) @@ -1169,10 +1162,6 @@ class FreeplayState extends MusicBeatSubState { currentDifficulty = rememberedDifficulty; } - - // Set the difficulty star count on the right. - var daSong:Null = grpCapsules.members[curSelected]?.songData; - albumRoll.setDifficultyStars(daSong?.songRating ?? 0); } function changeSelection(change:Int = 0):Void diff --git a/source/funkin/ui/mainmenu/MainMenuState.hx b/source/funkin/ui/mainmenu/MainMenuState.hx index f38db1ccd..c1dc54ffe 100644 --- a/source/funkin/ui/mainmenu/MainMenuState.hx +++ b/source/funkin/ui/mainmenu/MainMenuState.hx @@ -1,5 +1,6 @@ package funkin.ui.mainmenu; +import funkin.graphics.FunkinSprite; import flixel.addons.transition.FlxTransitionableState; import funkin.ui.debug.DebugMenuSubState; import flixel.FlxObject; @@ -56,7 +57,8 @@ class MainMenuState extends MusicBeatState persistentUpdate = false; persistentDraw = true; - var bg:FlxSprite = new FlxSprite(Paths.image('menuBG')); + var bg = FunkinSprite.create('menuDesat'); + bg.color = 0xFFFDE871; bg.scrollFactor.x = 0; bg.scrollFactor.y = 0.17; bg.setGraphicSize(Std.int(bg.width * 1.2)); From 08e8530ad4c29d2b9454b3f155d94baad16290e4 Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Fri, 5 Apr 2024 02:44:44 -0400 Subject: [PATCH 086/130] Fix SetCameraBopSongEvent to be additive --- art | 2 +- source/funkin/play/PlayState.hx | 3 ++- source/funkin/play/event/SetCameraBopSongEvent.hx | 4 ++-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/art b/art index 03e7c2a23..00463685f 160000 --- a/art +++ b/art @@ -1 +1 @@ -Subproject commit 03e7c2a2353b184e45955c96d763b7cdf1acbc34 +Subproject commit 00463685fa570f0c853d08e250b46ef80f30bc48 diff --git a/source/funkin/play/PlayState.hx b/source/funkin/play/PlayState.hx index de8597c17..0ee85ac9b 100644 --- a/source/funkin/play/PlayState.hx +++ b/source/funkin/play/PlayState.hx @@ -866,7 +866,7 @@ class PlayState extends MusicBeatSubState // Reset camera zooming cameraBopIntensity = Constants.DEFAULT_BOP_INTENSITY; - hudCameraZoomIntensity = 0.015 * 2.0; + hudCameraZoomIntensity = (cameraBopIntensity - 1.0) * 2.0; cameraZoomRate = Constants.DEFAULT_ZOOM_RATE; health = Constants.HEALTH_STARTING; @@ -976,6 +976,7 @@ class PlayState extends MusicBeatSubState FlxG.watch.addQuick('bfAnim', currentStage.getBoyfriend().getCurrentAnimation()); } FlxG.watch.addQuick('health', health); + FlxG.watch.addQuick('cameraBopIntensity', cameraBopIntensity); // TODO: Add a song event for Handle GF dance speed. diff --git a/source/funkin/play/event/SetCameraBopSongEvent.hx b/source/funkin/play/event/SetCameraBopSongEvent.hx index 9d3e785ed..f3efc04e3 100644 --- a/source/funkin/play/event/SetCameraBopSongEvent.hx +++ b/source/funkin/play/event/SetCameraBopSongEvent.hx @@ -50,8 +50,8 @@ class SetCameraBopSongEvent extends SongEvent var intensity:Null = data.getFloat('intensity'); if (intensity == null) intensity = 1.0; - PlayState.instance.cameraBopIntensity = Constants.DEFAULT_BOP_INTENSITY * intensity; - PlayState.instance.hudCameraZoomIntensity = 1.015 * intensity * 2.0; + PlayState.instance.cameraBopIntensity = (Constants.DEFAULT_BOP_INTENSITY - 1.0) * intensity + 1.0; + PlayState.instance.hudCameraZoomIntensity = (Constants.DEFAULT_BOP_INTENSITY - 1.0) * intensity * 2.0; PlayState.instance.cameraZoomRate = rate; trace('Set camera zoom rate to ${PlayState.instance.cameraZoomRate}'); } From 95434018f70fa84c0cfb6808a361d4c3021cfde7 Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Fri, 5 Apr 2024 02:56:47 -0400 Subject: [PATCH 087/130] Readd GF camera zoom into results state. --- source/funkin/play/PlayState.hx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/funkin/play/PlayState.hx b/source/funkin/play/PlayState.hx index b59c48888..795f493e8 100644 --- a/source/funkin/play/PlayState.hx +++ b/source/funkin/play/PlayState.hx @@ -966,7 +966,7 @@ class PlayState extends MusicBeatSubState if (health < Constants.HEALTH_MIN) health = Constants.HEALTH_MIN; // Apply camera zoom + multipliers. - if (subState == null) + if (subState == null && cameraZoomRate > 0.0 && !isInCutscene) { cameraBopMultiplier = FlxMath.lerp(1.0, cameraBopMultiplier, 0.95); // Lerp bop multiplier back to 1.0x var zoomPlusBop = currentCameraZoom * cameraBopMultiplier; // Apply camera bop multiplier. From ab18c648217b9d28d6a17f01324ad6d30c07cb76 Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Fri, 5 Apr 2024 03:33:15 -0400 Subject: [PATCH 088/130] Fix various audio fixes --- assets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets b/assets index 5027bc656..d44f74fe8 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit 5027bc656c9df5ec208ab256f9494bd7da425111 +Subproject commit d44f74fe8b7655d8fceea71d0854134279b1b61d From ab2c4bf20b5c91a75f8b0420b1f5baea39c22813 Mon Sep 17 00:00:00 2001 From: Cameron Taylor Date: Fri, 5 Apr 2024 16:42:14 -0400 Subject: [PATCH 089/130] assets submod --- assets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets b/assets index d44f74fe8..e8f4d2d91 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit d44f74fe8b7655d8fceea71d0854134279b1b61d +Subproject commit e8f4d2d91c7bd5a922465e7d67a0efb7d7574bd6 From af8a37d299aa6ea015dd7476ec4dfa8fbf4c9264 Mon Sep 17 00:00:00 2001 From: Cameron Taylor Date: Fri, 5 Apr 2024 19:33:24 -0400 Subject: [PATCH 090/130] assets submod --- assets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets b/assets index a11c558e4..2eb07acf1 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit a11c558e4c0ed796c34246b43abc9c2d024d0a42 +Subproject commit 2eb07acf1fbee70229b913f87cfc1bfddf22ab88 From a6d44b1f1552e747f45028659bf5887fc7da9f08 Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Fri, 5 Apr 2024 01:24:03 -0400 Subject: [PATCH 091/130] Removed many unused assets to optimize bandwidth usage. --- Project.xml | 4 + assets | 2 +- source/funkin/Paths.hx | 2 +- source/funkin/modding/PolymodHandler.hx | 4 +- source/funkin/play/cutscene/VideoCutscene.hx | 9 +- .../funkin/ui/credits/CreditsDataHandler.hx | 7 ++ .../components/ChartEditorNoteSprite.hx | 6 - source/funkin/ui/freeplay/DifficultyStars.hx | 106 ------------------ source/funkin/ui/freeplay/FreeplayState.hx | 11 +- source/funkin/ui/mainmenu/MainMenuState.hx | 4 +- 10 files changed, 29 insertions(+), 126 deletions(-) delete mode 100644 source/funkin/ui/freeplay/DifficultyStars.hx diff --git a/Project.xml b/Project.xml index 8ba14e7dc..db338d32a 100644 --- a/Project.xml +++ b/Project.xml @@ -45,6 +45,7 @@ +
@@ -58,10 +59,13 @@ +
+ + diff --git a/assets b/assets index e8f4d2d91..2eb07acf1 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit e8f4d2d91c7bd5a922465e7d67a0efb7d7574bd6 +Subproject commit 2eb07acf1fbee70229b913f87cfc1bfddf22ab88 diff --git a/source/funkin/Paths.hx b/source/funkin/Paths.hx index fd4ef76fa..54a4b7acf 100644 --- a/source/funkin/Paths.hx +++ b/source/funkin/Paths.hx @@ -113,7 +113,7 @@ class Paths public static function videos(key:String, ?library:String):String { - return getPath('videos/$key.${Constants.EXT_VIDEO}', BINARY, library); + return getPath('videos/$key.${Constants.EXT_VIDEO}', BINARY, library ?? 'videos'); } public static function voices(song:String, ?suffix:String = ''):String diff --git a/source/funkin/modding/PolymodHandler.hx b/source/funkin/modding/PolymodHandler.hx index 78f660d3f..62860ee0f 100644 --- a/source/funkin/modding/PolymodHandler.hx +++ b/source/funkin/modding/PolymodHandler.hx @@ -240,8 +240,8 @@ class PolymodHandler { return { assetLibraryPaths: [ - 'default' => 'preload', 'shared' => 'shared', 'songs' => 'songs', 'tutorial' => 'tutorial', 'week1' => 'week1', 'week2' => 'week2', - 'week3' => 'week3', 'week4' => 'week4', 'week5' => 'week5', 'week6' => 'week6', 'week7' => 'week7', 'weekend1' => 'weekend1', + 'default' => 'preload', 'shared' => 'shared', 'songs' => 'songs', 'videos' => 'videos', 'tutorial' => 'tutorial', 'week1' => 'week1', + 'week2' => 'week2', 'week3' => 'week3', 'week4' => 'week4', 'week5' => 'week5', 'week6' => 'week6', 'week7' => 'week7', 'weekend1' => 'weekend1', ], coreAssetRedirect: CORE_FOLDER, } diff --git a/source/funkin/play/cutscene/VideoCutscene.hx b/source/funkin/play/cutscene/VideoCutscene.hx index 0c05bc876..0939dae38 100644 --- a/source/funkin/play/cutscene/VideoCutscene.hx +++ b/source/funkin/play/cutscene/VideoCutscene.hx @@ -67,8 +67,13 @@ class VideoCutscene if (!openfl.Assets.exists(filePath)) { // Display a popup. - lime.app.Application.current.window.alert('Video file does not exist: ${filePath}', 'Error playing video'); - return; + // lime.app.Application.current.window.alert('Video file does not exist: ${filePath}', 'Error playing video'); + // return; + + // TODO: After moving videos to their own library, + // this function ALWAYS FAILS on web, but the video still plays. + // I think that's due to a weird quirk with how OpenFL libraries work. + trace('Video file does not exist: ${filePath}'); } var rawFilePath = Paths.stripLibrary(filePath); diff --git a/source/funkin/ui/credits/CreditsDataHandler.hx b/source/funkin/ui/credits/CreditsDataHandler.hx index 86afdafd1..628a9f893 100644 --- a/source/funkin/ui/credits/CreditsDataHandler.hx +++ b/source/funkin/ui/credits/CreditsDataHandler.hx @@ -99,12 +99,19 @@ class CreditsDataHandler static function fetchCreditsData():funkin.data.JsonFile { + #if !macro var rawJson:String = openfl.Assets.getText(CREDITS_DATA_PATH).trim(); return { fileName: CREDITS_DATA_PATH, contents: rawJson }; + #else + return { + fileName: CREDITS_DATA_PATH, + contents: null + }; + #end } static function parseCreditsData(file:JsonFile):Null diff --git a/source/funkin/ui/debug/charting/components/ChartEditorNoteSprite.hx b/source/funkin/ui/debug/charting/components/ChartEditorNoteSprite.hx index cd403c6f8..98f5a47aa 100644 --- a/source/funkin/ui/debug/charting/components/ChartEditorNoteSprite.hx +++ b/source/funkin/ui/debug/charting/components/ChartEditorNoteSprite.hx @@ -117,12 +117,6 @@ class ChartEditorNoteSprite extends FlxSprite { noteFrameCollection.pushFrame(frame); } - var frameCollectionNormal2:FlxAtlasFrames = Paths.getSparrowAtlas('NoteHoldNormal'); - - for (frame in frameCollectionNormal2.frames) - { - noteFrameCollection.pushFrame(frame); - } // Pixel notes var graphicPixel = FlxG.bitmap.add(Paths.image('weeb/pixelUI/arrows-pixels', 'week6'), false, null); diff --git a/source/funkin/ui/freeplay/DifficultyStars.hx b/source/funkin/ui/freeplay/DifficultyStars.hx deleted file mode 100644 index 51526bcbe..000000000 --- a/source/funkin/ui/freeplay/DifficultyStars.hx +++ /dev/null @@ -1,106 +0,0 @@ -package funkin.ui.freeplay; - -import flixel.group.FlxSpriteGroup; -import funkin.graphics.adobeanimate.FlxAtlasSprite; -import funkin.graphics.shaders.HSVShader; - -class DifficultyStars extends FlxSpriteGroup -{ - /** - * Internal handler var for difficulty... ranges from 0... to 15 - * 0 is 1 star... 15 is 0 stars! - */ - var curDifficulty(default, set):Int = 0; - - /** - * Range between 0 and 15 - */ - public var difficulty(default, set):Int = 1; - - public var stars:FlxAtlasSprite; - - var flames:FreeplayFlames; - - var hsvShader:HSVShader; - - public function new(x:Float, y:Float) - { - super(x, y); - - hsvShader = new HSVShader(); - - flames = new FreeplayFlames(0, 0); - add(flames); - - stars = new FlxAtlasSprite(0, 0, Paths.animateAtlas("freeplay/freeplayStars")); - stars.anim.play("diff stars"); - add(stars); - - stars.shader = hsvShader; - - for (memb in flames.members) - memb.shader = hsvShader; - } - - override function update(elapsed:Float):Void - { - super.update(elapsed); - - // "loops" the current animation - // for clarity, the animation file looks like - // frame : stars - // 0-99: 1 star - // 100-199: 2 stars - // ...... - // 1300-1499: 15 stars - // 1500 : 0 stars - if (curDifficulty < 15 && stars.anim.curFrame >= (curDifficulty + 1) * 100) - { - stars.anim.play("diff stars", true, false, curDifficulty * 100); - } - } - - function set_difficulty(value:Int):Int - { - difficulty = value; - - if (difficulty <= 0) - { - difficulty = 0; - curDifficulty = 15; - } - else if (difficulty <= 15) - { - difficulty = value; - curDifficulty = difficulty - 1; - } - else - { - difficulty = 15; - curDifficulty = difficulty - 1; - } - - if (difficulty > 10) flames.flameCount = difficulty - 10; - else - flames.flameCount = 0; - - return difficulty; - } - - function set_curDifficulty(value:Int):Int - { - curDifficulty = value; - if (curDifficulty == 15) - { - stars.anim.play("diff stars", true, false, 1500); - stars.anim.pause(); - } - else - { - stars.anim.curFrame = Std.int(curDifficulty * 100); - stars.anim.play("diff stars", true, false, curDifficulty * 100); - } - - return curDifficulty; - } -} diff --git a/source/funkin/ui/freeplay/FreeplayState.hx b/source/funkin/ui/freeplay/FreeplayState.hx index dc1f164ea..150f5a0b1 100644 --- a/source/funkin/ui/freeplay/FreeplayState.hx +++ b/source/funkin/ui/freeplay/FreeplayState.hx @@ -469,6 +469,10 @@ class FreeplayState extends MusicBeatSubState albumRoll.playIntro(); + new FlxTimer().start(0.75, function(_) { + albumRoll.showTitle(); + }); + FlxTween.tween(grpDifficulties, {x: 90}, 0.6, {ease: FlxEase.quartOut}); var diffSelLeft:DifficultySelector = new DifficultySelector(20, grpDifficulties.y - 10, false, controls); @@ -1039,9 +1043,6 @@ class FreeplayState extends MusicBeatSubState } } - // Set the difficulty star count on the right. - albumRoll.setDifficultyStars(daSong?.songRating); - // Set the album graphic and play the animation if relevant. var newAlbumId:String = daSong?.albumId; if (albumRoll.albumId != newAlbumId) @@ -1161,10 +1162,6 @@ class FreeplayState extends MusicBeatSubState { currentDifficulty = rememberedDifficulty; } - - // Set the difficulty star count on the right. - var daSong:Null = grpCapsules.members[curSelected]?.songData; - albumRoll.setDifficultyStars(daSong?.songRating ?? 0); } function changeSelection(change:Int = 0):Void diff --git a/source/funkin/ui/mainmenu/MainMenuState.hx b/source/funkin/ui/mainmenu/MainMenuState.hx index f38db1ccd..c1dc54ffe 100644 --- a/source/funkin/ui/mainmenu/MainMenuState.hx +++ b/source/funkin/ui/mainmenu/MainMenuState.hx @@ -1,5 +1,6 @@ package funkin.ui.mainmenu; +import funkin.graphics.FunkinSprite; import flixel.addons.transition.FlxTransitionableState; import funkin.ui.debug.DebugMenuSubState; import flixel.FlxObject; @@ -56,7 +57,8 @@ class MainMenuState extends MusicBeatState persistentUpdate = false; persistentDraw = true; - var bg:FlxSprite = new FlxSprite(Paths.image('menuBG')); + var bg = FunkinSprite.create('menuDesat'); + bg.color = 0xFFFDE871; bg.scrollFactor.x = 0; bg.scrollFactor.y = 0.17; bg.setGraphicSize(Std.int(bg.width * 1.2)); From da4f1fb424564b1be658fd0d32b7b53e743299a0 Mon Sep 17 00:00:00 2001 From: Cameron Taylor Date: Fri, 5 Apr 2024 19:47:33 -0400 Subject: [PATCH 092/130] remove difficulty stars --- source/funkin/ui/freeplay/AlbumRoll.hx | 52 +++++++++++----------- source/funkin/ui/freeplay/FreeplayState.hx | 2 +- 2 files changed, 26 insertions(+), 28 deletions(-) diff --git a/source/funkin/ui/freeplay/AlbumRoll.hx b/source/funkin/ui/freeplay/AlbumRoll.hx index 189e04973..89c6c73a6 100644 --- a/source/funkin/ui/freeplay/AlbumRoll.hx +++ b/source/funkin/ui/freeplay/AlbumRoll.hx @@ -37,8 +37,8 @@ class AlbumRoll extends FlxSpriteGroup } var newAlbumArt:FlxAtlasSprite; - var difficultyStars:DifficultyStars; + // var difficultyStars:DifficultyStars; var _exitMovers:Null; var albumData:Album; @@ -65,9 +65,9 @@ class AlbumRoll extends FlxSpriteGroup add(newAlbumArt); - difficultyStars = new DifficultyStars(140, 39); - difficultyStars.stars.visible = false; - add(difficultyStars); + // difficultyStars = new DifficultyStars(140, 39); + // difficultyStars.stars.visible = false; + // add(difficultyStars); } function onAlbumFinish(animName:String):Void @@ -86,7 +86,7 @@ class AlbumRoll extends FlxSpriteGroup { if (albumId == null) { - difficultyStars.stars.visible = false; + // difficultyStars.stars.visible = false; return; } @@ -133,12 +133,12 @@ class AlbumRoll extends FlxSpriteGroup wait: 0 }); - exitMovers.set([difficultyStars], - { - x: FlxG.width * 1.2, - speed: 0.2, - wait: 0.3 - }); + // exitMovers.set([difficultyStars], + // { + // x: FlxG.width * 1.2, + // speed: 0.2, + // wait: 0.3 + // }); } var titleTimer:Null = null; @@ -151,10 +151,10 @@ class AlbumRoll extends FlxSpriteGroup newAlbumArt.visible = true; newAlbumArt.playAnimation(animNames.get('$albumId-active'), false, false, false); - difficultyStars.stars.visible = false; + // difficultyStars.stars.visible = false; new FlxTimer().start(0.75, function(_) { // showTitle(); - showStars(); + // showStars(); }); } @@ -163,18 +163,16 @@ class AlbumRoll extends FlxSpriteGroup newAlbumArt.playAnimation(animNames.get('$albumId-trans'), false, false, false); } - public function setDifficultyStars(?difficulty:Int):Void - { - if (difficulty == null) return; - - difficultyStars.difficulty = difficulty; - } - - /** - * Make the album stars visible. - */ - public function showStars():Void - { - difficultyStars.stars.visible = false; // true; - } + // public function setDifficultyStars(?difficulty:Int):Void + // { + // if (difficulty == null) return; + // difficultyStars.difficulty = difficulty; + // } + // /** + // * Make the album stars visible. + // */ + // public function showStars():Void + // { + // difficultyStars.stars.visible = false; // true; + // } } diff --git a/source/funkin/ui/freeplay/FreeplayState.hx b/source/funkin/ui/freeplay/FreeplayState.hx index 150f5a0b1..ae51ba82a 100644 --- a/source/funkin/ui/freeplay/FreeplayState.hx +++ b/source/funkin/ui/freeplay/FreeplayState.hx @@ -470,7 +470,7 @@ class FreeplayState extends MusicBeatSubState albumRoll.playIntro(); new FlxTimer().start(0.75, function(_) { - albumRoll.showTitle(); + // albumRoll.showTitle(); }); FlxTween.tween(grpDifficulties, {x: 90}, 0.6, {ease: FlxEase.quartOut}); From 2462bd2d9943fe7839335d080db74c0b3f3e5059 Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Fri, 5 Apr 2024 22:05:34 -0400 Subject: [PATCH 093/130] Update assets submodule --- assets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets b/assets index 2eb07acf1..84c3c7fef 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit 2eb07acf1fbee70229b913f87cfc1bfddf22ab88 +Subproject commit 84c3c7fef411c616e558b5b497f70c106adc11d1 From 9a7a385af1e051a1affd19725eb14b731da5f921 Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Sat, 6 Apr 2024 01:11:27 -0400 Subject: [PATCH 094/130] Fix segmentation fault on Linux by rebuilding Lime. --- .vscode/settings.json | 5 +++++ hmm.json | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 13a1862d2..96481461d 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -96,6 +96,11 @@ "target": "windows", "args": ["-debug", "-DFORCE_DEBUG_VERSION"] }, + { + "label": "Linux / Debug", + "target": "linux", + "args": ["-debug", "-DFORCE_DEBUG_VERSION"] + }, { "label": "HashLink / Debug", "target": "hl", diff --git a/hmm.json b/hmm.json index 641ef1bbd..8c07023c7 100644 --- a/hmm.json +++ b/hmm.json @@ -104,7 +104,7 @@ "name": "lime", "type": "git", "dir": null, - "ref": "1359fe6ad52e91175dc636a516d460bd54ea22ed", + "ref": "43ebebdd8119936b99f23407057025c7849c5f5b", "url": "https://github.com/FunkinCrew/lime" }, { From 958ebe92a3b5f8e834706e306793426b4b98b5f1 Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Sat, 6 Apr 2024 01:59:39 -0400 Subject: [PATCH 095/130] Fix tankman's offsets to not suck. --- assets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets b/assets index e8f4d2d91..da3c17f2b 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit e8f4d2d91c7bd5a922465e7d67a0efb7d7574bd6 +Subproject commit da3c17f2b0473af1b95167e563c4b3799d006438 From 29f105a44d89487a69df84604719c5fd84df88f6 Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Sat, 6 Apr 2024 01:59:46 -0400 Subject: [PATCH 096/130] Practice mode = no highscore! --- source/funkin/play/PlayState.hx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/funkin/play/PlayState.hx b/source/funkin/play/PlayState.hx index 795f493e8..215979fdd 100644 --- a/source/funkin/play/PlayState.hx +++ b/source/funkin/play/PlayState.hx @@ -2786,7 +2786,7 @@ class PlayState extends MusicBeatSubState // adds current song data into the tallies for the level (story levels) Highscore.talliesLevel = Highscore.combineTallies(Highscore.tallies, Highscore.talliesLevel); - if (Save.instance.isSongHighScore(currentSong.id, currentDifficulty, data)) + if (!isPracticeMode && Save.instance.isSongHighScore(currentSong.id, currentDifficulty, data)) { Save.instance.setSongScore(currentSong.id, currentDifficulty, data); #if newgrounds From 99ee2b07ca1737430afc1bf8edcc1da58c12297f Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Sat, 6 Apr 2024 02:06:06 -0400 Subject: [PATCH 097/130] Make results screen use full campaign score in Story Mode --- source/funkin/play/PlayState.hx | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/source/funkin/play/PlayState.hx b/source/funkin/play/PlayState.hx index 215979fdd..2c8d72293 100644 --- a/source/funkin/play/PlayState.hx +++ b/source/funkin/play/PlayState.hx @@ -3072,18 +3072,18 @@ class PlayState extends MusicBeatSubState title: PlayStatePlaylist.isStoryMode ? ('${PlayStatePlaylist.campaignTitle}') : ('${currentChart.songName} by ${currentChart.songArtist}'), scoreData: { - score: songScore, + score: PlayStatePlaylist.isStoryMode ? PlayStatePlaylist.campaignScore : songScore, tallies: { - sick: Highscore.tallies.sick, - good: Highscore.tallies.good, - bad: Highscore.tallies.bad, - shit: Highscore.tallies.shit, - missed: Highscore.tallies.missed, - combo: Highscore.tallies.combo, - maxCombo: Highscore.tallies.maxCombo, - totalNotesHit: Highscore.tallies.totalNotesHit, - totalNotes: Highscore.tallies.totalNotes, + sick: talliesToUse.sick, + good: talliesToUse.good, + bad: talliesToUse.bad, + shit: talliesToUse.shit, + missed: talliesToUse.missed, + combo: talliesToUse.combo, + maxCombo: talliesToUse.maxCombo, + totalNotesHit: talliesToUse.totalNotesHit, + totalNotes: talliesToUse.totalNotes, }, accuracy: Highscore.tallies.totalNotesHit / Highscore.tallies.totalNotes, }, From 14869b937329e455049595d905b95ce0b830333f Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Sat, 6 Apr 2024 02:08:10 -0400 Subject: [PATCH 098/130] Also disable highscores in botplay --- source/funkin/play/PlayState.hx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/funkin/play/PlayState.hx b/source/funkin/play/PlayState.hx index 2c8d72293..474caf031 100644 --- a/source/funkin/play/PlayState.hx +++ b/source/funkin/play/PlayState.hx @@ -2786,7 +2786,7 @@ class PlayState extends MusicBeatSubState // adds current song data into the tallies for the level (story levels) Highscore.talliesLevel = Highscore.combineTallies(Highscore.tallies, Highscore.talliesLevel); - if (!isPracticeMode && Save.instance.isSongHighScore(currentSong.id, currentDifficulty, data)) + if (!isPracticeMode && !isBotPlayMode && Save.instance.isSongHighScore(currentSong.id, currentDifficulty, data)) { Save.instance.setSongScore(currentSong.id, currentDifficulty, data); #if newgrounds From 09d5370c2ead699969b135c61fd692075d7f72ee Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Sat, 6 Apr 2024 02:35:27 -0400 Subject: [PATCH 099/130] Fix an issue where Pico gets stuck blocking after a failed uppercut. --- assets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets b/assets index e8f4d2d91..c73fd0b0a 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit e8f4d2d91c7bd5a922465e7d67a0efb7d7574bd6 +Subproject commit c73fd0b0ab8f904ac22b594afc847be2d10587f4 From 5beb20ec7cb876e6b571c9da7bf53c19ae14647d Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Sat, 6 Apr 2024 21:42:18 -0400 Subject: [PATCH 100/130] Fix bug where restarting the song would sometimes crash. --- source/funkin/play/PlayState.hx | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/source/funkin/play/PlayState.hx b/source/funkin/play/PlayState.hx index 795f493e8..dbae9ed2a 100644 --- a/source/funkin/play/PlayState.hx +++ b/source/funkin/play/PlayState.hx @@ -834,9 +834,12 @@ class PlayState extends MusicBeatSubState inputSpitter = []; // Reset music properly. - FlxG.sound.music.time = startTimestamp - Conductor.instance.instrumentalOffset; - FlxG.sound.music.pitch = playbackRate; - FlxG.sound.music.pause(); + if (FlxG.sound.music != null) + { + FlxG.sound.music.time = startTimestamp - Conductor.instance.instrumentalOffset; + FlxG.sound.music.pitch = playbackRate; + FlxG.sound.music.pause(); + } if (!overrideMusic) { @@ -852,7 +855,7 @@ class PlayState extends MusicBeatSubState vocals.pause(); vocals.time = 0; - FlxG.sound.music.volume = 1; + if (FlxG.sound.music != null) FlxG.sound.music.volume = 1; vocals.volume = 1; vocals.playerVolume = 1; vocals.opponentVolume = 1; From ea1d123c49531d2f94063b0d4ed39a94b4654849 Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Sat, 6 Apr 2024 21:42:31 -0400 Subject: [PATCH 101/130] Fixes to Pico Blazin' animations. --- assets | 2 +- source/funkin/play/character/AnimateAtlasCharacter.hx | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/assets b/assets index e8f4d2d91..287f8e222 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit e8f4d2d91c7bd5a922465e7d67a0efb7d7574bd6 +Subproject commit 287f8e222d00cfd0d24eb79465b7a256bb80318f diff --git a/source/funkin/play/character/AnimateAtlasCharacter.hx b/source/funkin/play/character/AnimateAtlasCharacter.hx index f1dadf3e2..ed58b92b5 100644 --- a/source/funkin/play/character/AnimateAtlasCharacter.hx +++ b/source/funkin/play/character/AnimateAtlasCharacter.hx @@ -192,6 +192,7 @@ class AnimateAtlasCharacter extends BaseCharacter if (!this.mainSprite.hasAnimation(prefix)) { FlxG.log.warn('[ATLASCHAR] Animation ${prefix} not found in Animate Atlas ${_data.assetPath}'); + trace('[ATLASCHAR] Animation ${prefix} not found in Animate Atlas ${_data.assetPath}'); continue; } animations.set(anim.name, anim); From b464f51ba2572ce57d01caedde7cb0fa03789c77 Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Sat, 6 Apr 2024 22:38:32 -0400 Subject: [PATCH 102/130] Fix an issue where a missing stage would cause a crash (rather than an error popup) --- source/funkin/play/PlayState.hx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/source/funkin/play/PlayState.hx b/source/funkin/play/PlayState.hx index dbae9ed2a..a5fbb7624 100644 --- a/source/funkin/play/PlayState.hx +++ b/source/funkin/play/PlayState.hx @@ -1551,10 +1551,11 @@ class PlayState extends MusicBeatSubState function loadStage(id:String):Void { currentStage = StageRegistry.instance.fetchEntry(id); - currentStage.revive(); // Stages are killed and props destroyed when the PlayState is destroyed to save memory. if (currentStage != null) { + currentStage.revive(); // Stages are killed and props destroyed when the PlayState is destroyed to save memory. + // Actually create and position the sprites. var event:ScriptEvent = new ScriptEvent(CREATE, false); ScriptEventDispatcher.callEvent(currentStage, event); From 207eedf7b5dc4f9c92fc3c216576fff3858ea262 Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Sat, 6 Apr 2024 22:38:39 -0400 Subject: [PATCH 103/130] Update assets submodule. --- assets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets b/assets index 287f8e222..6e098afdc 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit 287f8e222d00cfd0d24eb79465b7a256bb80318f +Subproject commit 6e098afdcc30c8508afc09bc3e57b502821029ab From 6d374c7af9e0e784bedd1c949b59c5c468b04c3d Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Mon, 8 Apr 2024 18:39:51 -0400 Subject: [PATCH 104/130] Fix loading issue tied to -DSONG compile define. --- .vscode/settings.json | 5 ++++ source/funkin/InitState.hx | 33 +++++++++++++++++++++ source/funkin/ui/transition/LoadingState.hx | 1 - 3 files changed, 38 insertions(+), 1 deletion(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 13a1862d2..0cca68aab 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -130,6 +130,11 @@ "-DFORCE_DEBUG_VERSION" ] }, + { + "label": "Windows / Debug (Straight to Play - 2hot)", + "target": "windows", + "args": ["-debug", "-DSONG=2hot", "-DFORCE_DEBUG_VERSION"] + }, { "label": "HashLink / Debug (Straight to Play - Bopeebo Normal)", "target": "hl", diff --git a/source/funkin/InitState.hx b/source/funkin/InitState.hx index 6ea77ec18..9b842bc13 100644 --- a/source/funkin/InitState.hx +++ b/source/funkin/InitState.hx @@ -261,6 +261,35 @@ class InitState extends FlxState return; } + // TODO: Rework loading behavior so we don't have to do this. + switch (songId) + { + case 'tutorial' | 'bopeebo' | 'fresh' | 'dadbattle': + Paths.setCurrentLevel('week1'); + PlayStatePlaylist.campaignId = 'week1'; + case 'spookeez' | 'south' | 'monster': + Paths.setCurrentLevel('week2'); + PlayStatePlaylist.campaignId = 'week2'; + case 'pico' | 'philly-nice' | 'blammed': + Paths.setCurrentLevel('week3'); + PlayStatePlaylist.campaignId = 'week3'; + case 'high' | 'satin-panties' | 'milf': + Paths.setCurrentLevel('week4'); + PlayStatePlaylist.campaignId = 'week4'; + case 'cocoa' | 'eggnog' | 'winter-horrorland': + Paths.setCurrentLevel('week5'); + PlayStatePlaylist.campaignId = 'week5'; + case 'senpai' | 'roses' | 'thorns': + Paths.setCurrentLevel('week6'); + PlayStatePlaylist.campaignId = 'week6'; + case 'ugh' | 'guns' | 'stress': + Paths.setCurrentLevel('week7'); + PlayStatePlaylist.campaignId = 'week7'; + case 'darnell' | 'lit-up' | '2hot' | 'blazin': + Paths.setCurrentLevel('weekend1'); + PlayStatePlaylist.campaignId = 'weekend1'; + } + LoadingState.loadPlayState( { targetSong: songData, @@ -283,6 +312,10 @@ class InitState extends FlxState return; } + // TODO: Rework loading behavior so we don't have to do this. + Paths.setCurrentLevel(levelId); + PlayStatePlaylist.campaignId = levelId; + PlayStatePlaylist.playlistSongIds = currentLevel.getSongs(); PlayStatePlaylist.isStoryMode = true; PlayStatePlaylist.campaignScore = 0; diff --git a/source/funkin/ui/transition/LoadingState.hx b/source/funkin/ui/transition/LoadingState.hx index af8798ae2..347190993 100644 --- a/source/funkin/ui/transition/LoadingState.hx +++ b/source/funkin/ui/transition/LoadingState.hx @@ -281,7 +281,6 @@ class LoadingState extends MusicBeatSubState { // TODO: This section is a hack! Redo this later when we have a proper asset caching system. FunkinSprite.preparePurgeCache(); - FunkinSprite.cacheTexture(Paths.image('combo')); FunkinSprite.cacheTexture(Paths.image('healthBar')); FunkinSprite.cacheTexture(Paths.image('menuDesat')); FunkinSprite.cacheTexture(Paths.image('combo')); From 97884021c0ad7fab887611d7971cd189e63df597 Mon Sep 17 00:00:00 2001 From: Mike Welsh Date: Mon, 8 Apr 2024 22:08:24 -0700 Subject: [PATCH 105/130] Fix bad initial save data when no save data present If no save data was present, the game would check for legacy save data in the ninjamuffin99 path to migrate over. This code was incorrectly checking `FlxSave.data == null` to determine if legacy data was present. This caused an empty legacy save being migrated over, resulting in a `volume` of 0 for any new player of the game. --- source/funkin/save/Save.hx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/funkin/save/Save.hx b/source/funkin/save/Save.hx index af2730ddd..bfbda2a02 100644 --- a/source/funkin/save/Save.hx +++ b/source/funkin/save/Save.hx @@ -693,7 +693,7 @@ class Save trace("[SAVE] Checking for legacy save data..."); var legacySave:FlxSave = new FlxSave(); legacySave.bind(SAVE_NAME_LEGACY, SAVE_PATH_LEGACY); - if (legacySave?.data == null) + if (legacySave.isEmpty()) { trace("[SAVE] No legacy save data found."); return null; From dbcbb73338db3dcb3ad758a8d2a1d8f4153db51e Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Tue, 9 Apr 2024 15:10:58 -0400 Subject: [PATCH 106/130] Main menu fix and Week 3 train fix --- assets | 2 +- source/funkin/ui/mainmenu/MainMenuState.hx | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/assets b/assets index e8f4d2d91..1a7a0b6cc 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit e8f4d2d91c7bd5a922465e7d67a0efb7d7574bd6 +Subproject commit 1a7a0b6cc60dc8131f1651caa7abef0c1944a10c diff --git a/source/funkin/ui/mainmenu/MainMenuState.hx b/source/funkin/ui/mainmenu/MainMenuState.hx index f38db1ccd..ecd67b4da 100644 --- a/source/funkin/ui/mainmenu/MainMenuState.hx +++ b/source/funkin/ui/mainmenu/MainMenuState.hx @@ -174,6 +174,7 @@ class MainMenuState extends MusicBeatState { FlxG.cameras.reset(new FunkinCamera()); FlxG.camera.follow(camFollow, null, 0.06); + FlxG.camera.snapToTarget(); } function createMenuItem(name:String, atlas:String, callback:Void->Void, fireInstantly:Bool = false):Void From eb752c242f3c59d275640bacc875e99b80c5d5e5 Mon Sep 17 00:00:00 2001 From: Cameron Taylor Date: Tue, 9 Apr 2024 20:13:59 -0400 Subject: [PATCH 107/130] assets submod --- assets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets b/assets index 1a7a0b6cc..bef67ec4b 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit 1a7a0b6cc60dc8131f1651caa7abef0c1944a10c +Subproject commit bef67ec4b3c834416e73ce4e7c3e7128c5d7de63 From 1058181cc93a609363de5faf8ae5bcc69c5478cf Mon Sep 17 00:00:00 2001 From: Cameron Taylor Date: Tue, 9 Apr 2024 20:25:33 -0400 Subject: [PATCH 108/130] assets submod --- assets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets b/assets index 84c3c7fef..0782d868b 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit 84c3c7fef411c616e558b5b497f70c106adc11d1 +Subproject commit 0782d868ba8379d699ef9ab9547c3507580628e2 From 6f5c3a043f87152c813ea0915629c7224cd67e01 Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Wed, 10 Apr 2024 14:45:07 -0400 Subject: [PATCH 109/130] Fix crash caused when game tries to render disposed sprites during a Sticker transition. --- source/funkin/graphics/FunkinCamera.hx | 6 +++++- source/funkin/play/PlayState.hx | 2 +- .../funkin/ui/debug/charting/ChartEditorState.hx | 4 ++-- source/funkin/ui/freeplay/FreeplayState.hx | 2 +- source/funkin/ui/mainmenu/MainMenuState.hx | 2 +- source/funkin/ui/options/ControlsMenu.hx | 2 +- source/funkin/ui/options/PreferencesMenu.hx | 2 +- source/funkin/ui/transition/StickerSubState.hx | 14 +++++++++----- 8 files changed, 21 insertions(+), 13 deletions(-) diff --git a/source/funkin/graphics/FunkinCamera.hx b/source/funkin/graphics/FunkinCamera.hx index 90861c263..8c8a1c9a7 100644 --- a/source/funkin/graphics/FunkinCamera.hx +++ b/source/funkin/graphics/FunkinCamera.hx @@ -47,9 +47,13 @@ class FunkinCamera extends FlxCamera public var shouldDraw:Bool = true; - public function new(x:Int = 0, y:Int = 0, width:Int = 0, height:Int = 0, zoom:Float = 0) + // Used to identify the camera during debugging. + final id:String = 'unknown'; + + public function new(id:String = 'unknown', x:Int = 0, y:Int = 0, width:Int = 0, height:Int = 0, zoom:Float = 0) { super(x, y, width, height, zoom); + this.id = id; bgTexture = pickTexture(width, height); bgBitmap = FixedBitmapData.fromTexture(bgTexture); bgFrame = new FlxFrame(new FlxGraphic('', null)); diff --git a/source/funkin/play/PlayState.hx b/source/funkin/play/PlayState.hx index 795f493e8..486eb742c 100644 --- a/source/funkin/play/PlayState.hx +++ b/source/funkin/play/PlayState.hx @@ -1467,7 +1467,7 @@ class PlayState extends MusicBeatSubState */ function initCameras():Void { - camGame = new FunkinCamera(); + camGame = new FunkinCamera('playStateCamGame'); camGame.bgColor = BACKGROUND_COLOR; // Show a pink background behind the stage. camHUD = new FlxCamera(); camHUD.bgColor.alpha = 0; // Show the game scene behind the camera. diff --git a/source/funkin/ui/debug/charting/ChartEditorState.hx b/source/funkin/ui/debug/charting/ChartEditorState.hx index dba1a7e55..78222570a 100644 --- a/source/funkin/ui/debug/charting/ChartEditorState.hx +++ b/source/funkin/ui/debug/charting/ChartEditorState.hx @@ -2091,7 +2091,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState loadPreferences(); - uiCamera = new FunkinCamera(); + uiCamera = new FunkinCamera('chartEditorUI'); FlxG.cameras.reset(uiCamera); buildDefaultSongData(); @@ -5382,7 +5382,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState // Kill and replace the UI camera so it doesn't get destroyed during the state transition. uiCamera.kill(); FlxG.cameras.remove(uiCamera, false); - FlxG.cameras.reset(new FunkinCamera()); + FlxG.cameras.reset(new FunkinCamera('chartEditorUI2')); this.persistentUpdate = false; this.persistentDraw = false; diff --git a/source/funkin/ui/freeplay/FreeplayState.hx b/source/funkin/ui/freeplay/FreeplayState.hx index dc1f164ea..6fdc7e309 100644 --- a/source/funkin/ui/freeplay/FreeplayState.hx +++ b/source/funkin/ui/freeplay/FreeplayState.hx @@ -513,7 +513,7 @@ class FreeplayState extends MusicBeatSubState // var swag:Alphabet = new Alphabet(1, 0, 'swag'); - var funnyCam:FunkinCamera = new FunkinCamera(0, 0, FlxG.width, FlxG.height); + var funnyCam:FunkinCamera = new FunkinCamera('freeplayFunny', 0, 0, FlxG.width, FlxG.height); funnyCam.bgColor = FlxColor.TRANSPARENT; FlxG.cameras.add(funnyCam); diff --git a/source/funkin/ui/mainmenu/MainMenuState.hx b/source/funkin/ui/mainmenu/MainMenuState.hx index ecd67b4da..0e444782c 100644 --- a/source/funkin/ui/mainmenu/MainMenuState.hx +++ b/source/funkin/ui/mainmenu/MainMenuState.hx @@ -172,7 +172,7 @@ class MainMenuState extends MusicBeatState function resetCamStuff() { - FlxG.cameras.reset(new FunkinCamera()); + FlxG.cameras.reset(new FunkinCamera('mainMenu')); FlxG.camera.follow(camFollow, null, 0.06); FlxG.camera.snapToTarget(); } diff --git a/source/funkin/ui/options/ControlsMenu.hx b/source/funkin/ui/options/ControlsMenu.hx index 62ae4b1a9..dd7d5ff38 100644 --- a/source/funkin/ui/options/ControlsMenu.hx +++ b/source/funkin/ui/options/ControlsMenu.hx @@ -48,7 +48,7 @@ class ControlsMenu extends funkin.ui.options.OptionsState.Page { super(); - menuCamera = new FunkinCamera(); + menuCamera = new FunkinCamera('controlsMenu'); FlxG.cameras.add(menuCamera, false); menuCamera.bgColor = 0x0; camera = menuCamera; diff --git a/source/funkin/ui/options/PreferencesMenu.hx b/source/funkin/ui/options/PreferencesMenu.hx index c23c3f165..783aef0ba 100644 --- a/source/funkin/ui/options/PreferencesMenu.hx +++ b/source/funkin/ui/options/PreferencesMenu.hx @@ -21,7 +21,7 @@ class PreferencesMenu extends Page { super(); - menuCamera = new FunkinCamera(); + menuCamera = new FunkinCamera('prefMenu'); FlxG.cameras.add(menuCamera, false); menuCamera.bgColor = 0x0; camera = menuCamera; diff --git a/source/funkin/ui/transition/StickerSubState.hx b/source/funkin/ui/transition/StickerSubState.hx index 0b5e16f97..e5abef872 100644 --- a/source/funkin/ui/transition/StickerSubState.hx +++ b/source/funkin/ui/transition/StickerSubState.hx @@ -247,10 +247,6 @@ class StickerSubState extends MusicBeatSubState FlxTransitionableState.skipNextTransIn = true; FlxTransitionableState.skipNextTransOut = true; - // TODO: Rework this asset caching stuff - FunkinSprite.preparePurgeCache(); - FunkinSprite.purgeCache(); - // I think this grabs the screen and puts it under the stickers? // Leaving this commented out rather than stripping it out because it's cool... /* @@ -265,7 +261,15 @@ class StickerSubState extends MusicBeatSubState // FlxG.addChildBelowMouse(dipshit); */ - FlxG.switchState(() -> targetState(this)); + FlxG.switchState(() -> { + // TODO: Rework this asset caching stuff + // NOTE: This has to come AFTER the state switch, + // otherwise the game tries to render destroyed sprites! + FunkinSprite.preparePurgeCache(); + FunkinSprite.purgeCache(); + + return targetState(this); + }); } }); }); From 5e7b417d6f8dfcdea303b0d4e4e58b328027e9d6 Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Fri, 12 Apr 2024 14:44:01 -0400 Subject: [PATCH 110/130] Remove Kickstarter link from credits. --- assets | 2 +- source/funkin/ui/credits/CreditsDataHandler.hx | 8 ++------ 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/assets b/assets index 1a7a0b6cc..40d946207 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit 1a7a0b6cc60dc8131f1651caa7abef0c1944a10c +Subproject commit 40d946207aa14b996b152800f285f94b7a679ba4 diff --git a/source/funkin/ui/credits/CreditsDataHandler.hx b/source/funkin/ui/credits/CreditsDataHandler.hx index 86afdafd1..1294dd73a 100644 --- a/source/funkin/ui/credits/CreditsDataHandler.hx +++ b/source/funkin/ui/credits/CreditsDataHandler.hx @@ -57,10 +57,6 @@ class CreditsDataHandler {line: 'KawaiSprite'}, {line: 'evilsk8r'}, ] - }, - { - header: 'Kickstarter Backers', - appendBackers: true } ] }; @@ -68,11 +64,11 @@ class CreditsDataHandler public static function fetchBackerEntries():Array { - // TODO: Replace this with a web request. + // TODO: Implement a web request. // We can't just grab the current Kickstarter data and include it in builds, // because we don't want to deadname people who haven't logged into the portal yet. // It can be async and paginated for performance! - return ['See the list of backers at $BACKER_PUBLIC_URL.']; + return []; } #if HARDCODED_CREDITS From bc0af9ae9ffd0c0b1eb9ee1aa24e358ed7fd15b6 Mon Sep 17 00:00:00 2001 From: Cameron Taylor Date: Sun, 14 Apr 2024 03:01:07 -0400 Subject: [PATCH 111/130] temp enabling fps --- source/Main.hx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/source/Main.hx b/source/Main.hx index f4c5d9eb2..7037bf390 100644 --- a/source/Main.hx +++ b/source/Main.hx @@ -113,6 +113,8 @@ class Main extends Sprite addChild(game); + addChild(fpsCounter); + #if hxcpp_debug_server trace('hxcpp_debug_server is enabled! You can now connect to the game with a debugger.'); #else From 7644ce1019e75fb1d14ed7b8d1fc6686b282af60 Mon Sep 17 00:00:00 2001 From: Hazel Date: Sun, 14 Apr 2024 23:49:41 +0200 Subject: [PATCH 112/130] feat: ci parallelization, linux builds, ci refactoring (#484) * first linux build attempt * linux deps! * hxcodec dependencies * build timeouts * reup hxcpp cache every time by default gh actions will not update caches on cache hit. since the hxcpp cache grows with compiles, that's not what we want here. since we *do* need the files newly compiled. * ci speed test * group runners by purpose * REFACTOR CI. IT WAS NEEDED * smol changies * second attempt at libc * fix any format issues * it's 1:50am * migrate away from gacts/run-and-post-run@v1 * apt does not have a stable cli interface. use with caution in scripts * first attempt at libffi6 * second attempt at libffi6 * fuck that * sigh * html5 also needs new libc * make sure rerunning ln -s doesn't fail the build * desperate attempt * arc attempt * arc, ii * ci * apt-GET * who needs safeguards anyway * clean ci build * debug time * lots of connectivity debugging * :pleading_face: * natesales/q * i'm not very smart * debug hard? * whose traceroute? * pls * ... * we go even newer * merge moment * haxelib maybe * debug info * :pleading_face: * lower mtu runner? * libffi my beloved * no multiline env? * smol buggy * non docker-aware vars * i love bash * builds hopefully go nyoom * forgor native dep * [skip ci] meow * convenient typo * sigh * [skip ci] waow * [skip ci] docker is hard * i don't understand docker tbh * debuggering * docking * small amount of dumb but still doesn't explain why curl doesn't curl * just vsc things * ca certs issue? * please this has to be the one * find -type d fail, laugh at this user * too eepy * im not that smart am i * attempt to run containerized from docker base image * [skip-ci] some more docking * might as well try * :pleaading_face: * ? * ! * idea * sigh * i give in * aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa * :pleading_face: * hopefully fix hxcpp cache * [skip ci] a little dx never hurt anyone * try removing things until it breaks * welp that was easy * not-docker-friendly paths in non-docker env, etc. you get the point * more sane default cache size * finishing touches * welp * mounted volume * no systemd, got it * more failproof dockerfile * does this not have ossh * haxelib master * hopefully final docker build * bob the builder * docking :3 * image cleanup * github moment * okay mayb * gotta set it up first * i have an idea * hope we ready * :pleading_face: * fuck * sigh * trigger build on new image * no comment * global hxcpp, first idea * yikes * hxcpp oopsy * code dupe * more code dupe * lint * increase hxcpp cache size on native builds as well * buttons :3 * oops * forgor to export env variable * aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa --- .github/actions/setup-haxe/action.yml | 135 ++++++++++++++ .github/actions/setup-haxeshit/action.yml | 55 ------ .github/actions/upload-itch/action.yml | 142 ++++++++++---- .github/workflows/build-docker-image.yml | 53 ++++++ .github/workflows/build-game.yml | 125 +++++++++++++ .github/workflows/build-shit.yml | 136 -------------- .github/workflows/cancel-merged-branches.yml | 45 ++--- build/Dockerfile | 185 +++++++++++++++++++ 8 files changed, 633 insertions(+), 243 deletions(-) create mode 100644 .github/actions/setup-haxe/action.yml delete mode 100644 .github/actions/setup-haxeshit/action.yml create mode 100644 .github/workflows/build-docker-image.yml create mode 100644 .github/workflows/build-game.yml delete mode 100644 .github/workflows/build-shit.yml create mode 100644 build/Dockerfile diff --git a/.github/actions/setup-haxe/action.yml b/.github/actions/setup-haxe/action.yml new file mode 100644 index 000000000..54db9bf79 --- /dev/null +++ b/.github/actions/setup-haxe/action.yml @@ -0,0 +1,135 @@ +name: setup-haxeshit +description: "sets up haxe shit, using HMM!" + +inputs: + haxe: + description: 'Version of haxe to install' + required: true + default: '4.3.4' + hxcpp-cache: + description: 'Whether to use a shared hxcpp compile cache' + required: true + default: 'true' + hxcpp-cache-path: + description: 'Path to create hxcpp cache in' + required: true + default: ${{ runner.temp }}/hxcpp_cache + targets: + description: 'Targets we plan to compile to. Installs native dependencies needed.' + required: true + +runs: + using: "composite" + steps: + + - name: Setup timers + shell: bash + run: | + echo "TIMER_HAXE=$(date +%s)" >> "$GITHUB_ENV" + + - name: Install Haxe + uses: funkincrew/ci-haxe@v3.1.0 + with: + haxe-version: ${{ inputs.haxe }} + + - name: Install native dependencies + if: ${{ runner.os == 'Linux' }} + shell: bash + run: | + ls -lah /usr/lib/x86_64-linux-gnu/ + apt-get update + apt-get install -y \ + g++ \ + libx11-dev libxi-dev libxext-dev libxinerama-dev libxrandr-dev \ + libgl-dev libgl1-mesa-dev \ + libasound2-dev + ln -s /usr/lib/x86_64-linux-gnu/libffi.so.8 /usr/lib/x86_64-linux-gnu/libffi.so.6 || true + - name: Install linux-specific dependencies + if: ${{ runner.os == 'Linux' && contains(inputs.targets, 'linux') }} + shell: bash + run: | + apt-get install -y libvlc-dev libvlccore-dev + + - name: Config haxelib + shell: bash + run: | + echo "TIMER_HAXELIB=$(date +%s)" >> "$GITHUB_ENV" + haxelib --debug --never install haxelib 4.1.0 --global + haxelib --debug --never deleterepo || true + haxelib --debug --never newrepo + echo "HAXEPATH=$(haxelib config)" >> "$GITHUB_ENV" + haxelib --debug --never git haxelib https://github.com/HaxeFoundation/haxelib.git master + haxelib --debug --global install hmm + echo "TIMER_DEPS=$(date +%s)" >> "$GITHUB_ENV" + + - name: Restore cached dependencies + id: cache-hmm + uses: actions/cache@v4 + with: + path: .haxelib + key: haxe-hmm-${{ runner.os }}-${{ hashFiles('**/hmm.json') }} + + - if: ${{ steps.cache-hmm.outputs.cache-hit != 'true' }} + name: Install dependencies + shell: bash + run: | + haxelib --debug --global run hmm install + echo "TIMER_DONE=$(date +%s)" >> "$GITHUB_ENV" + + # by default use a shared hxcpp cache + - if: ${{ inputs.hxcpp-cache == 'true' }} + name: Restore hxcpp cache + uses: actions/cache@v4 + with: + path: ${{ inputs.hxcpp-cache-path }} + key: haxe-hxcpp-${{ runner.os }}-${{ github.ref_name }}-${{ github.sha }} + restore-keys: haxe-hxcpp-${{ runner.os }}-${{ github.ref_name }} + # export env for it to reuse in builds + - if: ${{ inputs.hxcpp-cache == 'true' }} + name: Persist env for hxcpp cache + shell: bash + run: | + echo "HXCPP_COMPILE_CACHE=${{ inputs.hxcpp-cache-path }}" >> "$GITHUB_ENV" + echo 'HXCPP_CACHE_MB="4096"' >> "$GITHUB_ENV" + + # if it's explicitly disabled, still cache export/ since that then contains the builds + - if: ${{ inputs.hxcpp-cache != 'true' }} + name: Restore export cache + uses: actions/cache@v4 + with: + path: ${{ inputs.hxcpp-cache-path }} + key: haxe-export-${{ runner.os }}-${{ github.ref_name }}-${{ github.sha }} + restore-keys: haxe-export-${{ runner.os }}-${{ github.ref_name }} + + - name: Print debug info + shell: bash + run: | + cat << EOF + runner: + kernel: $(uname -a) + haxe: + version: $(haxe -version) + which: $(which haxe) + haxepath: $HAXEPATH + took: $((TIMER_HAXELIB - TIMER_HAXE))s + haxelib: + version: $(haxelib version) + which: $(which haxelib) + local: + config: $(haxelib config) + path: $(haxelib path haxelib || true) + global + config: $(haxelib config --global) + path: $(haxelib path haxelib --global || true) + system + version: $(haxelib --system version) + local: + config: $(haxelib --system config) + global: + config: $(haxelib --system config --global) + took: $((TIMER_DEPS - TIMER_HAXELIB))s + deps: + took: $((TIMER_DONE - TIMER_DEPS))s + hxcpp_cache: | + $(haxelib run hxcpp cache list || true) + EOF diff --git a/.github/actions/setup-haxeshit/action.yml b/.github/actions/setup-haxeshit/action.yml deleted file mode 100644 index 236d29944..000000000 --- a/.github/actions/setup-haxeshit/action.yml +++ /dev/null @@ -1,55 +0,0 @@ -name: setup-haxeshit -description: "sets up haxe shit, using HMM!" -runs: - using: "composite" - steps: - - name: Install Haxe lol - uses: funkincrew/ci-haxe@v3.1.0 - with: - haxe-version: 4.3.3 - - name: Config haxelib - run: | - haxelib --never install haxelib 4.1.0 --global - haxelib --never deleterepo || true - haxelib --never newrepo - echo "HAXEPATH=$(haxelib config)" >> "$GITHUB_ENV" - haxelib --never git haxelib https://github.com/HaxeFoundation/haxelib.git master - shell: bash - - name: Gather debug info - run: | - cat << EOF >> "$GITHUB_STEP_SUMMARY" - ## haxe - - version: \`$(haxe -version)\` - - exe: \`$(which haxe)\` - ## haxelib - - version: \`$(haxelib version)\` - - exe: \`$(which haxelib)\` - - path: \`$HAXEPATH\` - ### local - - config: \`$(haxelib config)\` - - path: \`$(haxelib path haxelib || true)\` - ### global - - config: \`$(haxelib config --global)\` - - path: \`$(haxelib path haxelib --global || true)\` - ### system - - version: \`$(haxelib --system version)\` - - local: \`$(haxelib --system config)\` - - global: \`$(haxelib --system config --global)\` - EOF - shell: bash - - name: Install hmm - # hmm only supports global installs - run: | - haxelib --global install hmm - shell: bash - - name: Restore cached dependencies - id: cache-hmm - uses: actions/cache@v4 - with: - path: .haxelib - key: ${{ runner.os }}-hmm-${{ hashFiles('**/hmm.json') }} - - if: ${{ steps.cache-hmm.outputs.cache-hit != 'true' }} - name: hmm install - run: | - haxelib --global run hmm install - shell: bash diff --git a/.github/actions/upload-itch/action.yml b/.github/actions/upload-itch/action.yml index 2f7d3027d..fb049efc9 100644 --- a/.github/actions/upload-itch/action.yml +++ b/.github/actions/upload-itch/action.yml @@ -1,44 +1,124 @@ name: upload-itch description: "installs Butler, and uploads to itch.io!" + inputs: butler-key: description: "Butler API secret key" required: true + itch-repo: + description: "Where to upload the game to" + required: true + default: "ninja-muffin24/funkin-secret" build-dir: description: "Directory of the game build" - required: true + required: false target: - description: "Target (html5, win, linux, mac)" + description: "Target (html5, windows, linux, macos)" required: true + runs: using: "composite" steps: - - name: Install butler Windows - if: runner.os == 'Windows' - run: | - curl -L -o butler.zip https://broth.itch.ovh/butler/windows-amd64/LATEST/archive/default - 7z x butler.zip - ./butler -v - shell: bash - - name: Install butler Mac - if: runner.os == 'macOS' - run: | - curl -L -o butler.zip https://broth.itch.ovh/butler/darwin-amd64/LATEST/archive/default - unzip butler.zip - ./butler -V - shell: bash - - name: Install butler Linux - if: runner.os == 'Linux' - run: | - curl -L -o butler.zip https://broth.itch.ovh/butler/linux-amd64/LATEST/archive/default - unzip butler.zip - chmod +x butler - ./butler -V - shell: bash - - name: Upload game to itch.io - env: - BUTLER_API_KEY: ${{inputs.butler-key}} - run: | - ./butler login - ./butler push ${{inputs.build-dir}} ninja-muffin24/funkin-secret:${{inputs.target}}-${GITHUB_REF_NAME} - shell: bash + + # RUNNER_OS = Windows | macOS | Linux + # TARGET_BUILD = windows | macos | linux + # TARGET_ITCH = win | macos | linux + # TARGET_BUTLER_DOWNLOAD = windows-amd64 | darwin-amd64 | linux-amd64 + - name: Setup variables + shell: bash + run: | + TARGET_OS=${{ inputs.target }} + RUNNER=${RUNNER_OS@L} + TARGET=${TARGET_OS@L} + case "$TARGET" in + "windows") + TARGET_ITCH=win + ;; + *) + TARGET_ITCH=$TARGET + ;; + esac + case "$RUNNER" in + "macos") + OS_NODE=darwin + ;; + *) + OS_NODE=$RUNNER + ;; + esac + BUTLER_PATH=$RUNNER_TEMP/butler + + echo BUILD_DIR="export/release/$TARGET/bin" >> "$GITHUB_ENV" + echo ITCH_TAG=${{ inputs.itch-repo }}:$TARGET_ITCH-$GITHUB_REF_NAME >> "$GITHUB_ENV" + echo OS_AND_ARCH=$OS_NODE-amd64 >> "$GITHUB_ENV" + echo BUTLER_API_KEY=${{ inputs.butler-key }} >> "$GITHUB_ENV" + echo BUTLER_INSTALL_PATH=$BUTLER_PATH >> "$GITHUB_ENV" + echo TIMER_BUTLER=$(date +%s) >> "$GITHUB_ENV" + echo TARGET_ITCH=$TARGET_ITCH >> "$GITHUB_ENV" + + echo "$BUTLER_PATH" >> "$GITHUB_PATH" + + - name: Get latest butler version + shell: bash + run: | + LATEST=$(curl -sfL https://broth.itch.ovh/butler/$OS_AND_ARCH/LATEST) + echo BUTLER_LATEST=$LATEST >> "$GITHUB_ENV" + + command -v butler \ + && echo BUTLER_CURRENT=$(butler -V 2>&1 | cut -d ',' -f 1) >> "$GITHUB_ENV" \ + || echo BUTLER_CURRENT=none >> "$GITHUB_ENV" + + - name: Try to get butler from cache + id: cache-butler + uses: actions/cache@v4 + with: + path: ${{ env.BUTLER_INSTALL_PATH }} + key: butler-${{ runner.os }}-${{ env.BUTLER_LATEST }} + + - if: steps.cache-butler.outputs.cache-hit == 'true' + name: Make sure butler is executable + shell: bash + run: | + chmod +x $BUTLER_INSTALL_PATH/butler + + - if: steps.cache-butler.outputs.cache-hit != 'true' + name: Install butler + shell: bash + run: | + mkdir -p $BUTLER_INSTALL_PATH + cd $BUTLER_INSTALL_PATH + + curl -L -o butler.zip https://broth.itch.ovh/butler/$OS_AND_ARCH/LATEST/archive/default + unzip butler.zip + chmod +x butler + + - name: Upload game to itch.io + shell: bash + run: | + echo "TIMER_UPLOAD=$(date +%s)" >> "$GITHUB_ENV" + butler login + butler push $BUILD_DIR $ITCH_TAG + echo "TIMER_DONE=$(date +%s)" >> "$GITHUB_ENV" + + - name: Print debug info + shell: bash + run: | + cat << EOF + butler: + version: $( + if [[ "$BUTLER_CURRENT" == "$BUTLER_LATEST" ]] + then + echo $BUTLER_CURRENT + else + echo $BUTLER_CURRENT -> $BUTLER_LATEST + fi + ) + install: + took: $(($TIMER_UPLOAD-$TIMER_BUTLER))s + upload: + tag: $TARGET_ITCH/$GITHUB_REF_NAME + took: $(($TIMER_DONE-$TIMER_UPLOAD))s + EOF + cat << EOF >> "$GITHUB_STEP_SUMMARY" + ### open in launcher: [$TARGET_ITCH/$GITHUB_REF_NAME](https://run.funkin.me/$TARGET_ITCH/$GITHUB_REF_NAME) + EOF diff --git a/.github/workflows/build-docker-image.yml b/.github/workflows/build-docker-image.yml new file mode 100644 index 000000000..15c9e5582 --- /dev/null +++ b/.github/workflows/build-docker-image.yml @@ -0,0 +1,53 @@ +name: Create and publish Docker image + +on: + workflow_dispatch: + push: + paths: + - '**/Dockerfile' + - '.github/workflows/build-docker-image.yml' + +jobs: + build-and-push-image: + runs-on: build-set + permissions: + contents: read + packages: write + + steps: + - name: Get checkout token + uses: actions/create-github-app-token@v1 + id: app_token + with: + app-id: ${{ vars.APP_ID }} + private-key: ${{ secrets.APP_PEM }} + owner: ${{ github.repository_owner }} + + - name: Checkout repo + uses: funkincrew/ci-checkout@v6 + with: + submodules: false + token: ${{ steps.app_token.outputs.token }} + + - name: Log into GitHub Container Registry + uses: docker/login-action@v3.1.0 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Build and push Docker image + uses: docker/build-push-action@v5.3.0 + with: + context: ./build + push: true + tags: | + ghcr.io/funkincrew/build-dependencies:latest + ghcr.io/funkincrew/build-dependencies:${{ github.sha }} + labels: | + org.opencontainers.image.description=precooked haxe build-dependencies + org.opencontainers.image.revision=${{ github.sha }} + org.opencontainers.image.source=https://github.com/${{ github.repository }} + org.opencontainers.image.title=${{ github.repository_owner }}/build-dependencies + org.opencontainers.image.url=https://github.com/${{ github.repository }} + org.opencontainers.image.version=${{ github.sha }} diff --git a/.github/workflows/build-game.yml b/.github/workflows/build-game.yml new file mode 100644 index 000000000..3bfea20f2 --- /dev/null +++ b/.github/workflows/build-game.yml @@ -0,0 +1,125 @@ +name: Build and Upload nightly game builds + +on: + workflow_dispatch: + push: + paths-ignore: + - '**/Dockerfile' + - '.github/workflows/build-docker-image.yml' + +jobs: + + build-game-on-host: + strategy: + matrix: + include: + - target: windows + - target: macos + runs-on: + - ${{ matrix.target }} + defaults: + run: + shell: bash + + steps: + - name: Make git happy + if: ${{ matrix.target == 'macos' }} + run: | + git config --global --add safe.directory $GITHUB_WORKSPACE + + - name: Get checkout token + uses: actions/create-github-app-token@v1 + id: app_token + with: + app-id: ${{ vars.APP_ID }} + private-key: ${{ secrets.APP_PEM }} + owner: ${{ github.repository_owner }} + + - name: Checkout repo + uses: funkincrew/ci-checkout@v6 + with: + submodules: 'recursive' + token: ${{ steps.app_token.outputs.token }} + + - name: Setup build environment + uses: ./.github/actions/setup-haxe + + - name: Build game + if: ${{ matrix.target == 'windows' }} + run: | + haxelib run lime build windows -v -release -DGITHUB_BUILD + timeout-minutes: 120 + - name: Build game + if: ${{ matrix.target != 'windows' }} + run: | + haxelib run lime build ${{ matrix.target }} -v -release --times -DGITHUB_BUILD + timeout-minutes: 120 + + - name: Upload build artifacts + uses: ./.github/actions/upload-itch + with: + butler-key: ${{ secrets.BUTLER_API_KEY}} + target: ${{ matrix.target }} + + build-game-in-container: + runs-on: build-set + container: ghcr.io/funkincrew/build-dependencies:latest + strategy: + matrix: + include: + - target: linux + - target: html5 + defaults: + run: + shell: bash + + steps: + - name: Get checkout token + uses: actions/create-github-app-token@v1 + id: app_token + with: + app-id: ${{ vars.APP_ID }} + private-key: ${{ secrets.APP_PEM }} + owner: ${{ github.repository_owner }} + + - name: Checkout repo + uses: funkincrew/ci-checkout@v6 + with: + submodules: 'recursive' + token: ${{ steps.app_token.outputs.token }} + + - name: Config haxelib + run: | + haxelib --never newrepo + echo "HAXEPATH=$(haxelib config)" >> "$GITHUB_ENV" + + - name: Restore cached dependencies + id: cache-hmm + uses: actions/cache@v4 + with: + path: .haxelib + key: haxe-hmm-${{ runner.os }}-${{ hashFiles('**/hmm.json') }} + + - if: ${{ steps.cache-hmm.outputs.cache-hit != 'true' }} + name: Install dependencies + run: | + haxelib --global run hmm install + + - if: ${{ matrix.target != 'html5' }} + name: Restore hxcpp cache + uses: actions/cache@v4 + with: + path: /usr/share/hxcpp + key: haxe-hxcpp-${{ runner.os }}-${{ github.ref_name }}-${{ github.sha }} + restore-keys: haxe-hxcpp-${{ runner.os }}-${{ github.ref_name }} + + - name: Build game + run: | + haxelib run lime build ${{ matrix.target }} -v -release --times -DGITHUB_BUILD + timeout-minutes: 120 + + - name: Upload build artifacts + uses: ./.github/actions/upload-itch + with: + butler-key: ${{ secrets.BUTLER_API_KEY}} + target: ${{ matrix.target }} diff --git a/.github/workflows/build-shit.yml b/.github/workflows/build-shit.yml deleted file mode 100644 index 4d674f025..000000000 --- a/.github/workflows/build-shit.yml +++ /dev/null @@ -1,136 +0,0 @@ -name: build-upload -on: - workflow_dispatch: - push: - -concurrency: - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true - -jobs: - create-nightly-html5: - runs-on: [self-hosted, linux] - container: ubuntu:23.10 - steps: - - name: Install tools missing in container - run: | - 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 - - name: Get checkout token - uses: actions/create-github-app-token@v1 - id: app_token - with: - app-id: ${{ vars.APP_ID }} - private-key: ${{ secrets.APP_PEM }} - owner: ${{ github.repository_owner }} - - name: Checkout repo - uses: funkincrew/ci-checkout@v6 - with: - submodules: 'recursive' - token: ${{ steps.app_token.outputs.token }} - - name: Install Haxe, dependencies - uses: ./.github/actions/setup-haxeshit - - name: Install native dependencies - run: | - apt install -y \ - libx11-dev libxi-dev libxext-dev libxinerama-dev libxrandr-dev \ - libgl-dev libgl1-mesa-dev \ - libasound2-dev - - name: Build game - run: | - haxelib run lime build html5 -release --times -DGITHUB_BUILD - - name: Upload build artifacts - uses: ./.github/actions/upload-itch - with: - butler-key: ${{ secrets.BUTLER_API_KEY}} - build-dir: export/release/html5/bin - target: html5 - create-nightly-win: - runs-on: [self-hosted, windows] - defaults: - run: - shell: bash - steps: - - name: Get checkout token - uses: actions/create-github-app-token@v1 - id: app_token - with: - app-id: ${{ vars.APP_ID }} - private-key: ${{ secrets.APP_PEM }} - owner: ${{ github.repository_owner }} - - name: Checkout repo - uses: funkincrew/ci-checkout@v6 - with: - submodules: 'recursive' - token: ${{ steps.app_token.outputs.token }} - - name: Install Haxe, dependencies - uses: ./.github/actions/setup-haxeshit - - name: Setup build cache - run: | - mkdir -p ${{ runner.temp }}/hxcpp_cache - - name: Restore build cache - id: cache-build-win - uses: actions/cache@v4 - with: - path: | - export - ${{ runner.temp }}/hxcpp_cache - key: ${{ runner.os }}-build-win-${{ github.ref_name }} - - name: Build game - run: | - haxelib run lime build windows -v -release -DGITHUB_BUILD - env: - HXCPP_COMPILE_CACHE: "${{ runner.temp }}\\hxcpp_cache" - - name: Upload build artifacts - uses: ./.github/actions/upload-itch - with: - butler-key: ${{ secrets.BUTLER_API_KEY }} - build-dir: export/release/windows/bin - target: win - create-nightly-mac: - 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 - - name: Get checkout token - uses: actions/create-github-app-token@v1 - id: app_token - with: - app-id: ${{ vars.APP_ID }} - private-key: ${{ secrets.APP_PEM }} - owner: ${{ github.repository_owner }} - - name: Checkout repo - uses: funkincrew/ci-checkout@v6 - with: - submodules: 'recursive' - token: ${{ steps.app_token.outputs.token }} - - name: Install Haxe, dependencies - uses: ./.github/actions/setup-haxeshit - - name: Setup build cache - run: | - mkdir -p ${{ runner.temp }}/hxcpp_cache - - name: Restore build cache - id: cache-build-win - uses: actions/cache@v4 - with: - path: | - export - ${{ runner.temp }}/hxcpp_cache - key: ${{ runner.os }}-build-mac-${{ github.ref_name }} - - name: Build game - run: | - haxelib run lime build macos -release --times -DGITHUB_BUILD - env: - HXCPP_COMPILE_CACHE: "${{ runner.temp }}/hxcpp_cache" - - name: Upload build artifacts - uses: ./.github/actions/upload-itch - with: - butler-key: ${{ secrets.BUTLER_API_KEY}} - build-dir: export/release/macos/bin - target: macos diff --git a/.github/workflows/cancel-merged-branches.yml b/.github/workflows/cancel-merged-branches.yml index 84e3bedc9..f66f9647b 100644 --- a/.github/workflows/cancel-merged-branches.yml +++ b/.github/workflows/cancel-merged-branches.yml @@ -1,35 +1,38 @@ -name: cancel-merged-branches +name: Cancel queued workflows on PR merge + on: pull_request: types: - closed jobs: + cancel_stuff: if: github.event.pull_request.merged == true - runs-on: ubuntu-latest + runs-on: build-set permissions: actions: write + steps: - - uses: actions/github-script@v7 - id: cancel-runs - with: - result-encoding: string - retries: 3 - script: | - let branch_workflows = await github.rest.actions.listWorkflowRuns({ + - name: Cancel queued workflows for ${{ github.event.pull_request.head.ref }} + uses: actions/github-script@v7 + with: + result-encoding: string + retries: 3 + script: | + let branch_workflows = await github.rest.actions.listWorkflowRuns({ + owner: context.repo.owner, + repo: context.repo.repo, + workflow_id: "build-shit.yml", + status: "queued", + branch: "${{ github.event.pull_request.head.ref }}" + }); + let runs = branch_workflows.data.workflow_runs; + runs.forEach((run) => { + github.rest.actions.cancelWorkflowRun({ owner: context.repo.owner, repo: context.repo.repo, - workflow_id: "build-shit.yml", - status: "queued", - branch: "${{ github.event.pull_request.head.ref }}" + run_id: run.id }); - let runs = branch_workflows.data.workflow_runs; - runs.forEach((run) => { - github.rest.actions.cancelWorkflowRun({ - owner: context.repo.owner, - repo: context.repo.repo, - run_id: run.id - }); - }); - console.log(runs); + }); + console.log(runs); diff --git a/build/Dockerfile b/build/Dockerfile new file mode 100644 index 000000000..88b44f7a6 --- /dev/null +++ b/build/Dockerfile @@ -0,0 +1,185 @@ +FROM ubuntu:mantic + +ARG haxe_version=4.3.4 +ARG haxelib_version=4.1.0 +ARG neko_version=2.3.0 + +# prepare runner +ENV GITHUB_HOME="/github/home" + +RUN <> /etc/apt/apt.conf.d/10apt-autoremove +APT::Get::AutomaticRemove "0"; +APT::Get::HideAutoRemove "1"; +EOC + +echo <> /etc/apt/apt.conf.d/80retries +"APT::Acquire::Retries \"10\";" +EOC + +echo <> /etc/apt/apt.conf.d/90assumeyes +"APT::Get::Assume-Yes \"true\";" +EOC +EOF + +# Prepare apt-fast +RUN <> /etc/gitconfig +[safe] + directory = * +EOC + +ssh-keyscan -t rsa,ecdsa,ed25519 github.com >> /etc/ssh/ssh_known_hosts +ssh-keyscan -t rsa,ecdsa,ed25519 ravy.dev >> /etc/ssh/ssh_known_hosts +EOF + +# Haxe native dependencies +RUN < Date: Mon, 15 Apr 2024 19:21:55 -0400 Subject: [PATCH 113/130] Fix the saturation on the main menu background. --- source/funkin/ui/mainmenu/MainMenuState.hx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/source/funkin/ui/mainmenu/MainMenuState.hx b/source/funkin/ui/mainmenu/MainMenuState.hx index 3bdc2dfe6..1a4686c5b 100644 --- a/source/funkin/ui/mainmenu/MainMenuState.hx +++ b/source/funkin/ui/mainmenu/MainMenuState.hx @@ -58,7 +58,11 @@ class MainMenuState extends MusicBeatState persistentDraw = true; var bg = FunkinSprite.create('menuDesat'); + bg.color = 0xFFFDE871; + // This line accounts for the fact that the base color of menuDesat is #EFEFEF. + flixel.util.FlxColorTransformUtil.setOffsets(bg.colorTransform, 30, 27, 13, 0.0); + bg.scrollFactor.x = 0; bg.scrollFactor.y = 0.17; bg.setGraphicSize(Std.int(bg.width * 1.2)); From 43ec72fb9d96743388b05ea0db16dd4f3d62a2e1 Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Mon, 15 Apr 2024 20:36:38 -0400 Subject: [PATCH 114/130] Ensure playNoteHoldCover doesn't call if note is judged as 'miss' --- source/funkin/play/PlayState.hx | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/source/funkin/play/PlayState.hx b/source/funkin/play/PlayState.hx index 474caf031..3342a6b69 100644 --- a/source/funkin/play/PlayState.hx +++ b/source/funkin/play/PlayState.hx @@ -2388,13 +2388,6 @@ class PlayState extends MusicBeatSubState // Display the combo meter and add the calculation to the score. popUpScore(note, event.score, event.judgement, event.healthChange); - - if (note.isHoldNote && note.holdNoteSprite != null) - { - playerStrumline.playNoteHoldCover(note.holdNoteSprite); - } - - vocals.playerVolume = 1; } /** @@ -2676,6 +2669,13 @@ class PlayState extends MusicBeatSubState } comboPopUps.displayRating(daRating); if (Highscore.tallies.combo >= 10 || Highscore.tallies.combo == 0) comboPopUps.displayCombo(Highscore.tallies.combo); + + if (daNote.isHoldNote && daNote.holdNoteSprite != null) + { + playerStrumline.playNoteHoldCover(daNote.holdNoteSprite); + } + + vocals.playerVolume = 1; } /** From b553dbd517efcac4c53a6595e0d8b69f22312b7b Mon Sep 17 00:00:00 2001 From: Eric Date: Tue, 16 Apr 2024 13:24:41 -0400 Subject: [PATCH 115/130] Remove janky animation on Freeplay menu. (#488) --- source/funkin/ui/freeplay/FreeplayState.hx | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/source/funkin/ui/freeplay/FreeplayState.hx b/source/funkin/ui/freeplay/FreeplayState.hx index ae51ba82a..3ac441212 100644 --- a/source/funkin/ui/freeplay/FreeplayState.hx +++ b/source/funkin/ui/freeplay/FreeplayState.hx @@ -638,14 +638,7 @@ class FreeplayState extends MusicBeatSubState funnyMenu.favIcon.visible = tempSongs[i].isFav; funnyMenu.hsvShader = hsvShader; - if (i < 8) - { - funnyMenu.initJumpIn(Math.min(i, 4), force); - } - else - { - funnyMenu.forcePosition(); - } + funnyMenu.forcePosition(); grpCapsules.add(funnyMenu); } From 2210f8bc183888d755bcd23934a0152e6bd60370 Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Tue, 16 Apr 2024 18:42:43 -0400 Subject: [PATCH 116/130] Made Blazin' death a separate asset to fix blend modes. --- assets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets b/assets index 1b12b6c66..235d2695c 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit 1b12b6c6666af6c84addf5aa0795546aa0d04185 +Subproject commit 235d2695c6de11b0daa49277a602d1045d45e510 From bc0a27c985eb7319cef8d5e9350b6198b1177279 Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Tue, 16 Apr 2024 18:43:11 -0400 Subject: [PATCH 117/130] Fix references to missing graphics in Freeplay --- .vscode/settings.json | 5 +++++ source/funkin/ui/freeplay/SongMenuItem.hx | 24 +++++++++++------------ 2 files changed, 17 insertions(+), 12 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index c28bebeab..a8a67245b 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -170,6 +170,11 @@ "target": "windows", "args": ["-debug", "-DANIMDEBUG", "-DFORCE_DEBUG_VERSION"] }, + { + "label": "Windows / Debug (Debug hxCodec)", + "target": "windows", + "args": ["-debug", "-DHXC_LIBVLC_LOGGING", "-DFORCE_DEBUG_VERSION"] + }, { "label": "HashLink / Debug (Straight to Animation Editor)", "target": "hl", diff --git a/source/funkin/ui/freeplay/SongMenuItem.hx b/source/funkin/ui/freeplay/SongMenuItem.hx index f8b3d7ac3..f6d85e56e 100644 --- a/source/funkin/ui/freeplay/SongMenuItem.hx +++ b/source/funkin/ui/freeplay/SongMenuItem.hx @@ -46,7 +46,7 @@ class SongMenuItem extends FlxSpriteGroup public var hsvShader(default, set):HSVShader; - var diffRatingSprite:FlxSprite; + // var diffRatingSprite:FlxSprite; public function new(x:Float, y:Float) { @@ -65,13 +65,13 @@ class SongMenuItem extends FlxSpriteGroup var rank:String = FlxG.random.getObject(ranks); ranking = new FlxSprite(capsule.width * 0.84, 30); - ranking.loadGraphic(Paths.image('freeplay/ranks/' + rank)); - ranking.scale.x = ranking.scale.y = realScaled; + // ranking.loadGraphic(Paths.image('freeplay/ranks/' + rank)); + // ranking.scale.x = ranking.scale.y = realScaled; // ranking.alpha = 0.75; - ranking.visible = false; - ranking.origin.set(capsule.origin.x - ranking.x, capsule.origin.y - ranking.y); - add(ranking); - grpHide.add(ranking); + // ranking.visible = false; + // ranking.origin.set(capsule.origin.x - ranking.x, capsule.origin.y - ranking.y); + // add(ranking); + // grpHide.add(ranking); switch (rank) { @@ -81,9 +81,9 @@ class SongMenuItem extends FlxSpriteGroup grayscaleShader = new Grayscale(1); - diffRatingSprite = new FlxSprite(145, 90).loadGraphic(Paths.image('freeplay/diffRatings/diff00')); - diffRatingSprite.shader = grayscaleShader; - diffRatingSprite.origin.set(capsule.origin.x - diffRatingSprite.x, capsule.origin.y - diffRatingSprite.y); + // diffRatingSprite = new FlxSprite(145, 90).loadGraphic(Paths.image('freeplay/diffRatings/diff00')); + // diffRatingSprite.shader = grayscaleShader; + // diffRatingSprite.origin.set(capsule.origin.x - diffRatingSprite.x, capsule.origin.y - diffRatingSprite.y); // TODO: Readd once ratings are fully implemented // add(diffRatingSprite); // grpHide.add(diffRatingSprite); @@ -118,8 +118,8 @@ class SongMenuItem extends FlxSpriteGroup function updateDifficultyRating(newRating:Int):Void { var ratingPadded:String = newRating < 10 ? '0$newRating' : '$newRating'; - diffRatingSprite.loadGraphic(Paths.image('freeplay/diffRatings/diff${ratingPadded}')); - diffRatingSprite.visible = false; + // diffRatingSprite.loadGraphic(Paths.image('freeplay/diffRatings/diff${ratingPadded}')); + // diffRatingSprite.visible = false; } function set_hsvShader(value:HSVShader):HSVShader From d346c9387cdb1001977a9dcf6b7d691069cafbcf Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Tue, 16 Apr 2024 19:42:52 -0400 Subject: [PATCH 118/130] Fix a crash in the Results state. also nudge GF over to the spot she's in in the FLA --- source/funkin/play/ResultState.hx | 66 +++++++++++++++---------------- 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/source/funkin/play/ResultState.hx b/source/funkin/play/ResultState.hx index c05257338..591020955 100644 --- a/source/funkin/play/ResultState.hx +++ b/source/funkin/play/ResultState.hx @@ -80,34 +80,34 @@ class ResultState extends MusicBeatSubState bgFlash.visible = false; add(bgFlash); - var bfGfExcellent:FlxAtlasSprite = new FlxAtlasSprite(380, -170, Paths.animateAtlas("resultScreen/resultsBoyfriendExcellent", "shared")); - bfGfExcellent.visible = false; - add(bfGfExcellent); + // var bfGfExcellent:FlxAtlasSprite = new FlxAtlasSprite(380, -170, Paths.animateAtlas("resultScreen/resultsBoyfriendExcellent", "shared")); + // bfGfExcellent.visible = false; + // add(bfGfExcellent); + // + // var bfPerfect:FlxAtlasSprite = new FlxAtlasSprite(370, -180, Paths.animateAtlas("resultScreen/resultsBoyfriendPerfect", "shared")); + // bfPerfect.visible = false; + // add(bfPerfect); + // + // var bfSHIT:FlxAtlasSprite = new FlxAtlasSprite(0, 20, Paths.animateAtlas("resultScreen/resultsBoyfriendSHIT", "shared")); + // bfSHIT.visible = false; + // add(bfSHIT); + // + // bfGfExcellent.anim.onComplete = () -> { + // bfGfExcellent.anim.curFrame = 28; + // bfGfExcellent.anim.play(); // unpauses this anim, since it's on PlayOnce! + // }; + // + // bfPerfect.anim.onComplete = () -> { + // bfPerfect.anim.curFrame = 136; + // bfPerfect.anim.play(); // unpauses this anim, since it's on PlayOnce! + // }; + // + // bfSHIT.anim.onComplete = () -> { + // bfSHIT.anim.curFrame = 150; + // bfSHIT.anim.play(); // unpauses this anim, since it's on PlayOnce! + // }; - var bfPerfect:FlxAtlasSprite = new FlxAtlasSprite(370, -180, Paths.animateAtlas("resultScreen/resultsBoyfriendPerfect", "shared")); - bfPerfect.visible = false; - add(bfPerfect); - - var bfSHIT:FlxAtlasSprite = new FlxAtlasSprite(0, 20, Paths.animateAtlas("resultScreen/resultsBoyfriendSHIT", "shared")); - bfSHIT.visible = false; - add(bfSHIT); - - bfGfExcellent.anim.onComplete = () -> { - bfGfExcellent.anim.curFrame = 28; - bfGfExcellent.anim.play(); // unpauses this anim, since it's on PlayOnce! - }; - - bfPerfect.anim.onComplete = () -> { - bfPerfect.anim.curFrame = 136; - bfPerfect.anim.play(); // unpauses this anim, since it's on PlayOnce! - }; - - bfSHIT.anim.onComplete = () -> { - bfSHIT.anim.curFrame = 150; - bfSHIT.anim.play(); // unpauses this anim, since it's on PlayOnce! - }; - - var gf:FlxSprite = FunkinSprite.createSparrow(500, 300, 'resultScreen/resultGirlfriendGOOD'); + var gf:FlxSprite = FunkinSprite.createSparrow(625, 325, 'resultScreen/resultGirlfriendGOOD'); gf.animation.addByPrefix("clap", "Girlfriend Good Anim", 24, false); gf.visible = false; gf.animation.finishCallback = _ -> { @@ -268,9 +268,9 @@ class ResultState extends MusicBeatSubState switch (resultsVariation) { - case SHIT: - bfSHIT.visible = true; - bfSHIT.playAnimation(""); + // case SHIT: + // bfSHIT.visible = true; + // bfSHIT.playAnimation(""); case NORMAL: boyfriend.animation.play('fall'); @@ -292,9 +292,9 @@ class ResultState extends MusicBeatSubState gf.animation.play('clap', true); gf.visible = true; }); - case PERFECT: - bfPerfect.visible = true; - bfPerfect.playAnimation(""); + // case PERFECT: + // bfPerfect.visible = true; + // bfPerfect.playAnimation(""); // bfGfExcellent.visible = true; // bfGfExcellent.playAnimation(""); From 80a558ac08119b3cf427f6714bb1bc3596ad8c6e Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Tue, 16 Apr 2024 19:57:19 -0400 Subject: [PATCH 119/130] Fix an issue where changing focus would pause some sounds but not others. --- source/funkin/audio/FunkinSound.hx | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/source/funkin/audio/FunkinSound.hx b/source/funkin/audio/FunkinSound.hx index 8c1bf3b41..df05cc3ef 100644 --- a/source/funkin/audio/FunkinSound.hx +++ b/source/funkin/audio/FunkinSound.hx @@ -223,11 +223,12 @@ class FunkinSound extends FlxSound implements ICloneable // already paused before we lost focus. if (_lostFocus && !_alreadyPaused) { + trace('Resuming audio (${this._label}) on focus!'); resume(); } else { - trace('Not resuming audio on focus!'); + trace('Not resuming audio (${this._label}) on focus!'); } _lostFocus = false; } @@ -402,6 +403,12 @@ class FunkinSound extends FlxSound implements ICloneable sound.group = FlxG.sound.defaultSoundGroup; sound.persist = true; + // Make sure to add the sound to the list. + // If it's already in, it won't get re-added. + // If it's not in the list (it gets removed by FunkinSound.playMusic()), + // it will get re-added (then if this was called by playMusic(), removed again) + FlxG.sound.list.add(sound); + // Call onLoad() because the sound already loaded if (onLoad != null && sound._sound != null) onLoad(); From b9824848560d426247d4bf33403786e7898ab0fe Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Tue, 16 Apr 2024 20:19:20 -0400 Subject: [PATCH 120/130] Properly fix the menu background to use the correct line colors. --- assets | 2 +- source/funkin/ui/mainmenu/MainMenuState.hx | 10 ++-------- source/funkin/ui/options/OptionsState.hx | 3 +-- 3 files changed, 4 insertions(+), 11 deletions(-) diff --git a/assets b/assets index 1b12b6c66..f3d6cf30d 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit 1b12b6c6666af6c84addf5aa0795546aa0d04185 +Subproject commit f3d6cf30dee60a237a6773d8140bd1661f62bd4e diff --git a/source/funkin/ui/mainmenu/MainMenuState.hx b/source/funkin/ui/mainmenu/MainMenuState.hx index 1a4686c5b..d2d8adeca 100644 --- a/source/funkin/ui/mainmenu/MainMenuState.hx +++ b/source/funkin/ui/mainmenu/MainMenuState.hx @@ -57,12 +57,7 @@ class MainMenuState extends MusicBeatState persistentUpdate = false; persistentDraw = true; - var bg = FunkinSprite.create('menuDesat'); - - bg.color = 0xFFFDE871; - // This line accounts for the fact that the base color of menuDesat is #EFEFEF. - flixel.util.FlxColorTransformUtil.setOffsets(bg.colorTransform, 30, 27, 13, 0.0); - + var bg:FlxSprite = new FlxSprite(Paths.image('menuBG')); bg.scrollFactor.x = 0; bg.scrollFactor.y = 0.17; bg.setGraphicSize(Std.int(bg.width * 1.2)); @@ -73,7 +68,7 @@ class MainMenuState extends MusicBeatState camFollow = new FlxObject(0, 0, 1, 1); add(camFollow); - magenta = new FlxSprite(Paths.image('menuDesat')); + magenta = new FlxSprite(Paths.image('menuBGMagenta')); magenta.scrollFactor.x = bg.scrollFactor.x; magenta.scrollFactor.y = bg.scrollFactor.y; magenta.setGraphicSize(Std.int(bg.width)); @@ -81,7 +76,6 @@ class MainMenuState extends MusicBeatState magenta.x = bg.x; magenta.y = bg.y; magenta.visible = false; - magenta.color = 0xFFfd719b; // TODO: Why doesn't this line compile I'm going fucking feral diff --git a/source/funkin/ui/options/OptionsState.hx b/source/funkin/ui/options/OptionsState.hx index 0f33a0780..a00b28dbb 100644 --- a/source/funkin/ui/options/OptionsState.hx +++ b/source/funkin/ui/options/OptionsState.hx @@ -23,8 +23,7 @@ class OptionsState extends MusicBeatState override function create() { - var menuBG = new FlxSprite().loadGraphic(Paths.image('menuDesat')); - menuBG.color = 0xFFea71fd; + var menuBG = new FlxSprite().loadGraphic(Paths.image('menuBGBlue')); menuBG.setGraphicSize(Std.int(menuBG.width * 1.1)); menuBG.updateHitbox(); menuBG.screenCenter(); From 9a284c34e9fafa6ebb920e038551d25e34cede9b Mon Sep 17 00:00:00 2001 From: Cameron Taylor Date: Fri, 19 Apr 2024 13:45:36 -0400 Subject: [PATCH 121/130] assets update for submodule --- assets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets b/assets index 6e098afdc..39c221849 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit 6e098afdcc30c8508afc09bc3e57b502821029ab +Subproject commit 39c22184988e1b22bd63b07d83c30ece588e85df From 366bebc94cca62f36dadee505bf390cf0eb26446 Mon Sep 17 00:00:00 2001 From: Cameron Taylor Date: Fri, 19 Apr 2024 13:58:35 -0400 Subject: [PATCH 122/130] assets submod --- assets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets b/assets index 837a8639b..1266cb1c0 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit 837a8639bd7abe4aa8786dc3790e8d4576f04f28 +Subproject commit 1266cb1c0c5078158df52b2b36205b332ccde019 From f385379935b64706b10c6847f9628d8f4b032947 Mon Sep 17 00:00:00 2001 From: Cameron Taylor Date: Fri, 19 Apr 2024 14:01:19 -0400 Subject: [PATCH 123/130] assets update for submodule --- assets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets b/assets index 837a8639b..069c9bf45 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit 837a8639bd7abe4aa8786dc3790e8d4576f04f28 +Subproject commit 069c9bf45f197ebe0b38483d11bb30c15bbb5eca From 30d052f6ee4431ab295bc0aed758ffe202f56b3b Mon Sep 17 00:00:00 2001 From: Cameron Taylor Date: Fri, 19 Apr 2024 14:05:38 -0400 Subject: [PATCH 124/130] assets update for submodule --- assets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets b/assets index 235d2695c..a24f42932 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit 235d2695c6de11b0daa49277a602d1045d45e510 +Subproject commit a24f42932fbe9032d28be1603f197fb50c938276 From 3fa60cd2283037f338d2fd90107c69388466d856 Mon Sep 17 00:00:00 2001 From: FabsTheFabs Date: Sun, 7 Apr 2024 21:41:40 +0100 Subject: [PATCH 125/130] update assets submodule --- assets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets b/assets index a24f42932..31dfbf9d5 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit a24f42932fbe9032d28be1603f197fb50c938276 +Subproject commit 31dfbf9d545ea897e58d0257381cbdf8e4281d3c From 351cb8cbaa6ea0c5570563a40c24c24219af4fed Mon Sep 17 00:00:00 2001 From: FabsTheFabs Date: Tue, 9 Apr 2024 03:56:28 +0100 Subject: [PATCH 126/130] popupstuff changes + make combopopup able to be edited outside of playstate --- source/funkin/play/PlayState.hx | 2 +- source/funkin/play/components/PopUpStuff.hx | 25 ++++++++++++--------- 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/source/funkin/play/PlayState.hx b/source/funkin/play/PlayState.hx index 2e023dccd..9f6e5a16b 100644 --- a/source/funkin/play/PlayState.hx +++ b/source/funkin/play/PlayState.hx @@ -498,7 +498,7 @@ class PlayState extends MusicBeatSubState /** * The combo popups. Includes the real-time combo counter and the rating. */ - var comboPopUps:PopUpStuff; + public var comboPopUps:PopUpStuff; /** * PROPERTIES diff --git a/source/funkin/play/components/PopUpStuff.hx b/source/funkin/play/components/PopUpStuff.hx index 724bf0cb9..b062b22cf 100644 --- a/source/funkin/play/components/PopUpStuff.hx +++ b/source/funkin/play/components/PopUpStuff.hx @@ -10,6 +10,8 @@ import funkin.util.TimerUtil; class PopUpStuff extends FlxTypedGroup { + public var offsets:Array = [0, 0]; + override public function new() { super(); @@ -29,9 +31,9 @@ class PopUpStuff extends FlxTypedGroup rating.scrollFactor.set(0.2, 0.2); rating.zIndex = 1000; - rating.x = FlxG.width * 0.50; + rating.x = (FlxG.width * 0.474) + offsets[0]; // rating.x -= FlxG.camera.scroll.x * 0.2; - rating.y = FlxG.camera.height * 0.4 - 60; + rating.y = (FlxG.camera.height * 0.45 - 60) + offsets[1]; rating.acceleration.y = 550; rating.velocity.y -= FlxG.random.int(140, 175); rating.velocity.x -= FlxG.random.int(0, 10); @@ -40,16 +42,19 @@ class PopUpStuff extends FlxTypedGroup if (PlayState.instance.currentStageId.startsWith('school')) { - rating.setGraphicSize(Std.int(rating.width * Constants.PIXEL_ART_SCALE * 0.7)); + rating.setGraphicSize(Std.int(rating.width * Constants.PIXEL_ART_SCALE * 0.65)); rating.antialiasing = false; } else { - rating.setGraphicSize(Std.int(rating.width * 0.7)); + rating.setGraphicSize(Std.int(rating.width * 0.65)); rating.antialiasing = true; } rating.updateHitbox(); + rating.x -= rating.width / 2; + rating.y -= rating.height / 2; + FlxTween.tween(rating, {alpha: 0}, 0.2, { onComplete: function(tween:FlxTween) { @@ -77,8 +82,8 @@ class PopUpStuff extends FlxTypedGroup pixelShitPart2 = '-pixel'; } var comboSpr:FunkinSprite = FunkinSprite.create(pixelShitPart1 + 'combo' + pixelShitPart2); - comboSpr.y = FlxG.camera.height * 0.4 + 80; - comboSpr.x = FlxG.width * 0.50; + comboSpr.y = (FlxG.camera.height * 0.44) + offsets[1]; + comboSpr.x = (FlxG.width * 0.507) + offsets[0]; // comboSpr.x -= FlxG.camera.scroll.x * 0.2; comboSpr.acceleration.y = 600; @@ -133,14 +138,14 @@ class PopUpStuff extends FlxTypedGroup } else { - numScore.setGraphicSize(Std.int(numScore.width * 0.5)); + numScore.setGraphicSize(Std.int(numScore.width * 0.45)); numScore.antialiasing = true; } numScore.updateHitbox(); - numScore.x = comboSpr.x - (43 * daLoop); //- 90; - numScore.acceleration.y = FlxG.random.int(200, 300); - numScore.velocity.y -= FlxG.random.int(140, 160); + numScore.x = comboSpr.x - (36 * daLoop) - 65; //- 90; + numScore.acceleration.y = FlxG.random.int(250, 300); + numScore.velocity.y -= FlxG.random.int(130, 150); numScore.velocity.x = FlxG.random.float(-5, 5); add(numScore); From b3869f6504a3f098ce0b01111975cc4dc2081a8c Mon Sep 17 00:00:00 2001 From: Cameron Taylor Date: Fri, 19 Apr 2024 14:16:57 -0400 Subject: [PATCH 127/130] assets update for submodule --- assets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets b/assets index 31dfbf9d5..a24f42932 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit 31dfbf9d545ea897e58d0257381cbdf8e4281d3c +Subproject commit a24f42932fbe9032d28be1603f197fb50c938276 From 49a81189c40b35fc77ed62eba0b2914fbc4e23dc Mon Sep 17 00:00:00 2001 From: Cameron Taylor Date: Fri, 19 Apr 2024 15:00:12 -0400 Subject: [PATCH 128/130] use funkinaction in controls.hx --- source/funkin/input/Controls.hx | 72 ++++++++++++++++----------------- 1 file changed, 36 insertions(+), 36 deletions(-) diff --git a/source/funkin/input/Controls.hx b/source/funkin/input/Controls.hx index d76c26153..14b226d88 100644 --- a/source/funkin/input/Controls.hx +++ b/source/funkin/input/Controls.hx @@ -30,42 +30,42 @@ class Controls extends FlxActionSet * A list of actions that a player would invoke via some input device. * Uses FlxActions to funnel various inputs to a single action. */ - var _ui_up = new FlxActionDigital(Action.UI_UP); - var _ui_left = new FlxActionDigital(Action.UI_LEFT); - var _ui_right = new FlxActionDigital(Action.UI_RIGHT); - var _ui_down = new FlxActionDigital(Action.UI_DOWN); - var _ui_upP = new FlxActionDigital(Action.UI_UP_P); - var _ui_leftP = new FlxActionDigital(Action.UI_LEFT_P); - var _ui_rightP = new FlxActionDigital(Action.UI_RIGHT_P); - var _ui_downP = new FlxActionDigital(Action.UI_DOWN_P); - var _ui_upR = new FlxActionDigital(Action.UI_UP_R); - var _ui_leftR = new FlxActionDigital(Action.UI_LEFT_R); - var _ui_rightR = new FlxActionDigital(Action.UI_RIGHT_R); - var _ui_downR = new FlxActionDigital(Action.UI_DOWN_R); - var _note_up = new FlxActionDigital(Action.NOTE_UP); - var _note_left = new FlxActionDigital(Action.NOTE_LEFT); - var _note_right = new FlxActionDigital(Action.NOTE_RIGHT); - var _note_down = new FlxActionDigital(Action.NOTE_DOWN); - var _note_upP = new FlxActionDigital(Action.NOTE_UP_P); - var _note_leftP = new FlxActionDigital(Action.NOTE_LEFT_P); - var _note_rightP = new FlxActionDigital(Action.NOTE_RIGHT_P); - var _note_downP = new FlxActionDigital(Action.NOTE_DOWN_P); - var _note_upR = new FlxActionDigital(Action.NOTE_UP_R); - var _note_leftR = new FlxActionDigital(Action.NOTE_LEFT_R); - var _note_rightR = new FlxActionDigital(Action.NOTE_RIGHT_R); - var _note_downR = new FlxActionDigital(Action.NOTE_DOWN_R); - var _accept = new FlxActionDigital(Action.ACCEPT); - var _back = new FlxActionDigital(Action.BACK); - var _pause = new FlxActionDigital(Action.PAUSE); - var _reset = new FlxActionDigital(Action.RESET); - var _screenshot = new FlxActionDigital(Action.SCREENSHOT); - var _cutscene_advance = new FlxActionDigital(Action.CUTSCENE_ADVANCE); - var _debug_menu = new FlxActionDigital(Action.DEBUG_MENU); - var _debug_chart = new FlxActionDigital(Action.DEBUG_CHART); - var _debug_stage = new FlxActionDigital(Action.DEBUG_STAGE); - var _volume_up = new FlxActionDigital(Action.VOLUME_UP); - var _volume_down = new FlxActionDigital(Action.VOLUME_DOWN); - var _volume_mute = new FlxActionDigital(Action.VOLUME_MUTE); + var _ui_up = new FunkinAction(Action.UI_UP); + var _ui_left = new FunkinAction(Action.UI_LEFT); + var _ui_right = new FunkinAction(Action.UI_RIGHT); + var _ui_down = new FunkinAction(Action.UI_DOWN); + var _ui_upP = new FunkinAction(Action.UI_UP_P); + var _ui_leftP = new FunkinAction(Action.UI_LEFT_P); + var _ui_rightP = new FunkinAction(Action.UI_RIGHT_P); + var _ui_downP = new FunkinAction(Action.UI_DOWN_P); + var _ui_upR = new FunkinAction(Action.UI_UP_R); + var _ui_leftR = new FunkinAction(Action.UI_LEFT_R); + var _ui_rightR = new FunkinAction(Action.UI_RIGHT_R); + var _ui_downR = new FunkinAction(Action.UI_DOWN_R); + var _note_up = new FunkinAction(Action.NOTE_UP); + var _note_left = new FunkinAction(Action.NOTE_LEFT); + var _note_right = new FunkinAction(Action.NOTE_RIGHT); + var _note_down = new FunkinAction(Action.NOTE_DOWN); + var _note_upP = new FunkinAction(Action.NOTE_UP_P); + var _note_leftP = new FunkinAction(Action.NOTE_LEFT_P); + var _note_rightP = new FunkinAction(Action.NOTE_RIGHT_P); + var _note_downP = new FunkinAction(Action.NOTE_DOWN_P); + var _note_upR = new FunkinAction(Action.NOTE_UP_R); + var _note_leftR = new FunkinAction(Action.NOTE_LEFT_R); + var _note_rightR = new FunkinAction(Action.NOTE_RIGHT_R); + var _note_downR = new FunkinAction(Action.NOTE_DOWN_R); + var _accept = new FunkinAction(Action.ACCEPT); + var _back = new FunkinAction(Action.BACK); + var _pause = new FunkinAction(Action.PAUSE); + var _reset = new FunkinAction(Action.RESET); + var _screenshot = new FunkinAction(Action.SCREENSHOT); + var _cutscene_advance = new FunkinAction(Action.CUTSCENE_ADVANCE); + var _debug_menu = new FunkinAction(Action.DEBUG_MENU); + var _debug_chart = new FunkinAction(Action.DEBUG_CHART); + var _debug_stage = new FunkinAction(Action.DEBUG_STAGE); + var _volume_up = new FunkinAction(Action.VOLUME_UP); + var _volume_down = new FunkinAction(Action.VOLUME_DOWN); + var _volume_mute = new FunkinAction(Action.VOLUME_MUTE); var byName:Map = new Map(); From 57df7db5f10a7017a8602c576bf7a26f15d65198 Mon Sep 17 00:00:00 2001 From: Cameron Taylor Date: Fri, 19 Apr 2024 15:10:43 -0400 Subject: [PATCH 129/130] add small #if web define --- source/funkin/audio/visualize/ABotVis.hx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/source/funkin/audio/visualize/ABotVis.hx b/source/funkin/audio/visualize/ABotVis.hx index 1188d389f..5874b8921 100644 --- a/source/funkin/audio/visualize/ABotVis.hx +++ b/source/funkin/audio/visualize/ABotVis.hx @@ -83,8 +83,9 @@ class ABotVis extends FlxTypedSpriteGroup override function draw() { + #if web if (analyzer != null) drawFFT(); - + #end super.draw(); } From 7826c7987118356eee1875eb2fc18c8170620647 Mon Sep 17 00:00:00 2001 From: Cameron Taylor Date: Fri, 19 Apr 2024 15:11:20 -0400 Subject: [PATCH 130/130] assets update for submodule --- assets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets b/assets index f98e9c66a..daf702a6e 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit f98e9c66aa06b978fd8f418c9fae3c8d4c163897 +Subproject commit daf702a6ec8b60f1922261872cc74eb107fece06