From 3e8200ee9d3d6526dc4ad0ede5c029fd51df43f8 Mon Sep 17 00:00:00 2001
From: EliteMasterEric <ericmyllyoja@gmail.com>
Date: Fri, 12 Jan 2024 21:52:28 -0500
Subject: [PATCH 1/4] Allow builds without hxCodec if using hashlink

---
 Project.xml                                   |  2 +-
 source/funkin/input/Controls.hx               | 15 +++++++---
 source/funkin/play/cutscene/VideoCutscene.hx  | 28 ++++++++++++-------
 .../ui/debug/charting/ChartEditorState.hx     |  6 ++--
 .../handlers/ChartEditorAudioHandler.hx       |  2 +-
 source/funkin/ui/title/AttractState.hx        | 18 +++++++++---
 6 files changed, 48 insertions(+), 23 deletions(-)

diff --git a/Project.xml b/Project.xml
index f5d506688..1c9190899 100644
--- a/Project.xml
+++ b/Project.xml
@@ -105,7 +105,7 @@
 	<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="hxCodec" if="desktop release" /> <!-- Video playback -->
 
 	<haxelib name="json2object" /> <!-- JSON parsing -->
 	<haxelib name="tink_json" /> <!-- JSON parsing (DEPRECATED) -->
diff --git a/source/funkin/input/Controls.hx b/source/funkin/input/Controls.hx
index 3fa4e0f75..201c222a3 100644
--- a/source/funkin/input/Controls.hx
+++ b/source/funkin/input/Controls.hx
@@ -333,8 +333,12 @@ class Controls extends FlxActionSet
       throw 'Invalid name: $name';
     #end
 
-    return byName[name].inputs.map(function(input) return (input.device == KEYBOARD) ? input.inputID : null)
-      .filter(function(key) return key != null);
+    // TODO: Revert to `.map().filter()` once HashLink doesn't complain anymore.
+    var result:Array<FlxKey> = [];
+    for (input in byName[name].inputs) {
+      if (input.device == KEYBOARD) result.push(input.inputID);
+    }
+    return result;
   }
 
   public function getButtonsForAction(name:Action):Array<FlxGamepadInputID> {
@@ -343,8 +347,11 @@ class Controls extends FlxActionSet
       throw 'Invalid name: $name';
     #end
 
-    return byName[name].inputs.map(function(input) return (input.device == GAMEPAD) ? input.inputID : null)
-      .filter(function(key) return key != null);
+    var result:Array<FlxGamepadInputID> = [];
+    for (input in byName[name].inputs) {
+      if (input.device == GAMEPAD) result.push(input.inputID);
+    }
+    return result;
   }
 
   public function getDialogueName(action:FlxActionDigital):String
diff --git a/source/funkin/play/cutscene/VideoCutscene.hx b/source/funkin/play/cutscene/VideoCutscene.hx
index 24cf78c2a..934919b65 100644
--- a/source/funkin/play/cutscene/VideoCutscene.hx
+++ b/source/funkin/play/cutscene/VideoCutscene.hx
@@ -8,7 +8,8 @@ import flixel.util.FlxColor;
 import flixel.util.FlxTimer;
 #if html5
 import funkin.graphics.video.FlxVideo;
-#else
+#end
+#if hxCodec
 import hxcodec.flixel.FlxVideoSprite;
 #end
 
@@ -48,14 +49,20 @@ class VideoCutscene
 
     #if html5
     playVideoHTML5(filePath);
-    #else
+    #end
+
+    #if hxCodec
     playVideoNative(filePath);
     #end
   }
 
   public static function isPlaying():Bool
   {
+    #if (html5 || hxCodec)
     return vid != null;
+    #else
+    return false;
+    #end
   }
 
   #if html5
@@ -82,7 +89,9 @@ class VideoCutscene
       trace('ALERT: Video is null! Could not play cutscene!');
     }
   }
-  #else
+  #end
+
+  #if hxCodec
   static var vid:FlxVideoSprite;
 
   static function playVideoNative(filePath:String):Void
@@ -118,15 +127,20 @@ class VideoCutscene
     {
       PlayState.instance.remove(vid);
     }
-    #else
+    #end
+
+    #if hxCodec
     if (vid != null)
     {
       vid.stop();
       PlayState.instance.remove(vid);
     }
     #end
+
+    #if (html5 || hxCodec)
     vid.destroy();
     vid = null;
+    #end
 
     PlayState.instance.camCutscene.visible = true;
     PlayState.instance.camHUD.visible = true;
@@ -148,9 +162,3 @@ class VideoCutscene
       });
   }
 }
