From 3f2d1b4c1b188bba6fbe5ad0413abebf43db3bfa Mon Sep 17 00:00:00 2001
From: EliteMasterEric <ericmyllyoja@gmail.com>
Date: Thu, 14 Dec 2023 17:34:02 -0500
Subject: [PATCH 1/4] Update haxelibs, add flixel-text-input to fix overlapping
 text

---
 .vscode/settings.json                               |  3 +--
 Project.xml                                         | 10 ++++++----
 hmm.json                                            | 13 +++++++++----
 .../funkin/play/character/MultiSparrowCharacter.hx  |  2 +-
 4 files changed, 17 insertions(+), 11 deletions(-)

diff --git a/.vscode/settings.json b/.vscode/settings.json
index 92d49c3d4..cefbadcf6 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -4,8 +4,7 @@
     "editor.formatOnSave": true,
     "editor.formatOnPaste": true,
     "editor.codeActionsOnSave": {
-      // Compilation server issues can cause auto-cleanup to remove valid imports.
-      "source.organizeImports": false
+      "source.organizeImports": "never"
     },
     "editor.defaultFormatter": "nadako.vshaxe",
     "editor.tabSize": 2
diff --git a/Project.xml b/Project.xml
index 4c0ffdce7..e0677b026 100644
--- a/Project.xml
+++ b/Project.xml
@@ -99,18 +99,20 @@
 
 	<haxelib name="flixel-addons" /> <!-- Additional utilities for Flixel -->
 	<haxelib name="hscript" /> <!-- Scripting -->
-	<haxelib name="flixel-ui" /> <!-- UI framework (deprecate this? -->
+	<haxelib name="flixel-ui" /> <!-- UI framework (DEPRECATED) -->
 	<haxelib name="haxeui-core" /> <!-- UI framework -->
 	<haxelib name="haxeui-flixel" /> <!-- Integrate HaxeUI with Flixel -->
+	<haxelib name="flixel-text-input" /> <!-- Improved text field rendering for HaxeUI -->
 	<haxelib name="polymod" /> <!-- Modding framework -->
 	<haxelib name="flxanimate" /> <!-- Texture atlas rendering -->
 	<haxelib name="hxCodec" /> <!-- Video playback -->
 
 	<haxelib name="json2object" /> <!-- JSON parsing -->
-	<haxelib name="tink_json" /> <!-- JSON parsing -->
+	<haxelib name="tink_json" /> <!-- JSON parsing (DEPRECATED) -->
+	<haxelib name="thx.semver" /> <!-- Version string handling -->
+
+	<haxelib name="hxcpp-debug-server" if="desktop debug" /> <!-- VSCode debug support -->
 
-	<haxelib name="thx.semver" />
-	<haxelib name="hxcpp-debug-server" if="desktop debug" />
 	<!--Disable the Flixel core focus lost screen-->
 	<haxedef name="FLX_NO_FOCUS_LOST_SCREEN" />
 	<!--Disable the Flixel core debugger. Automatically gets set whenever you compile in release mode!-->
diff --git a/hmm.json b/hmm.json
index a10eed1a6..b85413bae 100644
--- a/hmm.json
+++ b/hmm.json
@@ -11,7 +11,7 @@
       "name": "flixel",
       "type": "git",
       "dir": null,
-      "ref": "da04cbda49a4c5eebe93fb61296dbaf4f0f1b556",
+      "ref": "9bdea914f3d0485b9b3ec158f28875b5ac95d476",
       "url": "https://github.com/EliteMasterEric/flixel"
     },
     {
@@ -21,6 +21,11 @@
       "ref": "c8c41e26d463aaf2edc0582fb23b6e228235bd16",
       "url": "https://github.com/EliteMasterEric/flixel-addons"
     },
+    {
+      "name": "flixel-text-input",
+      "type": "haxelib",
+      "version": "1.1.0"
+    },
     {
       "name": "flixel-ui",
       "type": "git",
@@ -32,8 +37,8 @@
       "name": "flxanimate",
       "type": "git",
       "dir": null,
-      "ref": "dd2903f7dc7024335b981edf2a770760cec912e1",
-      "url": "https://github.com/ninjamuffin99/flxanimate"
+      "ref": "d7c5621be742e2c98d523dfe5af7528835eaff1e",
+      "url": "https://github.com/EliteMasterEric/flxanimate"
     },
     {
       "name": "format",
@@ -158,4 +163,4 @@
       "version": "0.11.0"
     }
   ]
-}
+}
\ No newline at end of file
diff --git a/source/funkin/play/character/MultiSparrowCharacter.hx b/source/funkin/play/character/MultiSparrowCharacter.hx
index 968f613ff..0fc07399c 100644
--- a/source/funkin/play/character/MultiSparrowCharacter.hx
+++ b/source/funkin/play/character/MultiSparrowCharacter.hx
@@ -205,7 +205,7 @@ class MultiSparrowCharacter extends BaseCharacter
       graphic = value.parent;
       this.frames = value;
       this.frame = value.getByIndex(0);
-      this.numFrames = value.numFrames;
+      // this.numFrames = value.numFrames;
       resetHelpers();
       this.bakedRotationAngle = 0;
       this.animation.frameIndex = 0;

From 8dd6f29e2682aa7d9828ee62a9b44edeb10c3ec4 Mon Sep 17 00:00:00 2001
From: EliteMasterEric <ericmyllyoja@gmail.com>
Date: Fri, 15 Dec 2023 04:34:59 -0500
Subject: [PATCH 2/4] Move all haxelib forks to the FunkinCrew organization.

