diff --git a/Project.xml b/Project.xml
index 972749939..3f930bc73 100644
--- a/Project.xml
+++ b/Project.xml
@@ -145,9 +145,15 @@
 	<!--Enable this for Nape release builds for a serious peformance improvement-->
 	<haxedef name="NAPE_RELEASE_BUILD" unless="debug" />
 
-	<!-- TODO: REMOVE THIS!!!! -->
+	<!-- 
+		Hide deprecation warnings until they're fixed.
+		TODO: REMOVE THIS!!!!
+	-->
 	<haxeflag name="-w" value="-WDeprecated" />
 
+	<!-- Haxe 4.3.0+: Enable pretty syntax errors and stuff. -->
+	<haxedef name="message-reporting" value="pretty" />
+
 	<!-- _________________________________ Custom _______________________________ -->
 
 	<!-- Disable trace() calls in release builds to bump up performance. -->
diff --git a/source/funkin/play/character/BaseCharacter.hx b/source/funkin/play/character/BaseCharacter.hx
index f47f384a3..df3b60626 100644
--- a/source/funkin/play/character/BaseCharacter.hx
+++ b/source/funkin/play/character/BaseCharacter.hx
@@ -582,6 +582,13 @@ class BaseCharacter extends Bopper
     // restart even if already playing, because the character might sing the same note twice.
     playAnimation(anim, true);
   }
+
+  public override function playAnimation(name:String, restart:Bool = false, ?ignoreOther:Bool = false, ?reversed:Bool = false):Void
+  {
+    FlxG.watch.addQuick('playAnim(${characterName})', name);
+    trace('playAnim(${characterName}): ${name}');
+    super.playAnimation(name, restart, ignoreOther, reversed);
+  }
 }
 
 /**
diff --git a/source/funkin/ui/story/Level.hx b/source/funkin/ui/story/Level.hx
index 5d24de312..3ff0a5321 100644
--- a/source/funkin/ui/story/Level.hx
+++ b/source/funkin/ui/story/Level.hx
@@ -43,7 +43,8 @@ class Level implements IRegistryEntry<LevelData>
    */
   public function getSongs():Array<String>
   {
-    return _data.songs;
+    // Copy the array so that it can't be modified on accident
+    return _data.songs.copy();
   }
 
   /**
diff --git a/source/funkin/util/SerializerUtil.hx b/source/funkin/util/SerializerUtil.hx
index dae3327c6..3b77a04e5 100644
--- a/source/funkin/util/SerializerUtil.hx
+++ b/source/funkin/util/SerializerUtil.hx
@@ -1,6 +1,7 @@
 package funkin.util;
 
 import haxe.Json;
+import haxe.io.Bytes;
 import thx.semver.Version;
 
 typedef ScoreInput =
@@ -38,6 +39,14 @@ class SerializerUtil
     return Json.parse(input);
   }
 
+  /**
+   * Convert a JSON byte array to a Haxe object.
+   */
+  public static function fromJSONBytes(input:Bytes):Dynamic
+  {
+    return Json.parse(input.toString());
+  }
+
   /**
    * Customize how certain types are serialized when converting to JSON.
    */
diff --git a/source/funkin/util/tools/ArrayTools.hx b/source/funkin/util/tools/ArrayTools.hx
new file mode 100644
index 000000000..02671a8e8
--- /dev/null
+++ b/source/funkin/util/tools/ArrayTools.hx
@@ -0,0 +1,25 @@
+package funkin.util.tools;
+
+/**
+ * A static extension which provides utility functions for Arrays.
+ */
+class ArrayTools
+{
+  /**
+   * Returns a copy of the array with all duplicate elements removed.
+   * @param array The array to remove duplicates from.
+   * @return A copy of the array with all duplicate elements removed.
+   */
+  public static function unique<T>(array:Array<T>):Array<T>
+  {
+    var result:Array<T> = [];
+    for (element in array)
+    {
+      if (!result.contains(element))
+      {
+        result.push(element);
+      }
+    }
+    return result;
+  }
+}