WIP implementation of no stacking when pasting

This commit is contained in:
Hyper_ 2024-10-06 21:10:46 -03:00 committed by Hyper_
parent 21cee45cbb
commit 7396ad5508
3 changed files with 72 additions and 6 deletions

View file

@ -203,6 +203,12 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
*/
public static final NOTE_SELECT_BUTTON_HEIGHT:Int = 24;
/**
* How "close" in milliseconds two notes have to be to be considered as stacked.
* TODO: This should probably be turned into a modifiable value
*/
public static final STACK_NOTE_THRESHOLD:Int = 20;
/**
* The amount of padding between the menu bar and the chart grid when fully scrolled up.
*/
@ -3663,7 +3669,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
}
}
var stackedNotes:Array<SongNoteData> = NoteDataFilter.filterStackedNotes(displayedNoteData, 5);
var stackedNotes = NoteDataFilter.listStackedNotes(currentSongChartNoteData, STACK_NOTE_THRESHOLD);
// Add events that are now visible.
for (eventData in currentSongChartEventData)
@ -3801,6 +3807,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
}
else
{
// TODO: Move this to a function like isNoteSelected does
if (noteSprite.noteData != null && stackedNotes.contains(noteSprite.noteData))
{
// TODO: Maybe use another way to display these notes
@ -3864,6 +3871,11 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
// Sort the events DESCENDING. This keeps the sustain behind the associated note.
renderedEvents.sort(FlxSort.byY, FlxSort.DESCENDING); // TODO: .group.insertionSort()
}
if (FlxG.keys.pressed.CONTROL && FlxG.keys.justPressed.H)
{
// performCommand(new RemoveNotesCommand(stackedNotes));
}
}
/**

View file

@ -5,6 +5,8 @@ import funkin.data.song.SongData.SongNoteData;
import funkin.data.song.SongDataUtils;
import funkin.data.song.SongDataUtils.SongClipboardItems;
using funkin.ui.debug.charting.util.NoteDataFilter;
/**
* A command which inserts the contents of the clipboard into the chart editor.
*/
@ -41,7 +43,11 @@ class PasteItemsCommand implements ChartEditorCommand
addedEvents = SongDataUtils.offsetSongEventData(currentClipboard.events, Std.int(targetTimestamp));
addedEvents = SongDataUtils.clampSongEventData(addedEvents, 0.0, msCutoff);
state.currentSongChartNoteData = state.currentSongChartNoteData.concat(addedNotes);
// If a warning should appear when pasting a note on top of another
// TODO: Should events also not be allowed to stack?
var shouldWarn = false;
state.currentSongChartNoteData = state.currentSongChartNoteData.concatFilterStackedNotes(addedNotes, ChartEditorState.STACK_NOTE_THRESHOLD);
state.currentSongChartEventData = state.currentSongChartEventData.concat(addedEvents);
state.currentNoteSelection = addedNotes.copy();
state.currentEventSelection = addedEvents.copy();

View file

@ -15,7 +15,7 @@ class NoteDataFilter
* @param threshold Threshold in ms
* @return Stacked notes
*/
public static function filterStackedNotes(notes:Array<SongNoteData>, threshold:Float):Array<SongNoteData>
public static function listStackedNotes(notes:Array<SongNoteData>, threshold:Float):Array<SongNoteData>
{
var stackedNotes:Array<SongNoteData> = [];
@ -49,16 +49,16 @@ class NoteDataFilter
var noteI:SongNoteData = chunk[i];
var noteJ:SongNoteData = chunk[j];
if (noteI.getStrumlineIndex() == noteJ.getStrumlineIndex() && noteI.getDirection() == noteJ.getDirection())
if (canNotesStack(noteI, noteJ))
{
if (Math.abs(noteJ.time - noteI.time) <= threshold)
{
if (!stackedNotes.contains(noteI))
if (!stackedNotes.fastContains(noteI))
{
stackedNotes.push(noteI);
}
if (!stackedNotes.contains(noteJ))
if (!stackedNotes.fastContains(noteJ))
{
stackedNotes.push(noteJ);
}
@ -70,4 +70,52 @@ class NoteDataFilter
return stackedNotes;
}
/**
* Tries to concatenate two arrays of notes together but skips notes from `notesB` that overlap notes from `noteA`.
* @param notesA An array of notes into which `notesB` will be concatenated.
* @param notesB Another array of notes that will be concated into `input`.
* @param threshold Threshold in ms
* @param modifyB If `true` modifies `notesB` in-place by removing the notes that overlap notes from `notesA`.
* @return Array<SongNoteData>
*/
public static function concatFilterStackedNotes(notesA:Array<SongNoteData>, notesB:Array<SongNoteData>, threshold:Float,
modifyB:Bool = false):Array<SongNoteData>
{
// TODO: Maybe this whole function should be moved to SongNoteDataArrayTools
var result:Array<SongNoteData> = notesA.copy();
for (noteB in notesB)
{
var overlaps:Bool = false;
for (noteA in notesA)
{
if (canNotesStack(noteA, noteB))
{
if (Math.abs(noteA.time - noteB.time) < threshold)
{
overlaps = true;
break;
}
}
}
if (!overlaps)
{
result.push(noteB);
if (modifyB) notesB.remove(noteB);
}
}
return result;
}
/**
* @return Returns `true` if both notes are on the same strumline and have the same direction
*/
public static inline function canNotesStack(noteA:SongNoteData, noteB:SongNoteData):Bool
{
return noteA.getStrumlineIndex() == noteB.getStrumlineIndex() && noteA.getDirection() == noteB.getDirection();
}
}