---
 hmm.json | 26 +++++++++++++-------------
 1 file changed, 13 insertions(+), 13 deletions(-)

diff --git a/hmm.json b/hmm.json
index b85413bae..96ee75bc1 100644
--- a/hmm.json
+++ b/hmm.json
@@ -12,14 +12,14 @@
       "type": "git",
       "dir": null,
       "ref": "9bdea914f3d0485b9b3ec158f28875b5ac95d476",
-      "url": "https://github.com/EliteMasterEric/flixel"
+      "url": "https://github.com/FunkinCrew/flixel"
     },
     {
       "name": "flixel-addons",
       "type": "git",
       "dir": null,
-      "ref": "c8c41e26d463aaf2edc0582fb23b6e228235bd16",
-      "url": "https://github.com/EliteMasterEric/flixel-addons"
+      "ref": "fd3aecdeb5635fa0428dffee204fc78fc26b5885",
+      "url": "https://github.com/FunkinCrew/flixel-addons"
     },
     {
       "name": "flixel-text-input",
@@ -38,7 +38,7 @@
       "type": "git",
       "dir": null,
       "ref": "d7c5621be742e2c98d523dfe5af7528835eaff1e",
-      "url": "https://github.com/EliteMasterEric/flxanimate"
+      "url": "https://github.com/FunkinCrew/flxanimate"
     },
     {
       "name": "format",
@@ -54,14 +54,14 @@
       "name": "haxeui-core",
       "type": "git",
       "dir": null,
-      "ref": "032192e849cdb7d1070c0a3241c58ee555ffaccc",
+      "ref": "7021f1fbab928268d9196a73e7f47461ca3c3e4d",
       "url": "https://github.com/haxeui/haxeui-core"
     },
     {
       "name": "haxeui-flixel",
       "type": "git",
       "dir": null,
-      "ref": "d90758b229d05206400df867d333c79d9fdbd478",
+      "ref": "26b6bb132c92dfa9b77b4a61eaeda8f9a9efda98",
       "url": "https://github.com/haxeui/haxeui-flixel"
     },
     {
@@ -100,15 +100,15 @@
       "name": "json2object",
       "type": "git",
       "dir": null,
-      "ref": "f4df19cfa196f85eece55c3367021fc965f1fa9a",
-      "url": "https://github.com/EliteMasterEric/json2object"
+      "ref": "a0a78b60c41e47bae8bfa422488a199a58b4474e",
+      "url": "https://github.com/FunkinCrew/json2object"
     },
     {
       "name": "lime",
       "type": "git",
       "dir": null,
       "ref": "737b86f121cdc90358d59e2e527934f267c94a2c",
-      "url": "https://github.com/EliteMasterEric/lime"
+      "url": "https://github.com/FunkinCrew/lime"
     },
     {
       "name": "mconsole",
@@ -129,21 +129,21 @@
       "type": "git",
       "dir": "src",
       "ref": "master",
-      "url": "https://github.com/EliteMasterEric/mockatoo"
+      "url": "https://github.com/FunkinCrew/mockatoo"
     },
     {
       "name": "munit",
       "type": "git",
       "dir": "src",
       "ref": "master",
-      "url": "https://github.com/EliteMasterEric/MassiveUnit"
+      "url": "https://github.com/FunkinCrew/MassiveUnit"
     },
     {
       "name": "openfl",
       "type": "git",
       "dir": null,
       "ref": "f229d76361c7e31025a048fe7909847f75bb5d5e",
-      "url": "https://github.com/EliteMasterEric/openfl"
+      "url": "https://github.com/FunkinCrew/openfl"
     },
     {
       "name": "polymod",
@@ -163,4 +163,4 @@
       "version": "0.11.0"
     }
   ]
-}
\ No newline at end of file
+}

From 88ca58f9e22ed96d835ef28cd42dfc2aaa8997e0 Mon Sep 17 00:00:00 2001
From: EliteMasterEric <ericmyllyoja@gmail.com>
Date: Fri, 15 Dec 2023 21:09:01 -0500
Subject: [PATCH 3/4] Fixes for updated HaxeUI and Flixel.

---
 source/funkin/play/PlayState.hx               | 21 +----
 .../ui/debug/charting/ChartEditorState.hx     |  4 +-
 .../dialogs/ChartEditorAboutDialog.hx         |  8 +-
 .../charting/dialogs/ChartEditorBaseDialog.hx |  8 +-
 .../charting/dialogs/ChartEditorBaseMenu.hx   |  6 +-
 .../ChartEditorCharacterIconSelectorMenu.hx   | 28 +++----
 .../dialogs/ChartEditorUploadChartDialog.hx   | 21 ++---
 .../dialogs/ChartEditorWelcomeDialog.hx       | 26 +++----
 .../toolboxes/ChartEditorBaseToolbox.hx       |  6 +-
 .../toolboxes/ChartEditorMetadataToolbox.hx   | 78 +++++++++----------
 source/funkin/ui/freeplay/FreeplayState.hx    |  5 +-
 11 files changed, 99 insertions(+), 112 deletions(-)

diff --git a/source/funkin/play/PlayState.hx b/source/funkin/play/PlayState.hx
index 81757bcae..e0932e756 100644
--- a/source/funkin/play/PlayState.hx
+++ b/source/funkin/play/PlayState.hx
@@ -1097,23 +1097,6 @@ class PlayState extends MusicBeatSubState
   }
   #end
 
