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] 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.