-
-/*
-  trace('Video playback failed (${e})');
-  vid = null;
-  finishCutscene(0.5);
- */
diff --git a/source/funkin/ui/debug/charting/ChartEditorState.hx b/source/funkin/ui/debug/charting/ChartEditorState.hx
index 0853bf390..e98809ce8 100644
--- a/source/funkin/ui/debug/charting/ChartEditorState.hx
+++ b/source/funkin/ui/debug/charting/ChartEditorState.hx
@@ -5951,9 +5951,9 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
     ChartEditorNoteSprite.noteFrameCollection = null;
 
     // Stop the music.
-    welcomeMusic.destroy();
-    audioInstTrack.destroy();
-    audioVocalTrackGroup.destroy();
+    if (welcomeMusic != null) welcomeMusic.destroy();
+    if (audioInstTrack != null) audioInstTrack.destroy();
+    if (audioVocalTrackGroup != null) audioVocalTrackGroup.destroy();
   }
 
   function applyCanQuickSave():Void
diff --git a/source/funkin/ui/debug/charting/handlers/ChartEditorAudioHandler.hx b/source/funkin/ui/debug/charting/handlers/ChartEditorAudioHandler.hx
index d7fbd42c2..aad2db7fa 100644
--- a/source/funkin/ui/debug/charting/handlers/ChartEditorAudioHandler.hx
+++ b/source/funkin/ui/debug/charting/handlers/ChartEditorAudioHandler.hx
@@ -242,8 +242,8 @@ class ChartEditorAudioHandler
     snd.loadEmbedded(asset);
     snd.autoDestroy = true;
     FlxG.sound.list.add(snd);
+    snd.play(true);
     snd.volume = volume;
-    snd.play();
   }
 
   public static function wipeInstrumentalData(state:ChartEditorState):Void
diff --git a/source/funkin/ui/title/AttractState.hx b/source/funkin/ui/title/AttractState.hx
index 38cff7cc8..3294a4551 100644
--- a/source/funkin/ui/title/AttractState.hx
+++ b/source/funkin/ui/title/AttractState.hx
@@ -2,7 +2,8 @@ package funkin.ui.title;
 
 #if html5
 import funkin.graphics.video.FlxVideo;
-#else
+#end
+#if hxCodec
 import hxcodec.flixel.FlxVideoSprite;
 #end
 import funkin.ui.MusicBeatState;
@@ -25,7 +26,9 @@ class AttractState extends MusicBeatState
 
     #if html5
     playVideoHTML5(ATTRACT_VIDEO_PATH);
-    #else
+    #end
+
+    #if hxCodec
     playVideoNative(ATTRACT_VIDEO_PATH);
     #end
   }
@@ -50,7 +53,9 @@ class AttractState extends MusicBeatState
       trace('ALERT: Video is null! Could not play cutscene!');
     }
   }
-  #else
+  #end
+
+  #if hxCodec
   var vid:FlxVideoSprite;
 
   function playVideoNative(filePath:String):Void
@@ -95,15 +100,20 @@ class AttractState extends MusicBeatState
     {
       remove(vid);
     }
-    #else
+    #end
+
+    #if hxCodec
     if (vid != null)
     {
       vid.stop();
       remove(vid);
     }
     #end
+
+    #if (html5 || hxCodec)
     vid.destroy();
     vid = null;
+    #end
 
     FlxG.switchState(new TitleState());
   }

From 444e5b7040799ae36a82440f213b3d9e84b3ca6e Mon Sep 17 00:00:00 2001
From: EliteMasterEric <ericmyllyoja@gmail.com>
Date: Fri, 12 Jan 2024 22:02:37 -0500
Subject: [PATCH 2/4] Several library updates to fix bugs.

---
 hmm.json | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/hmm.json b/hmm.json
index 67ba4d18d..6edb88b00 100644
--- a/hmm.json
+++ b/hmm.json
@@ -107,7 +107,7 @@
       "name": "lime",
       "type": "git",
       "dir": null,