-  /**
-   * This function is called whenever Flixel switches switching to a new FlxState.
-   * @return Whether to actually switch to the new state.
-   */
-  @:haxe.warning("-WDeprecated")
-  override function switchTo(nextState:FlxState):Bool
-  {
-    var result:Bool = super.switchTo(nextState);
-
-    if (result)
-    {
-      performCleanup();
-    }
-
-    return result;
-  }
-
   /**
    * Removes any references to the current stage, then clears the stage cache,
    * then reloads all the stages.
@@ -1251,7 +1234,7 @@ class PlayState extends MusicBeatSubState
     return true;
   }
 
-  override function destroy():Void
+  public override function destroy():Void
   {
     if (currentConversation != null)
     {
@@ -1259,6 +1242,8 @@ class PlayState extends MusicBeatSubState
       currentConversation.kill();
     }
 
+    performCleanup();
+
     super.destroy();
   }
 
diff --git a/source/funkin/ui/debug/charting/ChartEditorState.hx b/source/funkin/ui/debug/charting/ChartEditorState.hx
index 78de08fdf..fa55750bf 100644
--- a/source/funkin/ui/debug/charting/ChartEditorState.hx
+++ b/source/funkin/ui/debug/charting/ChartEditorState.hx
@@ -2675,14 +2675,16 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
    * Open the backups folder in the file explorer.
    * Don't call this on HTML5.
    */
-  function openBackupsFolder(?_):Void
+  function openBackupsFolder(?_):Bool
   {
     #if sys
     // TODO: Is there a way to open a folder and highlight a file in it?
     var absoluteBackupsPath:String = Path.join([Sys.getCwd(), ChartEditorImportExportHandler.BACKUPS_PATH]);
     WindowUtil.openFolder(absoluteBackupsPath);
+    return true;
     #else
     trace('No file system access, cannot open backups folder.');
+    return false;
     #end
   }
 
