From 2916bd6ff7ec9f1e136d84323d8880ca009a3f4e Mon Sep 17 00:00:00 2001 From: Hundrec <hundrecard@gmail.com> Date: Fri, 14 Jun 2024 21:52:52 -0700 Subject: [PATCH 01/64] Reorder download Git step in compiling guide MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Moved “download Git” from the middle of the guide to the setup step Should prevent errors with Git before installing Git --- docs/COMPILING.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/COMPILING.md b/docs/COMPILING.md index e7c19875a..b8ddee4a7 100644 --- a/docs/COMPILING.md +++ b/docs/COMPILING.md @@ -2,14 +2,14 @@ 0. Setup - Download Haxe from [Haxe.org](https://haxe.org) + - Download Git from [git-scm.com](https://www.git-scm.com) 1. Cloning the Repository: Make sure when you clone, you clone the submodules to get the assets repo: - `git clone --recurse-submodules https://github.com/FunkinCrew/funkin.git` - If you accidentally cloned without the `assets` submodule (aka didn't follow the step above), you can run `git submodule update --init --recursive` to get the assets in a foolproof way. 2. Install `hmm` (run `haxelib --global install hmm` and then `haxelib --global run hmm setup`) -3. Download Git from [git-scm.com](https://www.git-scm.com) -4. Install all haxelibs of the current branch by running `hmm install` -5. Setup lime: `haxelib run lime setup` -6. Platform setup +3. Install all haxelibs of the current branch by running `hmm install` +4. Setup lime: `haxelib run lime setup` +5. Platform setup - For Windows, download the [Visual Studio Build Tools](https://aka.ms/vs/17/release/vs_BuildTools.exe) - When prompted, select "Individual Components" and make sure to download the following: - MSVC v143 VS 2022 C++ x64/x86 build tools @@ -17,8 +17,8 @@ - Mac: [`lime setup mac` Documentation](https://lime.openfl.org/docs/advanced-setup/macos/) - Linux: [`lime setup linux` Documentation](https://lime.openfl.org/docs/advanced-setup/linux/) - HTML5: Compiles without any extra setup -7. If you are targeting for native, you may need to run `lime rebuild PLATFORM` and `lime rebuild PLATFORM -debug` -8. `lime test PLATFORM` ! Add `-debug` to enable several debug features such as time travel (`PgUp`/`PgDn` in Play State). +6. If you are targeting for native, you may need to run `lime rebuild PLATFORM` and `lime rebuild PLATFORM -debug` +7. `lime test PLATFORM` ! Add `-debug` to enable several debug features such as time travel (`PgUp`/`PgDn` in Play State). # Troubleshooting From 9fb4a8719a6cd07aa2af2638adc494786ca5425e Mon Sep 17 00:00:00 2001 From: Hundrec <hundrecard@gmail.com> Date: Sat, 15 Jun 2024 13:37:21 -0400 Subject: [PATCH 02/64] Add ZIP button warning and restructured sentences Each step should be easier to follow with this structure --- docs/COMPILING.md | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/docs/COMPILING.md b/docs/COMPILING.md index b8ddee4a7..b2a106c86 100644 --- a/docs/COMPILING.md +++ b/docs/COMPILING.md @@ -3,12 +3,13 @@ 0. Setup - Download Haxe from [Haxe.org](https://haxe.org) - Download Git from [git-scm.com](https://www.git-scm.com) -1. Cloning the Repository: Make sure when you clone, you clone the submodules to get the assets repo: - - `git clone --recurse-submodules https://github.com/FunkinCrew/funkin.git` - - If you accidentally cloned without the `assets` submodule (aka didn't follow the step above), you can run `git submodule update --init --recursive` to get the assets in a foolproof way. -2. Install `hmm` (run `haxelib --global install hmm` and then `haxelib --global run hmm setup`) -3. Install all haxelibs of the current branch by running `hmm install` -4. Setup lime: `haxelib run lime setup` + - Do NOT download the repository using the Download ZIP button on GitHub or you may run into errors! + - Instead, open a command prompt and do the following steps... +1. Run `git clone --recurse-submodules https://github.com/FunkinCrew/funkin.git` to clone the repository with the necessary assets submodule + - _If you accidentally cloned without the `assets` submodule (aka didn't follow the step above), you can run `git submodule update --init --recursive` to get the assets in a foolproof way._ +2. Run `haxelib --global install hmm` and then `haxelib --global run hmm setup` to install hmm.json +3. Run `hmm install` to install all haxelibs of the current branch +4. Run `haxelib run lime setup` to set up lime 5. Platform setup - For Windows, download the [Visual Studio Build Tools](https://aka.ms/vs/17/release/vs_BuildTools.exe) - When prompted, select "Individual Components" and make sure to download the following: From 841a61408c13ff34760a448c588e35bc3b203bf0 Mon Sep 17 00:00:00 2001 From: Eric <ericmyllyoja@gmail.com> Date: Sun, 16 Jun 2024 18:48:01 -0400 Subject: [PATCH 03/64] Make downloading the assets submodule a separate step. --- docs/COMPILING.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/COMPILING.md b/docs/COMPILING.md index b2a106c86..cc90bd348 100644 --- a/docs/COMPILING.md +++ b/docs/COMPILING.md @@ -5,8 +5,9 @@ - Download Git from [git-scm.com](https://www.git-scm.com) - Do NOT download the repository using the Download ZIP button on GitHub or you may run into errors! - Instead, open a command prompt and do the following steps... -1. Run `git clone --recurse-submodules https://github.com/FunkinCrew/funkin.git` to clone the repository with the necessary assets submodule - - _If you accidentally cloned without the `assets` submodule (aka didn't follow the step above), you can run `git submodule update --init --recursive` to get the assets in a foolproof way._ +1. Run `git clone https://github.com/FunkinCrew/funkin.git` to clone the base repository. +2. Run `git submodule update --init --recursive` to download the game's assets. + - NOTE: By performing this operation, you are downloading Content which is proprietary and protected by national and international copyright and trademark laws. See [the LICENSE.md file for the Funkin.assets](https://github.com/FunkinCrew/funkin.assets/blob/main/LICENSE.md) repo for more information. 2. Run `haxelib --global install hmm` and then `haxelib --global run hmm setup` to install hmm.json 3. Run `hmm install` to install all haxelibs of the current branch 4. Run `haxelib run lime setup` to set up lime From 8a4f19d603b5900692c8c646c05e8b409688e963 Mon Sep 17 00:00:00 2001 From: EliteMasterEric <ericmyllyoja@gmail.com> Date: Tue, 25 Jun 2024 18:22:30 -0400 Subject: [PATCH 04/64] Add change counts labels to Actions labeler --- .github/changed-lines-count-labeler.yml | 12 ++++++++++++ .github/workflows/labeler.yml | 15 ++++++++++++++- 2 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 .github/changed-lines-count-labeler.yml diff --git a/.github/changed-lines-count-labeler.yml b/.github/changed-lines-count-labeler.yml new file mode 100644 index 000000000..6f890f534 --- /dev/null +++ b/.github/changed-lines-count-labeler.yml @@ -0,0 +1,12 @@ +# Add 'small' to any changes below 10 lines +small: + max: 9 + +# Add 'medium' to any changes between 10 and 100 lines +medium: + min: 10 + max: 99 + +# Add 'large' to any changes for more than 100 lines +large: + min: 100 diff --git a/.github/workflows/labeler.yml b/.github/workflows/labeler.yml index 0bcc420d3..a861af578 100644 --- a/.github/workflows/labeler.yml +++ b/.github/workflows/labeler.yml @@ -9,6 +9,19 @@ jobs: pull-requests: write runs-on: ubuntu-latest steps: - - uses: actions/labeler@v5 + - name: Set basic labels + uses: actions/labeler@v5 with: sync-labels: true + changed-lines-count-labeler: + permissions: + contents: read + pull-requests: write + runs-on: ubuntu-latest + name: An action for automatically labelling pull requests based on the changed lines count + steps: + - name: Set change count labels + uses: vkirilichev/changed-lines-count-labeler@v0.2 + with: + repo-token: ${{ secrets.GITHUB_TOKEN }} + configuration-path: .github/changed-lines-count-labeler.yml From fbc78adb65c7db8b045f1ea5d6599ae7348912a0 Mon Sep 17 00:00:00 2001 From: FlooferLand! <76737186+FlooferLand@users.noreply.github.com> Date: Mon, 1 Jul 2024 14:42:50 +0300 Subject: [PATCH 05/64] Added new settings items --- source/funkin/ui/options/MenuItemEnums.hx | 10 ++ source/funkin/ui/options/PreferencesMenu.hx | 149 +++++++++++------- .../options/items/CheckboxPreferenceItem.hx | 49 ++++++ .../ui/options/items/EnumPreferenceItem.hx | 84 ++++++++++ .../ui/options/items/NumberPreferenceItem.hx | 136 ++++++++++++++++ 5 files changed, 372 insertions(+), 56 deletions(-) create mode 100644 source/funkin/ui/options/MenuItemEnums.hx create mode 100644 source/funkin/ui/options/items/CheckboxPreferenceItem.hx create mode 100644 source/funkin/ui/options/items/EnumPreferenceItem.hx create mode 100644 source/funkin/ui/options/items/NumberPreferenceItem.hx diff --git a/source/funkin/ui/options/MenuItemEnums.hx b/source/funkin/ui/options/MenuItemEnums.hx new file mode 100644 index 000000000..4513a92af --- /dev/null +++ b/source/funkin/ui/options/MenuItemEnums.hx @@ -0,0 +1,10 @@ +package funkin.ui.options; + +// Add enums for use with `EnumPreferenceItem` here! +/* Example: + class MyOptionEnum + { + public static inline var YuhUh = "true"; // "true" is the value's ID + public static inline var NuhUh = "false"; + } + */ diff --git a/source/funkin/ui/options/PreferencesMenu.hx b/source/funkin/ui/options/PreferencesMenu.hx index 783aef0ba..5fbefceed 100644 --- a/source/funkin/ui/options/PreferencesMenu.hx +++ b/source/funkin/ui/options/PreferencesMenu.hx @@ -8,6 +8,11 @@ import funkin.ui.AtlasText.AtlasFont; import funkin.ui.options.OptionsState.Page; import funkin.graphics.FunkinCamera; import funkin.ui.TextMenuList.TextMenuItem; +import funkin.audio.FunkinSound; +import funkin.ui.options.MenuItemEnums; +import funkin.ui.options.items.CheckboxPreferenceItem; +import funkin.ui.options.items.NumberPreferenceItem; +import funkin.ui.options.items.EnumPreferenceItem; class PreferencesMenu extends Page { @@ -69,11 +74,51 @@ class PreferencesMenu extends Page }, Preferences.autoPause); } + override function update(elapsed:Float):Void + { + super.update(elapsed); + + // Indent the selected item. + items.forEach(function(daItem:TextMenuItem) { + var thyOffset:Int = 0; + + // Initializing thy text width (if thou text present) + var thyTextWidth:Int = 0; + if (Std.isOfType(daItem, EnumPreferenceItem)) thyTextWidth = cast(daItem, EnumPreferenceItem).lefthandText.getWidth(); + else if (Std.isOfType(daItem, NumberPreferenceItem)) thyTextWidth = cast(daItem, NumberPreferenceItem).lefthandText.getWidth(); + + if (thyTextWidth != 0) + { + // Magic number because of the weird offset thats being added by default + thyOffset += thyTextWidth - 75; + } + + if (items.selectedItem == daItem) + { + thyOffset += 150; + } + else + { + thyOffset += 120; + } + + daItem.x = thyOffset; + }); + } + + // - Preference item creation methods - + // Should be moved into a separate PreferenceItems class but you can't access PreferencesMenu.items and PreferencesMenu.preferenceItems from outside. + + /** + * Creates a pref item that works with booleans + * @param onChange Gets called every time the player changes the value; use this to apply the value + * @param defaultValue The value that is loaded in when the pref item is created (usually your Preferences.settingVariable) + */ function createPrefItemCheckbox(prefName:String, prefDesc:String, onChange:Bool->Void, defaultValue:Bool):Void { var checkbox:CheckboxPreferenceItem = new CheckboxPreferenceItem(0, 120 * (items.length - 1 + 1), defaultValue); - items.createItem(120, (120 * items.length) + 30, prefName, AtlasFont.BOLD, function() { + items.createItem(0, (120 * items.length) + 30, prefName, AtlasFont.BOLD, function() { var value = !checkbox.currentValue; onChange(value); checkbox.currentValue = value; @@ -82,62 +127,54 @@ class PreferencesMenu extends Page preferenceItems.add(checkbox); } - override function update(elapsed:Float) + /** + * Creates a pref item that works with general numbers + * @param onChange Gets called every time the player changes the value; use this to apply the value + * @param valueFormatter Will get called every time the game needs to display the float value; use this to change how the displayed value looks + * @param defaultValue The value that is loaded in when the pref item is created (usually your Preferences.settingVariable) + * @param min Minimum value (example: 0) + * @param max Maximum value (example: 10) + * @param step The value to increment/decrement by (default = 0.1) + * @param precision Rounds decimals up to a `precision` amount of digits (ex: 4 -> 0.1234, 2 -> 0.12) + */ + function createPrefItemNumber(prefName:String, prefDesc:String, onChange:Float->Void, ?valueFormatter:Float->String, defaultValue:Int, min:Int, max:Int, + step:Float = 0.1, precision:Int):Void { - super.update(elapsed); + var item = new NumberPreferenceItem(0, (120 * items.length) + 30, prefName, defaultValue, min, max, step, precision, onChange, valueFormatter); + items.addItem(prefName, item); + preferenceItems.add(item.lefthandText); + } - // Indent the selected item. - // TODO: Only do this on menu change? - items.forEach(function(daItem:TextMenuItem) { - if (items.selectedItem == daItem) daItem.x = 150; - else - daItem.x = 120; - }); - } -} - -class CheckboxPreferenceItem extends FlxSprite -{ - public var currentValue(default, set):Bool; - - public function new(x:Float, y:Float, defaultValue:Bool = false) - { - super(x, y); - - frames = Paths.getSparrowAtlas('checkboxThingie'); - animation.addByPrefix('static', 'Check Box unselected', 24, false); - animation.addByPrefix('checked', 'Check Box selecting animation', 24, false); - - setGraphicSize(Std.int(width * 0.7)); - updateHitbox(); - - this.currentValue = defaultValue; - } - - override function update(elapsed:Float) - { - super.update(elapsed); - - switch (animation.curAnim.name) - { - case 'static': - offset.set(); - case 'checked': - offset.set(17, 70); - } - } - - function set_currentValue(value:Bool):Bool - { - if (value) - { - animation.play('checked', true); - } - else - { - animation.play('static'); - } - - return currentValue = value; + /** + * Creates a pref item that works with number percentages + * @param onChange Gets called every time the player changes the value; use this to apply the value + * @param defaultValue The value that is loaded in when the pref item is created (usually your Preferences.settingVariable) + * @param min Minimum value (default = 0) + * @param max Maximum value (default = 100) + */ + function createPrefItemPercentage(prefName:String, prefDesc:String, onChange:Int->Void, defaultValue:Int, min:Int = 0, max:Int = 100):Void + { + var newCallback = function(value:Float) { + onChange(Std.int(value)); + }; + var formatter = function(value:Float) { + return '${value}%'; + }; + var item = new NumberPreferenceItem(0, (120 * items.length) + 30, prefName, defaultValue, min, max, 10, 0, newCallback, formatter); + items.addItem(prefName, item); + preferenceItems.add(item.lefthandText); + } + + /** + * Creates a pref item that works with enums + * @param values Maps enum values to display strings _(ex: `NoteHitSoundType.PingPong => "Ping pong"`)_ + * @param onChange Gets called every time the player changes the value; use this to apply the value + * @param defaultValue The value that is loaded in when the pref item is created (usually your Preferences.settingVariable) + */ + function createPrefItemEnum(prefName:String, prefDesc:String, values:Map<String, String>, onChange:String->Void, defaultValue:String):Void + { + var item = new EnumPreferenceItem(0, (120 * items.length) + 30, prefName, values, defaultValue, onChange); + items.addItem(prefName, item); + preferenceItems.add(item.lefthandText); } } diff --git a/source/funkin/ui/options/items/CheckboxPreferenceItem.hx b/source/funkin/ui/options/items/CheckboxPreferenceItem.hx new file mode 100644 index 000000000..88c4fb6b0 --- /dev/null +++ b/source/funkin/ui/options/items/CheckboxPreferenceItem.hx @@ -0,0 +1,49 @@ +package funkin.ui.options.items; + +import flixel.FlxSprite.FlxSprite; + +class CheckboxPreferenceItem extends FlxSprite +{ + public var currentValue(default, set):Bool; + + public function new(x:Float, y:Float, defaultValue:Bool = false) + { + super(x, y); + + frames = Paths.getSparrowAtlas('checkboxThingie'); + animation.addByPrefix('static', 'Check Box unselected', 24, false); + animation.addByPrefix('checked', 'Check Box selecting animation', 24, false); + + setGraphicSize(Std.int(width * 0.7)); + updateHitbox(); + + this.currentValue = defaultValue; + } + + override function update(elapsed:Float) + { + super.update(elapsed); + + switch (animation.curAnim.name) + { + case 'static': + offset.set(); + case 'checked': + offset.set(17, 70); + } + } + + function set_currentValue(value:Bool):Bool + { + if (value) + { + animation.play('checked', true); + } + else + { + animation.play('static'); + } + + return currentValue = value; + } +} diff --git a/source/funkin/ui/options/items/EnumPreferenceItem.hx b/source/funkin/ui/options/items/EnumPreferenceItem.hx new file mode 100644 index 000000000..02a273353 --- /dev/null +++ b/source/funkin/ui/options/items/EnumPreferenceItem.hx @@ -0,0 +1,84 @@ +package funkin.ui.options.items; + +import funkin.ui.TextMenuList; +import funkin.ui.AtlasText; +import funkin.input.Controls; +import funkin.ui.options.MenuItemEnums; +import haxe.EnumTools; + +/** + * Preference item that allows the player to pick a value from an enum (list of values) + */ +class EnumPreferenceItem extends TextMenuItem +{ + function controls():Controls + { + return PlayerSettings.player1.controls; + } + + public var lefthandText:AtlasText; + + public var currentValue:String; + public var onChangeCallback:Null<String->Void>; + public var map:Map<String, String>; + public var keys:Array<String> = []; + + var index = 0; + + public function new(x:Float, y:Float, name:String, map:Map<String, String>, defaultValue:String, ?callback:String->Void) + { + super(x, y, name, function() { + callback(this.currentValue); + }); + + updateHitbox(); + + this.map = map; + this.currentValue = defaultValue; + this.onChangeCallback = callback; + + var i:Int = 0; + for (key in map.keys()) + { + this.keys.push(key); + if (this.currentValue == key) index = i; + i += 1; + } + + lefthandText = new AtlasText(15, y, formatted(defaultValue), AtlasFont.DEFAULT); + } + + override function update(elapsed:Float):Void + { + super.update(elapsed); + + // var fancyTextFancyColor:Color; + if (selected) + { + var shouldDecrease:Bool = controls().UI_LEFT_P; + var shouldIncrease:Bool = controls().UI_RIGHT_P; + + if (shouldDecrease) index -= 1; + if (shouldIncrease) index += 1; + + if (index > keys.length - 1) index = 0; + if (index < 0) index = keys.length - 1; + + currentValue = keys[index]; + if (onChangeCallback != null && (shouldIncrease || shouldDecrease)) + { + onChangeCallback(currentValue); + } + } + + lefthandText.text = formatted(currentValue); + } + + function formatted(value:String):String + { + // FIXME: Can't add arrows around the text because the font doesn't support < > + // var leftArrow:String = selected ? '<' : ''; + // var rightArrow:String = selected ? '>' : ''; + return '${map.get(value) ?? value}'; + } +} diff --git a/source/funkin/ui/options/items/NumberPreferenceItem.hx b/source/funkin/ui/options/items/NumberPreferenceItem.hx new file mode 100644 index 000000000..f3cd3cd46 --- /dev/null +++ b/source/funkin/ui/options/items/NumberPreferenceItem.hx @@ -0,0 +1,136 @@ +package funkin.ui.options.items; + +import funkin.ui.TextMenuList; +import funkin.ui.AtlasText; +import funkin.input.Controls; + +/** + * Preference item that allows the player to pick a value between min and max + */ +class NumberPreferenceItem extends TextMenuItem +{ + function controls():Controls + { + return PlayerSettings.player1.controls; + } + + // Widgets + public var lefthandText:AtlasText; + + // Constants + static final HOLD_DELAY:Float = 0.3; // seconds + static final CHANGE_RATE:Float = 0.08; // seconds + + // Constructor-initialized variables + public var currentValue:Float; + public var min:Float; + public var max:Float; + public var step:Float; + public var precision:Int; + public var onChangeCallback:Null<Float->Void>; + public var valueFormatter:Null<Float->String>; + + // Variables + var holdDelayTimer:Float = HOLD_DELAY; // seconds + var changeRateTimer:Float = 0.0; // seconds + + /** + * @param min Minimum value (example: 0) + * @param max Maximum value (example: 100) + * @param step The value to increment/decrement by (example: 10) + * @param callback Will get called every time the user changes the setting; use this to apply/save the setting. + * @param valueFormatter Will get called every time the game needs to display the float value; use this to change how the displayed string looks + */ + public function new(x:Float, y:Float, name:String, defaultValue:Float, min:Float, max:Float, step:Float, precision:Int, ?callback:Float->Void, + ?valueFormatter:Float->String):Void + { + super(x, y, name, function() { + callback(this.currentValue); + }); + lefthandText = new AtlasText(15, y, formatted(defaultValue), AtlasFont.DEFAULT); + + updateHitbox(); + + this.currentValue = defaultValue; + this.min = min; + this.max = max; + this.step = step; + this.precision = precision; + this.onChangeCallback = callback; + this.valueFormatter = valueFormatter; + } + + override function update(elapsed:Float):Void + { + super.update(elapsed); + + // var fancyTextFancyColor:Color; + if (selected) + { + holdDelayTimer -= elapsed; + if (holdDelayTimer <= 0.0) + { + changeRateTimer -= elapsed; + } + + var jpLeft:Bool = controls().UI_LEFT_P; + var jpRight:Bool = controls().UI_RIGHT_P; + + if (jpLeft || jpRight) + { + holdDelayTimer = HOLD_DELAY; + changeRateTimer = 0.0; + } + + var shouldDecrease:Bool = jpLeft; + var shouldIncrease:Bool = jpRight; + + if (controls().UI_LEFT && holdDelayTimer <= 0.0 && changeRateTimer <= 0.0) + { + shouldDecrease = true; + changeRateTimer = CHANGE_RATE; + } + else if (controls().UI_RIGHT && holdDelayTimer <= 0.0 && changeRateTimer <= 0.0) + { + shouldIncrease = true; + changeRateTimer = CHANGE_RATE; + } + + // Actually increasing/decreasing the value + if (shouldDecrease) + { + var isBelowMin:Bool = currentValue - step < min; + currentValue = (currentValue - step).clamp(min, max); + if (onChangeCallback != null && !isBelowMin) onChangeCallback(currentValue); + } + else if (shouldIncrease) + { + var isAboveMax:Bool = currentValue + step > max; + currentValue = (currentValue + step).clamp(min, max); + if (onChangeCallback != null && !isAboveMax) onChangeCallback(currentValue); + } + } + + lefthandText.text = formatted(currentValue); + } + + /** Turns the float into a string */ + function formatted(value:Float):String + { + var float:Float = toFixed(value); + if (valueFormatter != null) + { + return valueFormatter(float); + } + else + { + return '${float}'; + } + } + + function toFixed(value:Float):Float + { + var multiplier:Float = Math.pow(10, precision); + return Math.floor(value * multiplier) / multiplier; + } +} From cd08116aed64f4761087e287a00786b77f40d02b Mon Sep 17 00:00:00 2001 From: FlooferLand! <76737186+FlooferLand@users.noreply.github.com> Date: Mon, 1 Jul 2024 14:44:23 +0300 Subject: [PATCH 06/64] Added getWidth --- source/funkin/ui/AtlasText.hx | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/source/funkin/ui/AtlasText.hx b/source/funkin/ui/AtlasText.hx index 186d87c2a..ef74abc1e 100644 --- a/source/funkin/ui/AtlasText.hx +++ b/source/funkin/ui/AtlasText.hx @@ -152,6 +152,32 @@ class AtlasText extends FlxTypedSpriteGroup<AtlasChar> } } + public function getWidth():Int + { + var width = 0; + for (char in this.text.split("")) + { + switch (char) + { + case " ": + { + width += 40; + } + case "\n": + {} + case char: + { + var sprite = new AtlasChar(atlas, char); + sprite.revive(); + sprite.char = char; + sprite.alpha = 1; + width += Std.int(sprite.width); + } + } + } + return width; + } + override function toString() { return "InputItem, " + FlxStringUtil.getDebugString([ From 4044a7d9360a391c59878bbca65ab65e5b69e16d Mon Sep 17 00:00:00 2001 From: Hundrec <hundrecard@gmail.com> Date: Fri, 14 Jun 2024 21:52:52 -0700 Subject: [PATCH 07/64] Reorder download Git step in compiling guide MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Moved “download Git” from the middle of the guide to the setup step Should prevent errors with Git before installing Git --- docs/COMPILING.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/COMPILING.md b/docs/COMPILING.md index e7c19875a..b8ddee4a7 100644 --- a/docs/COMPILING.md +++ b/docs/COMPILING.md @@ -2,14 +2,14 @@ 0. Setup - Download Haxe from [Haxe.org](https://haxe.org) + - Download Git from [git-scm.com](https://www.git-scm.com) 1. Cloning the Repository: Make sure when you clone, you clone the submodules to get the assets repo: - `git clone --recurse-submodules https://github.com/FunkinCrew/funkin.git` - If you accidentally cloned without the `assets` submodule (aka didn't follow the step above), you can run `git submodule update --init --recursive` to get the assets in a foolproof way. 2. Install `hmm` (run `haxelib --global install hmm` and then `haxelib --global run hmm setup`) -3. Download Git from [git-scm.com](https://www.git-scm.com) -4. Install all haxelibs of the current branch by running `hmm install` -5. Setup lime: `haxelib run lime setup` -6. Platform setup +3. Install all haxelibs of the current branch by running `hmm install` +4. Setup lime: `haxelib run lime setup` +5. Platform setup - For Windows, download the [Visual Studio Build Tools](https://aka.ms/vs/17/release/vs_BuildTools.exe) - When prompted, select "Individual Components" and make sure to download the following: - MSVC v143 VS 2022 C++ x64/x86 build tools @@ -17,8 +17,8 @@ - Mac: [`lime setup mac` Documentation](https://lime.openfl.org/docs/advanced-setup/macos/) - Linux: [`lime setup linux` Documentation](https://lime.openfl.org/docs/advanced-setup/linux/) - HTML5: Compiles without any extra setup -7. If you are targeting for native, you may need to run `lime rebuild PLATFORM` and `lime rebuild PLATFORM -debug` -8. `lime test PLATFORM` ! Add `-debug` to enable several debug features such as time travel (`PgUp`/`PgDn` in Play State). +6. If you are targeting for native, you may need to run `lime rebuild PLATFORM` and `lime rebuild PLATFORM -debug` +7. `lime test PLATFORM` ! Add `-debug` to enable several debug features such as time travel (`PgUp`/`PgDn` in Play State). # Troubleshooting From 562136ed554d73e04a015c32f9cb34b790b9cc07 Mon Sep 17 00:00:00 2001 From: Hundrec <hundrecard@gmail.com> Date: Sat, 15 Jun 2024 13:37:21 -0400 Subject: [PATCH 08/64] Add ZIP button warning and restructured sentences Each step should be easier to follow with this structure --- docs/COMPILING.md | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/docs/COMPILING.md b/docs/COMPILING.md index b8ddee4a7..b2a106c86 100644 --- a/docs/COMPILING.md +++ b/docs/COMPILING.md @@ -3,12 +3,13 @@ 0. Setup - Download Haxe from [Haxe.org](https://haxe.org) - Download Git from [git-scm.com](https://www.git-scm.com) -1. Cloning the Repository: Make sure when you clone, you clone the submodules to get the assets repo: - - `git clone --recurse-submodules https://github.com/FunkinCrew/funkin.git` - - If you accidentally cloned without the `assets` submodule (aka didn't follow the step above), you can run `git submodule update --init --recursive` to get the assets in a foolproof way. -2. Install `hmm` (run `haxelib --global install hmm` and then `haxelib --global run hmm setup`) -3. Install all haxelibs of the current branch by running `hmm install` -4. Setup lime: `haxelib run lime setup` + - Do NOT download the repository using the Download ZIP button on GitHub or you may run into errors! + - Instead, open a command prompt and do the following steps... +1. Run `git clone --recurse-submodules https://github.com/FunkinCrew/funkin.git` to clone the repository with the necessary assets submodule + - _If you accidentally cloned without the `assets` submodule (aka didn't follow the step above), you can run `git submodule update --init --recursive` to get the assets in a foolproof way._ +2. Run `haxelib --global install hmm` and then `haxelib --global run hmm setup` to install hmm.json +3. Run `hmm install` to install all haxelibs of the current branch +4. Run `haxelib run lime setup` to set up lime 5. Platform setup - For Windows, download the [Visual Studio Build Tools](https://aka.ms/vs/17/release/vs_BuildTools.exe) - When prompted, select "Individual Components" and make sure to download the following: From 6e65996180de85c42b74f6730773975f819e2efa Mon Sep 17 00:00:00 2001 From: Eric <ericmyllyoja@gmail.com> Date: Sun, 16 Jun 2024 18:48:01 -0400 Subject: [PATCH 09/64] Make downloading the assets submodule a separate step. --- docs/COMPILING.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/COMPILING.md b/docs/COMPILING.md index b2a106c86..cc90bd348 100644 --- a/docs/COMPILING.md +++ b/docs/COMPILING.md @@ -5,8 +5,9 @@ - Download Git from [git-scm.com](https://www.git-scm.com) - Do NOT download the repository using the Download ZIP button on GitHub or you may run into errors! - Instead, open a command prompt and do the following steps... -1. Run `git clone --recurse-submodules https://github.com/FunkinCrew/funkin.git` to clone the repository with the necessary assets submodule - - _If you accidentally cloned without the `assets` submodule (aka didn't follow the step above), you can run `git submodule update --init --recursive` to get the assets in a foolproof way._ +1. Run `git clone https://github.com/FunkinCrew/funkin.git` to clone the base repository. +2. Run `git submodule update --init --recursive` to download the game's assets. + - NOTE: By performing this operation, you are downloading Content which is proprietary and protected by national and international copyright and trademark laws. See [the LICENSE.md file for the Funkin.assets](https://github.com/FunkinCrew/funkin.assets/blob/main/LICENSE.md) repo for more information. 2. Run `haxelib --global install hmm` and then `haxelib --global run hmm setup` to install hmm.json 3. Run `hmm install` to install all haxelibs of the current branch 4. Run `haxelib run lime setup` to set up lime From 3f63bc35a4f27a51f07a5c1ac8053de2512d1757 Mon Sep 17 00:00:00 2001 From: EliteMasterEric <ericmyllyoja@gmail.com> Date: Tue, 25 Jun 2024 18:22:30 -0400 Subject: [PATCH 10/64] Add change counts labels to Actions labeler --- .github/changed-lines-count-labeler.yml | 12 ++++++++++++ .github/workflows/labeler.yml | 15 ++++++++++++++- 2 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 .github/changed-lines-count-labeler.yml diff --git a/.github/changed-lines-count-labeler.yml b/.github/changed-lines-count-labeler.yml new file mode 100644 index 000000000..6f890f534 --- /dev/null +++ b/.github/changed-lines-count-labeler.yml @@ -0,0 +1,12 @@ +# Add 'small' to any changes below 10 lines +small: + max: 9 + +# Add 'medium' to any changes between 10 and 100 lines +medium: + min: 10 + max: 99 + +# Add 'large' to any changes for more than 100 lines +large: + min: 100 diff --git a/.github/workflows/labeler.yml b/.github/workflows/labeler.yml index 0bcc420d3..a861af578 100644 --- a/.github/workflows/labeler.yml +++ b/.github/workflows/labeler.yml @@ -9,6 +9,19 @@ jobs: pull-requests: write runs-on: ubuntu-latest steps: - - uses: actions/labeler@v5 + - name: Set basic labels + uses: actions/labeler@v5 with: sync-labels: true + changed-lines-count-labeler: + permissions: + contents: read + pull-requests: write + runs-on: ubuntu-latest + name: An action for automatically labelling pull requests based on the changed lines count + steps: + - name: Set change count labels + uses: vkirilichev/changed-lines-count-labeler@v0.2 + with: + repo-token: ${{ secrets.GITHUB_TOKEN }} + configuration-path: .github/changed-lines-count-labeler.yml From 7b9e4a054284dbe6e69c1659e04571247276a599 Mon Sep 17 00:00:00 2001 From: gamerbross <55158797+gamerbross@users.noreply.github.com> Date: Wed, 10 Jul 2024 00:23:06 +0200 Subject: [PATCH 11/64] Fix F5 chart not reloading --- source/funkin/play/PlayState.hx | 59 ++----------------- source/funkin/ui/MusicBeatState.hx | 7 +-- source/funkin/ui/MusicBeatSubState.hx | 5 +- .../util/plugins/ReloadAssetsDebugPlugin.hx | 14 ++++- 4 files changed, 17 insertions(+), 68 deletions(-) diff --git a/source/funkin/play/PlayState.hx b/source/funkin/play/PlayState.hx index a4723611e..86e8e0241 100644 --- a/source/funkin/play/PlayState.hx +++ b/source/funkin/play/PlayState.hx @@ -1347,64 +1347,13 @@ class PlayState extends MusicBeatSubState } /** - * Removes any references to the current stage, then clears the stage cache, - * then reloads all the stages. - * - * This is useful for when you want to edit a stage without reloading the whole game. - * Reloading works on both the JSON and the HXC, if applicable. - * * Call this by pressing F5 on a debug build. */ - override function debug_refreshModules():Void + override function reloadAssets():Void { - // Prevent further gameplay updates, which will try to reference dead objects. - criticalFailure = true; - - // Remove the current stage. If the stage gets deleted while it's still in use, - // it'll probably crash the game or something. - if (this.currentStage != null) - { - remove(currentStage); - var event:ScriptEvent = new ScriptEvent(DESTROY, false); - ScriptEventDispatcher.callEvent(currentStage, event); - currentStage = null; - } - - if (!overrideMusic) - { - // Stop the instrumental. - if (FlxG.sound.music != null) - { - FlxG.sound.music.destroy(); - FlxG.sound.music = null; - } - - // Stop the vocals. - if (vocals != null && vocals.exists) - { - vocals.destroy(); - vocals = null; - } - } - else - { - // Stop the instrumental. - if (FlxG.sound.music != null) - { - FlxG.sound.music.stop(); - } - - // Stop the vocals. - if (vocals != null && vocals.exists) - { - vocals.stop(); - } - } - - super.debug_refreshModules(); - - var event:ScriptEvent = new ScriptEvent(CREATE, false); - ScriptEventDispatcher.callEvent(currentSong, event); + funkin.modding.PolymodHandler.forceReloadAssets(); + lastParams.targetSong = SongRegistry.instance.fetchEntry(currentSong.id); + LoadingState.loadPlayState(lastParams); } override function stepHit():Bool diff --git a/source/funkin/ui/MusicBeatState.hx b/source/funkin/ui/MusicBeatState.hx index 92169df75..8668b64c1 100644 --- a/source/funkin/ui/MusicBeatState.hx +++ b/source/funkin/ui/MusicBeatState.hx @@ -78,9 +78,6 @@ class MusicBeatState extends FlxTransitionableState implements IEventHandler { // Emergency exit button. if (FlxG.keys.justPressed.F4) FlxG.switchState(() -> new MainMenuState()); - - // This can now be used in EVERY STATE YAY! - if (FlxG.keys.justPressed.F5) debug_refreshModules(); } override function update(elapsed:Float) @@ -114,12 +111,10 @@ class MusicBeatState extends FlxTransitionableState implements IEventHandler ModuleHandler.callEvent(event); } - function debug_refreshModules() + function reloadAssets() { PolymodHandler.forceReloadAssets(); - this.destroy(); - // Create a new instance of the current state, so old data is cleared. FlxG.resetState(); } diff --git a/source/funkin/ui/MusicBeatSubState.hx b/source/funkin/ui/MusicBeatSubState.hx index 9035d12ff..5c40b37bc 100644 --- a/source/funkin/ui/MusicBeatSubState.hx +++ b/source/funkin/ui/MusicBeatSubState.hx @@ -72,9 +72,6 @@ class MusicBeatSubState extends FlxSubState implements IEventHandler // Emergency exit button. if (FlxG.keys.justPressed.F4) FlxG.switchState(() -> new MainMenuState()); - // This can now be used in EVERY STATE YAY! - if (FlxG.keys.justPressed.F5) debug_refreshModules(); - // Display Conductor info in the watch window. FlxG.watch.addQuick("musicTime", FlxG.sound.music?.time ?? 0.0); Conductor.watchQuick(conductorInUse); @@ -82,7 +79,7 @@ class MusicBeatSubState extends FlxSubState implements IEventHandler dispatchEvent(new UpdateScriptEvent(elapsed)); } - function debug_refreshModules() + function reloadAssets() { PolymodHandler.forceReloadAssets(); diff --git a/source/funkin/util/plugins/ReloadAssetsDebugPlugin.hx b/source/funkin/util/plugins/ReloadAssetsDebugPlugin.hx index f69609531..0e1e238ac 100644 --- a/source/funkin/util/plugins/ReloadAssetsDebugPlugin.hx +++ b/source/funkin/util/plugins/ReloadAssetsDebugPlugin.hx @@ -1,6 +1,9 @@ package funkin.util.plugins; +import flixel.FlxG; import flixel.FlxBasic; +import funkin.ui.MusicBeatState; +import funkin.ui.MusicBeatSubState; /** * A plugin which adds functionality to press `F5` to reload all game assets, then reload the current state. @@ -28,10 +31,15 @@ class ReloadAssetsDebugPlugin extends FlxBasic if (FlxG.keys.justPressed.F5) #end { - funkin.modding.PolymodHandler.forceReloadAssets(); + var state:Dynamic = FlxG.state; + if (state is MusicBeatState || state is MusicBeatSubState) state.reloadAssets(); + else + { + funkin.modding.PolymodHandler.forceReloadAssets(); - // Create a new instance of the current state, so old data is cleared. - FlxG.resetState(); + // Create a new instance of the current state, so old data is cleared. + FlxG.resetState(); + } } } From 18b795d4f74e81e8f9bbabd3e3e3e0fe7930a167 Mon Sep 17 00:00:00 2001 From: anysad <anysadiscool@gmail.com> Date: Thu, 11 Jul 2024 18:10:45 +0300 Subject: [PATCH 12/64] Add HEY! song events to Tutorial --- source/funkin/play/PlayState.hx | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/source/funkin/play/PlayState.hx b/source/funkin/play/PlayState.hx index 8d7d82aab..216acca71 100644 --- a/source/funkin/play/PlayState.hx +++ b/source/funkin/play/PlayState.hx @@ -1502,7 +1502,7 @@ class PlayState extends MusicBeatSubState if (opponentStrumline != null) opponentStrumline.onBeatHit(); // Make the characters dance on the beat - danceOnBeat(); + //danceOnBeat(); return true; } @@ -1522,16 +1522,6 @@ class PlayState extends MusicBeatSubState function danceOnBeat():Void { if (currentStage == null) return; - - // TODO: Add HEY! song events to Tutorial. - if (Conductor.instance.currentBeat % 16 == 15 - && currentStage.getDad().characterId == 'gf' - && Conductor.instance.currentBeat > 16 - && Conductor.instance.currentBeat < 48) - { - currentStage.getBoyfriend().playAnimation('hey', true); - currentStage.getDad().playAnimation('cheer', true); - } } /** From 305ab3146fe8891e925d34f5f2aafd9006ce1288 Mon Sep 17 00:00:00 2001 From: anysad <anysadiscool@gmail.com> Date: Thu, 11 Jul 2024 18:12:50 +0300 Subject: [PATCH 13/64] Add HEY! song events to Tutorial --- assets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets b/assets index 005c96f85..81e61c287 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit 005c96f85f4304865acb196e7cc4d6d83f9d76d8 +Subproject commit 81e61c287670f6aa8b7faf2c27561df57361f1ad From 4a7545a0dbdf7e8e1f1acca59940c87d59151646 Mon Sep 17 00:00:00 2001 From: EliteMasterEric <ericmyllyoja@gmail.com> Date: Thu, 11 Jul 2024 21:45:06 -0400 Subject: [PATCH 14/64] Remove empty function. --- source/funkin/play/PlayState.hx | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/source/funkin/play/PlayState.hx b/source/funkin/play/PlayState.hx index 216acca71..309c21438 100644 --- a/source/funkin/play/PlayState.hx +++ b/source/funkin/play/PlayState.hx @@ -1501,9 +1501,6 @@ class PlayState extends MusicBeatSubState if (playerStrumline != null) playerStrumline.onBeatHit(); if (opponentStrumline != null) opponentStrumline.onBeatHit(); - // Make the characters dance on the beat - //danceOnBeat(); - return true; } @@ -1514,16 +1511,6 @@ class PlayState extends MusicBeatSubState super.destroy(); } - /** - * Handles characters dancing to the beat of the current song. - * - * TODO: Move some of this logic into `Bopper.hx`, or individual character scripts. - */ - function danceOnBeat():Void - { - if (currentStage == null) return; - } - /** * Initializes the game and HUD cameras. */ From 90155bcfbfa86561571b7c556b1f63486c18877d Mon Sep 17 00:00:00 2001 From: gamerbross <55158797+gamerbross@users.noreply.github.com> Date: Wed, 10 Jul 2024 01:26:16 +0200 Subject: [PATCH 15/64] ChartEditor Live Input Code Refactor + 6 key fix --- .../ui/debug/charting/ChartEditorState.hx | 57 ++++++------------- 1 file changed, 18 insertions(+), 39 deletions(-) diff --git a/source/funkin/ui/debug/charting/ChartEditorState.hx b/source/funkin/ui/debug/charting/ChartEditorState.hx index f72cca77f..5e7493840 100644 --- a/source/funkin/ui/debug/charting/ChartEditorState.hx +++ b/source/funkin/ui/debug/charting/ChartEditorState.hx @@ -282,6 +282,21 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState */ public static final WELCOME_MUSIC_FADE_IN_DURATION:Float = 10.0; + /** + * A map of the keys for every live input style. + */ + public static final LIVE_INPUT_KEYS:Map<ChartEditorLiveInputStyle, Array<FlxKey>> = [ + NumberKeys => [ + FIVE, SIX, SEVEN, EIGHT, + ONE, TWO, THREE, FOUR + ], + WASDKeys => [ + LEFT, DOWN, UP, RIGHT, + A, S, W, D + ], + None => [] + ]; + /** * INSTANCE DATA */ @@ -5129,46 +5144,10 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState function handlePlayhead():Void { // Place notes at the playhead with the keyboard. - switch (currentLiveInputStyle) + for (note => key in LIVE_INPUT_KEYS[currentLiveInputStyle]) { - case ChartEditorLiveInputStyle.WASDKeys: - 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. + if (FlxG.keys.checkStatus(key, JUST_PRESSED)) placeNoteAtPlayhead(note) + else if (FlxG.keys.checkStatus(key, JUST_RELEASED)) finishPlaceNoteAtPlayhead(note); } // Place events at playhead. From 17f5a06256b34ff5224fde5b893cdac7c5086a5f Mon Sep 17 00:00:00 2001 From: gamerbross <55158797+gamerbross@users.noreply.github.com> Date: Mon, 20 May 2024 02:56:57 +0200 Subject: [PATCH 16/64] Add camOther to fix zooms on pause and stickers --- source/funkin/play/PlayState.hx | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/source/funkin/play/PlayState.hx b/source/funkin/play/PlayState.hx index 8d7d82aab..e87fde90c 100644 --- a/source/funkin/play/PlayState.hx +++ b/source/funkin/play/PlayState.hx @@ -503,9 +503,9 @@ class PlayState extends MusicBeatSubState public var camGame:FlxCamera; /** - * The camera which contains, and controls visibility of, a video cutscene. + * The camera which contains, and controls visibility of, a video cutscene, dialogue, pause menu and sticker transition. */ - public var camCutscene:FlxCamera; + public var camOther:FlxCamera; /** * The combo popups. Includes the real-time combo counter and the rating. @@ -975,7 +975,7 @@ class PlayState extends MusicBeatSubState FlxTransitionableState.skipNextTransIn = true; FlxTransitionableState.skipNextTransOut = true; - pauseSubState.camera = camHUD; + pauseSubState.camera = camOther; openSubState(pauseSubState); // boyfriendPos.put(); // TODO: Why is this here? } @@ -1543,12 +1543,12 @@ class PlayState extends MusicBeatSubState 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. - camCutscene = new FlxCamera(); - camCutscene.bgColor.alpha = 0; // Show the game scene behind the camera. + camOther = new FlxCamera(); + camOther.bgColor.alpha = 0; // Show the game scene behind the camera. FlxG.cameras.reset(camGame); FlxG.cameras.add(camHUD, false); - FlxG.cameras.add(camCutscene, false); + FlxG.cameras.add(camOther, false); // Configure camera follow point. if (previousCameraFollowPoint != null) @@ -1934,7 +1934,6 @@ class PlayState extends MusicBeatSubState if (!result) return; isInCutscene = false; - camCutscene.visible = false; // TODO: Maybe tween in the camera after any cutscenes. camHUD.visible = true; @@ -1953,7 +1952,7 @@ class PlayState extends MusicBeatSubState if (!currentConversation.alive) currentConversation.revive(); currentConversation.completeCallback = onConversationComplete; - currentConversation.cameras = [camCutscene]; + currentConversation.cameras = [camOther]; currentConversation.zIndex = 1000; add(currentConversation); refresh(); @@ -2788,7 +2787,7 @@ class PlayState extends MusicBeatSubState persistentUpdate = false; FlxTransitionableState.skipNextTransIn = true; FlxTransitionableState.skipNextTransOut = true; - pauseSubState.camera = camCutscene; + pauseSubState.camera = camOther; openSubState(pauseSubState); } } @@ -2804,7 +2803,7 @@ class PlayState extends MusicBeatSubState persistentUpdate = false; FlxTransitionableState.skipNextTransIn = true; FlxTransitionableState.skipNextTransOut = true; - pauseSubState.camera = camCutscene; + pauseSubState.camera = camOther; openSubState(pauseSubState); } } From e23e6c160d9ed9243a380c4b6842a059a3954768 Mon Sep 17 00:00:00 2001 From: gamerbross <55158797+gamerbross@users.noreply.github.com> Date: Mon, 20 May 2024 23:52:45 +0200 Subject: [PATCH 17/64] Fix references to camCutscene --- source/funkin/play/cutscene/VideoCutscene.hx | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/source/funkin/play/cutscene/VideoCutscene.hx b/source/funkin/play/cutscene/VideoCutscene.hx index abbcd4f54..7dac97885 100644 --- a/source/funkin/play/cutscene/VideoCutscene.hx +++ b/source/funkin/play/cutscene/VideoCutscene.hx @@ -81,12 +81,11 @@ class VideoCutscene // Trigger the cutscene. Don't play the song in the background. PlayState.instance.isInCutscene = true; PlayState.instance.camHUD.visible = false; - PlayState.instance.camCutscene.visible = true; // Display a black screen to hide the game while the video is playing. blackScreen = new FlxSprite(-200, -200).makeGraphic(FlxG.width * 2, FlxG.height * 2, FlxColor.BLACK); blackScreen.scrollFactor.set(0, 0); - blackScreen.cameras = [PlayState.instance.camCutscene]; + blackScreen.cameras = [PlayState.instance.camOther]; PlayState.instance.add(blackScreen); VideoCutscene.cutsceneType = cutsceneType; @@ -120,7 +119,7 @@ class VideoCutscene vid.finishCallback = finishVideo.bind(0.5); - vid.cameras = [PlayState.instance.camCutscene]; + vid.cameras = [PlayState.instance.camOther]; PlayState.instance.add(vid); @@ -147,7 +146,7 @@ class VideoCutscene vid.bitmap.onEndReached.add(finishVideo.bind(0.5)); vid.autoPause = FlxG.autoPause; - vid.cameras = [PlayState.instance.camCutscene]; + vid.cameras = [PlayState.instance.camOther]; PlayState.instance.add(vid); @@ -305,7 +304,6 @@ class VideoCutscene vid = null; #end - PlayState.instance.camCutscene.visible = true; PlayState.instance.camHUD.visible = true; FlxTween.tween(blackScreen, {alpha: 0}, transitionTime, From e6c97678002e1b4ba823b71471ec0d6052d96c0a Mon Sep 17 00:00:00 2001 From: gamerbross <55158797+gamerbross@users.noreply.github.com> Date: Wed, 12 Jun 2024 00:34:04 +0200 Subject: [PATCH 18/64] Revert camCutscene rename --- source/funkin/play/PlayState.hx | 16 ++++++++-------- source/funkin/play/cutscene/VideoCutscene.hx | 6 +++--- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/source/funkin/play/PlayState.hx b/source/funkin/play/PlayState.hx index e87fde90c..0bb57b8cb 100644 --- a/source/funkin/play/PlayState.hx +++ b/source/funkin/play/PlayState.hx @@ -505,7 +505,7 @@ class PlayState extends MusicBeatSubState /** * The camera which contains, and controls visibility of, a video cutscene, dialogue, pause menu and sticker transition. */ - public var camOther:FlxCamera; + public var camCutscene:FlxCamera; /** * The combo popups. Includes the real-time combo counter and the rating. @@ -975,7 +975,7 @@ class PlayState extends MusicBeatSubState FlxTransitionableState.skipNextTransIn = true; FlxTransitionableState.skipNextTransOut = true; - pauseSubState.camera = camOther; + pauseSubState.camera = camCutscene; openSubState(pauseSubState); // boyfriendPos.put(); // TODO: Why is this here? } @@ -1543,12 +1543,12 @@ class PlayState extends MusicBeatSubState 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. - camOther = new FlxCamera(); - camOther.bgColor.alpha = 0; // Show the game scene behind the camera. + camCutscene = new FlxCamera(); + camCutscene.bgColor.alpha = 0; // Show the game scene behind the camera. FlxG.cameras.reset(camGame); FlxG.cameras.add(camHUD, false); - FlxG.cameras.add(camOther, false); + FlxG.cameras.add(camCutscene, false); // Configure camera follow point. if (previousCameraFollowPoint != null) @@ -1952,7 +1952,7 @@ class PlayState extends MusicBeatSubState if (!currentConversation.alive) currentConversation.revive(); currentConversation.completeCallback = onConversationComplete; - currentConversation.cameras = [camOther]; + currentConversation.cameras = [camCutscene]; currentConversation.zIndex = 1000; add(currentConversation); refresh(); @@ -2787,7 +2787,7 @@ class PlayState extends MusicBeatSubState persistentUpdate = false; FlxTransitionableState.skipNextTransIn = true; FlxTransitionableState.skipNextTransOut = true; - pauseSubState.camera = camOther; + pauseSubState.camera = camCutscene; openSubState(pauseSubState); } } @@ -2803,7 +2803,7 @@ class PlayState extends MusicBeatSubState persistentUpdate = false; FlxTransitionableState.skipNextTransIn = true; FlxTransitionableState.skipNextTransOut = true; - pauseSubState.camera = camOther; + pauseSubState.camera = camCutscene; openSubState(pauseSubState); } } diff --git a/source/funkin/play/cutscene/VideoCutscene.hx b/source/funkin/play/cutscene/VideoCutscene.hx index 7dac97885..60454b881 100644 --- a/source/funkin/play/cutscene/VideoCutscene.hx +++ b/source/funkin/play/cutscene/VideoCutscene.hx @@ -85,7 +85,7 @@ class VideoCutscene // Display a black screen to hide the game while the video is playing. blackScreen = new FlxSprite(-200, -200).makeGraphic(FlxG.width * 2, FlxG.height * 2, FlxColor.BLACK); blackScreen.scrollFactor.set(0, 0); - blackScreen.cameras = [PlayState.instance.camOther]; + blackScreen.cameras = [PlayState.instance.camCutscene]; PlayState.instance.add(blackScreen); VideoCutscene.cutsceneType = cutsceneType; @@ -119,7 +119,7 @@ class VideoCutscene vid.finishCallback = finishVideo.bind(0.5); - vid.cameras = [PlayState.instance.camOther]; + vid.cameras = [PlayState.instance.camCutscene]; PlayState.instance.add(vid); @@ -146,7 +146,7 @@ class VideoCutscene vid.bitmap.onEndReached.add(finishVideo.bind(0.5)); vid.autoPause = FlxG.autoPause; - vid.cameras = [PlayState.instance.camOther]; + vid.cameras = [PlayState.instance.camCutscene]; PlayState.instance.add(vid); From a7482410b91e82fbd7b7cf37a123b0e7aaa72fec Mon Sep 17 00:00:00 2001 From: lemz <ismael.amjad07@gmail.com> Date: Fri, 31 May 2024 14:02:28 +0200 Subject: [PATCH 19/64] add note kind scripts --- source/funkin/InitState.hx | 3 ++ source/funkin/play/PlayState.hx | 8 +++- .../play/notes/notekind/NoteKindScript.hx | 45 ++++++++++++++++++ .../notes/notekind/NoteKindScriptManager.hx | 46 +++++++++++++++++++ .../notes/notekind/ScriptedNoteKindScript.hx | 9 ++++ .../charting/util/ChartEditorDropdowns.hx | 2 +- 6 files changed, 111 insertions(+), 2 deletions(-) create mode 100644 source/funkin/play/notes/notekind/NoteKindScript.hx create mode 100644 source/funkin/play/notes/notekind/NoteKindScriptManager.hx create mode 100644 source/funkin/play/notes/notekind/ScriptedNoteKindScript.hx diff --git a/source/funkin/InitState.hx b/source/funkin/InitState.hx index 6e370b5ff..a339d2655 100644 --- a/source/funkin/InitState.hx +++ b/source/funkin/InitState.hx @@ -27,6 +27,7 @@ import funkin.data.dialogue.speaker.SpeakerRegistry; import funkin.data.freeplay.album.AlbumRegistry; import funkin.data.song.SongRegistry; import funkin.play.character.CharacterData.CharacterDataParser; +import funkin.play.notes.notekind.NoteKindScriptManager; import funkin.modding.module.ModuleHandler; import funkin.ui.title.TitleState; import funkin.util.CLIUtil; @@ -176,6 +177,8 @@ class InitState extends FlxState // Move it to use a BaseRegistry. CharacterDataParser.loadCharacterCache(); + NoteKindScriptManager.loadScripts(); + ModuleHandler.buildModuleCallbacks(); ModuleHandler.loadModuleCache(); ModuleHandler.callOnCreate(); diff --git a/source/funkin/play/PlayState.hx b/source/funkin/play/PlayState.hx index 8d7d82aab..93306e9d5 100644 --- a/source/funkin/play/PlayState.hx +++ b/source/funkin/play/PlayState.hx @@ -49,6 +49,7 @@ import funkin.play.notes.NoteSprite; import funkin.play.notes.notestyle.NoteStyle; import funkin.play.notes.Strumline; import funkin.play.notes.SustainTrail; +import funkin.play.notes.notekind.NoteKindScriptManager; import funkin.play.scoring.Scoring; import funkin.play.song.Song; import funkin.play.stage.Stage; @@ -1177,7 +1178,12 @@ class PlayState extends MusicBeatSubState // Dispatch event to conversation script. ScriptEventDispatcher.callEvent(currentConversation, event); - // TODO: Dispatch event to note scripts + // Dispatch event to note script + if (Std.isOfType(event, NoteScriptEvent)) + { + var noteEvent:NoteScriptEvent = cast(event, NoteScriptEvent); + NoteKindScriptManager.callEvent(noteEvent.note.noteData.kind, noteEvent); + } } /** diff --git a/source/funkin/play/notes/notekind/NoteKindScript.hx b/source/funkin/play/notes/notekind/NoteKindScript.hx new file mode 100644 index 000000000..baa57b146 --- /dev/null +++ b/source/funkin/play/notes/notekind/NoteKindScript.hx @@ -0,0 +1,45 @@ +package funkin.play.notes.notekind; + +import funkin.modding.IScriptedClass.INoteScriptedClass; +import funkin.modding.events.ScriptEvent; + +/** + * Class for note scripts + */ +class NoteKindScript implements INoteScriptedClass +{ + /** + * the name of the note kind + */ + public var noteKind:String; + + /** + * description used in chart editor + */ + public var description:String = ""; + + public function new(noteKind:String, description:String = "") + { + this.noteKind = noteKind; + this.description = description; + } + + public function toString():String + { + return noteKind; + } + + public function onScriptEvent(event:ScriptEvent):Void {} + + public function onCreate(event:ScriptEvent):Void {} + + public function onDestroy(event:ScriptEvent):Void {} + + public function onUpdate(event:UpdateScriptEvent):Void {} + + public function onNoteIncoming(event:NoteScriptEvent):Void {} + + public function onNoteHit(event:HitNoteScriptEvent):Void {} + + public function onNoteMiss(event:NoteScriptEvent):Void {} +} diff --git a/source/funkin/play/notes/notekind/NoteKindScriptManager.hx b/source/funkin/play/notes/notekind/NoteKindScriptManager.hx new file mode 100644 index 000000000..dc22732b6 --- /dev/null +++ b/source/funkin/play/notes/notekind/NoteKindScriptManager.hx @@ -0,0 +1,46 @@ +package funkin.play.notes.notekind; + +import funkin.modding.events.ScriptEventDispatcher; +import funkin.modding.events.ScriptEvent; +import funkin.ui.debug.charting.util.ChartEditorDropdowns; + +class NoteKindScriptManager +{ + static var noteKindScripts:Map<String, NoteKindScript> = []; + + public static function loadScripts():Void + { + var scriptedClassName:Array<String> = ScriptedNoteKindScript.listScriptClasses(); + if (scriptedClassName.length > 0) + { + trace('Instantiating ${scriptedClassName.length} scripted note kind...'); + for (scriptedClass in scriptedClassName) + { + try + { + var script:NoteKindScript = ScriptedNoteKindScript.init(scriptedClass, "unknown"); + trace(' Initialized scripted note kind: ${script.noteKind}'); + noteKindScripts.set(script.noteKind, script); + ChartEditorDropdowns.NOTE_KINDS.set(script.noteKind, script.description); + } + catch (e) + { + trace(' FAILED to instantiate scripted note kind: ${scriptedClass}'); + trace(e); + } + } + } + } + + public static function callEvent(noteKind:String, event:ScriptEvent):Void + { + var noteKindScript:NoteKindScript = noteKindScripts.get(noteKind); + + if (noteKindScript == null) + { + return; + } + + ScriptEventDispatcher.callEvent(noteKindScript, event); + } +} diff --git a/source/funkin/play/notes/notekind/ScriptedNoteKindScript.hx b/source/funkin/play/notes/notekind/ScriptedNoteKindScript.hx new file mode 100644 index 000000000..d54a0cde2 --- /dev/null +++ b/source/funkin/play/notes/notekind/ScriptedNoteKindScript.hx @@ -0,0 +1,9 @@ +package funkin.play.notes.notekind; + +/** + * A script that can be tied to a NoteKindScript. + * Create a scripted class that extends NoteKindScript, + * then call `super('noteKind')` in the constructor to use this. + */ +@:hscriptClass +class ScriptedNoteKindScript extends NoteKindScript implements polymod.hscript.HScriptedClass {} diff --git a/source/funkin/ui/debug/charting/util/ChartEditorDropdowns.hx b/source/funkin/ui/debug/charting/util/ChartEditorDropdowns.hx index 55aab0ab0..f20b75650 100644 --- a/source/funkin/ui/debug/charting/util/ChartEditorDropdowns.hx +++ b/source/funkin/ui/debug/charting/util/ChartEditorDropdowns.hx @@ -146,7 +146,7 @@ class ChartEditorDropdowns return returnValue; } - static final NOTE_KINDS:Map<String, String> = [ + public static final NOTE_KINDS:Map<String, String> = [ // Base "" => "Default", "~CUSTOM~" => "Custom", From 134b4678769de803b245c182fed9afe07fc29049 Mon Sep 17 00:00:00 2001 From: lemz <ismael.amjad07@gmail.com> Date: Fri, 31 May 2024 16:55:42 +0200 Subject: [PATCH 20/64] rename stuff --- source/funkin/InitState.hx | 4 ++-- source/funkin/play/PlayState.hx | 4 ++-- .../notekind/{NoteKindScript.hx => NoteKind.hx} | 2 +- ...teKindScriptManager.hx => NoteKindManager.hx} | 16 ++++++++-------- .../play/notes/notekind/ScriptedNoteKind.hx | 9 +++++++++ .../notes/notekind/ScriptedNoteKindScript.hx | 9 --------- 6 files changed, 22 insertions(+), 22 deletions(-) rename source/funkin/play/notes/notekind/{NoteKindScript.hx => NoteKind.hx} (94%) rename source/funkin/play/notes/notekind/{NoteKindScriptManager.hx => NoteKindManager.hx} (64%) create mode 100644 source/funkin/play/notes/notekind/ScriptedNoteKind.hx delete mode 100644 source/funkin/play/notes/notekind/ScriptedNoteKindScript.hx diff --git a/source/funkin/InitState.hx b/source/funkin/InitState.hx index a339d2655..34516dee1 100644 --- a/source/funkin/InitState.hx +++ b/source/funkin/InitState.hx @@ -27,7 +27,7 @@ import funkin.data.dialogue.speaker.SpeakerRegistry; import funkin.data.freeplay.album.AlbumRegistry; import funkin.data.song.SongRegistry; import funkin.play.character.CharacterData.CharacterDataParser; -import funkin.play.notes.notekind.NoteKindScriptManager; +import funkin.play.notes.notekind.NoteKindManager; import funkin.modding.module.ModuleHandler; import funkin.ui.title.TitleState; import funkin.util.CLIUtil; @@ -177,7 +177,7 @@ class InitState extends FlxState // Move it to use a BaseRegistry. CharacterDataParser.loadCharacterCache(); - NoteKindScriptManager.loadScripts(); + NoteKindManager.loadScripts(); ModuleHandler.buildModuleCallbacks(); ModuleHandler.loadModuleCache(); diff --git a/source/funkin/play/PlayState.hx b/source/funkin/play/PlayState.hx index 93306e9d5..bc441a7d5 100644 --- a/source/funkin/play/PlayState.hx +++ b/source/funkin/play/PlayState.hx @@ -49,7 +49,7 @@ import funkin.play.notes.NoteSprite; import funkin.play.notes.notestyle.NoteStyle; import funkin.play.notes.Strumline; import funkin.play.notes.SustainTrail; -import funkin.play.notes.notekind.NoteKindScriptManager; +import funkin.play.notes.notekind.NoteKindManager; import funkin.play.scoring.Scoring; import funkin.play.song.Song; import funkin.play.stage.Stage; @@ -1182,7 +1182,7 @@ class PlayState extends MusicBeatSubState if (Std.isOfType(event, NoteScriptEvent)) { var noteEvent:NoteScriptEvent = cast(event, NoteScriptEvent); - NoteKindScriptManager.callEvent(noteEvent.note.noteData.kind, noteEvent); + NoteKindManager.callEvent(noteEvent.note.noteData.kind, noteEvent); } } diff --git a/source/funkin/play/notes/notekind/NoteKindScript.hx b/source/funkin/play/notes/notekind/NoteKind.hx similarity index 94% rename from source/funkin/play/notes/notekind/NoteKindScript.hx rename to source/funkin/play/notes/notekind/NoteKind.hx index baa57b146..77b2bbc45 100644 --- a/source/funkin/play/notes/notekind/NoteKindScript.hx +++ b/source/funkin/play/notes/notekind/NoteKind.hx @@ -6,7 +6,7 @@ import funkin.modding.events.ScriptEvent; /** * Class for note scripts */ -class NoteKindScript implements INoteScriptedClass +class NoteKind implements INoteScriptedClass { /** * the name of the note kind diff --git a/source/funkin/play/notes/notekind/NoteKindScriptManager.hx b/source/funkin/play/notes/notekind/NoteKindManager.hx similarity index 64% rename from source/funkin/play/notes/notekind/NoteKindScriptManager.hx rename to source/funkin/play/notes/notekind/NoteKindManager.hx index dc22732b6..eaee0d319 100644 --- a/source/funkin/play/notes/notekind/NoteKindScriptManager.hx +++ b/source/funkin/play/notes/notekind/NoteKindManager.hx @@ -4,13 +4,13 @@ import funkin.modding.events.ScriptEventDispatcher; import funkin.modding.events.ScriptEvent; import funkin.ui.debug.charting.util.ChartEditorDropdowns; -class NoteKindScriptManager +class NoteKindManager { - static var noteKindScripts:Map<String, NoteKindScript> = []; + static var noteKinds:Map<String, NoteKind> = []; public static function loadScripts():Void { - var scriptedClassName:Array<String> = ScriptedNoteKindScript.listScriptClasses(); + var scriptedClassName:Array<String> = ScriptedNoteKind.listScriptClasses(); if (scriptedClassName.length > 0) { trace('Instantiating ${scriptedClassName.length} scripted note kind...'); @@ -18,9 +18,9 @@ class NoteKindScriptManager { try { - var script:NoteKindScript = ScriptedNoteKindScript.init(scriptedClass, "unknown"); + var script:NoteKind = ScriptedNoteKind.init(scriptedClass, "unknown"); trace(' Initialized scripted note kind: ${script.noteKind}'); - noteKindScripts.set(script.noteKind, script); + noteKinds.set(script.noteKind, script); ChartEditorDropdowns.NOTE_KINDS.set(script.noteKind, script.description); } catch (e) @@ -34,13 +34,13 @@ class NoteKindScriptManager public static function callEvent(noteKind:String, event:ScriptEvent):Void { - var noteKindScript:NoteKindScript = noteKindScripts.get(noteKind); + var noteKind:NoteKind = noteKinds.get(noteKind); - if (noteKindScript == null) + if (noteKind == null) { return; } - ScriptEventDispatcher.callEvent(noteKindScript, event); + ScriptEventDispatcher.callEvent(noteKind, event); } } diff --git a/source/funkin/play/notes/notekind/ScriptedNoteKind.hx b/source/funkin/play/notes/notekind/ScriptedNoteKind.hx new file mode 100644 index 000000000..cd1781394 --- /dev/null +++ b/source/funkin/play/notes/notekind/ScriptedNoteKind.hx @@ -0,0 +1,9 @@ +package funkin.play.notes.notekind; + +/** + * A script that can be tied to a NoteKind. + * Create a scripted class that extends NoteKind, + * then call `super('noteKind')` in the constructor to use this. + */ +@:hscriptClass +class ScriptedNoteKind extends NoteKind implements polymod.hscript.HScriptedClass {} diff --git a/source/funkin/play/notes/notekind/ScriptedNoteKindScript.hx b/source/funkin/play/notes/notekind/ScriptedNoteKindScript.hx deleted file mode 100644 index d54a0cde2..000000000 --- a/source/funkin/play/notes/notekind/ScriptedNoteKindScript.hx +++ /dev/null @@ -1,9 +0,0 @@ -package funkin.play.notes.notekind; - -/** - * A script that can be tied to a NoteKindScript. - * Create a scripted class that extends NoteKindScript, - * then call `super('noteKind')` in the constructor to use this. - */ -@:hscriptClass -class ScriptedNoteKindScript extends NoteKindScript implements polymod.hscript.HScriptedClass {} From 606d9d4af47ea50a89e921ef369aaa73b5dc3c7b Mon Sep 17 00:00:00 2001 From: lemz <ismael.amjad07@gmail.com> Date: Fri, 31 May 2024 17:24:51 +0200 Subject: [PATCH 21/64] Update NoteKindManager.hx --- source/funkin/play/notes/notekind/NoteKindManager.hx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/funkin/play/notes/notekind/NoteKindManager.hx b/source/funkin/play/notes/notekind/NoteKindManager.hx index eaee0d319..99502af08 100644 --- a/source/funkin/play/notes/notekind/NoteKindManager.hx +++ b/source/funkin/play/notes/notekind/NoteKindManager.hx @@ -13,7 +13,7 @@ class NoteKindManager var scriptedClassName:Array<String> = ScriptedNoteKind.listScriptClasses(); if (scriptedClassName.length > 0) { - trace('Instantiating ${scriptedClassName.length} scripted note kind...'); + trace('Instantiating ${scriptedClassName.length} scripted note kind(s)...'); for (scriptedClass in scriptedClassName) { try From c83e505f5bae0e1a61a1d010aec8765d53cab36d Mon Sep 17 00:00:00 2001 From: lemz <ismael.amjad07@gmail.com> Date: Fri, 31 May 2024 17:49:25 +0200 Subject: [PATCH 22/64] onUpdate, etc. works now too --- source/funkin/play/PlayState.hx | 6 +++++- source/funkin/play/notes/notekind/NoteKindManager.hx | 8 ++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/source/funkin/play/PlayState.hx b/source/funkin/play/PlayState.hx index bc441a7d5..3b098be14 100644 --- a/source/funkin/play/PlayState.hx +++ b/source/funkin/play/PlayState.hx @@ -1178,12 +1178,16 @@ class PlayState extends MusicBeatSubState // Dispatch event to conversation script. ScriptEventDispatcher.callEvent(currentConversation, event); - // Dispatch event to note script + // Dispatch event to only the specific note script if (Std.isOfType(event, NoteScriptEvent)) { var noteEvent:NoteScriptEvent = cast(event, NoteScriptEvent); NoteKindManager.callEvent(noteEvent.note.noteData.kind, noteEvent); } + else // Dispatch event to all note scripts + { + NoteKindManager.callEventForAll(event); + } } /** diff --git a/source/funkin/play/notes/notekind/NoteKindManager.hx b/source/funkin/play/notes/notekind/NoteKindManager.hx index 99502af08..0de1a0a33 100644 --- a/source/funkin/play/notes/notekind/NoteKindManager.hx +++ b/source/funkin/play/notes/notekind/NoteKindManager.hx @@ -43,4 +43,12 @@ class NoteKindManager ScriptEventDispatcher.callEvent(noteKind, event); } + + public static function callEventForAll(event:ScriptEvent):Void + { + for (noteKind in noteKinds.iterator()) + { + ScriptEventDispatcher.callEvent(noteKind, event); + } + } } From e3e4e9fac01844a807ecd54e34fc162205c59ed9 Mon Sep 17 00:00:00 2001 From: lemz <ismael.amjad07@gmail.com> Date: Fri, 31 May 2024 20:28:56 +0200 Subject: [PATCH 23/64] helper function --- source/funkin/play/notes/notekind/NoteKind.hx | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/source/funkin/play/notes/notekind/NoteKind.hx b/source/funkin/play/notes/notekind/NoteKind.hx index 77b2bbc45..8b87e0442 100644 --- a/source/funkin/play/notes/notekind/NoteKind.hx +++ b/source/funkin/play/notes/notekind/NoteKind.hx @@ -18,6 +18,16 @@ class NoteKind implements INoteScriptedClass */ public var description:String = ""; + /** + * this only exists for people that don't like calling functions + */ + var notes(get, never):Array<NoteSprite>; + + function get_notes():Array<NoteSprite> + { + return this.getNotes(); + } + public function new(noteKind:String, description:String = "") { this.noteKind = noteKind; @@ -29,6 +39,18 @@ class NoteKind implements INoteScriptedClass return noteKind; } + /** + * Retrieve all notes of this kind + * @return Array<NoteSprite> + */ + function getNotes():Array<NoteSprite> + { + var allNotes:Array<NoteSprite> = PlayState.instance.playerStrumline.notes.members.concat(PlayState.instance.opponentStrumline.notes.members); + return allNotes.filter(function(note:NoteSprite) { + return note != null && note.noteData.kind == this.noteKind; + }); + } + public function onScriptEvent(event:ScriptEvent):Void {} public function onCreate(event:ScriptEvent):Void {} From 3f39d9509c1e2a02d4ace85553991b6679a83d14 Mon Sep 17 00:00:00 2001 From: lemz <ismael.amjad07@gmail.com> Date: Fri, 31 May 2024 23:56:57 +0200 Subject: [PATCH 24/64] make custom note style less clunky --- source/funkin/play/notes/notekind/NoteKind.hx | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/source/funkin/play/notes/notekind/NoteKind.hx b/source/funkin/play/notes/notekind/NoteKind.hx index 8b87e0442..f4936c59e 100644 --- a/source/funkin/play/notes/notekind/NoteKind.hx +++ b/source/funkin/play/notes/notekind/NoteKind.hx @@ -1,5 +1,7 @@ package funkin.play.notes.notekind; +import funkin.data.notestyle.NoteStyleRegistry; +import funkin.play.notes.notestyle.NoteStyle; import funkin.modding.IScriptedClass.INoteScriptedClass; import funkin.modding.events.ScriptEvent; @@ -39,6 +41,23 @@ class NoteKind implements INoteScriptedClass return noteKind; } + /** + * Changes the note style of the given note. Use this in `onNoteIncoming` + * @param note + * @param noteStyle + */ + function setNoteStyle(note:NoteSprite, noteStyleId:String):Void + { + var noteStyle:NoteStyle = NoteStyleRegistry.instance.fetchEntry(noteStyleId); + noteStyle.buildNoteSprite(note); + + note.setGraphicSize(Strumline.STRUMLINE_SIZE); + note.updateHitbox(); + + // this calls the setter for playing the correct animation + note.direction = note.direction; + } + /** * Retrieve all notes of this kind * @return Array<NoteSprite> From 14771e72deb7f08b9658e0801c9e088bb5d1aa96 Mon Sep 17 00:00:00 2001 From: lemz <ismael.amjad07@gmail.com> Date: Fri, 31 May 2024 23:59:40 +0200 Subject: [PATCH 25/64] no more note getter --- source/funkin/play/notes/notekind/NoteKind.hx | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/source/funkin/play/notes/notekind/NoteKind.hx b/source/funkin/play/notes/notekind/NoteKind.hx index f4936c59e..262660eea 100644 --- a/source/funkin/play/notes/notekind/NoteKind.hx +++ b/source/funkin/play/notes/notekind/NoteKind.hx @@ -20,16 +20,6 @@ class NoteKind implements INoteScriptedClass */ public var description:String = ""; - /** - * this only exists for people that don't like calling functions - */ - var notes(get, never):Array<NoteSprite>; - - function get_notes():Array<NoteSprite> - { - return this.getNotes(); - } - public function new(noteKind:String, description:String = "") { this.noteKind = noteKind; From b6eda8e498be12f40c6086678a48c7c038e4b69e Mon Sep 17 00:00:00 2001 From: lemz <ismael.amjad07@gmail.com> Date: Sat, 1 Jun 2024 18:25:46 +0200 Subject: [PATCH 26/64] remove note kind logic from playstate --- source/funkin/play/PlayState.hx | 12 ++----- .../play/notes/notekind/NoteKindManager.hx | 34 ++++++++++++------- 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/source/funkin/play/PlayState.hx b/source/funkin/play/PlayState.hx index 3b098be14..da343f43f 100644 --- a/source/funkin/play/PlayState.hx +++ b/source/funkin/play/PlayState.hx @@ -1178,16 +1178,8 @@ class PlayState extends MusicBeatSubState // Dispatch event to conversation script. ScriptEventDispatcher.callEvent(currentConversation, event); - // Dispatch event to only the specific note script - if (Std.isOfType(event, NoteScriptEvent)) - { - var noteEvent:NoteScriptEvent = cast(event, NoteScriptEvent); - NoteKindManager.callEvent(noteEvent.note.noteData.kind, noteEvent); - } - else // Dispatch event to all note scripts - { - NoteKindManager.callEventForAll(event); - } + // Dispatch event to note kind scripts + NoteKindManager.callEvent(event); } /** diff --git a/source/funkin/play/notes/notekind/NoteKindManager.hx b/source/funkin/play/notes/notekind/NoteKindManager.hx index 0de1a0a33..6efd601c7 100644 --- a/source/funkin/play/notes/notekind/NoteKindManager.hx +++ b/source/funkin/play/notes/notekind/NoteKindManager.hx @@ -32,23 +32,31 @@ class NoteKindManager } } - public static function callEvent(noteKind:String, event:ScriptEvent):Void + /** + * Calls the given event for note kind scripts + * @param event The event + */ + public static function callEvent(event:ScriptEvent):Void { - var noteKind:NoteKind = noteKinds.get(noteKind); - - if (noteKind == null) + // if it is a note script event, + // then only call the event for the specific note kind script + if (Std.isOfType(event, NoteScriptEvent)) { - return; + var noteEvent:NoteScriptEvent = cast(event, NoteScriptEvent); + + var noteKind:NoteKind = noteKinds.get(noteEvent.note.noteData.kind); + + if (noteKind != null) + { + ScriptEventDispatcher.callEvent(noteKind, event); + } } - - ScriptEventDispatcher.callEvent(noteKind, event); - } - - public static function callEventForAll(event:ScriptEvent):Void - { - for (noteKind in noteKinds.iterator()) + else // call the event for all note kind scripts { - ScriptEventDispatcher.callEvent(noteKind, event); + for (noteKind in noteKinds.iterator()) + { + ScriptEventDispatcher.callEvent(noteKind, event); + } } } } From 328e590f92901f3dab711a725af02cc40763f359 Mon Sep 17 00:00:00 2001 From: lemz <ismael.amjad07@gmail.com> Date: Sat, 1 Jun 2024 19:47:45 +0200 Subject: [PATCH 27/64] hold assets are updated aswell --- source/funkin/play/notes/NoteSprite.hx | 6 ++- source/funkin/play/notes/Strumline.hx | 7 ++++ source/funkin/play/notes/SustainTrail.hx | 38 ++++++++++++++----- source/funkin/play/notes/notekind/NoteKind.hx | 33 +++++----------- .../play/notes/notekind/NoteKindManager.hx | 16 +++++++- 5 files changed, 65 insertions(+), 35 deletions(-) diff --git a/source/funkin/play/notes/NoteSprite.hx b/source/funkin/play/notes/NoteSprite.hx index b16b88466..17a5e57fc 100644 --- a/source/funkin/play/notes/NoteSprite.hx +++ b/source/funkin/play/notes/NoteSprite.hx @@ -140,7 +140,11 @@ class NoteSprite extends FunkinSprite this.active = false; } - function setupNoteGraphic(noteStyle:NoteStyle):Void + /** + * Creates frames and animations + * @param noteStyle The `NoteStyle` instance + */ + public function setupNoteGraphic(noteStyle:NoteStyle):Void { noteStyle.buildNoteSprite(this); diff --git a/source/funkin/play/notes/Strumline.hx b/source/funkin/play/notes/Strumline.hx index fdb32bb85..ebc48a8c7 100644 --- a/source/funkin/play/notes/Strumline.hx +++ b/source/funkin/play/notes/Strumline.hx @@ -16,6 +16,7 @@ import funkin.data.song.SongData.SongNoteData; import funkin.ui.options.PreferencesMenu; import funkin.util.SortUtil; import funkin.modding.events.ScriptEvent; +import funkin.play.notes.notekind.NoteKindManager; /** * A group of sprites which handles the receptor, the note splashes, and the notes (with sustains) for a given player. @@ -708,6 +709,9 @@ class Strumline extends FlxSpriteGroup if (noteSprite != null) { + var noteKindStyle:NoteStyle = NoteKindManager.getNoteStyle(note.kind) ?? this.noteStyle; + noteSprite.setupNoteGraphic(noteKindStyle); + noteSprite.direction = note.getDirection(); noteSprite.noteData = note; @@ -727,6 +731,9 @@ class Strumline extends FlxSpriteGroup if (holdNoteSprite != null) { + var noteKindStyle:NoteStyle = NoteKindManager.getNoteStyle(note.kind) ?? this.noteStyle; + holdNoteSprite.setupHoldNoteGraphic(noteKindStyle); + holdNoteSprite.parentStrumline = this; holdNoteSprite.noteData = note; holdNoteSprite.strumTime = note.time; diff --git a/source/funkin/play/notes/SustainTrail.hx b/source/funkin/play/notes/SustainTrail.hx index f6d43b33f..570c05190 100644 --- a/source/funkin/play/notes/SustainTrail.hx +++ b/source/funkin/play/notes/SustainTrail.hx @@ -99,7 +99,27 @@ class SustainTrail extends FlxSprite */ public function new(noteDirection:NoteDirection, sustainLength:Float, noteStyle:NoteStyle) { - super(0, 0, noteStyle.getHoldNoteAssetPath()); + super(0, 0); + + // BASIC SETUP + this.sustainLength = sustainLength; + this.fullSustainLength = sustainLength; + this.noteDirection = noteDirection; + + setupHoldNoteGraphic(noteStyle); + + indices = new DrawData<Int>(12, true, TRIANGLE_VERTEX_INDICES); + + this.active = true; // This NEEDS to be true for the note to be drawn! + } + + /** + * Creates hold note graphic and applies correct zooming + * @param noteStyle The note style + */ + public function setupHoldNoteGraphic(noteStyle:NoteStyle):Void + { + loadGraphic(noteStyle.getHoldNoteAssetPath()); antialiasing = true; @@ -109,13 +129,9 @@ class SustainTrail extends FlxSprite endOffset = bottomClip = 1; antialiasing = false; } + + zoom = 1.0; zoom *= noteStyle.fetchHoldNoteScale(); - - // BASIC SETUP - this.sustainLength = sustainLength; - this.fullSustainLength = sustainLength; - this.noteDirection = noteDirection; - zoom *= 0.7; // CALCULATE SIZE @@ -131,9 +147,6 @@ class SustainTrail extends FlxSprite updateColorTransform(); updateClipping(); - indices = new DrawData<Int>(12, true, TRIANGLE_VERTEX_INDICES); - - this.active = true; // This NEEDS to be true for the note to be drawn! } function getBaseScrollSpeed() @@ -195,6 +208,11 @@ class SustainTrail extends FlxSprite */ public function updateClipping(songTime:Float = 0):Void { + if (graphic == null) + { + return; + } + var clipHeight:Float = FlxMath.bound(sustainHeight(sustainLength - (songTime - strumTime), parentStrumline?.scrollSpeed ?? 1.0), 0, graphicHeight); if (clipHeight <= 0.1) { diff --git a/source/funkin/play/notes/notekind/NoteKind.hx b/source/funkin/play/notes/notekind/NoteKind.hx index 262660eea..53393623a 100644 --- a/source/funkin/play/notes/notekind/NoteKind.hx +++ b/source/funkin/play/notes/notekind/NoteKind.hx @@ -1,7 +1,5 @@ package funkin.play.notes.notekind; -import funkin.data.notestyle.NoteStyleRegistry; -import funkin.play.notes.notestyle.NoteStyle; import funkin.modding.IScriptedClass.INoteScriptedClass; import funkin.modding.events.ScriptEvent; @@ -11,19 +9,25 @@ import funkin.modding.events.ScriptEvent; class NoteKind implements INoteScriptedClass { /** - * the name of the note kind + * The name of the note kind */ public var noteKind:String; /** - * description used in chart editor + * Description used in chart editor */ - public var description:String = ""; + public var description:String; - public function new(noteKind:String, description:String = "") + /** + * Custom note style + */ + public var noteStyleId:String; + + public function new(noteKind:String, description:String = "", noteStyleId:String = "") { this.noteKind = noteKind; this.description = description; + this.noteStyleId = noteStyleId; } public function toString():String @@ -31,23 +35,6 @@ class NoteKind implements INoteScriptedClass return noteKind; } - /** - * Changes the note style of the given note. Use this in `onNoteIncoming` - * @param note - * @param noteStyle - */ - function setNoteStyle(note:NoteSprite, noteStyleId:String):Void - { - var noteStyle:NoteStyle = NoteStyleRegistry.instance.fetchEntry(noteStyleId); - noteStyle.buildNoteSprite(note); - - note.setGraphicSize(Strumline.STRUMLINE_SIZE); - note.updateHitbox(); - - // this calls the setter for playing the correct animation - note.direction = note.direction; - } - /** * Retrieve all notes of this kind * @return Array<NoteSprite> diff --git a/source/funkin/play/notes/notekind/NoteKindManager.hx b/source/funkin/play/notes/notekind/NoteKindManager.hx index 6efd601c7..849034fc4 100644 --- a/source/funkin/play/notes/notekind/NoteKindManager.hx +++ b/source/funkin/play/notes/notekind/NoteKindManager.hx @@ -3,6 +3,8 @@ package funkin.play.notes.notekind; import funkin.modding.events.ScriptEventDispatcher; import funkin.modding.events.ScriptEvent; import funkin.ui.debug.charting.util.ChartEditorDropdowns; +import funkin.data.notestyle.NoteStyleRegistry; +import funkin.play.notes.notestyle.NoteStyle; class NoteKindManager { @@ -44,7 +46,7 @@ class NoteKindManager { var noteEvent:NoteScriptEvent = cast(event, NoteScriptEvent); - var noteKind:NoteKind = noteKinds.get(noteEvent.note.noteData.kind); + var noteKind:NoteKind = noteKinds.get(noteEvent.note.kind); if (noteKind != null) { @@ -59,4 +61,16 @@ class NoteKindManager } } } + + /** + * Retrieve the note style from the given note kind + * @param noteKind note kind name + * @return NoteStyle + */ + public static function getNoteStyle(noteKind:String):Null<NoteStyle> + { + var noteStyleId:String = noteKinds.get(noteKind)?.noteStyleId ?? ""; + + return NoteStyleRegistry.instance.fetchEntry(noteStyleId); + } } From ca69e7b850332e0aa4a35574566867cca649cdbf Mon Sep 17 00:00:00 2001 From: lemz <ismael.amjad07@gmail.com> Date: Sun, 2 Jun 2024 02:44:16 +0200 Subject: [PATCH 28/64] custom note styles in chart editor --- .../ui/debug/charting/ChartEditorState.hx | 2 + .../components/ChartEditorNoteSprite.hx | 106 ++++++++++-------- .../toolboxes/ChartEditorNoteDataToolbox.hx | 5 + 3 files changed, 64 insertions(+), 49 deletions(-) diff --git a/source/funkin/ui/debug/charting/ChartEditorState.hx b/source/funkin/ui/debug/charting/ChartEditorState.hx index f72cca77f..0117d8a51 100644 --- a/source/funkin/ui/debug/charting/ChartEditorState.hx +++ b/source/funkin/ui/debug/charting/ChartEditorState.hx @@ -1663,6 +1663,8 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState return currentSongMetadata.playData.characters.instrumental = value; } + var currentCustomNoteKindStyle:Null<String>; + /** * HAXEUI COMPONENTS */ diff --git a/source/funkin/ui/debug/charting/components/ChartEditorNoteSprite.hx b/source/funkin/ui/debug/charting/components/ChartEditorNoteSprite.hx index 98f5a47aa..c97aee1f8 100644 --- a/source/funkin/ui/debug/charting/components/ChartEditorNoteSprite.hx +++ b/source/funkin/ui/debug/charting/components/ChartEditorNoteSprite.hx @@ -7,7 +7,11 @@ import flixel.graphics.frames.FlxAtlasFrames; import flixel.graphics.frames.FlxFrame; import flixel.graphics.frames.FlxTileFrames; import flixel.math.FlxPoint; +import funkin.data.animation.AnimationData; import funkin.data.song.SongData.SongNoteData; +import funkin.data.notestyle.NoteStyleRegistry; +import funkin.play.notes.notestyle.NoteStyle; +import funkin.play.notes.NoteDirection; /** * A sprite that can be used to display a note in a chart. @@ -68,68 +72,62 @@ class ChartEditorNoteSprite extends FlxSprite if (noteFrameCollection == null) { - initFrameCollection(); + buildEmptyFrameCollection(); + + addNoteStyleFrames(fetchNoteStyle('funkin')); + addNoteStyleFrames(fetchNoteStyle('pixel')); } if (noteFrameCollection == null) throw 'ERROR: Could not initialize note sprite animations.'; this.frames = noteFrameCollection; - // Initialize all the animations, not just the one we're going to use immediately, - // so that later we can reuse the sprite without having to initialize more animations during scrolling. - this.animation.addByPrefix('tapLeftFunkin', 'purple instance'); - this.animation.addByPrefix('tapDownFunkin', 'blue instance'); - this.animation.addByPrefix('tapUpFunkin', 'green instance'); - this.animation.addByPrefix('tapRightFunkin', 'red instance'); - - this.animation.addByPrefix('holdLeftFunkin', 'LeftHoldPiece'); - this.animation.addByPrefix('holdDownFunkin', 'DownHoldPiece'); - this.animation.addByPrefix('holdUpFunkin', 'UpHoldPiece'); - this.animation.addByPrefix('holdRightFunkin', 'RightHoldPiece'); - - this.animation.addByPrefix('holdEndLeftFunkin', 'LeftHoldEnd'); - this.animation.addByPrefix('holdEndDownFunkin', 'DownHoldEnd'); - this.animation.addByPrefix('holdEndUpFunkin', 'UpHoldEnd'); - this.animation.addByPrefix('holdEndRightFunkin', 'RightHoldEnd'); - - this.animation.addByPrefix('tapLeftPixel', 'pixel4'); - this.animation.addByPrefix('tapDownPixel', 'pixel5'); - this.animation.addByPrefix('tapUpPixel', 'pixel6'); - this.animation.addByPrefix('tapRightPixel', 'pixel7'); + addNoteStyleAnimations(fetchNoteStyle('funkin')); + addNoteStyleAnimations(fetchNoteStyle('pixel')); } static var noteFrameCollection:Null<FlxFramesCollection> = null; - /** - * We load all the note frames once, then reuse them. - */ - static function initFrameCollection():Void + function fetchNoteStyle(noteStyleId:String):NoteStyle { - buildEmptyFrameCollection(); - if (noteFrameCollection == null) return; + return NoteStyleRegistry.instance.fetchEntry(noteStyleId) ?? NoteStyleRegistry.instance.fetchDefault(); + } - // TODO: Automatically iterate over the list of note skins. + @:access(funkin.play.notes.notestyle.NoteStyle) + @:nullSafety(Off) + static function addNoteStyleFrames(noteStyle:NoteStyle):Void + { + var prefix:String = noteStyle.id.toTitleCase(); - // Normal notes - var frameCollectionNormal:FlxAtlasFrames = Paths.getSparrowAtlas('NOTE_assets'); - - for (frame in frameCollectionNormal.frames) + var frameCollection:FlxAtlasFrames = Paths.getSparrowAtlas(noteStyle.getNoteAssetPath(), noteStyle.getNoteAssetLibrary()); + for (frame in frameCollection.frames) { - noteFrameCollection.pushFrame(frame); + // cloning the frame because else + // we will fuck up the frame data used in game + var clonedFrame:FlxFrame = frame.copyTo(); + clonedFrame.name = '$prefix${clonedFrame.name}'; + noteFrameCollection.pushFrame(clonedFrame); } + } - // Pixel notes - var graphicPixel = FlxG.bitmap.add(Paths.image('weeb/pixelUI/arrows-pixels', 'week6'), false, null); - if (graphicPixel == null) trace('ERROR: Could not load graphic: ' + Paths.image('weeb/pixelUI/arrows-pixels', 'week6')); - var frameCollectionPixel = FlxTileFrames.fromGraphic(graphicPixel, new FlxPoint(17, 17)); - for (i in 0...frameCollectionPixel.frames.length) - { - var frame:Null<FlxFrame> = frameCollectionPixel.frames[i]; - if (frame == null) continue; + @:access(funkin.play.notes.notestyle.NoteStyle) + @:nullSafety(Off) + function addNoteStyleAnimations(noteStyle:NoteStyle):Void + { + var prefix:String = noteStyle.id.toTitleCase(); + var suffix:String = noteStyle.id.toTitleCase(); - frame.name = 'pixel' + i; - noteFrameCollection.pushFrame(frame); - } + var leftData:AnimationData = noteStyle.fetchNoteAnimationData(NoteDirection.LEFT); + this.animation.addByPrefix('tapLeft$suffix', '$prefix${leftData.prefix}', leftData.frameRate, leftData.looped, leftData.flipX, leftData.flipY); + + var downData:AnimationData = noteStyle.fetchNoteAnimationData(NoteDirection.DOWN); + this.animation.addByPrefix('tapDown$suffix', '$prefix${downData.prefix}', downData.frameRate, downData.looped, downData.flipX, downData.flipY); + + var upData:AnimationData = noteStyle.fetchNoteAnimationData(NoteDirection.UP); + this.animation.addByPrefix('tapUp$suffix', '$prefix${upData.prefix}', upData.frameRate, upData.looped, upData.flipX, upData.flipY); + + var rightData:AnimationData = noteStyle.fetchNoteAnimationData(NoteDirection.RIGHT); + this.animation.addByPrefix('tapRight$suffix', '$prefix${rightData.prefix}', rightData.frameRate, rightData.looped, rightData.flipX, rightData.flipY); } @:nullSafety(Off) @@ -187,10 +185,20 @@ class ChartEditorNoteSprite extends FlxSprite function get_noteStyle():String { - // Fall back to Funkin' if it's not a valid note style. - return if (NOTE_STYLES.contains(this.parentState.currentSongNoteStyle)) this.parentState.currentSongNoteStyle else 'funkin'; + if (this.parentState.currentCustomNoteKindStyle != null) + { + return this.parentState.currentCustomNoteKindStyle; + } + + if (NOTE_STYLES.contains(this.parentState.currentSongNoteStyle)) + { + return this.parentState.currentSongNoteStyle; + } + + return 'funkin'; } + @:nullSafety(Off) public function playNoteAnimation():Void { if (this.noteData == null) return; @@ -213,8 +221,8 @@ class ChartEditorNoteSprite extends FlxSprite } this.updateHitbox(); - // TODO: Make this an attribute of the note skin. - this.antialiasing = (this.parentState.currentSongNoteStyle != 'Pixel'); + var bruhStyle:NoteStyle = fetchNoteStyle(this.noteStyle); + this.antialiasing = !bruhStyle._data?.assets?.note?.isPixel ?? true; } /** diff --git a/source/funkin/ui/debug/charting/toolboxes/ChartEditorNoteDataToolbox.hx b/source/funkin/ui/debug/charting/toolboxes/ChartEditorNoteDataToolbox.hx index d4fc69fc1..952513f0e 100644 --- a/source/funkin/ui/debug/charting/toolboxes/ChartEditorNoteDataToolbox.hx +++ b/source/funkin/ui/debug/charting/toolboxes/ChartEditorNoteDataToolbox.hx @@ -4,6 +4,8 @@ import haxe.ui.components.DropDown; import haxe.ui.components.TextField; import haxe.ui.events.UIEvent; import funkin.ui.debug.charting.util.ChartEditorDropdowns; +import funkin.play.notes.notestyle.NoteStyle; +import funkin.play.notes.notekind.NoteKindManager; /** * The toolbox which allows modifying information like Note Kind. @@ -73,6 +75,9 @@ class ChartEditorNoteDataToolbox extends ChartEditorBaseToolbox var customKind:Null<String> = event?.target?.text; chartEditorState.noteKindToPlace = customKind; + var noteStyle:Null<NoteStyle> = NoteKindManager.getNoteStyle(customKind); + chartEditorState.currentCustomNoteKindStyle = noteStyle?.id; + if (chartEditorState.currentEventSelection.length > 0) { // Edit the note data of any selected notes. From 9d7846a0d551a005897f1ea0ca099d19f4ac359f Mon Sep 17 00:00:00 2001 From: lemz <ismael.amjad07@gmail.com> Date: Sun, 2 Jun 2024 02:58:56 +0200 Subject: [PATCH 29/64] loop through all note style entries --- .../charting/components/ChartEditorNoteSprite.hx | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/source/funkin/ui/debug/charting/components/ChartEditorNoteSprite.hx b/source/funkin/ui/debug/charting/components/ChartEditorNoteSprite.hx index c97aee1f8..6517b61c2 100644 --- a/source/funkin/ui/debug/charting/components/ChartEditorNoteSprite.hx +++ b/source/funkin/ui/debug/charting/components/ChartEditorNoteSprite.hx @@ -70,20 +70,26 @@ class ChartEditorNoteSprite extends FlxSprite this.parentState = parent; + var entries:Array<String> = NoteStyleRegistry.instance.listEntryIds(); + if (noteFrameCollection == null) { buildEmptyFrameCollection(); - addNoteStyleFrames(fetchNoteStyle('funkin')); - addNoteStyleFrames(fetchNoteStyle('pixel')); + for (entry in entries) + { + addNoteStyleFrames(fetchNoteStyle(entry)); + } } if (noteFrameCollection == null) throw 'ERROR: Could not initialize note sprite animations.'; this.frames = noteFrameCollection; - addNoteStyleAnimations(fetchNoteStyle('funkin')); - addNoteStyleAnimations(fetchNoteStyle('pixel')); + for (entry in entries) + { + addNoteStyleAnimations(fetchNoteStyle(entry)); + } } static var noteFrameCollection:Null<FlxFramesCollection> = null; From ca2cbb44f520361b73c60378e0beaf0459e308c2 Mon Sep 17 00:00:00 2001 From: lemz <ismael.amjad07@gmail.com> Date: Sun, 2 Jun 2024 22:11:17 +0200 Subject: [PATCH 30/64] display custom note style in chart editor --- .../play/notes/notekind/NoteKindManager.hx | 10 ++++++ .../ui/debug/charting/ChartEditorState.hx | 10 ++++-- .../components/ChartEditorHoldNoteSprite.hx | 34 +++++++++++++++++++ .../components/ChartEditorNoteSprite.hx | 22 ++++++------ .../toolboxes/ChartEditorNoteDataToolbox.hx | 3 -- 5 files changed, 61 insertions(+), 18 deletions(-) diff --git a/source/funkin/play/notes/notekind/NoteKindManager.hx b/source/funkin/play/notes/notekind/NoteKindManager.hx index 849034fc4..82b2c4d39 100644 --- a/source/funkin/play/notes/notekind/NoteKindManager.hx +++ b/source/funkin/play/notes/notekind/NoteKindManager.hx @@ -73,4 +73,14 @@ class NoteKindManager return NoteStyleRegistry.instance.fetchEntry(noteStyleId); } + + /** + * Retrieve the note style id from the given note kind + * @param noteKind note kind name + * @return Null<String> + */ + public static function getNoteStyleId(noteKind:String):Null<String> + { + return noteKinds.get(noteKind)?.noteStyleId; + } } diff --git a/source/funkin/ui/debug/charting/ChartEditorState.hx b/source/funkin/ui/debug/charting/ChartEditorState.hx index 0117d8a51..bc0acc6d6 100644 --- a/source/funkin/ui/debug/charting/ChartEditorState.hx +++ b/source/funkin/ui/debug/charting/ChartEditorState.hx @@ -45,6 +45,7 @@ import funkin.input.TurboActionHandler; import funkin.input.TurboButtonHandler; import funkin.input.TurboKeyHandler; import funkin.modding.events.ScriptEvent; +import funkin.play.notes.notekind.NoteKindManager; import funkin.play.character.BaseCharacter.CharacterType; import funkin.play.character.CharacterData; import funkin.play.character.CharacterData.CharacterDataParser; @@ -1663,8 +1664,6 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState return currentSongMetadata.playData.characters.instrumental = value; } - var currentCustomNoteKindStyle:Null<String>; - /** * HAXEUI COMPONENTS */ @@ -3586,6 +3585,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState // The note sprite handles animation playback and positioning. noteSprite.noteData = noteData; + noteSprite.noteStyle = NoteKindManager.getNoteStyleId(noteData.kind) ?? currentSongNoteStyle; noteSprite.overrideStepTime = null; noteSprite.overrideData = null; @@ -3606,6 +3606,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState holdNoteSprite.noteData = noteSprite.noteData; holdNoteSprite.noteDirection = noteSprite.noteData.getDirection(); + holdNoteSprite.noteStyle = NoteKindManager.getNoteStyleId(noteSprite.noteData.kind) ?? currentSongNoteStyle; holdNoteSprite.setHeightDirectly(noteLengthPixels); @@ -3671,7 +3672,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState holdNoteSprite.noteData = noteData; holdNoteSprite.noteDirection = noteData.getDirection(); - + holdNoteSprite.noteStyle = NoteKindManager.getNoteStyleId(noteData.kind) ?? currentSongNoteStyle; holdNoteSprite.setHeightDirectly(noteLengthPixels); holdNoteSprite.updateHoldNotePosition(renderedHoldNotes); @@ -4570,6 +4571,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState gridGhostHoldNote.visible = true; gridGhostHoldNote.noteData = currentPlaceNoteData; gridGhostHoldNote.noteDirection = currentPlaceNoteData.getDirection(); + gridGhostHoldNote.noteStyle = NoteKindManager.getNoteStyleId(currentPlaceNoteData.kind) ?? currentSongNoteStyle; gridGhostHoldNote.setHeightDirectly(dragLengthPixels, true); gridGhostHoldNote.updateHoldNotePosition(renderedHoldNotes); @@ -4893,6 +4895,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState { noteData.kind = noteKindToPlace; noteData.data = cursorColumn; + gridGhostNote.noteStyle = NoteKindManager.getNoteStyleId(noteData.kind) ?? currentSongNoteStyle; gridGhostNote.playNoteAnimation(); } noteData.time = cursorSnappedMs; @@ -5281,6 +5284,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState // Readd the new ghost hold note. ghostHold.noteData = targetNoteData.clone(); ghostHold.noteDirection = ghostHold.noteData.getDirection(); + ghostHold.noteStyle = NoteKindManager.getNoteStyleId(ghostHold.noteData.kind) ?? currentSongNoteStyle; ghostHold.visible = true; ghostHold.alpha = 0.6; ghostHold.setHeightDirectly(0); diff --git a/source/funkin/ui/debug/charting/components/ChartEditorHoldNoteSprite.hx b/source/funkin/ui/debug/charting/components/ChartEditorHoldNoteSprite.hx index ded48abe3..ccf462c56 100644 --- a/source/funkin/ui/debug/charting/components/ChartEditorHoldNoteSprite.hx +++ b/source/funkin/ui/debug/charting/components/ChartEditorHoldNoteSprite.hx @@ -2,6 +2,7 @@ package funkin.ui.debug.charting.components; import funkin.play.notes.Strumline; import funkin.data.notestyle.NoteStyleRegistry; +import funkin.play.notes.notestyle.NoteStyle; import flixel.FlxObject; import flixel.FlxSprite; import flixel.graphics.frames.FlxFramesCollection; @@ -15,6 +16,7 @@ import flixel.math.FlxMath; * A sprite that can be used to display the trail of a hold note in a chart. * Designed to be used and reused efficiently. Has no gameplay functionality. */ +@:access(funkin.ui.debug.charting.ChartEditorState) @:nullSafety class ChartEditorHoldNoteSprite extends SustainTrail { @@ -23,6 +25,22 @@ class ChartEditorHoldNoteSprite extends SustainTrail */ public var parentState:ChartEditorState; + @:isVar + public var noteStyle(get, set):Null<String>; + + function get_noteStyle():Null<String> + { + return this.noteStyle ?? this.parentState.currentSongNoteStyle; + } + + @:nullSafety(Off) + function set_noteStyle(value:Null<String>):Null<String> + { + this.noteStyle = value; + this.updateHoldNoteGraphic(); + return value; + } + public function new(parent:ChartEditorState) { var noteStyle = NoteStyleRegistry.instance.fetchDefault(); @@ -41,6 +59,22 @@ class ChartEditorHoldNoteSprite extends SustainTrail setup(); } + @:nullSafety(Off) + function updateHoldNoteGraphic():Void + { + var bruhStyle:NoteStyle = NoteStyleRegistry.instance.fetchEntry(noteStyle); + this.setupHoldNoteGraphic(bruhStyle); + + zoom = 1.0; + zoom *= bruhStyle.fetchHoldNoteScale(); + zoom *= 0.7; + zoom *= ChartEditorState.GRID_SIZE / Strumline.STRUMLINE_SIZE; + + flipY = false; + + setup(); + } + public override function updateHitbox():Void { // Expand the clickable hitbox to the full column width, then nudge to the left to re-center it. diff --git a/source/funkin/ui/debug/charting/components/ChartEditorNoteSprite.hx b/source/funkin/ui/debug/charting/components/ChartEditorNoteSprite.hx index 6517b61c2..009532401 100644 --- a/source/funkin/ui/debug/charting/components/ChartEditorNoteSprite.hx +++ b/source/funkin/ui/debug/charting/components/ChartEditorNoteSprite.hx @@ -40,7 +40,8 @@ class ChartEditorNoteSprite extends FlxSprite /** * The name of the note style currently in use. */ - public var noteStyle(get, never):String; + @:isVar + public var noteStyle(get, set):Null<String>; public var overrideStepTime(default, set):Null<Float> = null; @@ -189,19 +190,16 @@ class ChartEditorNoteSprite extends FlxSprite } } - function get_noteStyle():String + function get_noteStyle():Null<String> { - if (this.parentState.currentCustomNoteKindStyle != null) - { - return this.parentState.currentCustomNoteKindStyle; - } + return this.noteStyle ?? this.parentState.currentSongNoteStyle; + } - if (NOTE_STYLES.contains(this.parentState.currentSongNoteStyle)) - { - return this.parentState.currentSongNoteStyle; - } - - return 'funkin'; + function set_noteStyle(value:Null<String>):Null<String> + { + this.noteStyle = value; + this.playNoteAnimation(); + return value; } @:nullSafety(Off) diff --git a/source/funkin/ui/debug/charting/toolboxes/ChartEditorNoteDataToolbox.hx b/source/funkin/ui/debug/charting/toolboxes/ChartEditorNoteDataToolbox.hx index 952513f0e..f1223eb9c 100644 --- a/source/funkin/ui/debug/charting/toolboxes/ChartEditorNoteDataToolbox.hx +++ b/source/funkin/ui/debug/charting/toolboxes/ChartEditorNoteDataToolbox.hx @@ -75,9 +75,6 @@ class ChartEditorNoteDataToolbox extends ChartEditorBaseToolbox var customKind:Null<String> = event?.target?.text; chartEditorState.noteKindToPlace = customKind; - var noteStyle:Null<NoteStyle> = NoteKindManager.getNoteStyle(customKind); - chartEditorState.currentCustomNoteKindStyle = noteStyle?.id; - if (chartEditorState.currentEventSelection.length > 0) { // Edit the note data of any selected notes. From 040fc85a6263408646e6cac60c1a25da2c99fcaf Mon Sep 17 00:00:00 2001 From: lemz <ismael.amjad07@gmail.com> Date: Sun, 2 Jun 2024 23:31:49 +0200 Subject: [PATCH 31/64] change note style on change --- .../components/ChartEditorHoldNoteSprite.hx | 2 +- .../toolboxes/ChartEditorNoteDataToolbox.hx | 26 +++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/source/funkin/ui/debug/charting/components/ChartEditorHoldNoteSprite.hx b/source/funkin/ui/debug/charting/components/ChartEditorHoldNoteSprite.hx index ccf462c56..26322c6f9 100644 --- a/source/funkin/ui/debug/charting/components/ChartEditorHoldNoteSprite.hx +++ b/source/funkin/ui/debug/charting/components/ChartEditorHoldNoteSprite.hx @@ -63,7 +63,7 @@ class ChartEditorHoldNoteSprite extends SustainTrail function updateHoldNoteGraphic():Void { var bruhStyle:NoteStyle = NoteStyleRegistry.instance.fetchEntry(noteStyle); - this.setupHoldNoteGraphic(bruhStyle); + setupHoldNoteGraphic(bruhStyle); zoom = 1.0; zoom *= bruhStyle.fetchHoldNoteScale(); diff --git a/source/funkin/ui/debug/charting/toolboxes/ChartEditorNoteDataToolbox.hx b/source/funkin/ui/debug/charting/toolboxes/ChartEditorNoteDataToolbox.hx index f1223eb9c..d872eda38 100644 --- a/source/funkin/ui/debug/charting/toolboxes/ChartEditorNoteDataToolbox.hx +++ b/source/funkin/ui/debug/charting/toolboxes/ChartEditorNoteDataToolbox.hx @@ -4,6 +4,8 @@ import haxe.ui.components.DropDown; import haxe.ui.components.TextField; import haxe.ui.events.UIEvent; import funkin.ui.debug.charting.util.ChartEditorDropdowns; +import funkin.ui.debug.charting.components.ChartEditorNoteSprite; +import funkin.ui.debug.charting.components.ChartEditorHoldNoteSprite; import funkin.play.notes.notestyle.NoteStyle; import funkin.play.notes.notekind.NoteKindManager; @@ -59,8 +61,32 @@ class ChartEditorNoteDataToolbox extends ChartEditorBaseToolbox if (!_initializing && chartEditorState.currentNoteSelection.length > 0) { // Edit the note data of any selected notes. + var noteSprites:Array<ChartEditorNoteSprite> = chartEditorState.renderedNotes.members.copy(); + var holdNoteSprites:Array<ChartEditorHoldNoteSprite> = chartEditorState.renderedHoldNotes.members.copy(); for (note in chartEditorState.currentNoteSelection) { + // update note sprites + for (noteSprite in noteSprites) + { + if (noteSprite.noteData == note) + { + noteSprite.noteStyle = NoteKindManager.getNoteStyleId(chartEditorState.noteKindToPlace) ?? chartEditorState.currentSongNoteStyle; + noteSprites.remove(noteSprite); + break; + } + } + + // update hold note sprites + for (holdNoteSprite in holdNoteSprites) + { + if (holdNoteSprite.noteData == note) + { + holdNoteSprite.noteStyle = NoteKindManager.getNoteStyleId(chartEditorState.noteKindToPlace) ?? chartEditorState.currentSongNoteStyle; + holdNoteSprites.remove(holdNoteSprite); + break; + } + } + note.kind = chartEditorState.noteKindToPlace; } chartEditorState.saveDataDirty = true; From bb975491712445a272f5e8817e34dacbd62a0d03 Mon Sep 17 00:00:00 2001 From: lemz <ismael.amjad07@gmail.com> Date: Mon, 3 Jun 2024 00:03:47 +0200 Subject: [PATCH 32/64] fixed a bit --- .../ui/debug/charting/ChartEditorState.hx | 11 ++++++----- .../components/ChartEditorHoldNoteSprite.hx | 2 ++ .../toolboxes/ChartEditorNoteDataToolbox.hx | 18 +++++++----------- 3 files changed, 15 insertions(+), 16 deletions(-) diff --git a/source/funkin/ui/debug/charting/ChartEditorState.hx b/source/funkin/ui/debug/charting/ChartEditorState.hx index bc0acc6d6..c867ddfd2 100644 --- a/source/funkin/ui/debug/charting/ChartEditorState.hx +++ b/source/funkin/ui/debug/charting/ChartEditorState.hx @@ -3606,10 +3606,11 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState holdNoteSprite.noteData = noteSprite.noteData; holdNoteSprite.noteDirection = noteSprite.noteData.getDirection(); - holdNoteSprite.noteStyle = NoteKindManager.getNoteStyleId(noteSprite.noteData.kind) ?? currentSongNoteStyle; holdNoteSprite.setHeightDirectly(noteLengthPixels); + holdNoteSprite.noteStyle = NoteKindManager.getNoteStyleId(noteSprite.noteData.kind) ?? currentSongNoteStyle; + holdNoteSprite.updateHoldNotePosition(renderedHoldNotes); trace(holdNoteSprite.x + ', ' + holdNoteSprite.y + ', ' + holdNoteSprite.width + ', ' + holdNoteSprite.height); @@ -3672,9 +3673,10 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState holdNoteSprite.noteData = noteData; holdNoteSprite.noteDirection = noteData.getDirection(); - holdNoteSprite.noteStyle = NoteKindManager.getNoteStyleId(noteData.kind) ?? currentSongNoteStyle; holdNoteSprite.setHeightDirectly(noteLengthPixels); + holdNoteSprite.noteStyle = NoteKindManager.getNoteStyleId(noteData.kind) ?? currentSongNoteStyle; + holdNoteSprite.updateHoldNotePosition(renderedHoldNotes); displayedHoldNoteData.push(noteData); @@ -4571,9 +4573,8 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState gridGhostHoldNote.visible = true; gridGhostHoldNote.noteData = currentPlaceNoteData; gridGhostHoldNote.noteDirection = currentPlaceNoteData.getDirection(); - gridGhostHoldNote.noteStyle = NoteKindManager.getNoteStyleId(currentPlaceNoteData.kind) ?? currentSongNoteStyle; gridGhostHoldNote.setHeightDirectly(dragLengthPixels, true); - + gridGhostHoldNote.noteStyle = NoteKindManager.getNoteStyleId(currentPlaceNoteData.kind) ?? currentSongNoteStyle; gridGhostHoldNote.updateHoldNotePosition(renderedHoldNotes); } else @@ -5284,10 +5285,10 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState // Readd the new ghost hold note. ghostHold.noteData = targetNoteData.clone(); ghostHold.noteDirection = ghostHold.noteData.getDirection(); - ghostHold.noteStyle = NoteKindManager.getNoteStyleId(ghostHold.noteData.kind) ?? currentSongNoteStyle; ghostHold.visible = true; ghostHold.alpha = 0.6; ghostHold.setHeightDirectly(0); + ghostHold.noteStyle = NoteKindManager.getNoteStyleId(ghostHold.noteData.kind) ?? currentSongNoteStyle; ghostHold.updateHoldNotePosition(renderedHoldNotes); } diff --git a/source/funkin/ui/debug/charting/components/ChartEditorHoldNoteSprite.hx b/source/funkin/ui/debug/charting/components/ChartEditorHoldNoteSprite.hx index 26322c6f9..e8ca991b6 100644 --- a/source/funkin/ui/debug/charting/components/ChartEditorHoldNoteSprite.hx +++ b/source/funkin/ui/debug/charting/components/ChartEditorHoldNoteSprite.hx @@ -73,6 +73,8 @@ class ChartEditorHoldNoteSprite extends SustainTrail flipY = false; setup(); + + triggerRedraw(); } public override function updateHitbox():Void diff --git a/source/funkin/ui/debug/charting/toolboxes/ChartEditorNoteDataToolbox.hx b/source/funkin/ui/debug/charting/toolboxes/ChartEditorNoteDataToolbox.hx index d872eda38..531bce255 100644 --- a/source/funkin/ui/debug/charting/toolboxes/ChartEditorNoteDataToolbox.hx +++ b/source/funkin/ui/debug/charting/toolboxes/ChartEditorNoteDataToolbox.hx @@ -60,34 +60,30 @@ class ChartEditorNoteDataToolbox extends ChartEditorBaseToolbox if (!_initializing && chartEditorState.currentNoteSelection.length > 0) { - // Edit the note data of any selected notes. - var noteSprites:Array<ChartEditorNoteSprite> = chartEditorState.renderedNotes.members.copy(); - var holdNoteSprites:Array<ChartEditorHoldNoteSprite> = chartEditorState.renderedHoldNotes.members.copy(); for (note in chartEditorState.currentNoteSelection) { + // Edit the note data of any selected notes. + note.kind = chartEditorState.noteKindToPlace; + // update note sprites - for (noteSprite in noteSprites) + for (noteSprite in chartEditorState.renderedNotes.members) { if (noteSprite.noteData == note) { - noteSprite.noteStyle = NoteKindManager.getNoteStyleId(chartEditorState.noteKindToPlace) ?? chartEditorState.currentSongNoteStyle; - noteSprites.remove(noteSprite); + noteSprite.noteStyle = NoteKindManager.getNoteStyleId(note.kind) ?? chartEditorState.currentSongNoteStyle; break; } } // update hold note sprites - for (holdNoteSprite in holdNoteSprites) + for (holdNoteSprite in chartEditorState.renderedHoldNotes.members) { if (holdNoteSprite.noteData == note) { - holdNoteSprite.noteStyle = NoteKindManager.getNoteStyleId(chartEditorState.noteKindToPlace) ?? chartEditorState.currentSongNoteStyle; - holdNoteSprites.remove(holdNoteSprite); + holdNoteSprite.noteStyle = NoteKindManager.getNoteStyleId(note.kind) ?? chartEditorState.currentSongNoteStyle; break; } } - - note.kind = chartEditorState.noteKindToPlace; } chartEditorState.saveDataDirty = true; chartEditorState.noteDisplayDirty = true; From 49d302be956edb19d470ccfdee3792d3fcdae324 Mon Sep 17 00:00:00 2001 From: lemz <ismael.amjad07@gmail.com> Date: Wed, 5 Jun 2024 19:47:34 +0200 Subject: [PATCH 33/64] make code a bit simpler --- .../components/ChartEditorHoldNoteSprite.hx | 36 ++++++++++++------- 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/source/funkin/ui/debug/charting/components/ChartEditorHoldNoteSprite.hx b/source/funkin/ui/debug/charting/components/ChartEditorHoldNoteSprite.hx index e8ca991b6..e474ee93d 100644 --- a/source/funkin/ui/debug/charting/components/ChartEditorHoldNoteSprite.hx +++ b/source/funkin/ui/debug/charting/components/ChartEditorHoldNoteSprite.hx @@ -48,15 +48,6 @@ class ChartEditorHoldNoteSprite extends SustainTrail super(0, 100, noteStyle); this.parentState = parent; - - zoom = 1.0; - zoom *= noteStyle.fetchHoldNoteScale(); - zoom *= 0.7; - zoom *= ChartEditorState.GRID_SIZE / Strumline.STRUMLINE_SIZE; - - flipY = false; - - setup(); } @:nullSafety(Off) @@ -64,17 +55,38 @@ class ChartEditorHoldNoteSprite extends SustainTrail { var bruhStyle:NoteStyle = NoteStyleRegistry.instance.fetchEntry(noteStyle); setupHoldNoteGraphic(bruhStyle); + } + + override function setupHoldNoteGraphic(noteStyle:NoteStyle):Void + { + loadGraphic(noteStyle.getHoldNoteAssetPath()); + + antialiasing = true; + + this.isPixel = noteStyle.isHoldNotePixel(); + if (isPixel) + { + endOffset = bottomClip = 1; + antialiasing = false; + } zoom = 1.0; - zoom *= bruhStyle.fetchHoldNoteScale(); + zoom *= noteStyle.fetchHoldNoteScale(); zoom *= 0.7; zoom *= ChartEditorState.GRID_SIZE / Strumline.STRUMLINE_SIZE; + graphicWidth = graphic.width / 8 * zoom; // amount of notes * 2 + graphicHeight = sustainLength * 0.45; // sustainHeight + flipY = false; - setup(); + alpha = 1.0; - triggerRedraw(); + updateColorTransform(); + + updateClipping(); + + setup(); } public override function updateHitbox():Void From c4855c0ca8e6e77d62b32b705c40ab0a0e106c11 Mon Sep 17 00:00:00 2001 From: lemz <ismael.amjad07@gmail.com> Date: Tue, 11 Jun 2024 20:52:08 +0200 Subject: [PATCH 34/64] fix hold note --- source/funkin/play/notes/SustainTrail.hx | 5 +++++ .../debug/charting/components/ChartEditorHoldNoteSprite.hx | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/source/funkin/play/notes/SustainTrail.hx b/source/funkin/play/notes/SustainTrail.hx index 570c05190..90b36b009 100644 --- a/source/funkin/play/notes/SustainTrail.hx +++ b/source/funkin/play/notes/SustainTrail.hx @@ -129,6 +129,11 @@ class SustainTrail extends FlxSprite endOffset = bottomClip = 1; antialiasing = false; } + else + { + endOffset = 0.5; + bottomClip = 0.9; + } zoom = 1.0; zoom *= noteStyle.fetchHoldNoteScale(); diff --git a/source/funkin/ui/debug/charting/components/ChartEditorHoldNoteSprite.hx b/source/funkin/ui/debug/charting/components/ChartEditorHoldNoteSprite.hx index e474ee93d..b8d6ee22e 100644 --- a/source/funkin/ui/debug/charting/components/ChartEditorHoldNoteSprite.hx +++ b/source/funkin/ui/debug/charting/components/ChartEditorHoldNoteSprite.hx @@ -69,6 +69,11 @@ class ChartEditorHoldNoteSprite extends SustainTrail endOffset = bottomClip = 1; antialiasing = false; } + else + { + endOffset = 0.5; + bottomClip = 0.9; + } zoom = 1.0; zoom *= noteStyle.fetchHoldNoteScale(); From 928de7b8eb8861878b2e78a3502a8ee64b2784d9 Mon Sep 17 00:00:00 2001 From: lemz <ismael.amjad07@gmail.com> Date: Tue, 11 Jun 2024 23:45:08 +0200 Subject: [PATCH 35/64] check for pixel style if necessary --- source/funkin/play/notes/Strumline.hx | 4 ++-- source/funkin/play/notes/notekind/NoteKind.hx | 4 ++-- .../play/notes/notekind/NoteKindManager.hx | 21 +++++++++++++++---- .../ui/debug/charting/ChartEditorState.hx | 17 +++++++++------ 4 files changed, 32 insertions(+), 14 deletions(-) diff --git a/source/funkin/play/notes/Strumline.hx b/source/funkin/play/notes/Strumline.hx index ebc48a8c7..86b7a3ee1 100644 --- a/source/funkin/play/notes/Strumline.hx +++ b/source/funkin/play/notes/Strumline.hx @@ -709,7 +709,7 @@ class Strumline extends FlxSpriteGroup if (noteSprite != null) { - var noteKindStyle:NoteStyle = NoteKindManager.getNoteStyle(note.kind) ?? this.noteStyle; + var noteKindStyle:NoteStyle = NoteKindManager.getNoteStyle(note.kind, this.noteStyle.isHoldNotePixel()) ?? this.noteStyle; noteSprite.setupNoteGraphic(noteKindStyle); noteSprite.direction = note.getDirection(); @@ -731,7 +731,7 @@ class Strumline extends FlxSpriteGroup if (holdNoteSprite != null) { - var noteKindStyle:NoteStyle = NoteKindManager.getNoteStyle(note.kind) ?? this.noteStyle; + var noteKindStyle:NoteStyle = NoteKindManager.getNoteStyle(note.kind, this.noteStyle.isHoldNotePixel()) ?? this.noteStyle; holdNoteSprite.setupHoldNoteGraphic(noteKindStyle); holdNoteSprite.parentStrumline = this; diff --git a/source/funkin/play/notes/notekind/NoteKind.hx b/source/funkin/play/notes/notekind/NoteKind.hx index 53393623a..6d7bad77f 100644 --- a/source/funkin/play/notes/notekind/NoteKind.hx +++ b/source/funkin/play/notes/notekind/NoteKind.hx @@ -21,9 +21,9 @@ class NoteKind implements INoteScriptedClass /** * Custom note style */ - public var noteStyleId:String; + public var noteStyleId:Null<String>; - public function new(noteKind:String, description:String = "", noteStyleId:String = "") + public function new(noteKind:String, description:String = "", ?noteStyleId:String) { this.noteKind = noteKind; this.description = description; diff --git a/source/funkin/play/notes/notekind/NoteKindManager.hx b/source/funkin/play/notes/notekind/NoteKindManager.hx index 82b2c4d39..110e1859b 100644 --- a/source/funkin/play/notes/notekind/NoteKindManager.hx +++ b/source/funkin/play/notes/notekind/NoteKindManager.hx @@ -65,11 +65,17 @@ class NoteKindManager /** * Retrieve the note style from the given note kind * @param noteKind note kind name + * @param isPixel whether to use pixel style * @return NoteStyle */ - public static function getNoteStyle(noteKind:String):Null<NoteStyle> + public static function getNoteStyle(noteKind:String, isPixel:Bool = false):Null<NoteStyle> { - var noteStyleId:String = noteKinds.get(noteKind)?.noteStyleId ?? ""; + var noteStyleId:Null<String> = getNoteStyleId(noteKind, isPixel); + + if (noteStyleId == null) + { + return null; + } return NoteStyleRegistry.instance.fetchEntry(noteStyleId); } @@ -77,10 +83,17 @@ class NoteKindManager /** * Retrieve the note style id from the given note kind * @param noteKind note kind name + * @param isPixel whether to use pixel style * @return Null<String> */ - public static function getNoteStyleId(noteKind:String):Null<String> + public static function getNoteStyleId(noteKind:String, isPixel:Bool = false):Null<String> { - return noteKinds.get(noteKind)?.noteStyleId; + var noteStyleId:Null<String> = noteKinds.get(noteKind)?.noteStyleId; + if (isPixel && noteStyleId != null) + { + noteStyleId = NoteStyleRegistry.instance.hasEntry('$noteStyleId-pixel') ? '$noteStyleId-pixel' : noteStyleId; + } + + return noteStyleId; } } diff --git a/source/funkin/ui/debug/charting/ChartEditorState.hx b/source/funkin/ui/debug/charting/ChartEditorState.hx index c867ddfd2..2a07be52d 100644 --- a/source/funkin/ui/debug/charting/ChartEditorState.hx +++ b/source/funkin/ui/debug/charting/ChartEditorState.hx @@ -3585,7 +3585,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState // The note sprite handles animation playback and positioning. noteSprite.noteData = noteData; - noteSprite.noteStyle = NoteKindManager.getNoteStyleId(noteData.kind) ?? currentSongNoteStyle; + noteSprite.noteStyle = NoteKindManager.getNoteStyleId(noteData.kind, isPixelStyle()) ?? currentSongNoteStyle; noteSprite.overrideStepTime = null; noteSprite.overrideData = null; @@ -3609,7 +3609,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState holdNoteSprite.setHeightDirectly(noteLengthPixels); - holdNoteSprite.noteStyle = NoteKindManager.getNoteStyleId(noteSprite.noteData.kind) ?? currentSongNoteStyle; + holdNoteSprite.noteStyle = NoteKindManager.getNoteStyleId(noteSprite.noteData.kind, isPixelStyle()) ?? currentSongNoteStyle; holdNoteSprite.updateHoldNotePosition(renderedHoldNotes); @@ -3675,7 +3675,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState holdNoteSprite.noteDirection = noteData.getDirection(); holdNoteSprite.setHeightDirectly(noteLengthPixels); - holdNoteSprite.noteStyle = NoteKindManager.getNoteStyleId(noteData.kind) ?? currentSongNoteStyle; + holdNoteSprite.noteStyle = NoteKindManager.getNoteStyleId(noteData.kind, isPixelStyle()) ?? currentSongNoteStyle; holdNoteSprite.updateHoldNotePosition(renderedHoldNotes); @@ -4574,7 +4574,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState gridGhostHoldNote.noteData = currentPlaceNoteData; gridGhostHoldNote.noteDirection = currentPlaceNoteData.getDirection(); gridGhostHoldNote.setHeightDirectly(dragLengthPixels, true); - gridGhostHoldNote.noteStyle = NoteKindManager.getNoteStyleId(currentPlaceNoteData.kind) ?? currentSongNoteStyle; + gridGhostHoldNote.noteStyle = NoteKindManager.getNoteStyleId(currentPlaceNoteData.kind, isPixelStyle()) ?? currentSongNoteStyle; gridGhostHoldNote.updateHoldNotePosition(renderedHoldNotes); } else @@ -4896,7 +4896,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState { noteData.kind = noteKindToPlace; noteData.data = cursorColumn; - gridGhostNote.noteStyle = NoteKindManager.getNoteStyleId(noteData.kind) ?? currentSongNoteStyle; + gridGhostNote.noteStyle = NoteKindManager.getNoteStyleId(noteData.kind, isPixelStyle()) ?? currentSongNoteStyle; gridGhostNote.playNoteAnimation(); } noteData.time = cursorSnappedMs; @@ -5288,7 +5288,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState ghostHold.visible = true; ghostHold.alpha = 0.6; ghostHold.setHeightDirectly(0); - ghostHold.noteStyle = NoteKindManager.getNoteStyleId(ghostHold.noteData.kind) ?? currentSongNoteStyle; + ghostHold.noteStyle = NoteKindManager.getNoteStyleId(ghostHold.noteData.kind, isPixelStyle()) ?? currentSongNoteStyle; ghostHold.updateHoldNotePosition(renderedHoldNotes); } @@ -6413,6 +6413,11 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState return note != null && currentNoteSelection.indexOf(note) != -1; } + function isPixelStyle():Bool + { + return currentSongNoteStyle == 'pixel'; + } + override function destroy():Void { super.destroy(); From 7a0c7ade357a7e6151295b182650dd807e52390f Mon Sep 17 00:00:00 2001 From: lemz <ismael.amjad07@gmail.com> Date: Tue, 11 Jun 2024 23:48:05 +0200 Subject: [PATCH 36/64] Update ChartEditorDropdowns.hx --- source/funkin/ui/debug/charting/util/ChartEditorDropdowns.hx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/source/funkin/ui/debug/charting/util/ChartEditorDropdowns.hx b/source/funkin/ui/debug/charting/util/ChartEditorDropdowns.hx index f20b75650..65ec2a0c3 100644 --- a/source/funkin/ui/debug/charting/util/ChartEditorDropdowns.hx +++ b/source/funkin/ui/debug/charting/util/ChartEditorDropdowns.hx @@ -126,7 +126,10 @@ class ChartEditorDropdowns { dropDown.dataSource.clear(); - var noteStyleIds:Array<String> = NoteStyleRegistry.instance.listEntryIds(); + // hardcoding this because i dont want note kind styles to be shown as well + // there is probably a better solution + // var noteStyleIds:Array<String> = NoteStyleRegistry.instance.listEntryIds(); + var noteStyleIds:Array<String> = ['funkin', 'pixel']; var returnValue:DropDownEntry = {id: "funkin", text: "Funkin'"}; From fbcc73dceebdcfcba2b14922c6b7c38adae0b086 Mon Sep 17 00:00:00 2001 From: lemz <ismael.amjad07@gmail.com> Date: Mon, 17 Jun 2024 17:21:52 +0200 Subject: [PATCH 37/64] unhardcode notestyledropdown --- .../ui/debug/charting/util/ChartEditorDropdowns.hx | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/source/funkin/ui/debug/charting/util/ChartEditorDropdowns.hx b/source/funkin/ui/debug/charting/util/ChartEditorDropdowns.hx index 65ec2a0c3..6a426c391 100644 --- a/source/funkin/ui/debug/charting/util/ChartEditorDropdowns.hx +++ b/source/funkin/ui/debug/charting/util/ChartEditorDropdowns.hx @@ -126,10 +126,7 @@ class ChartEditorDropdowns { dropDown.dataSource.clear(); - // hardcoding this because i dont want note kind styles to be shown as well - // there is probably a better solution - // var noteStyleIds:Array<String> = NoteStyleRegistry.instance.listEntryIds(); - var noteStyleIds:Array<String> = ['funkin', 'pixel']; + var noteStyleIds:Array<String> = NoteStyleRegistry.instance.listEntryIds(); var returnValue:DropDownEntry = {id: "funkin", text: "Funkin'"}; @@ -138,6 +135,14 @@ class ChartEditorDropdowns var noteStyle:Null<NoteStyle> = NoteStyleRegistry.instance.fetchEntry(noteStyleId); if (noteStyle == null) continue; + // check if the note style has all necessary assets (strums, notes, holdNotes) + if (noteStyle._data?.assets?.noteStrumline == null + || noteStyle._data?.assets?.note == null + || noteStyle._data?.assets?.holdNote == null) + { + continue; + } + var value = {id: noteStyleId, text: noteStyle.getName()}; if (startingStyleId == noteStyleId) returnValue = value; From acd8912d162d71b3dd11d97e112e64da06815ec9 Mon Sep 17 00:00:00 2001 From: lemz <ismael.amjad07@gmail.com> Date: Fri, 21 Jun 2024 23:54:29 +0200 Subject: [PATCH 38/64] Add Custom Params For NoteKind still need to implement the chart editor stuff --- source/funkin/play/notes/notekind/NoteKind.hx | 70 ++++++++++++++++++- 1 file changed, 69 insertions(+), 1 deletion(-) diff --git a/source/funkin/play/notes/notekind/NoteKind.hx b/source/funkin/play/notes/notekind/NoteKind.hx index 6d7bad77f..6d7ddcd1b 100644 --- a/source/funkin/play/notes/notekind/NoteKind.hx +++ b/source/funkin/play/notes/notekind/NoteKind.hx @@ -23,11 +23,17 @@ class NoteKind implements INoteScriptedClass */ public var noteStyleId:Null<String>; - public function new(noteKind:String, description:String = "", ?noteStyleId:String) + /** + * Custom parameters for the chart editor + */ + public var params:Array<NoteKindParam>; + + public function new(noteKind:String, description:String = "", ?noteStyleId:String, ?params:Array<NoteKindParam>) { this.noteKind = noteKind; this.description = description; this.noteStyleId = noteStyleId; + this.params = params ?? []; } public function toString():String @@ -35,6 +41,25 @@ class NoteKind implements INoteScriptedClass return noteKind; } + /** + * Retrieve the param with the given name + * If there exists no param with the given name then `null` is returned + * @param name Name of the param + * @return Null<NoteKindParam> + */ + public function getParam(name:String):Null<NoteKindParam> + { + for (param in params) + { + if (param.name == name) + { + return param; + } + } + + return null; + } + /** * Retrieve all notes of this kind * @return Array<NoteSprite> @@ -61,3 +86,46 @@ class NoteKind implements INoteScriptedClass public function onNoteMiss(event:NoteScriptEvent):Void {} } + +/** + * Abstract for setting the type of the `NoteKindParam` + * This was supposed to be an enum but polymod kept being annoying + */ +abstract NoteKindParamType(String) +{ + public static var STRING:String = "String"; + + public static var INT:String = "Int"; + + public static var RANGED_INT:String = "RangedInt"; + + public static var FLOAT:String = "Float"; + + public static var RANGED_FLOAT:String = "RangedFloat"; +} + +typedef NoteKindParamData = +{ + /** + * Only used for `RangedInt` and `RangedFloat` + */ + var min:Null<Float>; + + /** + * Only used for `RangedInt` and `RangedFloat` + */ + var max:Null<Float>; + + var value:Dynamic; +} + +/** + * Typedef for creating custom parameters in the chart editor + */ +typedef NoteKindParam = +{ + var name:String; + var description:String; + var type:NoteKindParamType; + var data:NoteKindParamData; +} From c8d019da2fdcc22627dbfb78c587a5374273f6b6 Mon Sep 17 00:00:00 2001 From: lemz <ismael.amjad07@gmail.com> Date: Sat, 22 Jun 2024 00:20:58 +0200 Subject: [PATCH 39/64] Update NoteKind.hx --- source/funkin/play/notes/notekind/NoteKind.hx | 38 ++++++++++++++++--- 1 file changed, 33 insertions(+), 5 deletions(-) diff --git a/source/funkin/play/notes/notekind/NoteKind.hx b/source/funkin/play/notes/notekind/NoteKind.hx index 6d7ddcd1b..3aa02088b 100644 --- a/source/funkin/play/notes/notekind/NoteKind.hx +++ b/source/funkin/play/notes/notekind/NoteKind.hx @@ -2,6 +2,7 @@ package funkin.play.notes.notekind; import funkin.modding.IScriptedClass.INoteScriptedClass; import funkin.modding.events.ScriptEvent; +import flixel.math.FlxMath; /** * Class for note scripts @@ -42,24 +43,49 @@ class NoteKind implements INoteScriptedClass } /** - * Retrieve the param with the given name + * Retrieve the value of the param with the given name * If there exists no param with the given name then `null` is returned * @param name Name of the param - * @return Null<NoteKindParam> + * @return Null<Dynamic> */ - public function getParam(name:String):Null<NoteKindParam> + public function getParam(name:String):Null<Dynamic> { for (param in params) { if (param.name == name) { - return param; + return param.data.value; } } return null; } + /** + * Set the value of the param with the given name + * @param name Name of the param + * @param value New value + */ + public function setParam(name:String, value:Dynamic):Void + { + for (param in params) + { + if (param.name == name) + { + if (param.type == NoteKindParamType.RANGED_INT || param.type == NoteKindParamType.RANGED_FLOAT) + { + param.data.value = FlxMath.bound(value, param.data.min, param.data.max); + } + else + { + param.data.value = value; + } + + break; + } + } + } + /** * Retrieve all notes of this kind * @return Array<NoteSprite> @@ -91,7 +117,7 @@ class NoteKind implements INoteScriptedClass * Abstract for setting the type of the `NoteKindParam` * This was supposed to be an enum but polymod kept being annoying */ -abstract NoteKindParamType(String) +abstract NoteKindParamType(String) to String { public static var STRING:String = "String"; @@ -108,11 +134,13 @@ typedef NoteKindParamData = { /** * Only used for `RangedInt` and `RangedFloat` + * If `min` is null, there is no minimum */ var min:Null<Float>; /** * Only used for `RangedInt` and `RangedFloat` + * If `max` is null, there is no maximum */ var max:Null<Float>; From 94fe4a06b90089fb8187c177c39cb255c90609fb Mon Sep 17 00:00:00 2001 From: lemz <ismael.amjad07@gmail.com> Date: Sat, 22 Jun 2024 10:44:12 +0200 Subject: [PATCH 40/64] Update NoteKind.hx --- source/funkin/play/notes/notekind/NoteKind.hx | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/source/funkin/play/notes/notekind/NoteKind.hx b/source/funkin/play/notes/notekind/NoteKind.hx index 3aa02088b..a0f759949 100644 --- a/source/funkin/play/notes/notekind/NoteKind.hx +++ b/source/funkin/play/notes/notekind/NoteKind.hx @@ -72,13 +72,12 @@ class NoteKind implements INoteScriptedClass { if (param.name == name) { - if (param.type == NoteKindParamType.RANGED_INT || param.type == NoteKindParamType.RANGED_FLOAT) + switch (param.type) { - param.data.value = FlxMath.bound(value, param.data.min, param.data.max); - } - else - { - param.data.value = value; + case NoteKindParamType.INT | NoteKindParamType.FLOAT: + param.data.value = FlxMath.bound(value, param.data.min, param.data.max); + default: + param.data.value = value; } break; @@ -123,23 +122,17 @@ abstract NoteKindParamType(String) to String public static var INT:String = "Int"; - public static var RANGED_INT:String = "RangedInt"; - public static var FLOAT:String = "Float"; - - public static var RANGED_FLOAT:String = "RangedFloat"; } typedef NoteKindParamData = { /** - * Only used for `RangedInt` and `RangedFloat` * If `min` is null, there is no minimum */ var min:Null<Float>; /** - * Only used for `RangedInt` and `RangedFloat` * If `max` is null, there is no maximum */ var max:Null<Float>; From 9a563ec46b56e4daacd70f301c1d107347e6738f Mon Sep 17 00:00:00 2001 From: lemz <ismael.amjad07@gmail.com> Date: Sat, 22 Jun 2024 10:52:26 +0200 Subject: [PATCH 41/64] switch seemingly doesnt work --- source/funkin/play/notes/notekind/NoteKind.hx | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/source/funkin/play/notes/notekind/NoteKind.hx b/source/funkin/play/notes/notekind/NoteKind.hx index a0f759949..f2a44dc8a 100644 --- a/source/funkin/play/notes/notekind/NoteKind.hx +++ b/source/funkin/play/notes/notekind/NoteKind.hx @@ -72,12 +72,13 @@ class NoteKind implements INoteScriptedClass { if (param.name == name) { - switch (param.type) + if (param.type == NoteKindParamType.INT || param.type == NoteKindParamType.FLOAT) { - case NoteKindParamType.INT | NoteKindParamType.FLOAT: - param.data.value = FlxMath.bound(value, param.data.min, param.data.max); - default: - param.data.value = value; + param.data.value = FlxMath.bound(value, param.data.min, param.data.max); + } + else + { + param.data.value = value; } break; @@ -118,11 +119,11 @@ class NoteKind implements INoteScriptedClass */ abstract NoteKindParamType(String) to String { - public static var STRING:String = "String"; + public static final STRING:String = 'String'; - public static var INT:String = "Int"; + public static final INT:String = 'Int'; - public static var FLOAT:String = "Float"; + public static final FLOAT:String = 'Float'; } typedef NoteKindParamData = From d9b9854d9106d20d2ea7ec75468fcc315b281e98 Mon Sep 17 00:00:00 2001 From: lemz <ismael.amjad07@gmail.com> Date: Sat, 22 Jun 2024 14:17:07 +0200 Subject: [PATCH 42/64] add params to toolbox not completely finished --- .../play/notes/notekind/NoteKindManager.hx | 10 +++ .../toolboxes/ChartEditorNoteDataToolbox.hx | 73 ++++++++++++++++++- 2 files changed, 80 insertions(+), 3 deletions(-) diff --git a/source/funkin/play/notes/notekind/NoteKindManager.hx b/source/funkin/play/notes/notekind/NoteKindManager.hx index 110e1859b..3e2174a66 100644 --- a/source/funkin/play/notes/notekind/NoteKindManager.hx +++ b/source/funkin/play/notes/notekind/NoteKindManager.hx @@ -96,4 +96,14 @@ class NoteKindManager return noteStyleId; } + + /** + * Retrive custom params of the given note kind + * @param noteKind Name of the note kind + * @return Array<NoteKind.NoteKindParam> + */ + public static function getParams(noteKind:String):Array<NoteKind.NoteKindParam> + { + return noteKinds.get(noteKind)?.params ?? []; + } } diff --git a/source/funkin/ui/debug/charting/toolboxes/ChartEditorNoteDataToolbox.hx b/source/funkin/ui/debug/charting/toolboxes/ChartEditorNoteDataToolbox.hx index 531bce255..472372a6e 100644 --- a/source/funkin/ui/debug/charting/toolboxes/ChartEditorNoteDataToolbox.hx +++ b/source/funkin/ui/debug/charting/toolboxes/ChartEditorNoteDataToolbox.hx @@ -2,11 +2,12 @@ package funkin.ui.debug.charting.toolboxes; import haxe.ui.components.DropDown; import haxe.ui.components.TextField; +import haxe.ui.components.Label; +import haxe.ui.components.NumberStepper; +import haxe.ui.containers.Grid; +import haxe.ui.core.Component; import haxe.ui.events.UIEvent; import funkin.ui.debug.charting.util.ChartEditorDropdowns; -import funkin.ui.debug.charting.components.ChartEditorNoteSprite; -import funkin.ui.debug.charting.components.ChartEditorHoldNoteSprite; -import funkin.play.notes.notestyle.NoteStyle; import funkin.play.notes.notekind.NoteKindManager; /** @@ -16,8 +17,12 @@ import funkin.play.notes.notekind.NoteKindManager; @:build(haxe.ui.ComponentBuilder.build("assets/exclude/data/ui/chart-editor/toolboxes/note-data.xml")) class ChartEditorNoteDataToolbox extends ChartEditorBaseToolbox { + static final DIALOG_HEIGHT:Int = 100; + + var toolboxNotesGrid:Grid; var toolboxNotesNoteKind:DropDown; var toolboxNotesCustomKind:TextField; + var toolboxNotesParams:Array<ToolboxNoteKindParam> = []; var _initializing:Bool = true; @@ -49,6 +54,7 @@ class ChartEditorNoteDataToolbox extends ChartEditorBaseToolbox if (noteKind == '~CUSTOM~') { showCustom(); + clearNoteKindParams(); toolboxNotesCustomKind.value = chartEditorState.noteKindToPlace; } else @@ -56,6 +62,25 @@ class ChartEditorNoteDataToolbox extends ChartEditorBaseToolbox hideCustom(); chartEditorState.noteKindToPlace = noteKind; toolboxNotesCustomKind.value = chartEditorState.noteKindToPlace; + + clearNoteKindParams(); + for (param in NoteKindManager.getParams(noteKind)) + { + var paramLabel:Label = new Label(); + paramLabel.value = param.description; + paramLabel.verticalAlign = "center"; + paramLabel.horizontalAlign = "right"; + + var paramStepper:NumberStepper = new NumberStepper(); + paramStepper.min = param.data.min; + paramStepper.max = param.data.max; + paramStepper.value = param.data.value; + paramStepper.precision = 1; + paramStepper.step = 0.1; + paramStepper.percentWidth = 100; + + addNoteKindParam(paramLabel, paramStepper); + } } if (!_initializing && chartEditorState.currentNoteSelection.length > 0) @@ -110,6 +135,9 @@ class ChartEditorNoteDataToolbox extends ChartEditorBaseToolbox } }; toolboxNotesCustomKind.value = chartEditorState.noteKindToPlace; + + // just to be safe + clearNoteKindParams(); } public override function refresh():Void @@ -132,8 +160,47 @@ class ChartEditorNoteDataToolbox extends ChartEditorBaseToolbox toolboxNotesCustomKind.hidden = true; } + function addNoteKindParam(label:Label, component:Component):Void + { + toolboxNotesParams.push({label: label, component: component}); + toolboxNotesGrid.addComponent(label); + toolboxNotesGrid.addComponent(component); + + this.height = Math.max(DIALOG_HEIGHT, DIALOG_HEIGHT - 30 + toolboxNotesParams.length * 30); + } + + override function update(elapsed:Float):Void + { + super.update(elapsed); + + // toolboxNotesGrid.height + 45 + // this is what i found out is the calculation by printing this.height and grid.height + var heightToSet:Int = Std.int(Math.max(DIALOG_HEIGHT, toolboxNotesGrid.height + 45)); + if (this.height != heightToSet) + { + this.height = heightToSet; + } + } + + function clearNoteKindParams():Void + { + for (param in toolboxNotesParams) + { + toolboxNotesGrid.removeComponent(param.component); + toolboxNotesGrid.removeComponent(param.label); + } + toolboxNotesParams = []; + this.height = DIALOG_HEIGHT; + } + public static function build(chartEditorState:ChartEditorState):ChartEditorNoteDataToolbox { return new ChartEditorNoteDataToolbox(chartEditorState); } } + +typedef ToolboxNoteKindParam = +{ + var label:Label; + var component:Component; +} From 93475ae8aa94ff5d12872dd5ebe4b1e207d3d85e Mon Sep 17 00:00:00 2001 From: lemz <ismael.amjad07@gmail.com> Date: Sat, 22 Jun 2024 14:31:07 +0200 Subject: [PATCH 43/64] minimized check --- .../charting/toolboxes/ChartEditorNoteDataToolbox.hx | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/source/funkin/ui/debug/charting/toolboxes/ChartEditorNoteDataToolbox.hx b/source/funkin/ui/debug/charting/toolboxes/ChartEditorNoteDataToolbox.hx index 472372a6e..c557eef1f 100644 --- a/source/funkin/ui/debug/charting/toolboxes/ChartEditorNoteDataToolbox.hx +++ b/source/funkin/ui/debug/charting/toolboxes/ChartEditorNoteDataToolbox.hx @@ -135,9 +135,6 @@ class ChartEditorNoteDataToolbox extends ChartEditorBaseToolbox } }; toolboxNotesCustomKind.value = chartEditorState.noteKindToPlace; - - // just to be safe - clearNoteKindParams(); } public override function refresh():Void @@ -173,6 +170,12 @@ class ChartEditorNoteDataToolbox extends ChartEditorBaseToolbox { super.update(elapsed); + // current dialog is minimized, dont change the height + if (this.minimized) + { + return; + } + // toolboxNotesGrid.height + 45 // this is what i found out is the calculation by printing this.height and grid.height var heightToSet:Int = Std.int(Math.max(DIALOG_HEIGHT, toolboxNotesGrid.height + 45)); From 437cc68ba7af70f4060efc739dfc6d3ff21bbeed Mon Sep 17 00:00:00 2001 From: lemz <ismael.amjad07@gmail.com> Date: Sat, 22 Jun 2024 14:49:04 +0200 Subject: [PATCH 44/64] adapt to minimize problem --- .../toolboxes/ChartEditorNoteDataToolbox.hx | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/source/funkin/ui/debug/charting/toolboxes/ChartEditorNoteDataToolbox.hx b/source/funkin/ui/debug/charting/toolboxes/ChartEditorNoteDataToolbox.hx index c557eef1f..278fc1fd6 100644 --- a/source/funkin/ui/debug/charting/toolboxes/ChartEditorNoteDataToolbox.hx +++ b/source/funkin/ui/debug/charting/toolboxes/ChartEditorNoteDataToolbox.hx @@ -17,8 +17,18 @@ import funkin.play.notes.notekind.NoteKindManager; @:build(haxe.ui.ComponentBuilder.build("assets/exclude/data/ui/chart-editor/toolboxes/note-data.xml")) class ChartEditorNoteDataToolbox extends ChartEditorBaseToolbox { + // 100 is the height used in note-data.xml static final DIALOG_HEIGHT:Int = 100; + // toolboxNotesGrid.height + 45 + // this is what i found out by printing this.height and grid.height + // and then seeing that this.height is 100 and grid.height is 55 + static final HEIGHT_OFFSET:Int = 45; + + // minimizing creates a gray bar the bottom, which would obscure the components, + // which is why we use an extra offset of 20 + static final MINIMIZE_FIX:Int = 20; + var toolboxNotesGrid:Grid; var toolboxNotesNoteKind:DropDown; var toolboxNotesCustomKind:TextField; @@ -176,9 +186,7 @@ class ChartEditorNoteDataToolbox extends ChartEditorBaseToolbox return; } - // toolboxNotesGrid.height + 45 - // this is what i found out is the calculation by printing this.height and grid.height - var heightToSet:Int = Std.int(Math.max(DIALOG_HEIGHT, toolboxNotesGrid.height + 45)); + var heightToSet:Int = Std.int(Math.max(DIALOG_HEIGHT, toolboxNotesGrid.height + HEIGHT_OFFSET)) + MINIMIZE_FIX; if (this.height != heightToSet) { this.height = heightToSet; From 0fe726cefa926b2e4de6963acc0284090e2fed99 Mon Sep 17 00:00:00 2001 From: lemz <ismael.amjad07@gmail.com> Date: Sat, 22 Jun 2024 15:38:04 +0200 Subject: [PATCH 45/64] fix min, max --- source/funkin/play/notes/notekind/NoteKind.hx | 58 +++---------------- .../toolboxes/ChartEditorNoteDataToolbox.hx | 14 ++++- 2 files changed, 18 insertions(+), 54 deletions(-) diff --git a/source/funkin/play/notes/notekind/NoteKind.hx b/source/funkin/play/notes/notekind/NoteKind.hx index f2a44dc8a..7efa93de6 100644 --- a/source/funkin/play/notes/notekind/NoteKind.hx +++ b/source/funkin/play/notes/notekind/NoteKind.hx @@ -42,50 +42,6 @@ class NoteKind implements INoteScriptedClass return noteKind; } - /** - * Retrieve the value of the param with the given name - * If there exists no param with the given name then `null` is returned - * @param name Name of the param - * @return Null<Dynamic> - */ - public function getParam(name:String):Null<Dynamic> - { - for (param in params) - { - if (param.name == name) - { - return param.data.value; - } - } - - return null; - } - - /** - * Set the value of the param with the given name - * @param name Name of the param - * @param value New value - */ - public function setParam(name:String, value:Dynamic):Void - { - for (param in params) - { - if (param.name == name) - { - if (param.type == NoteKindParamType.INT || param.type == NoteKindParamType.FLOAT) - { - param.data.value = FlxMath.bound(value, param.data.min, param.data.max); - } - else - { - param.data.value = value; - } - - break; - } - } - } - /** * Retrieve all notes of this kind * @return Array<NoteSprite> @@ -131,14 +87,14 @@ typedef NoteKindParamData = /** * If `min` is null, there is no minimum */ - var min:Null<Float>; + ?min:Null<Float>, /** * If `max` is null, there is no maximum */ - var max:Null<Float>; + ?max:Null<Float>, - var value:Dynamic; + defaultValue:Dynamic } /** @@ -146,8 +102,8 @@ typedef NoteKindParamData = */ typedef NoteKindParam = { - var name:String; - var description:String; - var type:NoteKindParamType; - var data:NoteKindParamData; + name:String, + description:String, + type:NoteKindParamType, + data:NoteKindParamData } diff --git a/source/funkin/ui/debug/charting/toolboxes/ChartEditorNoteDataToolbox.hx b/source/funkin/ui/debug/charting/toolboxes/ChartEditorNoteDataToolbox.hx index 278fc1fd6..751af5dff 100644 --- a/source/funkin/ui/debug/charting/toolboxes/ChartEditorNoteDataToolbox.hx +++ b/source/funkin/ui/debug/charting/toolboxes/ChartEditorNoteDataToolbox.hx @@ -82,13 +82,21 @@ class ChartEditorNoteDataToolbox extends ChartEditorBaseToolbox paramLabel.horizontalAlign = "right"; var paramStepper:NumberStepper = new NumberStepper(); - paramStepper.min = param.data.min; - paramStepper.max = param.data.max; - paramStepper.value = param.data.value; + paramStepper.value = param.data.defaultValue; paramStepper.precision = 1; paramStepper.step = 0.1; paramStepper.percentWidth = 100; + // this check should be unnecessary but for some reason even when min or max is null it will set it to 0 + if (param.data.min != null) + { + paramStepper.min = param.data.min; + } + if (param.data.max != null) + { + paramStepper.max = param.data.max; + } + addNoteKindParam(paramLabel, paramStepper); } } From 764cdee63de762395f070916369a99bc6d81c80d Mon Sep 17 00:00:00 2001 From: lemz <ismael.amjad07@gmail.com> Date: Sat, 22 Jun 2024 15:48:07 +0200 Subject: [PATCH 46/64] add more options --- source/funkin/play/notes/notekind/NoteKind.hx | 10 ++++++++++ .../charting/toolboxes/ChartEditorNoteDataToolbox.hx | 10 +++++++--- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/source/funkin/play/notes/notekind/NoteKind.hx b/source/funkin/play/notes/notekind/NoteKind.hx index 7efa93de6..a06670503 100644 --- a/source/funkin/play/notes/notekind/NoteKind.hx +++ b/source/funkin/play/notes/notekind/NoteKind.hx @@ -94,6 +94,16 @@ typedef NoteKindParamData = */ ?max:Null<Float>, + /** + * If `step` is null, it will use 1.0 + */ + ?step:Null<Float>, + + /** + * If `precision` is null, there will be 0 decimal places + */ + ?precision:Null<Int>, + defaultValue:Dynamic } diff --git a/source/funkin/ui/debug/charting/toolboxes/ChartEditorNoteDataToolbox.hx b/source/funkin/ui/debug/charting/toolboxes/ChartEditorNoteDataToolbox.hx index 751af5dff..26e495dcc 100644 --- a/source/funkin/ui/debug/charting/toolboxes/ChartEditorNoteDataToolbox.hx +++ b/source/funkin/ui/debug/charting/toolboxes/ChartEditorNoteDataToolbox.hx @@ -83,11 +83,11 @@ class ChartEditorNoteDataToolbox extends ChartEditorBaseToolbox var paramStepper:NumberStepper = new NumberStepper(); paramStepper.value = param.data.defaultValue; - paramStepper.precision = 1; - paramStepper.step = 0.1; paramStepper.percentWidth = 100; + paramStepper.step = param.data.step ?? 1; - // this check should be unnecessary but for some reason even when min or max is null it will set it to 0 + // this check should be unnecessary but for some reason + // even when these are null it will set it to 0 if (param.data.min != null) { paramStepper.min = param.data.min; @@ -96,6 +96,10 @@ class ChartEditorNoteDataToolbox extends ChartEditorBaseToolbox { paramStepper.max = param.data.max; } + if (param.data.precision != null) + { + paramStepper.precision = param.data.precision; + } addNoteKindParam(paramLabel, paramStepper); } From c41d846df5dfd5331dad37e71aa4d2b18595b3a9 Mon Sep 17 00:00:00 2001 From: lemz <ismael.amjad07@gmail.com> Date: Sat, 22 Jun 2024 20:49:30 +0200 Subject: [PATCH 47/64] store params in chart chart editor still doesnt fully work --- source/funkin/data/song/SongData.hx | 41 +++++++++++++++++-- source/funkin/play/notes/NoteSprite.hx | 34 +++++++++++++++ .../play/notes/notekind/NoteKindManager.hx | 5 ++- .../ui/debug/charting/ChartEditorState.hx | 19 ++++++--- .../toolboxes/ChartEditorNoteDataToolbox.hx | 24 ++++++++++- 5 files changed, 111 insertions(+), 12 deletions(-) diff --git a/source/funkin/data/song/SongData.hx b/source/funkin/data/song/SongData.hx index 769af8f08..6bbeb4435 100644 --- a/source/funkin/data/song/SongData.hx +++ b/source/funkin/data/song/SongData.hx @@ -951,12 +951,18 @@ class SongNoteDataRaw implements ICloneable<SongNoteDataRaw> return this.kind = value; } - public function new(time:Float, data:Int, length:Float = 0, kind:String = '') + @:alias("p") + @:default([]) + @:optional + public var params:Array<NoteParamData>; + + public function new(time:Float, data:Int, length:Float = 0, kind:String = '', ?params:Array<NoteParamData>) { this.time = time; this.data = data; this.length = length; this.kind = kind; + this.params = params ?? []; } /** @@ -1053,7 +1059,7 @@ class SongNoteDataRaw implements ICloneable<SongNoteDataRaw> public function clone():SongNoteDataRaw { - return new SongNoteDataRaw(this.time, this.data, this.length, this.kind); + return new SongNoteDataRaw(this.time, this.data, this.length, this.kind, this.params); } public function toString():String @@ -1069,9 +1075,9 @@ class SongNoteDataRaw implements ICloneable<SongNoteDataRaw> @:forward abstract SongNoteData(SongNoteDataRaw) from SongNoteDataRaw to SongNoteDataRaw { - public function new(time:Float, data:Int, length:Float = 0, kind:String = '') + public function new(time:Float, data:Int, length:Float = 0, kind:String = '', ?params:Array<NoteParamData>) { - this = new SongNoteDataRaw(time, data, length, kind); + this = new SongNoteDataRaw(time, data, length, kind, params); } public static function buildDirectionName(data:Int, strumlineSize:Int = 4):String @@ -1183,3 +1189,30 @@ abstract SongNoteData(SongNoteDataRaw) from SongNoteDataRaw to SongNoteDataRaw + (this.kind != '' ? ' [kind: ${this.kind}])' : ')'); } } + +class NoteParamData implements ICloneable<NoteParamData> +{ + @:alias("n") + public var name:String; + + @:alias("v") + @:jcustomparse(funkin.data.DataParse.dynamicValue) + @:jcustomwrite(funkin.data.DataWrite.dynamicValue) + public var value:Dynamic; + + public function new(name:String, value:Dynamic) + { + this.name = name; + this.value = value; + } + + public function clone():NoteParamData + { + return new NoteParamData(this.name, this.value); + } + + public function toString():String + { + return 'NoteParamData(${this.name}, ${this.value})'; + } +} diff --git a/source/funkin/play/notes/NoteSprite.hx b/source/funkin/play/notes/NoteSprite.hx index 17a5e57fc..d8d471496 100644 --- a/source/funkin/play/notes/NoteSprite.hx +++ b/source/funkin/play/notes/NoteSprite.hx @@ -1,6 +1,7 @@ package funkin.play.notes; import funkin.data.song.SongData.SongNoteData; +import funkin.data.song.SongData.NoteParamData; import funkin.play.notes.notestyle.NoteStyle; import flixel.graphics.frames.FlxAtlasFrames; import flixel.FlxSprite; @@ -65,6 +66,22 @@ class NoteSprite extends FunkinSprite return this.noteData.kind = value; } + /** + * An array of custom parameters for this note + */ + public var params(get, set):Array<NoteParamData>; + + function get_params():Array<NoteParamData> + { + return this.noteData?.params ?? []; + } + + function set_params(value:Array<NoteParamData>):Array<NoteParamData> + { + if (this.noteData == null) return value; + return this.noteData.params = value; + } + /** * The data of the note (i.e. the direction.) */ @@ -154,6 +171,23 @@ class NoteSprite extends FunkinSprite this.shader = hsvShader; } + /** + * Retrieve the value of the param with the given name + * @param name Name of the param + * @return Null<Dynamic> + */ + public function getParam(name:String):Null<Dynamic> + { + for (param in params) + { + if (param.name == name) + { + return param.value; + } + } + return null; + } + #if FLX_DEBUG /** * Call this to override how debug bounding boxes are drawn for this sprite. diff --git a/source/funkin/play/notes/notekind/NoteKindManager.hx b/source/funkin/play/notes/notekind/NoteKindManager.hx index 3e2174a66..30eede978 100644 --- a/source/funkin/play/notes/notekind/NoteKindManager.hx +++ b/source/funkin/play/notes/notekind/NoteKindManager.hx @@ -5,6 +5,7 @@ import funkin.modding.events.ScriptEvent; import funkin.ui.debug.charting.util.ChartEditorDropdowns; import funkin.data.notestyle.NoteStyleRegistry; import funkin.play.notes.notestyle.NoteStyle; +import funkin.play.notes.notekind.NoteKind.NoteKindParam; class NoteKindManager { @@ -100,9 +101,9 @@ class NoteKindManager /** * Retrive custom params of the given note kind * @param noteKind Name of the note kind - * @return Array<NoteKind.NoteKindParam> + * @return Array<NoteKindParam> */ - public static function getParams(noteKind:String):Array<NoteKind.NoteKindParam> + public static function getParams(noteKind:String):Array<NoteKindParam> { return noteKinds.get(noteKind)?.params ?? []; } diff --git a/source/funkin/ui/debug/charting/ChartEditorState.hx b/source/funkin/ui/debug/charting/ChartEditorState.hx index 2a07be52d..22de29849 100644 --- a/source/funkin/ui/debug/charting/ChartEditorState.hx +++ b/source/funkin/ui/debug/charting/ChartEditorState.hx @@ -35,6 +35,7 @@ import funkin.data.song.SongData.SongEventData; import funkin.data.song.SongData.SongMetadata; import funkin.data.song.SongData.SongNoteData; import funkin.data.song.SongData.SongOffsets; +import funkin.data.song.SongData.NoteParamData; import funkin.data.song.SongDataUtils; import funkin.data.song.SongRegistry; import funkin.data.stage.StageData; @@ -539,6 +540,11 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState */ var noteKindToPlace:Null<String> = null; + /** + * The note params to use for notes being placed in the chart. Defaults to `[]`. + */ + var noteParamsToPlace:Array<NoteParamData> = []; + /** * The event type to use for events being placed in the chart. Defaults to `''`. */ @@ -2437,7 +2443,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState gridGhostNote = new ChartEditorNoteSprite(this); gridGhostNote.alpha = 0.6; - gridGhostNote.noteData = new SongNoteData(0, 0, 0, ""); + gridGhostNote.noteData = new SongNoteData(0, 0, 0, "", []); gridGhostNote.visible = false; add(gridGhostNote); gridGhostNote.zIndex = 11; @@ -4731,7 +4737,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState else { // Create a note and place it in the chart. - var newNoteData:SongNoteData = new SongNoteData(cursorSnappedMs, cursorColumn, 0, noteKindToPlace); + var newNoteData:SongNoteData = new SongNoteData(cursorSnappedMs, cursorColumn, 0, noteKindToPlace, noteParamsToPlace.clone()); performCommand(new AddNotesCommand([newNoteData], FlxG.keys.pressed.CONTROL)); @@ -4890,11 +4896,13 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState if (gridGhostNote == null) throw "ERROR: Tried to handle cursor, but gridGhostNote is null! Check ChartEditorState.buildGrid()"; - var noteData:SongNoteData = gridGhostNote.noteData != null ? gridGhostNote.noteData : new SongNoteData(cursorMs, cursorColumn, 0, noteKindToPlace); + var noteData:SongNoteData = gridGhostNote.noteData != null ? gridGhostNote.noteData : new SongNoteData(cursorMs, cursorColumn, 0, noteKindToPlace, + noteParamsToPlace.clone()); - if (cursorColumn != noteData.data || noteKindToPlace != noteData.kind) + if (cursorColumn != noteData.data || noteKindToPlace != noteData.kind || noteParamsToPlace != noteData.params) { noteData.kind = noteKindToPlace; + noteData.params = noteParamsToPlace; noteData.data = cursorColumn; gridGhostNote.noteStyle = NoteKindManager.getNoteStyleId(noteData.kind, isPixelStyle()) ?? currentSongNoteStyle; gridGhostNote.playNoteAnimation(); @@ -5202,7 +5210,7 @@ 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); + var newNoteData:SongNoteData = new SongNoteData(playheadPosSnappedMs, column, 0, noteKindToPlace, noteParamsToPlace.clone()); performCommand(new AddNotesCommand([newNoteData], FlxG.keys.pressed.CONTROL)); currentLiveInputPlaceNoteData[column] = newNoteData; } @@ -5655,6 +5663,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState FlxG.watch.addQuick('musicTime', audioInstTrack?.time ?? 0.0); FlxG.watch.addQuick('noteKindToPlace', noteKindToPlace); + FlxG.watch.addQuick('noteParamsToPlace', noteParamsToPlace); FlxG.watch.addQuick('eventKindToPlace', eventKindToPlace); FlxG.watch.addQuick('scrollPosInPixels', scrollPositionInPixels); diff --git a/source/funkin/ui/debug/charting/toolboxes/ChartEditorNoteDataToolbox.hx b/source/funkin/ui/debug/charting/toolboxes/ChartEditorNoteDataToolbox.hx index 26e495dcc..027ffdf81 100644 --- a/source/funkin/ui/debug/charting/toolboxes/ChartEditorNoteDataToolbox.hx +++ b/source/funkin/ui/debug/charting/toolboxes/ChartEditorNoteDataToolbox.hx @@ -9,6 +9,8 @@ import haxe.ui.core.Component; import haxe.ui.events.UIEvent; import funkin.ui.debug.charting.util.ChartEditorDropdowns; import funkin.play.notes.notekind.NoteKindManager; +import funkin.play.notes.notekind.NoteKind.NoteKindParam; +import funkin.data.song.SongData.NoteParamData; /** * The toolbox which allows modifying information like Note Kind. @@ -60,6 +62,13 @@ class ChartEditorNoteDataToolbox extends ChartEditorBaseToolbox trace('ChartEditorToolboxHandler.buildToolboxNoteDataLayout() - Note kind changed: $noteKind'); + var noteKindParams:Array<NoteKindParam> = NoteKindManager.getParams(noteKind); + var noteParamData:Array<NoteParamData> = []; + for (noteKindParam in noteKindParams) + { + noteParamData.push(new NoteParamData(noteKindParam.name, noteKindParam.data.defaultValue)); + } + // Edit the note data to place. if (noteKind == '~CUSTOM~') { @@ -71,10 +80,11 @@ class ChartEditorNoteDataToolbox extends ChartEditorBaseToolbox { hideCustom(); chartEditorState.noteKindToPlace = noteKind; + chartEditorState.noteParamsToPlace = noteParamData; toolboxNotesCustomKind.value = chartEditorState.noteKindToPlace; clearNoteKindParams(); - for (param in NoteKindManager.getParams(noteKind)) + for (param in noteKindParams) { var paramLabel:Label = new Label(); paramLabel.value = param.description; @@ -107,10 +117,22 @@ class ChartEditorNoteDataToolbox extends ChartEditorBaseToolbox if (!_initializing && chartEditorState.currentNoteSelection.length > 0) { + for (i in 0...toolboxNotesParams.length) + { + var toolboxComponent:Component = toolboxNotesParams[i].component; + toolboxComponent.onChange = function(event:UIEvent) { + for (note in chartEditorState.currentNoteSelection) + { + note.params[i].value = toolboxComponent.value; + } + } + } + for (note in chartEditorState.currentNoteSelection) { // Edit the note data of any selected notes. note.kind = chartEditorState.noteKindToPlace; + note.params = noteParamData.clone(); // update note sprites for (noteSprite in chartEditorState.renderedNotes.members) From 44d978531727eba19e694ac0bed8e0f1f9c76306 Mon Sep 17 00:00:00 2001 From: lemz <ismael.amjad07@gmail.com> Date: Sat, 22 Jun 2024 22:36:39 +0200 Subject: [PATCH 48/64] editing them works now still need to implement String and do some testing --- source/funkin/data/song/SongData.hx | 18 +- .../play/notes/notekind/NoteKindManager.hx | 7 +- .../ui/debug/charting/ChartEditorState.hx | 17 +- .../toolboxes/ChartEditorNoteDataToolbox.hx | 157 +++++++++++------- 4 files changed, 128 insertions(+), 71 deletions(-) diff --git a/source/funkin/data/song/SongData.hx b/source/funkin/data/song/SongData.hx index 6bbeb4435..7bf3f8f19 100644 --- a/source/funkin/data/song/SongData.hx +++ b/source/funkin/data/song/SongData.hx @@ -1057,9 +1057,19 @@ class SongNoteDataRaw implements ICloneable<SongNoteDataRaw> _stepLength = null; } + public function cloneParams():Array<NoteParamData> + { + var params:Array<NoteParamData> = []; + for (param in this.params) + { + params.push(param.clone()); + } + return params; + } + public function clone():SongNoteDataRaw { - return new SongNoteDataRaw(this.time, this.data, this.length, this.kind, this.params); + return new SongNoteDataRaw(this.time, this.data, this.length, this.kind, cloneParams()); } public function toString():String @@ -1121,7 +1131,7 @@ abstract SongNoteData(SongNoteDataRaw) from SongNoteDataRaw to SongNoteDataRaw if (other.kind == '' || this.kind == null) return false; } - return this.time == other.time && this.data == other.data && this.length == other.length; + return this.time == other.time && this.data == other.data && this.length == other.length && this.params == other.params; } @:op(A != B) @@ -1140,7 +1150,7 @@ abstract SongNoteData(SongNoteDataRaw) from SongNoteDataRaw to SongNoteDataRaw if (other.kind == '') return true; } - return this.time != other.time || this.data != other.data || this.length != other.length; + return this.time != other.time || this.data != other.data || this.length != other.length || this.params != other.params; } @:op(A > B) @@ -1177,7 +1187,7 @@ abstract SongNoteData(SongNoteDataRaw) from SongNoteDataRaw to SongNoteDataRaw public function clone():SongNoteData { - return new SongNoteData(this.time, this.data, this.length, this.kind); + return new SongNoteData(this.time, this.data, this.length, this.kind, this.params); } /** diff --git a/source/funkin/play/notes/notekind/NoteKindManager.hx b/source/funkin/play/notes/notekind/NoteKindManager.hx index 30eede978..8de3cdcca 100644 --- a/source/funkin/play/notes/notekind/NoteKindManager.hx +++ b/source/funkin/play/notes/notekind/NoteKindManager.hx @@ -103,8 +103,13 @@ class NoteKindManager * @param noteKind Name of the note kind * @return Array<NoteKindParam> */ - public static function getParams(noteKind:String):Array<NoteKindParam> + public static function getParams(noteKind:Null<String>):Array<NoteKindParam> { + if (noteKind == null) + { + return []; + } + return noteKinds.get(noteKind)?.params ?? []; } } diff --git a/source/funkin/ui/debug/charting/ChartEditorState.hx b/source/funkin/ui/debug/charting/ChartEditorState.hx index 22de29849..f7abfba89 100644 --- a/source/funkin/ui/debug/charting/ChartEditorState.hx +++ b/source/funkin/ui/debug/charting/ChartEditorState.hx @@ -4737,7 +4737,8 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState else { // Create a note and place it in the chart. - var newNoteData:SongNoteData = new SongNoteData(cursorSnappedMs, cursorColumn, 0, noteKindToPlace, noteParamsToPlace.clone()); + var newNoteData:SongNoteData = new SongNoteData(cursorSnappedMs, cursorColumn, 0, noteKindToPlace, + ChartEditorState.cloneNoteParams(noteParamsToPlace)); performCommand(new AddNotesCommand([newNoteData], FlxG.keys.pressed.CONTROL)); @@ -4897,7 +4898,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState if (gridGhostNote == null) throw "ERROR: Tried to handle cursor, but gridGhostNote is null! Check ChartEditorState.buildGrid()"; var noteData:SongNoteData = gridGhostNote.noteData != null ? gridGhostNote.noteData : new SongNoteData(cursorMs, cursorColumn, 0, noteKindToPlace, - noteParamsToPlace.clone()); + ChartEditorState.cloneNoteParams(noteParamsToPlace)); if (cursorColumn != noteData.data || noteKindToPlace != noteData.kind || noteParamsToPlace != noteData.params) { @@ -5210,7 +5211,7 @@ 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, noteParamsToPlace.clone()); + var newNoteData:SongNoteData = new SongNoteData(playheadPosSnappedMs, column, 0, noteKindToPlace, ChartEditorState.cloneNoteParams(noteParamsToPlace)); performCommand(new AddNotesCommand([newNoteData], FlxG.keys.pressed.CONTROL)); currentLiveInputPlaceNoteData[column] = newNoteData; } @@ -6532,6 +6533,16 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState } return input; } + + public static function cloneNoteParams(paramsToClone:Array<NoteParamData>):Array<NoteParamData> + { + var params:Array<NoteParamData> = []; + for (param in paramsToClone) + { + params.push(param.clone()); + } + return params; + } } /** diff --git a/source/funkin/ui/debug/charting/toolboxes/ChartEditorNoteDataToolbox.hx b/source/funkin/ui/debug/charting/toolboxes/ChartEditorNoteDataToolbox.hx index 027ffdf81..a81cac5c2 100644 --- a/source/funkin/ui/debug/charting/toolboxes/ChartEditorNoteDataToolbox.hx +++ b/source/funkin/ui/debug/charting/toolboxes/ChartEditorNoteDataToolbox.hx @@ -62,77 +62,30 @@ class ChartEditorNoteDataToolbox extends ChartEditorBaseToolbox trace('ChartEditorToolboxHandler.buildToolboxNoteDataLayout() - Note kind changed: $noteKind'); - var noteKindParams:Array<NoteKindParam> = NoteKindManager.getParams(noteKind); - var noteParamData:Array<NoteParamData> = []; - for (noteKindParam in noteKindParams) - { - noteParamData.push(new NoteParamData(noteKindParam.name, noteKindParam.data.defaultValue)); - } - // Edit the note data to place. if (noteKind == '~CUSTOM~') { showCustom(); - clearNoteKindParams(); toolboxNotesCustomKind.value = chartEditorState.noteKindToPlace; } else { hideCustom(); chartEditorState.noteKindToPlace = noteKind; - chartEditorState.noteParamsToPlace = noteParamData; toolboxNotesCustomKind.value = chartEditorState.noteKindToPlace; - - clearNoteKindParams(); - for (param in noteKindParams) - { - var paramLabel:Label = new Label(); - paramLabel.value = param.description; - paramLabel.verticalAlign = "center"; - paramLabel.horizontalAlign = "right"; - - var paramStepper:NumberStepper = new NumberStepper(); - paramStepper.value = param.data.defaultValue; - paramStepper.percentWidth = 100; - paramStepper.step = param.data.step ?? 1; - - // this check should be unnecessary but for some reason - // even when these are null it will set it to 0 - if (param.data.min != null) - { - paramStepper.min = param.data.min; - } - if (param.data.max != null) - { - paramStepper.max = param.data.max; - } - if (param.data.precision != null) - { - paramStepper.precision = param.data.precision; - } - - addNoteKindParam(paramLabel, paramStepper); - } } + createNoteKindParams(noteKind); + if (!_initializing && chartEditorState.currentNoteSelection.length > 0) { - for (i in 0...toolboxNotesParams.length) - { - var toolboxComponent:Component = toolboxNotesParams[i].component; - toolboxComponent.onChange = function(event:UIEvent) { - for (note in chartEditorState.currentNoteSelection) - { - note.params[i].value = toolboxComponent.value; - } - } - } - for (note in chartEditorState.currentNoteSelection) { // Edit the note data of any selected notes. note.kind = chartEditorState.noteKindToPlace; - note.params = noteParamData.clone(); + trace(note.params); + note.params = ChartEditorState.cloneNoteParams(chartEditorState.noteParamsToPlace); + trace(note.params); // update note sprites for (noteSprite in chartEditorState.renderedNotes.members) @@ -187,6 +140,8 @@ class ChartEditorNoteDataToolbox extends ChartEditorBaseToolbox toolboxNotesNoteKind.value = ChartEditorDropdowns.lookupNoteKind(chartEditorState.noteKindToPlace); toolboxNotesCustomKind.value = chartEditorState.noteKindToPlace; + + createNoteKindParams(chartEditorState.noteKindToPlace); } function showCustom():Void @@ -201,6 +156,82 @@ class ChartEditorNoteDataToolbox extends ChartEditorBaseToolbox toolboxNotesCustomKind.hidden = true; } + function createNoteKindParams(noteKind:Null<String>):Void + { + clearNoteKindParams(); + + var setParamsToPlace:Bool = false; + if (!_initializing) + { + for (note in chartEditorState.currentNoteSelection) + { + if (note.kind == chartEditorState.noteKindToPlace) + { + chartEditorState.noteParamsToPlace = ChartEditorState.cloneNoteParams(note.params); + setParamsToPlace = true; + break; + } + } + } + + var noteKindParams:Array<NoteKindParam> = NoteKindManager.getParams(noteKind); + + for (i in 0...noteKindParams.length) + { + var param:NoteKindParam = noteKindParams[i]; + + var paramLabel:Label = new Label(); + paramLabel.value = param.description; + paramLabel.verticalAlign = "center"; + paramLabel.horizontalAlign = "right"; + + var paramStepper:NumberStepper = new NumberStepper(); + paramStepper.value = (setParamsToPlace ? chartEditorState.noteParamsToPlace[i].value : param.data.defaultValue); + paramStepper.percentWidth = 100; + paramStepper.step = param.data.step ?? 1; + + // this check should be unnecessary but for some reason + // even when these are null it will set it to 0 + if (param.data.min != null) + { + paramStepper.min = param.data.min; + } + if (param.data.max != null) + { + paramStepper.max = param.data.max; + } + if (param.data.precision != null) + { + paramStepper.precision = param.data.precision; + } + + paramStepper.onChange = function(event:UIEvent) { + chartEditorState.noteParamsToPlace[i].value = paramStepper.value; + + for (note in chartEditorState.currentNoteSelection) + { + if (note.params[i].name == param.name) + { + note.params[i].value = paramStepper.value; + trace(note.params[i]); + } + } + } + + addNoteKindParam(paramLabel, paramStepper); + } + + if (!setParamsToPlace) + { + var noteParamData:Array<NoteParamData> = []; + for (param in noteKindParams) + { + noteParamData.push(new NoteParamData(param.name, param.data.defaultValue)); + } + chartEditorState.noteParamsToPlace = noteParamData; + } + } + function addNoteKindParam(label:Label, component:Component):Void { toolboxNotesParams.push({label: label, component: component}); @@ -210,6 +241,17 @@ class ChartEditorNoteDataToolbox extends ChartEditorBaseToolbox this.height = Math.max(DIALOG_HEIGHT, DIALOG_HEIGHT - 30 + toolboxNotesParams.length * 30); } + function clearNoteKindParams():Void + { + for (param in toolboxNotesParams) + { + toolboxNotesGrid.removeComponent(param.component); + toolboxNotesGrid.removeComponent(param.label); + } + toolboxNotesParams = []; + this.height = DIALOG_HEIGHT; + } + override function update(elapsed:Float):Void { super.update(elapsed); @@ -227,17 +269,6 @@ class ChartEditorNoteDataToolbox extends ChartEditorBaseToolbox } } - function clearNoteKindParams():Void - { - for (param in toolboxNotesParams) - { - toolboxNotesGrid.removeComponent(param.component); - toolboxNotesGrid.removeComponent(param.label); - } - toolboxNotesParams = []; - this.height = DIALOG_HEIGHT; - } - public static function build(chartEditorState:ChartEditorState):ChartEditorNoteDataToolbox { return new ChartEditorNoteDataToolbox(chartEditorState); From 492af8add4e575d7e648f67911d2fafb006c9219 Mon Sep 17 00:00:00 2001 From: lemz <ismael.amjad07@gmail.com> Date: Sun, 23 Jun 2024 15:25:53 +0200 Subject: [PATCH 49/64] String works now --- source/funkin/play/notes/notekind/NoteKind.hx | 4 +- .../toolboxes/ChartEditorNoteDataToolbox.hx | 72 ++++++++++++------- 2 files changed, 49 insertions(+), 27 deletions(-) diff --git a/source/funkin/play/notes/notekind/NoteKind.hx b/source/funkin/play/notes/notekind/NoteKind.hx index a06670503..89c175e54 100644 --- a/source/funkin/play/notes/notekind/NoteKind.hx +++ b/source/funkin/play/notes/notekind/NoteKind.hx @@ -104,7 +104,7 @@ typedef NoteKindParamData = */ ?precision:Null<Int>, - defaultValue:Dynamic + ?defaultValue:Dynamic } /** @@ -115,5 +115,5 @@ typedef NoteKindParam = name:String, description:String, type:NoteKindParamType, - data:NoteKindParamData + ?data:NoteKindParamData } diff --git a/source/funkin/ui/debug/charting/toolboxes/ChartEditorNoteDataToolbox.hx b/source/funkin/ui/debug/charting/toolboxes/ChartEditorNoteDataToolbox.hx index a81cac5c2..264e62c5a 100644 --- a/source/funkin/ui/debug/charting/toolboxes/ChartEditorNoteDataToolbox.hx +++ b/source/funkin/ui/debug/charting/toolboxes/ChartEditorNoteDataToolbox.hx @@ -10,6 +10,7 @@ import haxe.ui.events.UIEvent; import funkin.ui.debug.charting.util.ChartEditorDropdowns; import funkin.play.notes.notekind.NoteKindManager; import funkin.play.notes.notekind.NoteKind.NoteKindParam; +import funkin.play.notes.notekind.NoteKind.NoteKindParamType; import funkin.data.song.SongData.NoteParamData; /** @@ -83,9 +84,7 @@ class ChartEditorNoteDataToolbox extends ChartEditorBaseToolbox { // Edit the note data of any selected notes. note.kind = chartEditorState.noteKindToPlace; - trace(note.params); note.params = ChartEditorState.cloneNoteParams(chartEditorState.noteParamsToPlace); - trace(note.params); // update note sprites for (noteSprite in chartEditorState.renderedNotes.members) @@ -185,48 +184,71 @@ class ChartEditorNoteDataToolbox extends ChartEditorBaseToolbox paramLabel.verticalAlign = "center"; paramLabel.horizontalAlign = "right"; - var paramStepper:NumberStepper = new NumberStepper(); - paramStepper.value = (setParamsToPlace ? chartEditorState.noteParamsToPlace[i].value : param.data.defaultValue); - paramStepper.percentWidth = 100; - paramStepper.step = param.data.step ?? 1; + var paramComponent:Component = null; - // this check should be unnecessary but for some reason - // even when these are null it will set it to 0 - if (param.data.min != null) + final paramType:String = param.type; + switch (paramType) { - paramStepper.min = param.data.min; - } - if (param.data.max != null) - { - paramStepper.max = param.data.max; - } - if (param.data.precision != null) - { - paramStepper.precision = param.data.precision; + case NoteKindParamType.INT | NoteKindParamType.FLOAT: + var paramStepper:NumberStepper = new NumberStepper(); + paramStepper.value = (setParamsToPlace ? chartEditorState.noteParamsToPlace[i].value : param.data?.defaultValue) ?? 0.0; + paramStepper.percentWidth = 100; + paramStepper.step = param.data?.step ?? 1; + + // this check should be unnecessary but for some reason + // even when these are null it will set it to 0 + if (param.data?.min != null) + { + paramStepper.min = param.data.min; + } + if (param.data?.max != null) + { + paramStepper.max = param.data.max; + } + if (param.data?.precision != null) + { + paramStepper.precision = param.data.precision; + } + paramComponent = paramStepper; + + case NoteKindParamType.STRING: + var paramTextField:TextField = new TextField(); + paramTextField.value = (setParamsToPlace ? chartEditorState.noteParamsToPlace[i].value : param.data?.defaultValue) ?? ''; + paramTextField.percentWidth = 100; + paramComponent = paramTextField; } - paramStepper.onChange = function(event:UIEvent) { - chartEditorState.noteParamsToPlace[i].value = paramStepper.value; + if (paramComponent == null) + { + continue; + } + + paramComponent.onChange = function(event:UIEvent) { + chartEditorState.noteParamsToPlace[i].value = paramComponent.value; for (note in chartEditorState.currentNoteSelection) { + if (note.params.length != noteKindParams.length) + { + break; + } + if (note.params[i].name == param.name) { - note.params[i].value = paramStepper.value; - trace(note.params[i]); + note.params[i].value = paramComponent.value; } } } - addNoteKindParam(paramLabel, paramStepper); + addNoteKindParam(paramLabel, paramComponent); } if (!setParamsToPlace) { var noteParamData:Array<NoteParamData> = []; - for (param in noteKindParams) + for (i in 0...noteKindParams.length) { - noteParamData.push(new NoteParamData(param.name, param.data.defaultValue)); + noteParamData.push(new NoteParamData(noteKindParams[i].name, toolboxNotesParams[i].component.value)); } chartEditorState.noteParamsToPlace = noteParamData; } From f9bccb057a129443148e6031c907045c2ff8fb31 Mon Sep 17 00:00:00 2001 From: lemz <ismael.amjad07@gmail.com> Date: Mon, 24 Jun 2024 21:45:58 +0200 Subject: [PATCH 50/64] use suffixes instead of pixel boolean --- source/funkin/play/notes/Strumline.hx | 4 ++-- .../play/notes/notekind/NoteKindManager.hx | 23 +++++++++++-------- .../ui/debug/charting/ChartEditorState.hx | 17 +++++--------- 3 files changed, 22 insertions(+), 22 deletions(-) diff --git a/source/funkin/play/notes/Strumline.hx b/source/funkin/play/notes/Strumline.hx index 86b7a3ee1..5e76afa51 100644 --- a/source/funkin/play/notes/Strumline.hx +++ b/source/funkin/play/notes/Strumline.hx @@ -709,7 +709,7 @@ class Strumline extends FlxSpriteGroup if (noteSprite != null) { - var noteKindStyle:NoteStyle = NoteKindManager.getNoteStyle(note.kind, this.noteStyle.isHoldNotePixel()) ?? this.noteStyle; + var noteKindStyle:NoteStyle = NoteKindManager.getNoteStyle(note.kind, this.noteStyle.id) ?? this.noteStyle; noteSprite.setupNoteGraphic(noteKindStyle); noteSprite.direction = note.getDirection(); @@ -731,7 +731,7 @@ class Strumline extends FlxSpriteGroup if (holdNoteSprite != null) { - var noteKindStyle:NoteStyle = NoteKindManager.getNoteStyle(note.kind, this.noteStyle.isHoldNotePixel()) ?? this.noteStyle; + var noteKindStyle:NoteStyle = NoteKindManager.getNoteStyle(note.kind, this.noteStyle.id) ?? this.noteStyle; holdNoteSprite.setupHoldNoteGraphic(noteKindStyle); holdNoteSprite.parentStrumline = this; diff --git a/source/funkin/play/notes/notekind/NoteKindManager.hx b/source/funkin/play/notes/notekind/NoteKindManager.hx index 8de3cdcca..d97eefcf8 100644 --- a/source/funkin/play/notes/notekind/NoteKindManager.hx +++ b/source/funkin/play/notes/notekind/NoteKindManager.hx @@ -66,12 +66,12 @@ class NoteKindManager /** * Retrieve the note style from the given note kind * @param noteKind note kind name - * @param isPixel whether to use pixel style + * @param suffix Used for song note styles * @return NoteStyle */ - public static function getNoteStyle(noteKind:String, isPixel:Bool = false):Null<NoteStyle> + public static function getNoteStyle(noteKind:String, ?suffix:String):Null<NoteStyle> { - var noteStyleId:Null<String> = getNoteStyleId(noteKind, isPixel); + var noteStyleId:Null<String> = getNoteStyleId(noteKind, suffix); if (noteStyleId == null) { @@ -83,16 +83,21 @@ class NoteKindManager /** * Retrieve the note style id from the given note kind - * @param noteKind note kind name - * @param isPixel whether to use pixel style + * @param noteKind Note kind name + * @param suffix Used for song note styles * @return Null<String> */ - public static function getNoteStyleId(noteKind:String, isPixel:Bool = false):Null<String> + public static function getNoteStyleId(noteKind:String, ?suffix:String):Null<String> { - var noteStyleId:Null<String> = noteKinds.get(noteKind)?.noteStyleId; - if (isPixel && noteStyleId != null) + if (suffix == null) { - noteStyleId = NoteStyleRegistry.instance.hasEntry('$noteStyleId-pixel') ? '$noteStyleId-pixel' : noteStyleId; + suffix = ''; + } + + var noteStyleId:Null<String> = noteKinds.get(noteKind)?.noteStyleId; + if (noteStyleId != null) + { + noteStyleId = NoteStyleRegistry.instance.hasEntry('$noteStyleId-$suffix') ? '$noteStyleId-$suffix' : noteStyleId; } return noteStyleId; diff --git a/source/funkin/ui/debug/charting/ChartEditorState.hx b/source/funkin/ui/debug/charting/ChartEditorState.hx index f7abfba89..d3ddb1bca 100644 --- a/source/funkin/ui/debug/charting/ChartEditorState.hx +++ b/source/funkin/ui/debug/charting/ChartEditorState.hx @@ -3591,7 +3591,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState // The note sprite handles animation playback and positioning. noteSprite.noteData = noteData; - noteSprite.noteStyle = NoteKindManager.getNoteStyleId(noteData.kind, isPixelStyle()) ?? currentSongNoteStyle; + noteSprite.noteStyle = NoteKindManager.getNoteStyleId(noteData.kind, currentSongNoteStyle) ?? currentSongNoteStyle; noteSprite.overrideStepTime = null; noteSprite.overrideData = null; @@ -3615,7 +3615,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState holdNoteSprite.setHeightDirectly(noteLengthPixels); - holdNoteSprite.noteStyle = NoteKindManager.getNoteStyleId(noteSprite.noteData.kind, isPixelStyle()) ?? currentSongNoteStyle; + holdNoteSprite.noteStyle = NoteKindManager.getNoteStyleId(noteSprite.noteData.kind, currentSongNoteStyle) ?? currentSongNoteStyle; holdNoteSprite.updateHoldNotePosition(renderedHoldNotes); @@ -3681,7 +3681,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState holdNoteSprite.noteDirection = noteData.getDirection(); holdNoteSprite.setHeightDirectly(noteLengthPixels); - holdNoteSprite.noteStyle = NoteKindManager.getNoteStyleId(noteData.kind, isPixelStyle()) ?? currentSongNoteStyle; + holdNoteSprite.noteStyle = NoteKindManager.getNoteStyleId(noteData.kind, currentSongNoteStyle) ?? currentSongNoteStyle; holdNoteSprite.updateHoldNotePosition(renderedHoldNotes); @@ -4580,7 +4580,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState gridGhostHoldNote.noteData = currentPlaceNoteData; gridGhostHoldNote.noteDirection = currentPlaceNoteData.getDirection(); gridGhostHoldNote.setHeightDirectly(dragLengthPixels, true); - gridGhostHoldNote.noteStyle = NoteKindManager.getNoteStyleId(currentPlaceNoteData.kind, isPixelStyle()) ?? currentSongNoteStyle; + gridGhostHoldNote.noteStyle = NoteKindManager.getNoteStyleId(currentPlaceNoteData.kind, currentSongNoteStyle) ?? currentSongNoteStyle; gridGhostHoldNote.updateHoldNotePosition(renderedHoldNotes); } else @@ -4905,7 +4905,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState noteData.kind = noteKindToPlace; noteData.params = noteParamsToPlace; noteData.data = cursorColumn; - gridGhostNote.noteStyle = NoteKindManager.getNoteStyleId(noteData.kind, isPixelStyle()) ?? currentSongNoteStyle; + gridGhostNote.noteStyle = NoteKindManager.getNoteStyleId(noteData.kind, currentSongNoteStyle) ?? currentSongNoteStyle; gridGhostNote.playNoteAnimation(); } noteData.time = cursorSnappedMs; @@ -5297,7 +5297,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState ghostHold.visible = true; ghostHold.alpha = 0.6; ghostHold.setHeightDirectly(0); - ghostHold.noteStyle = NoteKindManager.getNoteStyleId(ghostHold.noteData.kind, isPixelStyle()) ?? currentSongNoteStyle; + ghostHold.noteStyle = NoteKindManager.getNoteStyleId(ghostHold.noteData.kind, currentSongNoteStyle) ?? currentSongNoteStyle; ghostHold.updateHoldNotePosition(renderedHoldNotes); } @@ -6423,11 +6423,6 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState return note != null && currentNoteSelection.indexOf(note) != -1; } - function isPixelStyle():Bool - { - return currentSongNoteStyle == 'pixel'; - } - override function destroy():Void { super.destroy(); From 4746c1da0eed756e2af8630d572ad9770a5185f1 Mon Sep 17 00:00:00 2001 From: lemz <ismael.amjad07@gmail.com> Date: Mon, 24 Jun 2024 21:48:09 +0200 Subject: [PATCH 51/64] checking empty suffix is stupid --- source/funkin/play/notes/notekind/NoteKindManager.hx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/source/funkin/play/notes/notekind/NoteKindManager.hx b/source/funkin/play/notes/notekind/NoteKindManager.hx index d97eefcf8..3040c0a96 100644 --- a/source/funkin/play/notes/notekind/NoteKindManager.hx +++ b/source/funkin/play/notes/notekind/NoteKindManager.hx @@ -89,13 +89,13 @@ class NoteKindManager */ public static function getNoteStyleId(noteKind:String, ?suffix:String):Null<String> { - if (suffix == null) + if (suffix == '') { - suffix = ''; + suffix = null; } var noteStyleId:Null<String> = noteKinds.get(noteKind)?.noteStyleId; - if (noteStyleId != null) + if (noteStyleId != null && suffix != null) { noteStyleId = NoteStyleRegistry.instance.hasEntry('$noteStyleId-$suffix') ? '$noteStyleId-$suffix' : noteStyleId; } From 1fe44fa3686b33f91b99efdb00070e4c59fdee45 Mon Sep 17 00:00:00 2001 From: lemz <ismael.amjad07@gmail.com> Date: Sat, 29 Jun 2024 15:33:41 +0200 Subject: [PATCH 52/64] add from --- source/funkin/play/notes/notekind/NoteKind.hx | 2 +- .../ui/debug/charting/toolboxes/ChartEditorNoteDataToolbox.hx | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/source/funkin/play/notes/notekind/NoteKind.hx b/source/funkin/play/notes/notekind/NoteKind.hx index 89c175e54..c1c6e815a 100644 --- a/source/funkin/play/notes/notekind/NoteKind.hx +++ b/source/funkin/play/notes/notekind/NoteKind.hx @@ -73,7 +73,7 @@ class NoteKind implements INoteScriptedClass * Abstract for setting the type of the `NoteKindParam` * This was supposed to be an enum but polymod kept being annoying */ -abstract NoteKindParamType(String) to String +abstract NoteKindParamType(String) from String to String { public static final STRING:String = 'String'; diff --git a/source/funkin/ui/debug/charting/toolboxes/ChartEditorNoteDataToolbox.hx b/source/funkin/ui/debug/charting/toolboxes/ChartEditorNoteDataToolbox.hx index 264e62c5a..ea46cf72a 100644 --- a/source/funkin/ui/debug/charting/toolboxes/ChartEditorNoteDataToolbox.hx +++ b/source/funkin/ui/debug/charting/toolboxes/ChartEditorNoteDataToolbox.hx @@ -186,8 +186,7 @@ class ChartEditorNoteDataToolbox extends ChartEditorBaseToolbox var paramComponent:Component = null; - final paramType:String = param.type; - switch (paramType) + switch (param.type) { case NoteKindParamType.INT | NoteKindParamType.FLOAT: var paramStepper:NumberStepper = new NumberStepper(); From f76309c91ec2cd0ca4bad6163b47fefa2e57228c Mon Sep 17 00:00:00 2001 From: EliteMasterEric <ericmyllyoja@gmail.com> Date: Fri, 12 Jul 2024 04:13:20 -0400 Subject: [PATCH 53/64] Update rendering for custom note styles --- source/funkin/data/notestyle/NoteStyleData.hx | 8 ++++++++ source/funkin/play/notes/NoteSprite.hx | 16 +++++++++------- source/funkin/play/notes/Strumline.hx | 1 + source/funkin/play/notes/notestyle/NoteStyle.hx | 16 ++++++++++++++-- .../charting/components/ChartEditorNoteSprite.hx | 10 ++++++++-- .../toolboxes/ChartEditorNoteDataToolbox.hx | 2 +- .../debug/charting/util/ChartEditorDropdowns.hx | 6 +++--- 7 files changed, 44 insertions(+), 15 deletions(-) diff --git a/source/funkin/data/notestyle/NoteStyleData.hx b/source/funkin/data/notestyle/NoteStyleData.hx index 04fda67ca..fcdb3b4f9 100644 --- a/source/funkin/data/notestyle/NoteStyleData.hx +++ b/source/funkin/data/notestyle/NoteStyleData.hx @@ -109,6 +109,14 @@ typedef NoteStyleAssetData<T> = @:optional var isPixel:Bool; + /** + * If true, animations will be played on the graphic. + * @default `false` to save performance. + */ + @:default(false) + @:optional + var animated:Bool; + /** * The structure of this data depends on the asset. */ diff --git a/source/funkin/play/notes/NoteSprite.hx b/source/funkin/play/notes/NoteSprite.hx index d8d471496..e8cacaa4d 100644 --- a/source/funkin/play/notes/NoteSprite.hx +++ b/source/funkin/play/notes/NoteSprite.hx @@ -91,7 +91,7 @@ class NoteSprite extends FunkinSprite { if (frames == null) return value; - animation.play(DIRECTION_COLORS[value] + 'Scroll'); + playNoteAnimation(value); this.direction = value; return this.direction; @@ -152,9 +152,6 @@ class NoteSprite extends FunkinSprite this.hsvShader = new HSVShader(); setupNoteGraphic(noteStyle); - - // Disables the update() function for performance. - this.active = false; } /** @@ -165,10 +162,10 @@ class NoteSprite extends FunkinSprite { noteStyle.buildNoteSprite(this); - setGraphicSize(Strumline.STRUMLINE_SIZE); - updateHitbox(); - this.shader = hsvShader; + + // `false` disables the update() function for performance. + this.active = noteStyle.isNoteAnimated(); } /** @@ -211,6 +208,11 @@ class NoteSprite extends FunkinSprite } #end + function playNoteAnimation(value:Int):Void + { + animation.play(DIRECTION_COLORS[value] + 'Scroll'); + } + public function desaturate():Void { this.hsvShader.saturation = 0.2; diff --git a/source/funkin/play/notes/Strumline.hx b/source/funkin/play/notes/Strumline.hx index 5e76afa51..1e5782ad2 100644 --- a/source/funkin/play/notes/Strumline.hx +++ b/source/funkin/play/notes/Strumline.hx @@ -717,6 +717,7 @@ class Strumline extends FlxSpriteGroup noteSprite.x = this.x; noteSprite.x += getXPos(DIRECTIONS[note.getDirection() % KEY_COUNT]); + noteSprite.x -= (noteSprite.width - Strumline.STRUMLINE_SIZE) / 2; // Center it noteSprite.x -= NUDGE; // noteSprite.x += INITIAL_OFFSET; noteSprite.y = -9999; diff --git a/source/funkin/play/notes/notestyle/NoteStyle.hx b/source/funkin/play/notes/notestyle/NoteStyle.hx index d0cc09f6a..3993cce52 100644 --- a/source/funkin/play/notes/notestyle/NoteStyle.hx +++ b/source/funkin/play/notes/notestyle/NoteStyle.hx @@ -89,12 +89,14 @@ class NoteStyle implements IRegistryEntry<NoteStyleData> target.frames = atlas; - target.scale.x = _data.assets.note.scale; - target.scale.y = _data.assets.note.scale; target.antialiasing = !_data.assets.note.isPixel; // Apply the animations. buildNoteAnimations(target); + + // Set the scale. + target.setGraphicSize(Strumline.STRUMLINE_SIZE * getNoteScale()); + target.updateHitbox(); } var noteFrames:FlxAtlasFrames = null; @@ -156,6 +158,16 @@ class NoteStyle implements IRegistryEntry<NoteStyleData> target.animation.addByPrefix('redScroll', rightData.prefix, rightData.frameRate, rightData.looped, rightData.flipX, rightData.flipY); } + public function isNoteAnimated():Bool + { + return _data.assets.note.animated; + } + + public function getNoteScale():Float + { + return _data.assets.note.scale; + } + function fetchNoteAnimationData(dir:NoteDirection):AnimationData { var result:Null<AnimationData> = switch (dir) diff --git a/source/funkin/ui/debug/charting/components/ChartEditorNoteSprite.hx b/source/funkin/ui/debug/charting/components/ChartEditorNoteSprite.hx index 009532401..5fd0c74aa 100644 --- a/source/funkin/ui/debug/charting/components/ChartEditorNoteSprite.hx +++ b/source/funkin/ui/debug/charting/components/ChartEditorNoteSprite.hx @@ -107,6 +107,12 @@ class ChartEditorNoteSprite extends FlxSprite var prefix:String = noteStyle.id.toTitleCase(); var frameCollection:FlxAtlasFrames = Paths.getSparrowAtlas(noteStyle.getNoteAssetPath(), noteStyle.getNoteAssetLibrary()); + if (frameCollection == null) + { + trace('Could not retrieve frame collection for ${noteStyle}: ${Paths.image(noteStyle.getNoteAssetPath(), noteStyle.getNoteAssetLibrary())}'); + FlxG.log.error('Could not retrieve frame collection for ${noteStyle}: ${Paths.image(noteStyle.getNoteAssetPath(), noteStyle.getNoteAssetLibrary())}'); + return; + } for (frame in frameCollection.frames) { // cloning the frame because else @@ -221,9 +227,9 @@ class ChartEditorNoteSprite extends FlxSprite switch (baseAnimationName) { case 'tap': - this.setGraphicSize(0, ChartEditorState.GRID_SIZE); + this.setGraphicSize(ChartEditorState.GRID_SIZE, 0); + this.updateHitbox(); } - this.updateHitbox(); var bruhStyle:NoteStyle = fetchNoteStyle(this.noteStyle); this.antialiasing = !bruhStyle._data?.assets?.note?.isPixel ?? true; diff --git a/source/funkin/ui/debug/charting/toolboxes/ChartEditorNoteDataToolbox.hx b/source/funkin/ui/debug/charting/toolboxes/ChartEditorNoteDataToolbox.hx index ea46cf72a..12f7f7d63 100644 --- a/source/funkin/ui/debug/charting/toolboxes/ChartEditorNoteDataToolbox.hx +++ b/source/funkin/ui/debug/charting/toolboxes/ChartEditorNoteDataToolbox.hx @@ -283,7 +283,7 @@ class ChartEditorNoteDataToolbox extends ChartEditorBaseToolbox return; } - var heightToSet:Int = Std.int(Math.max(DIALOG_HEIGHT, toolboxNotesGrid.height + HEIGHT_OFFSET)) + MINIMIZE_FIX; + var heightToSet:Int = Std.int(Math.max(DIALOG_HEIGHT, (toolboxNotesGrid?.height ?? 50) + HEIGHT_OFFSET)) + MINIMIZE_FIX; if (this.height != heightToSet) { this.height = heightToSet; diff --git a/source/funkin/ui/debug/charting/util/ChartEditorDropdowns.hx b/source/funkin/ui/debug/charting/util/ChartEditorDropdowns.hx index 6a426c391..21938b005 100644 --- a/source/funkin/ui/debug/charting/util/ChartEditorDropdowns.hx +++ b/source/funkin/ui/debug/charting/util/ChartEditorDropdowns.hx @@ -195,11 +195,11 @@ class ChartEditorDropdowns { dropDown.dataSource.clear(); - var returnValue:DropDownEntry = lookupNoteKind('~CUSTOM'); + var returnValue:DropDownEntry = lookupNoteKind(''); for (noteKindId in NOTE_KINDS.keys()) { - var noteKind:String = NOTE_KINDS.get(noteKindId) ?? 'Default'; + var noteKind:String = NOTE_KINDS.get(noteKindId) ?? 'Unknown'; var value:DropDownEntry = {id: noteKindId, text: noteKind}; if (startingKindId == noteKindId) returnValue = value; @@ -216,7 +216,7 @@ class ChartEditorDropdowns { if (noteKindId == null) return lookupNoteKind(''); if (!NOTE_KINDS.exists(noteKindId)) return {id: '~CUSTOM~', text: 'Custom'}; - return {id: noteKindId ?? '', text: NOTE_KINDS.get(noteKindId) ?? 'Default'}; + return {id: noteKindId ?? '', text: NOTE_KINDS.get(noteKindId) ?? 'Unknown'}; } /** From ace762413e42a211a92ad37544ec22f1c2f3da8d Mon Sep 17 00:00:00 2001 From: EliteMasterEric <ericmyllyoja@gmail.com> Date: Fri, 12 Jul 2024 16:39:42 -0400 Subject: [PATCH 54/64] Fix an issue where display would break on invalid note styles. --- assets | 2 +- source/funkin/ui/debug/charting/ChartEditorState.hx | 4 +++- .../charting/components/ChartEditorHoldNoteSprite.hx | 3 ++- .../charting/components/ChartEditorNoteSprite.hx | 12 ++++++++++-- 4 files changed, 16 insertions(+), 5 deletions(-) diff --git a/assets b/assets index 005c96f85..4af95a506 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit 005c96f85f4304865acb196e7cc4d6d83f9d76d8 +Subproject commit 4af95a506fc62cd683422dfb9c599877b26c27db diff --git a/source/funkin/ui/debug/charting/ChartEditorState.hx b/source/funkin/ui/debug/charting/ChartEditorState.hx index d3ddb1bca..6f5979c90 100644 --- a/source/funkin/ui/debug/charting/ChartEditorState.hx +++ b/source/funkin/ui/debug/charting/ChartEditorState.hx @@ -1408,7 +1408,9 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState function get_currentSongNoteStyle():String { - if (currentSongMetadata.playData.noteStyle == null) + if (currentSongMetadata.playData.noteStyle == null + || currentSongMetadata.playData.noteStyle == '' + || currentSongMetadata.playData.noteStyle == 'item') { // Initialize to the default value if not set. currentSongMetadata.playData.noteStyle = Constants.DEFAULT_NOTE_STYLE; diff --git a/source/funkin/ui/debug/charting/components/ChartEditorHoldNoteSprite.hx b/source/funkin/ui/debug/charting/components/ChartEditorHoldNoteSprite.hx index b8d6ee22e..1e631f2cf 100644 --- a/source/funkin/ui/debug/charting/components/ChartEditorHoldNoteSprite.hx +++ b/source/funkin/ui/debug/charting/components/ChartEditorHoldNoteSprite.hx @@ -53,7 +53,8 @@ class ChartEditorHoldNoteSprite extends SustainTrail @:nullSafety(Off) function updateHoldNoteGraphic():Void { - var bruhStyle:NoteStyle = NoteStyleRegistry.instance.fetchEntry(noteStyle); + var bruhStyle:Null<NoteStyle> = NoteStyleRegistry.instance.fetchEntry(noteStyle); + if (bruhStyle == null) bruhStyle = NoteStyleRegistry.instance.fetchDefault(); setupHoldNoteGraphic(bruhStyle); } diff --git a/source/funkin/ui/debug/charting/components/ChartEditorNoteSprite.hx b/source/funkin/ui/debug/charting/components/ChartEditorNoteSprite.hx index 5fd0c74aa..c8f40da62 100644 --- a/source/funkin/ui/debug/charting/components/ChartEditorNoteSprite.hx +++ b/source/funkin/ui/debug/charting/components/ChartEditorNoteSprite.hx @@ -97,7 +97,9 @@ class ChartEditorNoteSprite extends FlxSprite function fetchNoteStyle(noteStyleId:String):NoteStyle { - return NoteStyleRegistry.instance.fetchEntry(noteStyleId) ?? NoteStyleRegistry.instance.fetchDefault(); + var result = NoteStyleRegistry.instance.fetchEntry(noteStyleId); + if (result != null) return result; + return NoteStyleRegistry.instance.fetchDefault(); } @:access(funkin.play.notes.notestyle.NoteStyle) @@ -198,7 +200,12 @@ class ChartEditorNoteSprite extends FlxSprite function get_noteStyle():Null<String> { - return this.noteStyle ?? this.parentState.currentSongNoteStyle; + if (this.noteStyle == null) + { + var result = this.parentState.currentSongNoteStyle; + return result; + } + return this.noteStyle; } function set_noteStyle(value:Null<String>):Null<String> @@ -218,6 +225,7 @@ class ChartEditorNoteSprite extends FlxSprite // Play the appropriate animation for the type, direction, and skin. var dirName:String = overrideData != null ? SongNoteData.buildDirectionName(overrideData) : this.noteData.getDirectionName(); + var noteStyleSuffix:String = this.noteStyle?.toTitleCase() ?? Constants.DEFAULT_NOTE_STYLE.toTitleCase(); var animationName:String = '${baseAnimationName}${dirName}${this.noteStyle.toTitleCase()}'; this.animation.play(animationName); From d4cbe74939425c5a86f0ad752e2620e560380e27 Mon Sep 17 00:00:00 2001 From: EliteMasterEric <ericmyllyoja@gmail.com> Date: Fri, 12 Jul 2024 21:40:46 -0400 Subject: [PATCH 55/64] Smaller fixes tied to note kinds --- source/funkin/data/song/importer/FNFLegacyImporter.hx | 2 ++ source/funkin/modding/PolymodHandler.hx | 2 ++ source/funkin/play/PlayState.hx | 6 +++--- source/funkin/play/character/BaseCharacter.hx | 6 ++++++ source/funkin/play/notes/notekind/NoteKindManager.hx | 1 + source/funkin/play/stage/Bopper.hx | 4 ++-- 6 files changed, 16 insertions(+), 5 deletions(-) diff --git a/source/funkin/data/song/importer/FNFLegacyImporter.hx b/source/funkin/data/song/importer/FNFLegacyImporter.hx index acbb99342..96a1051cc 100644 --- a/source/funkin/data/song/importer/FNFLegacyImporter.hx +++ b/source/funkin/data/song/importer/FNFLegacyImporter.hx @@ -199,6 +199,8 @@ class FNFLegacyImporter { // Handle the dumb logic for mustHitSection. var noteData = note.data; + if (noteData < 0) continue; // Exclude Psych event notes. + if (noteData > (STRUMLINE_SIZE * 2)) noteData = noteData % (2 * STRUMLINE_SIZE); // Handle other engine event notes. // Flip notes if mustHitSection is FALSE (not true lol). if (!mustHitSection) diff --git a/source/funkin/modding/PolymodHandler.hx b/source/funkin/modding/PolymodHandler.hx index c352aa606..59c8707f7 100644 --- a/source/funkin/modding/PolymodHandler.hx +++ b/source/funkin/modding/PolymodHandler.hx @@ -7,6 +7,7 @@ import funkin.data.dialogue.speaker.SpeakerRegistry; import funkin.data.event.SongEventRegistry; import funkin.data.story.level.LevelRegistry; import funkin.data.notestyle.NoteStyleRegistry; +import funkin.play.notes.notekind.NoteKindManager; import funkin.data.song.SongRegistry; import funkin.data.freeplay.player.PlayerRegistry; import funkin.data.stage.StageRegistry; @@ -383,6 +384,7 @@ class PolymodHandler StageRegistry.instance.loadEntries(); CharacterDataParser.loadCharacterCache(); // TODO: Migrate characters to BaseRegistry. + NoteKindManager.loadScripts(); ModuleHandler.loadModuleCache(); } } diff --git a/source/funkin/play/PlayState.hx b/source/funkin/play/PlayState.hx index da343f43f..10546cdbd 100644 --- a/source/funkin/play/PlayState.hx +++ b/source/funkin/play/PlayState.hx @@ -1166,6 +1166,9 @@ class PlayState extends MusicBeatSubState // super.dispatchEvent(event) dispatches event to module scripts. super.dispatchEvent(event); + // Dispatch event to note kind scripts + NoteKindManager.callEvent(event); + // Dispatch event to stage script. ScriptEventDispatcher.callEvent(currentStage, event); @@ -1177,9 +1180,6 @@ class PlayState extends MusicBeatSubState // Dispatch event to conversation script. ScriptEventDispatcher.callEvent(currentConversation, event); - - // Dispatch event to note kind scripts - NoteKindManager.callEvent(event); } /** diff --git a/source/funkin/play/character/BaseCharacter.hx b/source/funkin/play/character/BaseCharacter.hx index 0dab2101a..432881164 100644 --- a/source/funkin/play/character/BaseCharacter.hx +++ b/source/funkin/play/character/BaseCharacter.hx @@ -521,6 +521,9 @@ class BaseCharacter extends Bopper { super.onNoteHit(event); + // If another script cancelled the event, don't do anything. + if (event.eventCanceled) return; + if (event.note.noteData.getMustHitNote() && characterType == BF) { // If the note is from the same strumline, play the sing animation. @@ -553,6 +556,9 @@ class BaseCharacter extends Bopper { super.onNoteMiss(event); + // If another script cancelled the event, don't do anything. + if (event.eventCanceled) return; + if (event.note.noteData.getMustHitNote() && characterType == BF) { // If the note is from the same strumline, play the sing animation. diff --git a/source/funkin/play/notes/notekind/NoteKindManager.hx b/source/funkin/play/notes/notekind/NoteKindManager.hx index 3040c0a96..e17e103d1 100644 --- a/source/funkin/play/notes/notekind/NoteKindManager.hx +++ b/source/funkin/play/notes/notekind/NoteKindManager.hx @@ -5,6 +5,7 @@ import funkin.modding.events.ScriptEvent; import funkin.ui.debug.charting.util.ChartEditorDropdowns; import funkin.data.notestyle.NoteStyleRegistry; import funkin.play.notes.notestyle.NoteStyle; +import funkin.play.notes.notekind.ScriptedNoteKind; import funkin.play.notes.notekind.NoteKind.NoteKindParam; class NoteKindManager diff --git a/source/funkin/play/stage/Bopper.hx b/source/funkin/play/stage/Bopper.hx index 87151de21..fa35b4e15 100644 --- a/source/funkin/play/stage/Bopper.hx +++ b/source/funkin/play/stage/Bopper.hx @@ -45,8 +45,8 @@ class Bopper extends StageProp implements IPlayStateScriptedClass public var idleSuffix(default, set):String = ''; /** - * If this bopper is rendered with pixel art, - * disable anti-aliasing and render at 6x scale. + * If this bopper is rendered with pixel art, disable anti-aliasing. + * @default `false` */ public var isPixel(default, set):Bool = false; From 558ec535320cf87c1ad4e31f3f611758c93a74a8 Mon Sep 17 00:00:00 2001 From: EliteMasterEric <ericmyllyoja@gmail.com> Date: Thu, 18 Jul 2024 23:27:12 -0400 Subject: [PATCH 56/64] Switch songs with no difficulties from an error to a warning. --- source/funkin/play/song/Song.hx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/funkin/play/song/Song.hx b/source/funkin/play/song/Song.hx index 91d35d8fa..147923add 100644 --- a/source/funkin/play/song/Song.hx +++ b/source/funkin/play/song/Song.hx @@ -277,7 +277,7 @@ class Song implements IPlayStateScriptedClass implements IRegistryEntry<SongMeta // If there are no difficulties in the metadata, there's a problem. if (metadata.playData.difficulties.length == 0) { - throw 'Song $id has no difficulties listed in metadata!'; + trace('[WARN] Song $id has no difficulties listed in metadata!'); } // There may be more difficulties in the chart file than in the metadata, From 729745899ede349dad49d58309e84b72b6126192 Mon Sep 17 00:00:00 2001 From: EliteMasterEric <ericmyllyoja@gmail.com> Date: Thu, 18 Jul 2024 23:27:24 -0400 Subject: [PATCH 57/64] Blacklist haxe.Unserializer in scripts. --- source/funkin/modding/PolymodHandler.hx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/source/funkin/modding/PolymodHandler.hx b/source/funkin/modding/PolymodHandler.hx index c352aa606..c5dfcdca3 100644 --- a/source/funkin/modding/PolymodHandler.hx +++ b/source/funkin/modding/PolymodHandler.hx @@ -251,6 +251,10 @@ class PolymodHandler // Lib.load() can load malicious DLLs Polymod.blacklistImport('cpp.Lib'); + // `Unserializer` + // Unserializerr.DEFAULT_RESOLVER.resolveClass() can access blacklisted packages + Polymod.blacklistImport('Unserializer'); + // `polymod.*` // You can probably unblacklist a module for (cls in ClassMacro.listClassesInPackage('polymod')) From 754787553593fe42a2479db09db728192673603d Mon Sep 17 00:00:00 2001 From: EliteMasterEric <ericmyllyoja@gmail.com> Date: Thu, 18 Jul 2024 23:27:41 -0400 Subject: [PATCH 58/64] Allow hiding HUD on launcher builds. --- source/funkin/play/PlayState.hx | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/source/funkin/play/PlayState.hx b/source/funkin/play/PlayState.hx index 8d7d82aab..a39f10d97 100644 --- a/source/funkin/play/PlayState.hx +++ b/source/funkin/play/PlayState.hx @@ -578,7 +578,6 @@ class PlayState extends MusicBeatSubState // TODO: Refactor or document var generatedMusic:Bool = false; - var perfectMode:Bool = false; static final BACKGROUND_COLOR:FlxColor = FlxColor.BLACK; @@ -2610,12 +2609,6 @@ class PlayState extends MusicBeatSubState */ function debugKeyShit():Void { - #if !debug - perfectMode = false; - #else - if (FlxG.keys.justPressed.H) camHUD.visible = !camHUD.visible; - #end - #if CHART_EDITOR_SUPPORTED // Open the stage editor overlaying the current state. if (controls.DEBUG_STAGE) @@ -2647,6 +2640,9 @@ class PlayState extends MusicBeatSubState #end #if (debug || FORCE_DEBUG_VERSION) + // H: Hide the HUD. + if (FlxG.keys.justPressed.H) camHUD.visible = !camHUD.visible; + // 1: End the song immediately. if (FlxG.keys.justPressed.ONE) endSong(true); From 9b8961d4b5c8e150a2c77d39d53566bed5fe6ea7 Mon Sep 17 00:00:00 2001 From: Cameron Taylor <cameron.taylor.ninja@gmail.com> Date: Mon, 22 Jul 2024 22:20:51 -0400 Subject: [PATCH 59/64] assets submod --- assets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets b/assets index 4af95a506..aa1231e8c 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit 4af95a506fc62cd683422dfb9c599877b26c27db +Subproject commit aa1231e8cf2990bb902eac3b37815c010fa9919a From aaab24850df5b3882b2282d5b3c8f6d8174853be Mon Sep 17 00:00:00 2001 From: Cameron Taylor <cameron.taylor.ninja@gmail.com> Date: Mon, 24 Jun 2024 22:21:53 -0400 Subject: [PATCH 60/64] flixel haxelib updates --- hmm.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/hmm.json b/hmm.json index 8eaf24212..07216a351 100644 --- a/hmm.json +++ b/hmm.json @@ -11,14 +11,14 @@ "name": "flixel", "type": "git", "dir": null, - "ref": "a7d8e3bad89a0a3506a4714121f73d8e34522c49", + "ref": "10c2a203c43a78ff1ff26b8368fd736576829d8d", "url": "https://github.com/FunkinCrew/flixel" }, { "name": "flixel-addons", "type": "git", "dir": null, - "ref": "a523c3b56622f0640933944171efed46929e360e", + "ref": "9c6fb47968e894eb36bf10e94725cd7640c49281", "url": "https://github.com/FunkinCrew/flixel-addons" }, { @@ -30,7 +30,7 @@ "name": "flixel-ui", "type": "git", "dir": null, - "ref": "719b4f10d94186ed55f6fef1b6618d32abec8c15", + "ref": "d0afed7293c71ffdb1184751317fc709b44c9056", "url": "https://github.com/HaxeFlixel/flixel-ui" }, { From a15695c3dc8b3c38d8049cb39db4bbf27f2f1d9a Mon Sep 17 00:00:00 2001 From: Cameron Taylor <cameron.taylor.ninja@gmail.com> Date: Fri, 19 Jul 2024 19:13:58 -0400 Subject: [PATCH 61/64] compile dev version of hxcpp --- .github/workflows/build-game.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build-game.yml b/.github/workflows/build-game.yml index 07802557c..ba8167607 100644 --- a/.github/workflows/build-game.yml +++ b/.github/workflows/build-game.yml @@ -45,7 +45,11 @@ jobs: uses: ./.github/actions/setup-haxe with: gh-token: ${{ steps.app_token.outputs.token }} - + - name: Setup HXCPP dev commit + run: | + cd .haxelib/hxcpp/git/tools/hxcpp + haxe compile.hxml + cd ../../../../.. - name: Build game if: ${{ matrix.target == 'windows' }} run: | From 4dfb46955239664439fbb3c64d8bd40a41b1169c Mon Sep 17 00:00:00 2001 From: Cameron Taylor <cameron.taylor.ninja@gmail.com> Date: Mon, 22 Jul 2024 10:12:41 -0400 Subject: [PATCH 62/64] update hxcpp haxelib --- hmm.json | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/hmm.json b/hmm.json index 8eaf24212..387d63f5e 100644 --- a/hmm.json +++ b/hmm.json @@ -99,8 +99,10 @@ }, { "name": "hxcpp", - "type": "haxelib", - "version": "4.3.2" + "type": "git", + "dir": null, + "url": "https://github.com/HaxeFoundation/hxcpp", + "ref": "01cfee282a9a783e10c5a7774a3baaf547e6b0a7" }, { "name": "hxcpp-debug-server", From 3db0cf3e0ab4817f211cd3d8a74c616b15be1239 Mon Sep 17 00:00:00 2001 From: EliteMasterEric <ericmyllyoja@gmail.com> Date: Fri, 26 Jul 2024 00:22:36 -0400 Subject: [PATCH 63/64] Update Polymod to support applying JSON patches in the _merge folder of mods. --- hmm.json | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/hmm.json b/hmm.json index 375fdd0ac..fabd8b51d 100644 --- a/hmm.json +++ b/hmm.json @@ -123,6 +123,20 @@ "ref": "a8c26f18463c98da32f744c214fe02273e1823fa", "url": "https://github.com/FunkinCrew/json2object" }, + { + "name": "jsonpatch", + "type": "git", + "dir": null, + "ref": "f9b83215acd586dc28754b4ae7f69d4c06c3b4d3", + "url": "https://github.com/EliteMasterEric/jsonpatch" + }, + { + "name": "jsonpath", + "type": "git", + "dir": null, + "ref": "7a24193717b36393458c15c0435bb7c4470ecdda", + "url": "https://github.com/EliteMasterEric/jsonpath" + }, { "name": "lime", "type": "git", @@ -169,7 +183,7 @@ "name": "polymod", "type": "git", "dir": null, - "ref": "bfbe30d81601b3543d80dce580108ad6b7e182c7", + "ref": "98945c6c7f5ecde01a32c4623d3515bf012a023a", "url": "https://github.com/larsiusprime/polymod" }, { From f3624f7e76cdd8dcba0762a39ebe1be28389ecef Mon Sep 17 00:00:00 2001 From: EliteMasterEric <ericmyllyoja@gmail.com> Date: Sun, 28 Jul 2024 01:42:09 -0400 Subject: [PATCH 64/64] Fixes for scripted song events, define vocal tracks per variation, display suffixed difficulties properly. --- source/funkin/data/event/SongEventRegistry.hx | 4 +- source/funkin/data/song/CHANGELOG.md | 7 + source/funkin/data/song/SongData.hx | 59 +++--- source/funkin/modding/PolymodHandler.hx | 2 + source/funkin/play/PlayState.hx | 8 +- source/funkin/play/song/Song.hx | 168 ++++++++++++------ source/funkin/ui/freeplay/FreeplayState.hx | 30 +++- source/funkin/ui/freeplay/SongMenuItem.hx | 3 +- 8 files changed, 188 insertions(+), 93 deletions(-) diff --git a/source/funkin/data/event/SongEventRegistry.hx b/source/funkin/data/event/SongEventRegistry.hx index 9b0163557..5ee2d39fa 100644 --- a/source/funkin/data/event/SongEventRegistry.hx +++ b/source/funkin/data/event/SongEventRegistry.hx @@ -46,7 +46,7 @@ class SongEventRegistry if (event != null) { - trace(' Loaded built-in song event: (${event.id})'); + trace(' Loaded built-in song event: ${event.id}'); eventCache.set(event.id, event); } else @@ -59,9 +59,9 @@ class SongEventRegistry static function registerScriptedEvents() { var scriptedEventClassNames:Array<String> = ScriptedSongEvent.listScriptClasses(); + trace('Instantiating ${scriptedEventClassNames.length} scripted song events...'); if (scriptedEventClassNames == null || scriptedEventClassNames.length == 0) return; - trace('Instantiating ${scriptedEventClassNames.length} scripted song events...'); for (eventCls in scriptedEventClassNames) { var event:SongEvent = ScriptedSongEvent.init(eventCls, "UKNOWN"); diff --git a/source/funkin/data/song/CHANGELOG.md b/source/funkin/data/song/CHANGELOG.md index 4f1c66ade..ca36a1d6d 100644 --- a/source/funkin/data/song/CHANGELOG.md +++ b/source/funkin/data/song/CHANGELOG.md @@ -5,6 +5,13 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [2.2.4] +### Added +- Added `playData.characters.opponentVocals` to specify which vocal track(s) to play for the opponent. + - If the value isn't present, it will use the `playData.characters.opponent`, but if it is present, it will be used (even if it's empty, in which case no vocals will be used for the opponent) +- Added `playData.characters.playerVocals` to specify which vocal track(s) to play for the player. + - If the value isn't present, it will use the `playData.characters.player`, but if it is present, it will be used (even if it's empty, in which case no vocals will be used for the player) + ## [2.2.3] ### Added - Added `charter` field to denote authorship of a chart. diff --git a/source/funkin/data/song/SongData.hx b/source/funkin/data/song/SongData.hx index 7bf3f8f19..f487eb54d 100644 --- a/source/funkin/data/song/SongData.hx +++ b/source/funkin/data/song/SongData.hx @@ -529,12 +529,26 @@ class SongCharacterData implements ICloneable<SongCharacterData> @:default([]) public var altInstrumentals:Array<String> = []; - public function new(player:String = '', girlfriend:String = '', opponent:String = '', instrumental:String = '') + @:optional + public var opponentVocals:Null<Array<String>> = null; + + @:optional + public var playerVocals:Null<Array<String>> = null; + + public function new(player:String = '', girlfriend:String = '', opponent:String = '', instrumental:String = '', ?altInstrumentals:Array<String>, + ?opponentVocals:Array<String>, ?playerVocals:Array<String>) { this.player = player; this.girlfriend = girlfriend; this.opponent = opponent; this.instrumental = instrumental; + + this.altInstrumentals = altInstrumentals; + this.opponentVocals = opponentVocals; + this.playerVocals = playerVocals; + + if (opponentVocals == null) this.opponentVocals = [opponent]; + if (playerVocals == null) this.playerVocals = [player]; } public function clone():SongCharacterData @@ -722,18 +736,6 @@ class SongEventDataRaw implements ICloneable<SongEventDataRaw> { return new SongEventDataRaw(this.time, this.eventKind, this.value); } -} - -/** - * Wrap SongEventData in an abstract so we can overload operators. - */ -@:forward(time, eventKind, value, activated, getStepTime, clone) -abstract SongEventData(SongEventDataRaw) from SongEventDataRaw to SongEventDataRaw -{ - public function new(time:Float, eventKind:String, value:Dynamic = null) - { - this = new SongEventDataRaw(time, eventKind, value); - } public function valueAsStruct(?defaultKey:String = "key"):Dynamic { @@ -757,27 +759,27 @@ abstract SongEventData(SongEventDataRaw) from SongEventDataRaw to SongEventDataR } } - public inline function getHandler():Null<SongEvent> + public function getHandler():Null<SongEvent> { return SongEventRegistry.getEvent(this.eventKind); } - public inline function getSchema():Null<SongEventSchema> + public function getSchema():Null<SongEventSchema> { return SongEventRegistry.getEventSchema(this.eventKind); } - public inline function getDynamic(key:String):Null<Dynamic> + public function getDynamic(key:String):Null<Dynamic> { return this.value == null ? null : Reflect.field(this.value, key); } - public inline function getBool(key:String):Null<Bool> + public function getBool(key:String):Null<Bool> { return this.value == null ? null : cast Reflect.field(this.value, key); } - public inline function getInt(key:String):Null<Int> + public function getInt(key:String):Null<Int> { if (this.value == null) return null; var result = Reflect.field(this.value, key); @@ -787,7 +789,7 @@ abstract SongEventData(SongEventDataRaw) from SongEventDataRaw to SongEventDataR return cast result; } - public inline function getFloat(key:String):Null<Float> + public function getFloat(key:String):Null<Float> { if (this.value == null) return null; var result = Reflect.field(this.value, key); @@ -797,17 +799,17 @@ abstract SongEventData(SongEventDataRaw) from SongEventDataRaw to SongEventDataR return cast result; } - public inline function getString(key:String):String + public function getString(key:String):String { return this.value == null ? null : cast Reflect.field(this.value, key); } - public inline function getArray(key:String):Array<Dynamic> + public function getArray(key:String):Array<Dynamic> { return this.value == null ? null : cast Reflect.field(this.value, key); } - public inline function getBoolArray(key:String):Array<Bool> + public function getBoolArray(key:String):Array<Bool> { return this.value == null ? null : cast Reflect.field(this.value, key); } @@ -839,6 +841,19 @@ abstract SongEventData(SongEventDataRaw) from SongEventDataRaw to SongEventDataR return result; } +} + +/** + * Wrap SongEventData in an abstract so we can overload operators. + */ +@:forward(time, eventKind, value, activated, getStepTime, clone, getHandler, getSchema, getDynamic, getBool, getInt, getFloat, getString, getArray, + getBoolArray, buildTooltip, valueAsStruct) +abstract SongEventData(SongEventDataRaw) from SongEventDataRaw to SongEventDataRaw +{ + public function new(time:Float, eventKind:String, value:Dynamic = null) + { + this = new SongEventDataRaw(time, eventKind, value); + } public function clone():SongEventData { diff --git a/source/funkin/modding/PolymodHandler.hx b/source/funkin/modding/PolymodHandler.hx index 9a9ef9e66..5767199ba 100644 --- a/source/funkin/modding/PolymodHandler.hx +++ b/source/funkin/modding/PolymodHandler.hx @@ -234,6 +234,8 @@ class PolymodHandler // NOTE: Scripted classes are automatically aliased to their parent class. Polymod.addImportAlias('flixel.math.FlxPoint', flixel.math.FlxPoint.FlxBasePoint); + Polymod.addImportAlias('funkin.data.event.SongEventSchema', funkin.data.event.SongEventSchema.SongEventSchemaRaw); + // Add blacklisting for prohibited classes and packages. // `Sys` diff --git a/source/funkin/play/PlayState.hx b/source/funkin/play/PlayState.hx index 32b6e7b62..871c784df 100644 --- a/source/funkin/play/PlayState.hx +++ b/source/funkin/play/PlayState.hx @@ -580,6 +580,8 @@ class PlayState extends MusicBeatSubState // TODO: Refactor or document var generatedMusic:Bool = false; + var skipEndingTransition:Bool = false; + static final BACKGROUND_COLOR:FlxColor = FlxColor.BLACK; /** @@ -1926,7 +1928,9 @@ class PlayState extends MusicBeatSubState return; } - FlxG.sound.music.onComplete = endSong.bind(false); + FlxG.sound.music.onComplete = function() { + endSong(skipEndingTransition); + }; // A negative instrumental offset means the song skips the first few milliseconds of the track. // This just gets added into the startTimestamp behavior so we don't need to do anything extra. FlxG.sound.music.play(true, startTimestamp - Conductor.instance.instrumentalOffset); @@ -1965,7 +1969,7 @@ class PlayState extends MusicBeatSubState if (vocals == null) return; // Skip this if the music is paused (GameOver, Pause menu, start-of-song offset, etc.) - if (!FlxG.sound.music.playing) return; + if (!(FlxG?.sound?.music?.playing ?? false)) return; vocals.pause(); diff --git a/source/funkin/play/song/Song.hx b/source/funkin/play/song/Song.hx index 147923add..2e7e13f51 100644 --- a/source/funkin/play/song/Song.hx +++ b/source/funkin/play/song/Song.hx @@ -494,6 +494,24 @@ class Song implements IPlayStateScriptedClass implements IRegistryEntry<SongMeta return diffFiltered; } + public function listSuffixedDifficulties(variationIds:Array<String>, ?showLocked:Bool, ?showHidden:Bool):Array<String> + { + var result = []; + + for (variation in variationIds) + { + var difficulties = listDifficulties(variation, null, showLocked, showHidden); + for (difficulty in difficulties) + { + var suffixedDifficulty = (variation != Constants.DEFAULT_VARIATION + && variation != 'erect') ? '$difficulty-${variation}' : difficulty; + result.push(suffixedDifficulty); + } + } + + return result; + } + public function hasDifficulty(diffId:String, ?variationId:String, ?variationIds:Array<String>):Bool { if (variationIds == null) variationIds = []; @@ -706,10 +724,11 @@ class SongDifficulty * Cache the vocals for a given character. * @param id The character we are about to play. */ - public inline function cacheVocals():Void + public function cacheVocals():Void { for (voice in buildVoiceList()) { + trace('Caching vocal track: $voice'); FlxG.sound.cache(voice); } } @@ -721,6 +740,20 @@ class SongDifficulty * @param id The character we are about to play. */ public function buildVoiceList():Array<String> + { + var result:Array<String> = []; + result = result.concat(buildPlayerVoiceList()); + result = result.concat(buildOpponentVoiceList()); + if (result.length == 0) + { + var suffix:String = (variation != null && variation != '' && variation != 'default') ? '-$variation' : ''; + // Try to use `Voices.ogg` if no other voices are found. + if (Assets.exists(Paths.voices(this.song.id, ''))) result.push(Paths.voices(this.song.id, '$suffix')); + } + return result; + } + + public function buildPlayerVoiceList():Array<String> { var suffix:String = (variation != null && variation != '' && variation != 'default') ? '-$variation' : ''; @@ -728,62 +761,88 @@ class SongDifficulty // For example, if `Voices-bf-car-erect.ogg` does not exist, check for `Voices-bf-erect.ogg`. // Then, check for `Voices-bf-car.ogg`, then `Voices-bf.ogg`. - var playerId:String = characters.player; - var voicePlayer:String = Paths.voices(this.song.id, '-$playerId$suffix'); - while (voicePlayer != null && !Assets.exists(voicePlayer)) + if (characters.playerVocals == null) { - // Remove the last suffix. - // For example, bf-car becomes bf. - playerId = playerId.split('-').slice(0, -1).join('-'); - // Try again. - voicePlayer = playerId == '' ? null : Paths.voices(this.song.id, '-${playerId}$suffix'); - } - if (voicePlayer == null) - { - // Try again without $suffix. - playerId = characters.player; - voicePlayer = Paths.voices(this.song.id, '-${playerId}'); - while (voicePlayer != null && !Assets.exists(voicePlayer)) + var playerId:String = characters.player; + var playerVoice:String = Paths.voices(this.song.id, '-${playerId}$suffix'); + + while (playerVoice != null && !Assets.exists(playerVoice)) { // Remove the last suffix. + // For example, bf-car becomes bf. playerId = playerId.split('-').slice(0, -1).join('-'); // Try again. - voicePlayer = playerId == '' ? null : Paths.voices(this.song.id, '-${playerId}$suffix'); + playerVoice = playerId == '' ? null : Paths.voices(this.song.id, '-${playerId}$suffix'); + } + if (playerVoice == null) + { + // Try again without $suffix. + playerId = characters.player; + playerVoice = Paths.voices(this.song.id, '-${playerId}'); + while (playerVoice != null && !Assets.exists(playerVoice)) + { + // Remove the last suffix. + playerId = playerId.split('-').slice(0, -1).join('-'); + // Try again. + playerVoice = playerId == '' ? null : Paths.voices(this.song.id, '-${playerId}$suffix'); + } } - } - var opponentId:String = characters.opponent; - var voiceOpponent:String = Paths.voices(this.song.id, '-${opponentId}$suffix'); - while (voiceOpponent != null && !Assets.exists(voiceOpponent)) - { - // Remove the last suffix. - opponentId = opponentId.split('-').slice(0, -1).join('-'); - // Try again. - voiceOpponent = opponentId == '' ? null : Paths.voices(this.song.id, '-${opponentId}$suffix'); + return playerVoice != null ? [playerVoice] : []; } - if (voiceOpponent == null) + else { - // Try again without $suffix. - opponentId = characters.opponent; - voiceOpponent = Paths.voices(this.song.id, '-${opponentId}'); - while (voiceOpponent != null && !Assets.exists(voiceOpponent)) + // The metadata explicitly defines the list of voices. + var playerIds:Array<String> = characters?.playerVocals ?? [characters.player]; + var playerVoices:Array<String> = playerIds.map((id) -> Paths.voices(this.song.id, '-$id$suffix')); + + return playerVoices; + } + } + + public function buildOpponentVoiceList():Array<String> + { + var suffix:String = (variation != null && variation != '' && variation != 'default') ? '-$variation' : ''; + + // Automatically resolve voices by removing suffixes. + // For example, if `Voices-bf-car-erect.ogg` does not exist, check for `Voices-bf-erect.ogg`. + // Then, check for `Voices-bf-car.ogg`, then `Voices-bf.ogg`. + + if (characters.opponentVocals == null) + { + var opponentId:String = characters.opponent; + var opponentVoice:String = Paths.voices(this.song.id, '-${opponentId}$suffix'); + while (opponentVoice != null && !Assets.exists(opponentVoice)) { // Remove the last suffix. opponentId = opponentId.split('-').slice(0, -1).join('-'); // Try again. - voiceOpponent = opponentId == '' ? null : Paths.voices(this.song.id, '-${opponentId}$suffix'); + opponentVoice = opponentId == '' ? null : Paths.voices(this.song.id, '-${opponentId}$suffix'); + } + if (opponentVoice == null) + { + // Try again without $suffix. + opponentId = characters.opponent; + opponentVoice = Paths.voices(this.song.id, '-${opponentId}'); + while (opponentVoice != null && !Assets.exists(opponentVoice)) + { + // Remove the last suffix. + opponentId = opponentId.split('-').slice(0, -1).join('-'); + // Try again. + opponentVoice = opponentId == '' ? null : Paths.voices(this.song.id, '-${opponentId}$suffix'); + } } - } - var result:Array<String> = []; - if (voicePlayer != null) result.push(voicePlayer); - if (voiceOpponent != null) result.push(voiceOpponent); - if (voicePlayer == null && voiceOpponent == null) - { - // Try to use `Voices.ogg` if no other voices are found. - if (Assets.exists(Paths.voices(this.song.id, ''))) result.push(Paths.voices(this.song.id, '$suffix')); + return opponentVoice != null ? [opponentVoice] : []; + } + else + { + // The metadata explicitly defines the list of voices. + var opponentIds:Array<String> = characters?.opponentVocals ?? [characters.opponent]; + var opponentVoices:Array<String> = opponentIds.map((id) -> Paths.voices(this.song.id, '-$id$suffix')); + + return opponentVoices; } - return result; } /** @@ -795,26 +854,19 @@ class SongDifficulty { var result:VoicesGroup = new VoicesGroup(); - var voiceList:Array<String> = buildVoiceList(); - - if (voiceList.length == 0) - { - trace('Could not find any voices for song ${this.song.id}'); - return result; - } + var playerVoiceList:Array<String> = this.buildPlayerVoiceList(); + var opponentVoiceList:Array<String> = this.buildOpponentVoiceList(); // Add player vocals. - if (voiceList[0] != null) result.addPlayerVoice(FunkinSound.load(voiceList[0])); - // Add opponent vocals. - if (voiceList[1] != null) result.addOpponentVoice(FunkinSound.load(voiceList[1])); - - // Add additional vocals. - if (voiceList.length > 2) + for (playerVoice in playerVoiceList) { - for (i in 2...voiceList.length) - { - result.add(FunkinSound.load(Assets.getSound(voiceList[i]))); - } + result.addPlayerVoice(FunkinSound.load(playerVoice)); + } + + // Add opponent vocals. + for (opponentVoice in opponentVoiceList) + { + result.addOpponentVoice(FunkinSound.load(opponentVoice)); } result.playerVoicesOffset = offsets.getVocalOffset(characters.player); diff --git a/source/funkin/ui/freeplay/FreeplayState.hx b/source/funkin/ui/freeplay/FreeplayState.hx index dc42bd651..2341f04a6 100644 --- a/source/funkin/ui/freeplay/FreeplayState.hx +++ b/source/funkin/ui/freeplay/FreeplayState.hx @@ -339,7 +339,7 @@ class FreeplayState extends MusicBeatSubState // Only display songs which actually have available difficulties for the current character. var displayedVariations = song.getVariationsByCharacter(currentCharacter); trace('Displayed Variations (${songId}): $displayedVariations'); - var availableDifficultiesForSong:Array<String> = song.listDifficulties(displayedVariations, false); + var availableDifficultiesForSong:Array<String> = song.listSuffixedDifficulties(displayedVariations, false, false); trace('Available Difficulties: $availableDifficultiesForSong'); if (availableDifficultiesForSong.length == 0) continue; @@ -1120,7 +1120,7 @@ class FreeplayState extends MusicBeatSubState // NOW we can interact with the menu busy = false; - grpCapsules.members[curSelected].sparkle.alpha = 0.7; + capsule.sparkle.alpha = 0.7; playCurSongPreview(capsule); }, null); @@ -1674,6 +1674,9 @@ class FreeplayState extends MusicBeatSubState songCapsule.init(null, null, null); } } + + // Reset the song preview in case we changed variations (normal->erect etc) + playCurSongPreview(); } // Set the album graphic and play the animation if relevant. @@ -1912,8 +1915,10 @@ class FreeplayState extends MusicBeatSubState } } - public function playCurSongPreview(daSongCapsule:SongMenuItem):Void + public function playCurSongPreview(?daSongCapsule:SongMenuItem):Void { + if (daSongCapsule == null) daSongCapsule = grpCapsules.members[curSelected]; + if (curSelected == 0) { FunkinSound.playMusic('freeplayRandom', @@ -2145,7 +2150,7 @@ class FreeplaySongData function updateValues(variations:Array<String>):Void { - this.songDifficulties = song.listDifficulties(null, variations, false, false); + this.songDifficulties = song.listSuffixedDifficulties(variations, false, false); if (!this.songDifficulties.contains(currentDifficulty)) currentDifficulty = Constants.DEFAULT_DIFFICULTY; var songDifficulty:SongDifficulty = song.getDifficulty(currentDifficulty, null, variations); @@ -2207,15 +2212,26 @@ class DifficultySprite extends FlxSprite difficultyId = diffId; - if (Assets.exists(Paths.file('images/freeplay/freeplay${diffId}.xml'))) + var assetDiffId:String = diffId; + while (!Assets.exists(Paths.image('freeplay/freeplay${assetDiffId}'))) { - this.frames = Paths.getSparrowAtlas('freeplay/freeplay${diffId}'); + // Remove the last suffix of the difficulty id until we find an asset or there are no more suffixes. + var assetDiffIdParts:Array<String> = assetDiffId.split('-'); + assetDiffIdParts.pop(); + if (assetDiffIdParts.length == 0) break; + assetDiffId = assetDiffIdParts.join('-'); + } + + // Check for an XML to use an animation instead of an image. + if (Assets.exists(Paths.file('images/freeplay/freeplay${assetDiffId}.xml'))) + { + this.frames = Paths.getSparrowAtlas('freeplay/freeplay${assetDiffId}'); this.animation.addByPrefix('idle', 'idle0', 24, true); if (Preferences.flashingLights) this.animation.play('idle'); } else { - this.loadGraphic(Paths.image('freeplay/freeplay' + diffId)); + this.loadGraphic(Paths.image('freeplay/freeplay' + assetDiffId)); } } } diff --git a/source/funkin/ui/freeplay/SongMenuItem.hx b/source/funkin/ui/freeplay/SongMenuItem.hx index 2eec83223..b4409d377 100644 --- a/source/funkin/ui/freeplay/SongMenuItem.hx +++ b/source/funkin/ui/freeplay/SongMenuItem.hx @@ -162,7 +162,7 @@ class SongMenuItem extends FlxSpriteGroup sparkle = new FlxSprite(ranking.x, ranking.y); sparkle.frames = Paths.getSparrowAtlas('freeplay/sparkle'); - sparkle.animation.addByPrefix('sparkle', 'sparkle', 24, false); + sparkle.animation.addByPrefix('sparkle', 'sparkle Export0', 24, false); sparkle.animation.play('sparkle', true); sparkle.scale.set(0.8, 0.8); sparkle.blend = BlendMode.ADD; @@ -523,7 +523,6 @@ class SongMenuItem extends FlxSpriteGroup checkWeek(songData?.songId); } - var frameInTicker:Float = 0; var frameInTypeBeat:Int = 0;