-      "ref": "fff39ba6fc64969cd51987ef7491d9345043dc5d",
+      "ref": "1359fe6ad52e91175dc636a516d460bd54ea22ed",
       "url": "https://github.com/FunkinCrew/lime"
     },
     {
@@ -149,13 +149,15 @@
       "name": "polymod",
       "type": "git",
       "dir": null,
-      "ref": "80d1d309803c1b111866524f9769325e3b8b0b1b",
+      "ref": "a9963b3a982e5f66a2ba02421aabf4b926953fbc",
       "url": "https://github.com/larsiusprime/polymod"
     },
     {
       "name": "thx.semver",
-      "type": "haxelib",
-      "version": "0.2.2"
+      "type": "git",
+      "dir": null,
+      "ref": "cf8d213589a2c7ce4a59b0fdba9e8ff36bc029fa",
+      "url": "https://github.com/FunkinCrew/thx.semver"
     },
     {
       "name": "tink_json",

From e37fc09e89e16b7383f6ac5f6dd6b7093a52c65c Mon Sep 17 00:00:00 2001
From: EliteMasterEric <ericmyllyoja@gmail.com>
Date: Tue, 13 Feb 2024 03:03:11 -0500
Subject: [PATCH 3/4] Hashlink actually working!

---
 source/funkin/InitState.hx                             |  4 ++--
 source/funkin/audio/SoundGroup.hx                      |  2 +-
 source/funkin/graphics/shaders/BlendModesShader.hx     | 10 ++++++----
 .../ui/debug/charting/commands/CopyItemsCommand.hx     |  2 +-
 source/funkin/ui/story/StoryMenuState.hx               |  4 ++--
 5 files changed, 12 insertions(+), 10 deletions(-)

diff --git a/source/funkin/InitState.hx b/source/funkin/InitState.hx
index 5e69f58b9..399f52498 100644
--- a/source/funkin/InitState.hx
+++ b/source/funkin/InitState.hx
@@ -245,9 +245,9 @@ class InitState extends FlxState
     #elseif LEVEL // -DLEVEL=week1 -DDIFFICULTY=hard
     startLevel(defineLevel(), defineDifficulty());
     #elseif FREEPLAY // -DFREEPLAY
-    FlxG.switchState(new FreeplayState());
+    FlxG.switchState(() -> new funkin.ui.freeplay.FreeplayState());
     #elseif DIALOGUE // -DDIALOGUE
-    FlxG.switchState(new funkin.ui.debug.dialogue.ConversationDebugState());
+    FlxG.switchState(() -> new funkin.ui.debug.dialogue.ConversationDebugState());
     #elseif ANIMATE // -DANIMATE
     FlxG.switchState(() -> new funkin.ui.debug.anim.FlxAnimateTest());
     #elseif WAVEFORM // -DWAVEFORM
diff --git a/source/funkin/audio/SoundGroup.hx b/source/funkin/audio/SoundGroup.hx
index df3a67ae1..0e81a0901 100644
--- a/source/funkin/audio/SoundGroup.hx
+++ b/source/funkin/audio/SoundGroup.hx
@@ -192,7 +192,7 @@ class SoundGroup extends FlxTypedGroup<FunkinSound>
 
   function get_playing():Bool
   {
-    if (getFirstAlive != null) return getFirstAlive().playing;
+    if (getFirstAlive() != null) return getFirstAlive().playing;
     else
       return false;
   }
diff --git a/source/funkin/graphics/shaders/BlendModesShader.hx b/source/funkin/graphics/shaders/BlendModesShader.hx
index acd2c1586..b7a405dd1 100644
--- a/source/funkin/graphics/shaders/BlendModesShader.hx
+++ b/source/funkin/graphics/shaders/BlendModesShader.hx
@@ -4,20 +4,22 @@ import flixel.addons.display.FlxRuntimeShader;
 import funkin.Paths;
 import openfl.utils.Assets;
 import openfl.display.BitmapData;
+import openfl.display.ShaderInput;
 
 class BlendModesShader extends FlxRuntimeShader
 {
-  public var camera:BitmapData;
+  public var camera:ShaderInput<BitmapData>;
+  public var cameraData:BitmapData;
 
   public function new()
   {
     super(Assets.getText(Paths.frag('blendModes')));
   }
 
-  public function setCamera(camera:BitmapData):Void
+  public function setCamera(cameraData:BitmapData):Void
   {
-    this.camera = camera;
+    this.cameraData = cameraData;
 
-    this.setBitmapData('camera', camera);
+    this.setBitmapData('camera', this.cameraData);
   }
 }
diff --git a/source/funkin/ui/debug/charting/commands/CopyItemsCommand.hx b/source/funkin/ui/debug/charting/commands/CopyItemsCommand.hx
index 6c5152a29..376d0cebd 100644
--- a/source/funkin/ui/debug/charting/commands/CopyItemsCommand.hx
+++ b/source/funkin/ui/debug/charting/commands/CopyItemsCommand.hx
@@ -138,7 +138,7 @@ class CopyItemsCommand implements ChartEditorCommand
       state.txtCopyNotif.y = FlxG.mouse.y - 16;
       FlxTween.tween(state.txtCopyNotif, {y: state.txtCopyNotif.y - 32}, 0.5,
         {
-          type: FlxTween.ONESHOT,
+          type: FlxTweenType.ONESHOT,
           ease: FlxEase.quadOut,
           onComplete: function(_) {
             state.txtCopyNotif.visible = false;
diff --git a/source/funkin/ui/story/StoryMenuState.hx b/source/funkin/ui/story/StoryMenuState.hx
index 2f0111841..1905a7c57 100644
--- a/source/funkin/ui/story/StoryMenuState.hx
+++ b/source/funkin/ui/story/StoryMenuState.hx
@@ -509,10 +509,10 @@ class StoryMenuState extends MusicBeatState
     // super.dispatchEvent(event) dispatches event to module scripts.
     super.dispatchEvent(event);
 
-    if (levelProps != null && levelProps.length > 0)
+    if (levelProps?.members != null && levelProps.members.length > 0)
     {
       // Dispatch event to props.
-      for (prop in levelProps)
+      for (prop in levelProps.members)
       {
         ScriptEventDispatcher.callEvent(prop, event);
       }

From 923f8f423ef948901f4a1230dc591099762fe768 Mon Sep 17 00:00:00 2001
From: Cameron Taylor <cameron.taylor.ninja@gmail.com>
Date: Tue, 13 Feb 2024 03:32:20 -0500
Subject: [PATCH 4/4] swag truthers we are BACK

---
 source/funkin/graphics/FunkinCamera.hx           |  4 ++--
 .../graphics/shaders/RuntimeCustomBlendShader.hx | 16 +++++++++-------
 .../funkin/graphics/shaders/RuntimeRainShader.hx |  6 +++---
 3 files changed, 14 insertions(+), 12 deletions(-)

diff --git a/source/funkin/graphics/FunkinCamera.hx b/source/funkin/graphics/FunkinCamera.hx
index f80e799ea..90861c263 100644
--- a/source/funkin/graphics/FunkinCamera.hx
+++ b/source/funkin/graphics/FunkinCamera.hx
@@ -192,8 +192,8 @@ class FunkinCamera extends FlxCamera
       // get the isolated bitmap
       final isolated = grabScreen(false, true);
       // apply fullscreen blend
-      customBlendShader.blend = blend;
-      customBlendShader.source = isolated;
+      customBlendShader.blendSwag = blend;
+      customBlendShader.sourceSwag = isolated;
       customBlendShader.updateViewInfo(FlxG.width, FlxG.height, this);
       applyFilter(customBlendFilter);
     }
diff --git a/source/funkin/graphics/shaders/RuntimeCustomBlendShader.hx b/source/funkin/graphics/shaders/RuntimeCustomBlendShader.hx
index a07124d23..3e8dfedd3 100644
--- a/source/funkin/graphics/shaders/RuntimeCustomBlendShader.hx
+++ b/source/funkin/graphics/shaders/RuntimeCustomBlendShader.hx
@@ -6,20 +6,22 @@ import openfl.utils.Assets;
 
 class RuntimeCustomBlendShader extends RuntimePostEffectShader
 {
-  public var source(default, set):BitmapData;
+  // only different name purely for hashlink fix
+  public var sourceSwag(default, set):BitmapData;
 
-  function set_source(value:BitmapData):BitmapData
+  function set_sourceSwag(value:BitmapData):BitmapData
   {
-    this.setBitmapData("source", value);
-    return source = value;
+    this.setBitmapData("sourceSwag", value);
+    return sourceSwag = value;
   }
 
-  public var blend(default, set):BlendMode;
+  // name change make sure it's not the same variable name as whatever is in the shader file
+  public var blendSwag(default, set):BlendMode;
 
-  function set_blend(value:BlendMode):BlendMode
+  function set_blendSwag(value:BlendMode):BlendMode
   {
     this.setInt("blendMode", cast value);
-    return blend = value;
+    return blendSwag = value;
   }
 
   public function new()
diff --git a/source/funkin/graphics/shaders/RuntimeRainShader.hx b/source/funkin/graphics/shaders/RuntimeRainShader.hx
index 05bc68f72..239276bbe 100644
--- a/source/funkin/graphics/shaders/RuntimeRainShader.hx
+++ b/source/funkin/graphics/shaders/RuntimeRainShader.hx
@@ -94,12 +94,12 @@ class RuntimeRainShader extends RuntimePostEffectShader
     return lightMap = value;
   }
 
-  public var numLights(default, set):Int = 0;
+  public var numLightsSwag(default, set):Int = 0; // swag heads, we have never been more back (needs different name purely for hashlink casting fix)
 
-  function set_numLights(value:Int):Int
+  function set_numLightsSwag(value:Int):Int
   {
     this.setInt('numLights', value);
-    return numLights = value;
+    return numLightsSwag = value;
   }
 
   public function new()