diff --git a/source/funkin/ui/debug/charting/dialogs/ChartEditorAboutDialog.hx b/source/funkin/ui/debug/charting/dialogs/ChartEditorAboutDialog.hx
index e6f57c49f..8b55be540 100644
--- a/source/funkin/ui/debug/charting/dialogs/ChartEditorAboutDialog.hx
+++ b/source/funkin/ui/debug/charting/dialogs/ChartEditorAboutDialog.hx
@@ -5,14 +5,14 @@ import funkin.ui.debug.charting.dialogs.ChartEditorBaseDialog.DialogParams;
 @:build(haxe.ui.ComponentBuilder.build("assets/exclude/data/ui/chart-editor/dialogs/about.xml"))
 class ChartEditorAboutDialog extends ChartEditorBaseDialog
 {
-  public function new(state2:ChartEditorState, params2:DialogParams)
+  public function new(chartEditorState2:ChartEditorState, params2:DialogParams)
   {
-    super(state2, params2);
+    super(chartEditorState2, params2);
   }
 
-  public static function build(state:ChartEditorState, ?closable:Bool, ?modal:Bool):ChartEditorAboutDialog
+  public static function build(chartEditorState:ChartEditorState, ?closable:Bool, ?modal:Bool):ChartEditorAboutDialog
   {
-    var dialog = new ChartEditorAboutDialog(state,
+    var dialog = new ChartEditorAboutDialog(chartEditorState,
       {
         closable: closable ?? true,
         modal: modal ?? true
diff --git a/source/funkin/ui/debug/charting/dialogs/ChartEditorBaseDialog.hx b/source/funkin/ui/debug/charting/dialogs/ChartEditorBaseDialog.hx
index 6f76e543e..5b7cb15e1 100644
--- a/source/funkin/ui/debug/charting/dialogs/ChartEditorBaseDialog.hx
+++ b/source/funkin/ui/debug/charting/dialogs/ChartEditorBaseDialog.hx
@@ -11,16 +11,16 @@ import haxe.ui.core.Component;
 @:access(funkin.ui.debug.charting.ChartEditorState)
 class ChartEditorBaseDialog extends Dialog
 {
-  var state:ChartEditorState;
+  var chartEditorState:ChartEditorState;
   var params:DialogParams;
 
   var locked:Bool = false;
 
-  public function new(state:ChartEditorState, params:DialogParams)
+  public function new(chartEditorState:ChartEditorState, params:DialogParams)
   {
     super();
 
-    this.state = state;
+    this.chartEditorState = chartEditorState;
     this.params = params;
 
     this.destroyOnClose = true;
@@ -47,7 +47,7 @@ class ChartEditorBaseDialog extends Dialog
    */
   public function onClose(event:DialogEvent):Void
   {
-    state.isHaxeUIDialogOpen = false;
+    chartEditorState.isHaxeUIDialogOpen = false;
   }
 
   /**
diff --git a/source/funkin/ui/debug/charting/dialogs/ChartEditorBaseMenu.hx b/source/funkin/ui/debug/charting/dialogs/ChartEditorBaseMenu.hx
index cb4cb447b..19ca2535c 100644
--- a/source/funkin/ui/debug/charting/dialogs/ChartEditorBaseMenu.hx
+++ b/source/funkin/ui/debug/charting/dialogs/ChartEditorBaseMenu.hx
@@ -11,13 +11,13 @@ import haxe.ui.containers.menus.Menu;
 @:access(funkin.ui.debug.charting.ChartEditorState)
 class ChartEditorBaseMenu extends Menu
 {
-  var state:ChartEditorState;
+  var chartEditorState:ChartEditorState;
 
-  public function new(state:ChartEditorState)
+  public function new(chartEditorState:ChartEditorState)
   {
     super();
 
-    this.state = state;
+    this.chartEditorState = chartEditorState;
 
     // this.destroyOnClose = true;
   }
diff --git a/source/funkin/ui/debug/charting/dialogs/ChartEditorCharacterIconSelectorMenu.hx b/source/funkin/ui/debug/charting/dialogs/ChartEditorCharacterIconSelectorMenu.hx
index d7e9c259b..eb60cb6db 100644
--- a/source/funkin/ui/debug/charting/dialogs/ChartEditorCharacterIconSelectorMenu.hx
+++ b/source/funkin/ui/debug/charting/dialogs/ChartEditorCharacterIconSelectorMenu.hx
@@ -24,9 +24,9 @@ class ChartEditorCharacterIconSelectorMenu extends ChartEditorBaseMenu
   public var charSelectScroll:ScrollView;
   public var charIconName:Label;
 
-  public function new(state2:ChartEditorState, charType:CharacterType, lockPosition:Bool = false)
+  public function new(chartEditorState2:ChartEditorState, charType:CharacterType, lockPosition:Bool = false)
   {
-    super(state2);
+    super(chartEditorState2);
 
     initialize(charType, lockPosition);
     this.alpha = 0;
@@ -38,17 +38,17 @@ class ChartEditorCharacterIconSelectorMenu extends ChartEditorBaseMenu
   {
     var currentCharId:String = switch (charType)
     {
-      case BF: state.currentSongMetadata.playData.characters.player;
-      case GF: state.currentSongMetadata.playData.characters.girlfriend;
-      case DAD: state.currentSongMetadata.playData.characters.opponent;
+      case BF: chartEditorState.currentSongMetadata.playData.characters.player;
+      case GF: chartEditorState.currentSongMetadata.playData.characters.girlfriend;
+      case DAD: chartEditorState.currentSongMetadata.playData.characters.opponent;
       default: throw 'Invalid charType: ' + charType;
     };
 
     // Position this menu.
     var targetHealthIcon:Null<HealthIcon> = switch (charType)
     {
-      case BF: state.healthIconBF;
-      case DAD: state.healthIconDad;
+      case BF: chartEditorState.healthIconBF;
+      case DAD: chartEditorState.healthIconDad;
       default: null;
     };
 
@@ -101,14 +101,14 @@ class ChartEditorCharacterIconSelectorMenu extends ChartEditorBaseMenu
       charButton.onClick = _ -> {
         switch (charType)
         {
-          case BF: state.currentSongMetadata.playData.characters.player = charId;
-          case GF: state.currentSongMetadata.playData.characters.girlfriend = charId;
-          case DAD: state.currentSongMetadata.playData.characters.opponent = charId;
+          case BF: chartEditorState.currentSongMetadata.playData.characters.player = charId;
+          case GF: chartEditorState.currentSongMetadata.playData.characters.girlfriend = charId;
+          case DAD: chartEditorState.currentSongMetadata.playData.characters.opponent = charId;
           default: throw 'Invalid charType: ' + charType;
         };
 
-        state.healthIconsDirty = true;
-        state.refreshToolbox(ChartEditorState.CHART_EDITOR_TOOLBOX_METADATA_LAYOUT);
+        chartEditorState.healthIconsDirty = true;
+        chartEditorState.refreshToolbox(ChartEditorState.CHART_EDITOR_TOOLBOX_METADATA_LAYOUT);
       };
 
       charButton.onMouseOver = _ -> {
@@ -123,9 +123,9 @@ class ChartEditorCharacterIconSelectorMenu extends ChartEditorBaseMenu
     charIconName.text = defaultText;
   }
 
-  public static function build(state2:ChartEditorState, charType:CharacterType, lockPosition:Bool = false):ChartEditorCharacterIconSelectorMenu
+  public static function build(chartEditorState:ChartEditorState, charType:CharacterType, lockPosition:Bool = false):ChartEditorCharacterIconSelectorMenu
   {
-    var menu = new ChartEditorCharacterIconSelectorMenu(state2, charType, lockPosition);
+    var menu = new ChartEditorCharacterIconSelectorMenu(chartEditorState, charType, lockPosition);
 
     Screen.instance.addComponent(menu);
 
diff --git a/source/funkin/ui/debug/charting/dialogs/ChartEditorUploadChartDialog.hx b/source/funkin/ui/debug/charting/dialogs/ChartEditorUploadChartDialog.hx
index 4b7a950be..5b84148c6 100644
--- a/source/funkin/ui/debug/charting/dialogs/ChartEditorUploadChartDialog.hx
+++ b/source/funkin/ui/debug/charting/dialogs/ChartEditorUploadChartDialog.hx
@@ -64,12 +64,12 @@ class ChartEditorUploadChartDialog extends ChartEditorBaseDialog
     if (event.button != DialogButton.APPLY && !this.closable)
     {
       // User cancelled the wizard! Back to the welcome dialog.
-      state.openWelcomeDialog(this.closable);
+      chartEditorState.openWelcomeDialog(this.closable);
     }
 
     for (dropTarget in dropHandlers)
     {
-      state.removeDropHandler(dropTarget);
+      chartEditorState.removeDropHandler(dropTarget);
     }
   }
 
@@ -111,20 +111,21 @@ class ChartEditorUploadChartDialog extends ChartEditorBaseDialog
 
     try
     {
-      var result:Null<Array<String>> = ChartEditorImportExportHandler.loadFromFNFCPath(state, path.toString());
+      var result:Null<Array<String>> = ChartEditorImportExportHandler.loadFromFNFCPath(chartEditorState, path.toString());
       if (result != null)
       {
-        state.success('Loaded Chart', result.length == 0 ? 'Loaded chart (${path.toString()})' : 'Loaded chart (${path.toString()})\n${result.join("\n")}');
+        chartEditorState.success('Loaded Chart',
+          result.length == 0 ? 'Loaded chart (${path.toString()})' : 'Loaded chart (${path.toString()})\n${result.join("\n")}');
         this.hideDialog(DialogButton.APPLY);
       }
       else
       {
-        state.failure('Failed to Load Chart', 'Failed to load chart (${path.toString()})');
+        chartEditorState.failure('Failed to Load Chart', 'Failed to load chart (${path.toString()})');
       }
     }
     catch (err)
     {
-      state.failure('Failed to Load Chart', 'Failed to load chart (${path.toString()}): ${err}');
+      chartEditorState.failure('Failed to Load Chart', 'Failed to load chart (${path.toString()}): ${err}');
     }
   }
 
@@ -139,19 +140,19 @@ class ChartEditorUploadChartDialog extends ChartEditorBaseDialog
     {
       try
       {
-        var result:Null<Array<String>> = ChartEditorImportExportHandler.loadFromFNFC(state, selectedFile.bytes);
+        var result:Null<Array<String>> = ChartEditorImportExportHandler.loadFromFNFC(chartEditorState, selectedFile.bytes);
         if (result != null)
         {
-          state.success('Loaded Chart',
+          chartEditorState.success('Loaded Chart',
             result.length == 0 ? 'Loaded chart (${selectedFile.name})' : 'Loaded chart (${selectedFile.name})\n${result.join("\n")}');
 
-          if (selectedFile.fullPath != null) state.currentWorkingFilePath = selectedFile.fullPath;
+          if (selectedFile.fullPath != null) chartEditorState.currentWorkingFilePath = selectedFile.fullPath;
           this.hideDialog(DialogButton.APPLY);
         }
       }
       catch (err)
       {
-        state.failure('Failed to Load Chart', 'Failed to load chart (${selectedFile.name}): ${err}');
+        chartEditorState.failure('Failed to Load Chart', 'Failed to load chart (${selectedFile.name}): ${err}');
       }
     }
   }
diff --git a/source/funkin/ui/debug/charting/dialogs/ChartEditorWelcomeDialog.hx b/source/funkin/ui/debug/charting/dialogs/ChartEditorWelcomeDialog.hx
index 2a30c7d9e..7539b9725 100644
--- a/source/funkin/ui/debug/charting/dialogs/ChartEditorWelcomeDialog.hx
+++ b/source/funkin/ui/debug/charting/dialogs/ChartEditorWelcomeDialog.hx
@@ -41,26 +41,26 @@ class ChartEditorWelcomeDialog extends ChartEditorBaseDialog
 
     // Add items to the Recent Charts list
     #if sys
-    for (chartPath in state.previousWorkingFilePaths)
+    for (chartPath in chartEditorState.previousWorkingFilePaths)
     {
       if (chartPath == null) continue;
-      this.addRecentFilePath(state, chartPath);
+      this.addRecentFilePath(chartEditorState, chartPath);
     }
     #else
     this.addHTML5RecentFileMessage();
     #end
 
     // Add items to the Load From Template list
-    this.buildTemplateSongList(state);
+    this.buildTemplateSongList(chartEditorState);
   }
 
   /**
    * @param state The current state of the chart editor.
    * @return A newly created `ChartEditorWelcomeDialog`.
    */
-  public static function build(state:ChartEditorState, ?closable:Bool, ?modal:Bool):ChartEditorWelcomeDialog
+  public static function build(chartEditorState:ChartEditorState, ?closable:Bool, ?modal:Bool):ChartEditorWelcomeDialog
   {
-    var dialog = new ChartEditorWelcomeDialog(state,
+    var dialog = new ChartEditorWelcomeDialog(chartEditorState,
       {
         closable: closable ?? false,
         modal: modal ?? true
@@ -102,12 +102,12 @@ class ChartEditorWelcomeDialog extends ChartEditorBaseDialog
       var result:Null<Array<String>> = ChartEditorImportExportHandler.loadFromFNFCPath(state, chartPath);
       if (result != null)
       {
-        state.success('Loaded Chart',
+        chartEditorState.success('Loaded Chart',
           result.length == 0 ? 'Loaded chart (${chartPath.toString()})' : 'Loaded chart (${chartPath.toString()})\n${result.join("\n")}');
       }
       else
       {
-        state.error('Failed to Load Chart', 'Failed to load chart (${chartPath.toString()})');
+        chartEditorState.error('Failed to Load Chart', 'Failed to load chart (${chartPath.toString()})');
       }
     }
 
@@ -157,7 +157,7 @@ class ChartEditorWelcomeDialog extends ChartEditorBaseDialog
         this.hideDialog(DialogButton.CANCEL);
 
         // Load song from template
-        state.loadSongAsTemplate(targetSongId);
+        chartEditorState.loadSongAsTemplate(targetSongId);
       });
     }
   }
@@ -184,7 +184,7 @@ class ChartEditorWelcomeDialog extends ChartEditorBaseDialog
     this.hideDialog(DialogButton.CANCEL);
 
     // Open the "Open Chart" dialog
-    state.openBrowseFNFC(false);
+    chartEditorState.openBrowseFNFC(false);
   }
 
   /**
@@ -199,7 +199,7 @@ class ChartEditorWelcomeDialog extends ChartEditorBaseDialog
     //
     // Create Song Wizard
     //
-    state.openCreateSongWizardBasicOnly(false);
+    chartEditorState.openCreateSongWizardBasicOnly(false);
   }
 
   /**
@@ -214,7 +214,7 @@ class ChartEditorWelcomeDialog extends ChartEditorBaseDialog
     //
     // Create Song Wizard
     //
-    state.openCreateSongWizardErectOnly(false);
+    chartEditorState.openCreateSongWizardErectOnly(false);
   }
 
   /**
@@ -229,7 +229,7 @@ class ChartEditorWelcomeDialog extends ChartEditorBaseDialog
     //
     // Create Song Wizard
     //
-    state.openCreateSongWizardBasicErect(false);
+    chartEditorState.openCreateSongWizardBasicErect(false);
   }
 
   /**
@@ -242,6 +242,6 @@ class ChartEditorWelcomeDialog extends ChartEditorBaseDialog
     this.hideDialog(DialogButton.CANCEL);
 
     // Open the "Import Chart" dialog
-    state.openImportChartWizard('legacy', false);
+    chartEditorState.openImportChartWizard('legacy', false);
   }
 }
diff --git a/source/funkin/ui/debug/charting/toolboxes/ChartEditorBaseToolbox.hx b/source/funkin/ui/debug/charting/toolboxes/ChartEditorBaseToolbox.hx
index c4c532205..7df06c249 100644
--- a/source/funkin/ui/debug/charting/toolboxes/ChartEditorBaseToolbox.hx
+++ b/source/funkin/ui/debug/charting/toolboxes/ChartEditorBaseToolbox.hx
@@ -12,13 +12,13 @@ import haxe.ui.core.Component;
 @:access(funkin.ui.debug.charting.ChartEditorState)
 class ChartEditorBaseToolbox extends CollapsibleDialog
 {
-  var state:ChartEditorState;
+  var chartEditorState:ChartEditorState;
 
-  private function new(state:ChartEditorState)
+  private function new(chartEditorState:ChartEditorState)
   {
     super();
 
-    this.state = state;
+    this.chartEditorState = chartEditorState;
   }
 
   /**
diff --git a/source/funkin/ui/debug/charting/toolboxes/ChartEditorMetadataToolbox.hx b/source/funkin/ui/debug/charting/toolboxes/ChartEditorMetadataToolbox.hx
index e0ee4aca3..509aa5b07 100644
--- a/source/funkin/ui/debug/charting/toolboxes/ChartEditorMetadataToolbox.hx
+++ b/source/funkin/ui/debug/charting/toolboxes/ChartEditorMetadataToolbox.hx
@@ -40,9 +40,9 @@ class ChartEditorMetadataToolbox extends ChartEditorBaseToolbox
   var frameVariation:Frame;
   var frameDifficulty:Frame;
 
-  public function new(state2:ChartEditorState)
+  public function new(chartEditorState2:ChartEditorState)
   {
-    super(state2);
+    super(chartEditorState2);
 
     initialize();
 
@@ -51,7 +51,7 @@ class ChartEditorMetadataToolbox extends ChartEditorBaseToolbox
 
   function onClose(event:UIEvent)
   {
-    state.menubarItemToggleToolboxMetadata.selected = false;
+    chartEditorState.menubarItemToggleToolboxMetadata.selected = false;
   }
 
   function initialize():Void
@@ -67,11 +67,11 @@ class ChartEditorMetadataToolbox extends ChartEditorBaseToolbox
       if (valid)
       {
         inputSongName.removeClass('invalid-value');
-        state.currentSongMetadata.songName = event.target.text;
+        chartEditorState.currentSongMetadata.songName = event.target.text;
       }
       else
       {
-        state.currentSongMetadata.songName = '';
+        chartEditorState.currentSongMetadata.songName = '';
       }
     };
 
@@ -81,11 +81,11 @@ class ChartEditorMetadataToolbox extends ChartEditorBaseToolbox
       if (valid)
       {
         inputSongArtist.removeClass('invalid-value');
-        state.currentSongMetadata.artist = event.target.text;
+        chartEditorState.currentSongMetadata.artist = event.target.text;
       }
       else
       {
-        state.currentSongMetadata.artist = '';
+        chartEditorState.currentSongMetadata.artist = '';
       }
     };
 
@@ -94,41 +94,41 @@ class ChartEditorMetadataToolbox extends ChartEditorBaseToolbox
 
       if (valid)
       {
-        state.currentSongMetadata.playData.stage = event.data.id;
+        chartEditorState.currentSongMetadata.playData.stage = event.data.id;
       }
     };
-    var startingValueStage = ChartEditorDropdowns.populateDropdownWithStages(inputStage, state.currentSongMetadata.playData.stage);
+    var startingValueStage = ChartEditorDropdowns.populateDropdownWithStages(inputStage, chartEditorState.currentSongMetadata.playData.stage);
     inputStage.value = startingValueStage;
 
     inputNoteStyle.onChange = function(event:UIEvent) {
       if (event.data?.id == null) return;
-      state.currentSongNoteStyle = event.data.id;
+      chartEditorState.currentSongNoteStyle = event.data.id;
     };
 
     inputBPM.onChange = function(event:UIEvent) {
       if (event.value == null || event.value <= 0) return;
 
       // Use a command so we can undo/redo this action.
-      var startingBPM = state.currentSongMetadata.timeChanges[0].bpm;
+      var startingBPM = chartEditorState.currentSongMetadata.timeChanges[0].bpm;
       if (event.value != startingBPM)
       {
-        state.performCommand(new ChangeStartingBPMCommand(event.value));
+        chartEditorState.performCommand(new ChangeStartingBPMCommand(event.value));
       }
     };
 
     inputOffsetInst.onChange = function(event:UIEvent) {
       if (event.value == null) return;
 
-      state.currentInstrumentalOffset = event.value;
+      chartEditorState.currentInstrumentalOffset = event.value;
       Conductor.instrumentalOffset = event.value;
       // Update song length.
-      state.songLengthInMs = (state.audioInstTrack?.length ?? 1000.0) + Conductor.instrumentalOffset;
+      chartEditorState.songLengthInMs = (chartEditorState.audioInstTrack?.length ?? 1000.0) + Conductor.instrumentalOffset;
     };
 
     inputOffsetVocal.onChange = function(event:UIEvent) {
       if (event.value == null) return;
 
-      state.currentSongMetadata.offsets.setVocalOffset(state.currentSongMetadata.playData.characters.player, event.value);
+      chartEditorState.currentSongMetadata.offsets.setVocalOffset(chartEditorState.currentSongMetadata.playData.characters.player, event.value);
     };
     inputScrollSpeed.onChange = function(event:UIEvent) {
       var valid:Bool = event.target.value != null && event.target.value > 0;
@@ -136,25 +136,25 @@ class ChartEditorMetadataToolbox extends ChartEditorBaseToolbox
       if (valid)
       {
         inputScrollSpeed.removeClass('invalid-value');
-        state.currentSongChartScrollSpeed = event.target.value;
+        chartEditorState.currentSongChartScrollSpeed = event.target.value;
       }
       else
       {
-        state.currentSongChartScrollSpeed = 1.0;
+        chartEditorState.currentSongChartScrollSpeed = 1.0;
       }
-      labelScrollSpeed.text = 'Scroll Speed: ${state.currentSongChartScrollSpeed}x';
+      labelScrollSpeed.text = 'Scroll Speed: ${chartEditorState.currentSongChartScrollSpeed}x';
     };
 
     buttonCharacterOpponent.onClick = function(_) {
-      state.openCharacterDropdown(CharacterType.DAD, false);
+      chartEditorState.openCharacterDropdown(CharacterType.DAD, false);
     };
 
     buttonCharacterGirlfriend.onClick = function(_) {
-      state.openCharacterDropdown(CharacterType.GF, false);
+      chartEditorState.openCharacterDropdown(CharacterType.GF, false);
     };
 
     buttonCharacterPlayer.onClick = function(_) {
-      state.openCharacterDropdown(CharacterType.BF, false);
+      chartEditorState.openCharacterDropdown(CharacterType.BF, false);
     };
 
     refresh();
@@ -162,17 +162,17 @@ class ChartEditorMetadataToolbox extends ChartEditorBaseToolbox
 
   public override function refresh():Void
   {
-    inputSongName.value = state.currentSongMetadata.songName;
-    inputSongArtist.value = state.currentSongMetadata.artist;
-    inputStage.value = state.currentSongMetadata.playData.stage;
-    inputNoteStyle.value = state.currentSongMetadata.playData.noteStyle;
-    inputBPM.value = state.currentSongMetadata.timeChanges[0].bpm;
-    inputScrollSpeed.value = state.currentSongChartScrollSpeed;
-    labelScrollSpeed.text = 'Scroll Speed: ${state.currentSongChartScrollSpeed}x';
-    frameVariation.text = 'Variation: ${state.selectedVariation.toTitleCase()}';
-    frameDifficulty.text = 'Difficulty: ${state.selectedDifficulty.toTitleCase()}';
+    inputSongName.value = chartEditorState.currentSongMetadata.songName;
+    inputSongArtist.value = chartEditorState.currentSongMetadata.artist;
+    inputStage.value = chartEditorState.currentSongMetadata.playData.stage;
+    inputNoteStyle.value = chartEditorState.currentSongMetadata.playData.noteStyle;
+    inputBPM.value = chartEditorState.currentSongMetadata.timeChanges[0].bpm;
+    inputScrollSpeed.value = chartEditorState.currentSongChartScrollSpeed;
+    labelScrollSpeed.text = 'Scroll Speed: ${chartEditorState.currentSongChartScrollSpeed}x';
+    frameVariation.text = 'Variation: ${chartEditorState.selectedVariation.toTitleCase()}';
+    frameDifficulty.text = 'Difficulty: ${chartEditorState.selectedDifficulty.toTitleCase()}';
 
-    var stageId:String = state.currentSongMetadata.playData.stage;
+    var stageId:String = chartEditorState.currentSongMetadata.playData.stage;
     var stageData:Null<StageData> = StageDataParser.parseStageData(stageId);
     if (inputStage != null)
     {
@@ -183,21 +183,21 @@ class ChartEditorMetadataToolbox extends ChartEditorBaseToolbox
 
     var LIMIT = 6;
 
-    var charDataOpponent:CharacterData = CharacterDataParser.fetchCharacterData(state.currentSongMetadata.playData.characters.opponent);
-    buttonCharacterOpponent.icon = CharacterDataParser.getCharPixelIconAsset(state.currentSongMetadata.playData.characters.opponent);
+    var charDataOpponent:CharacterData = CharacterDataParser.fetchCharacterData(chartEditorState.currentSongMetadata.playData.characters.opponent);
+    buttonCharacterOpponent.icon = CharacterDataParser.getCharPixelIconAsset(chartEditorState.currentSongMetadata.playData.characters.opponent);
     buttonCharacterOpponent.text = charDataOpponent.name.length > LIMIT ? '${charDataOpponent.name.substr(0, LIMIT)}.' : '${charDataOpponent.name}';
 
-    var charDataGirlfriend:CharacterData = CharacterDataParser.fetchCharacterData(state.currentSongMetadata.playData.characters.girlfriend);
-    buttonCharacterGirlfriend.icon = CharacterDataParser.getCharPixelIconAsset(state.currentSongMetadata.playData.characters.girlfriend);
+    var charDataGirlfriend:CharacterData = CharacterDataParser.fetchCharacterData(chartEditorState.currentSongMetadata.playData.characters.girlfriend);
+    buttonCharacterGirlfriend.icon = CharacterDataParser.getCharPixelIconAsset(chartEditorState.currentSongMetadata.playData.characters.girlfriend);
     buttonCharacterGirlfriend.text = charDataGirlfriend.name.length > LIMIT ? '${charDataGirlfriend.name.substr(0, LIMIT)}.' : '${charDataGirlfriend.name}';
 
-    var charDataPlayer:CharacterData = CharacterDataParser.fetchCharacterData(state.currentSongMetadata.playData.characters.player);
-    buttonCharacterPlayer.icon = CharacterDataParser.getCharPixelIconAsset(state.currentSongMetadata.playData.characters.player);
+    var charDataPlayer:CharacterData = CharacterDataParser.fetchCharacterData(chartEditorState.currentSongMetadata.playData.characters.player);
+    buttonCharacterPlayer.icon = CharacterDataParser.getCharPixelIconAsset(chartEditorState.currentSongMetadata.playData.characters.player);
     buttonCharacterPlayer.text = charDataPlayer.name.length > LIMIT ? '${charDataPlayer.name.substr(0, LIMIT)}.' : '${charDataPlayer.name}';
   }
 
-  public static function build(state:ChartEditorState):ChartEditorMetadataToolbox
+  public static function build(chartEditorState:ChartEditorState):ChartEditorMetadataToolbox
   {
-    return new ChartEditorMetadataToolbox(state);
+    return new ChartEditorMetadataToolbox(chartEditorState);
   }
 }
diff --git a/source/funkin/ui/freeplay/FreeplayState.hx b/source/funkin/ui/freeplay/FreeplayState.hx
index 371021114..7c69804d9 100644
--- a/source/funkin/ui/freeplay/FreeplayState.hx
+++ b/source/funkin/ui/freeplay/FreeplayState.hx
@@ -874,15 +874,14 @@ class FreeplayState extends MusicBeatSubState
     }
   }
 
-  @:haxe.warning("-WDeprecated")
-  override function switchTo(nextState:FlxState):Bool
+  public override function destroy():Void
   {
+    super.destroy();
     var daSong = songs[curSelected];
     if (daSong != null)
     {
       clearDaCache(daSong.songName);
     }
-    return super.switchTo(nextState);
   }
 
   function changeDiff(change:Int = 0)

From 4fc56a22800aa2311f3726fb2feea1e8652ed473 Mon Sep 17 00:00:00 2001
From: Cameron Taylor <cameron.taylor.ninja@gmail.com>
Date: Fri, 15 Dec 2023 21:46:09 -0500
Subject: [PATCH 4/4] small fix to backups folder not existing

---
 assets                                                          | 2 +-
 .../debug/charting/handlers/ChartEditorImportExportHandler.hx   | 2 ++
 2 files changed, 3 insertions(+), 1 deletion(-)

diff --git a/assets b/assets
index dfaf23dfa..c354795f7 160000
--- a/assets
+++ b/assets
@@ -1 +1 @@
-Subproject commit dfaf23dfa11ff67be2eea9113a80ff5dc0040f76
+Subproject commit c354795f7f560fa096b855c6e6bca745f77fa414
diff --git a/source/funkin/ui/debug/charting/handlers/ChartEditorImportExportHandler.hx b/source/funkin/ui/debug/charting/handlers/ChartEditorImportExportHandler.hx
index 0c8d6a205..267d2208a 100644
--- a/source/funkin/ui/debug/charting/handlers/ChartEditorImportExportHandler.hx
+++ b/source/funkin/ui/debug/charting/handlers/ChartEditorImportExportHandler.hx
@@ -315,6 +315,8 @@ class ChartEditorImportExportHandler
   public static function getLatestBackupPath():Null<String>
   {
     #if sys
+    if (!sys.FileSystem.exists(BACKUPS_PATH)) sys.FileSystem.createDirectory(BACKUPS_PATH);
+
     var entries:Array<String> = sys.FileSystem.readDirectory(BACKUPS_PATH);
     entries.sort(SortUtil.alphabetically);