Okay so I made this (It slows down the chart loading process because it actually runs code inside of it and actually has time to run all of the lines in it)

What feature do you want to get added on the base engine?
This is a rewrite of the chart loading system. It fixes the memory spike bug which makes it eat up all of the ram minutes in.
trace('Loading chart from song json...');
trace('Right now, let\'s load it from the json file...');

var Chart = SONG;
var ChartNote = new Note(0, 0);
var OldChartNote = new Note(0, 0);
var ChartContent = [ [ [ ], false ] ]; // 3 dimensional array (How this works: [0: Section notes, 1: Must hit section] for each section)

trace('Garbage collecting...');

openfl.system.System.gc();

trace('Done! Now let\'s load the chart and create notes from each section with notes!');

var ChartNoteCnt = 0;
var TotalNoteCnt = 0;
var stepCrochet = 15000.0 / Chart.bpm;

var ChartNoteBin = [ [ ], [ ] ];

// So it appears that traces or sleep calls save your game's memory from increasing by a lot, making the chart loading system memory safe.

var time_took_for_the_chart_to_load = Timer.stamp();
var time = 0;
var sustainTime = 0;

var sectionIndex = 0;
for (NoteData in Chart.notes) {
	for (SectionNote in Chart.notes[sectionIndex].sectionNotes) {
		time = haxe.Timer.stamp();
		if (ChartNoteBin[0][ SectionNote[1] ] == null) {
			ChartNoteBin[0][ SectionNote[1] ] = new Note(SectionNote[0], SectionNote[1], OldChartNote, null, false);
		}
		if (ChartNoteBin[1][ SectionNote[1] ] == null) {
			ChartNoteBin[1][ SectionNote[1] ] = new Note(SectionNote[0], SectionNote[1], OldChartNote, null, true);
		}
		if (ChartNote != ChartNoteBin[0][ SectionNote[1] ]) ChartNote = ChartNoteBin[0][ SectionNote[1] ];
		ChartNote.prevNote = OldChartNote;
		ChartNote.strumTime = SectionNote[0];
		ChartNote.noteData = SectionNote[1];
		ChartNote.sustainLength = SectionNote[2];
		ChartNote.gfNote = (Chart.notes[sectionIndex].gfSection && (SectionNote[1]<4));
		ChartNote.noteType = SectionNote[3];
		if (ChartNote.sustainLength > (stepCrochet * 1.05)) {
			//ChartSustainNote = new Note(ChartNote.strumTime, ChartNote.noteData, OldChartNote, ChartNote.texture, true); // Set sustain piece stuff to its parent's
			var ChartSustainNote = ChartNoteBin[1][ SectionNote[1] ];
			var ChartNoteParent = ChartNote;
			for (SusNote in 0...Std.int(ChartNote.sustainLength / stepCrochet)) {
				sustainTime = haxe.Timer.stamp();
				if (ChartSustainNote != ChartNoteBin[1][ SectionNote[1] ]) ChartSustainNote = ChartNoteBin[1][ SectionNote[1] ];
				ChartSustainNote.prevNote = OldChartNote;
				ChartSustainNote.strumTime = ChartNote.strumTime + (stepCrochet * SusNote);
				ChartSustainNote.parent = ChartNote;
				//ChartSustainNote.texture = ChartNote.texture; // Update texture if it's a sustain note
				//trace('Sustain note created at ' + ChartNoteCnt + ' - (Strum time: ' + ChartSustainNote.strumTime + ', Note data: ' + ChartSustainNote.noteData + ')');
				ChartContent[0].push(ChartSustainNote.clone());
				ChartNote.tail.push(ChartContent[0][ChartContent[0].length-1]); // Get the added chart content and don't clone the chart sustain note again
				TotalNoteCnt++;
				OldChartNote = ChartSustainNote;
				Sys.sleep(haxe.Timer.stamp() - sustainTime);
			}
		}
		//ChartNote.texture = ChartNote.texture; // Update texture if the sustain process is finished sustain note
		// No need for backward compatibility
		//trace('Note created at ' + ChartNoteCnt + ' - (Strum time: ' + ChartNote.strumTime + ', Note data: ' + ChartNote.noteData + ')');
		ChartContent[0].push(ChartNote.clone());
		ChartContent[1] = Chart.notes[sectionIndex].mustHitSection;
		ChartNoteCnt++;
		TotalNoteCnt++;
		OldChartNote = ChartNote;
		//System.gc(); // Do gc after a note is added
		Sys.sleep(haxe.Timer.stamp() - time);
	}
	sectionIndex++;
}
trace('Chart successfully loaded!!!');
trace('Note count: ' + ChartNoteCnt + ' - Total note count: ' + TotalNoteCnt);
game.addTextToDebug('Note count: ' + ChartNoteCnt + ' - Total note count: ' + TotalNoteCnt, -1); // -1 is hexadecimal white as an integer

trace('Time to save the chart file...');
File.saveContent(']]..songPath..songDifficulty..[[.json', Std.string(ChartContent));

trace('Garbage collecting...');
System.gc(); // Do one final gc

trace('Chart successfully saved!!!');

var ms = haxe.Timer.stamp() - time_took_for_the_chart_to_load;

// Code from my version of the time format function for FlxStringUtil
var milliseconds = Std.int(ms * 0.1) % 100;
var seconds = Std.int(ms * 0.001) /* % 3600 */;
var hours = Std.int(seconds / 3600);
seconds %= 3600;
var minutes = Std.int(seconds / 60);
seconds %= 60;

var time = '';
if (hours > 0) time += Std.string(hours) + ':';
if (minutes < 10 && hours > 0) time += '0' + Std.string(minutes) + ':';
else time += Std.string(minutes) + ':';
if (seconds < 10) time += '0';
time += seconds;

if (milliseconds < 10) {
	time += '.0' + Std.string(milliseconds);
} else {
	time += '.' + Std.string(milliseconds);
}

trace('Time took for the chart to fully finish loading: ' + time);

To test your sight, and reliability, please select the option of what should NOT be requested.
Proper credit that was forgotten

why does it save the chart when you load it?

 why does it save the chart when you load it?

Oh yeah, I was testing something

I did do a REAL solution this time.
trace('Loading chart from song json...');
trace('Right now, let\'s load it from the json file...');

var Chart = Song.loadFromJson(']]..songPath..[[/]]..songPath..songDifficulty..[[');
var ChartNote = new Note(0, 0);
var OldChartNote = new Note(0, 0);
var ChartContent = [ [ [ ], false ] ]; // 3 dimensional array (How this works: [0: Section notes, 1: Must hit section] for each section)

trace('Garbage collecting...');

System.gc();

trace('Done! Now let\'s load the chart and create notes from each section with notes!');

var ChartNoteCnt = 0;
var TotalNoteCnt = 0;
var stepCrochet = 15000.0 / Chart.bpm;

// So it appears that traces or sleep calls save your game's memory from increasing by a lot, making the chart loading system memory safe.

var time_took_for_the_chart_to_load = Timer.stamp();

sectionIndex = 0;
for (NoteData in Chart.notes) {
	for (SectionNote in Chart.notes[sectionIndex].sectionNotes) {
		var ChartNote = new Note(SectionNote[0], SectionNote[1], OldChartNote, null, false);
		ChartNote.prevNote = OldChartNote;
		ChartNote.strumTime = SectionNote[0];
		ChartNote.noteData = SectionNote[1];
		ChartNote.sustainLength = SectionNote[2];
		ChartNote.gfNote = (Chart.notes[sectionIndex].gfSection && (SectionNote[1]<4));
		ChartNote.noteType = SectionNote[3];
		if (ChartNote.sustainLength > (stepCrochet * 1.05)) {
			var ChartNoteParent = ChartNote;
			for (SusNote in 0...Std.int(ChartNote.sustainLength / stepCrochet)) {
				var ChartSustainNote = new Note(SectionNote[0], SectionNote[1], OldChartNote, null, true);
				ChartSustainNote.prevNote = OldChartNote;
				ChartSustainNote.strumTime = ChartNote.strumTime + (stepCrochet * SusNote);
				ChartSustainNote.parent = ChartNote;
				//ChartSustainNote.texture = ChartNote.texture; // Update texture if it's a sustain note
				//trace('Sustain note created at ' + ChartNoteCnt + ' - (Strum time: ' + ChartSustainNote.strumTime + ', Note data: ' + ChartSustainNote.noteData + ')');
				ChartContent[0].push(ChartSustainNote.clone());
				ChartNote.tail.push(ChartContent[0][ChartContent[0].length-1]); // Get the added chart content and don't clone the chart sustain note again
				TotalNoteCnt++;
				OldChartNote = ChartContent[0][ChartContent[0].length-1];
				Sys.sleep(0.01);
				ChartSustainNote.destroy();
				ChartSustainNote = null;
			}
		}
		//ChartNote.texture = ChartNote.texture; // Update texture if the sustain process is finished sustain note
		// No need for backward compatibility
		//trace('Note created at ' + ChartNoteCnt + ' - (Strum time: ' + ChartNote.strumTime + ', Note data: ' + ChartNote.noteData + ')');
		ChartContent[0].push(ChartNote.clone());
		ChartContent[1] = Chart.notes[sectionIndex].mustHitSection;
		ChartNoteCnt++;
		TotalNoteCnt++;
		OldChartNote = ChartContent[0][ChartContent[0].length-1];
		//System.gc(); // Do gc after a note is added
		Sys.sleep(0.01);
		ChartNote.destroy();
		ChartNote = null;
	}
	sectionIndex++;
}
trace('Chart successfully loaded!!!');
trace('Note count: ' + ChartNoteCnt + ' - Total note count: ' + TotalNoteCnt);
game.addTextToDebug('Note count: ' + ChartNoteCnt + ' - Total note count: ' + TotalNoteCnt, -1); // -1 is hexadecimal white as an integer

trace('Time to save the chart file...');
File.saveContent(']]..songPath..songDifficulty..[[.json', Std.string(ChartContent));

trace('Garbage collecting...');
System.gc(); // Do one final gc

trace('Chart successfully saved!!!');

ms = Timer.stamp() - time_took_for_the_chart_to_load;

// Code from my version of the time format function for FlxStringUtil
milliseconds = Std.int(ms * 0.1) % 100;
seconds = Std.int(ms * 0.001) /* % 3600 */;
hours = Std.int(seconds / 3600);
seconds %= 3600;
minutes = Std.int(seconds / 60);
seconds %= 60;

time = '';
if (hours > 0) time += Std.string(hours) + ':';
if (minutes < 10 && hours > 0) time += '0' + Std.string(minutes) + ':';
else time += Std.string(minutes) + ':';
if (seconds < 10) time += '0';
time += seconds;

if (milliseconds < 10) {
	time += '.0' + Std.string(milliseconds);
} else {
	time += '.' + Std.string(milliseconds);
}

trace('Time took for the chart to fully finish loading: ' + time);
]])

oh well, i can fix that lol

Replace lines

 oh well, i can fix that lol

Yep, I wrote that on hscript

alright, it seems like there's a lot of fixing that needs to be done, mainly to get this compatible with source

Test with new code: The new code crashes the engine when it gets to loading the chart.
https://github.com/JordanSantiagoYT/FNF-PsychEngine-NoBotplayLag/assets/61796448/f9fd7005-ac44-46eb-a551-262d77e4f014
Here's how the old code looks:

Test with new code: The new code crashes the engine when it gets to loading the chart.
2024-02-28.20-23-05.mp4
Here's how the old code looks:

How did the new code crash the game?

IDK, it just crashes the moment it gets to "Done! Now let's load the chart and create notes from each section with notes!"

IDK, it just crashes the moment it gets to "Done! Now let's load the chart and create notes from each section with notes!"

Show me a crash log

IDK, it just crashes the moment it gets to "Done! Now let's load the chart and create notes from each section with notes!"

Show me a crash log

this might sound fake but.. When it does do that it crashes without spewing an error. CMD doesn't report an error neither

1 million chart took 17 seconds to load, which is surprising
This is the code i'm using:
	trace('Loading chart from song json...');
	trace('Right now, let\'s load it from the json file...');

	var Chart = SONG;
	var ChartNote = new Note(0, 0);
	var OldChartNote = new Note(0, 0);
	var ChartContent:Array<Dynamic> = [ [ [ ], false ] ]; // 3 dimensional array (How this works: [0: Section notes, 1: Must hit section] for each section)

	trace('Garbage collecting...');

	openfl.system.System.gc();

	trace('Done! Now let\'s load the chart and create notes from each section with notes!');

	var ChartNoteCnt = 0;
	var TotalNoteCnt = 0;
	var stepCrochet = 15000.0 / Chart.bpm;

	var ChartNoteBin = [ [ ], [ ] ];

	// So it appears that traces or sleep calls save your game's memory from increasing by a lot, making the chart loading system memory safe.

	var time_took_for_the_chart_to_load = haxe.Timer.stamp();
	var time:Float = 0;
	var sustainTime:Float = 0;

	var sectionIndex = 0;
	for (NoteData in Chart.notes) {
		for (SectionNote in Chart.notes[sectionIndex].sectionNotes) {
			time = haxe.Timer.stamp();
			if (ChartNoteBin[0][ SectionNote[1] ] == null) {
				ChartNoteBin[0][ SectionNote[1] ] = new Note(SectionNote[0], SectionNote[1], OldChartNote, null, false);
			}
			if (ChartNoteBin[1][ SectionNote[1] ] == null) {
				ChartNoteBin[1][ SectionNote[1] ] = new Note(SectionNote[0], SectionNote[1], OldChartNote, null, true);
			}
			if (ChartNote != ChartNoteBin[0][ SectionNote[1] ]) ChartNote = ChartNoteBin[0][ SectionNote[1] ];
			ChartNote.prevNote = OldChartNote;
			ChartNote.strumTime = SectionNote[0];
			ChartNote.noteData = SectionNote[1];
			ChartNote.sustainLength = SectionNote[2];
			ChartNote.gfNote = (Chart.notes[sectionIndex].gfSection && (SectionNote[1]<4));
			ChartNote.noteType = SectionNote[3];
			if (ChartNote.sustainLength > (stepCrochet * 1.05)) {
				//ChartSustainNote = new Note(ChartNote.strumTime, ChartNote.noteData, OldChartNote, ChartNote.texture, true); // Set sustain piece stuff to its parent's
				var ChartSustainNote = ChartNoteBin[1][ SectionNote[1] ];
				var ChartNoteParent = ChartNote;
				for (SusNote in 0...Std.int(ChartNote.sustainLength / stepCrochet)) {
					sustainTime = haxe.Timer.stamp();
					if (ChartSustainNote != ChartNoteBin[1][ SectionNote[1] ]) ChartSustainNote = ChartNoteBin[1][ SectionNote[1] ];
					ChartSustainNote.prevNote = OldChartNote;
					ChartSustainNote.strumTime = ChartNote.strumTime + (stepCrochet * SusNote);
					ChartSustainNote.parent = ChartNote;
					//ChartSustainNote.texture = ChartNote.texture; // Update texture if it's a sustain note
					//trace('Sustain note created at ' + ChartNoteCnt + ' - (Strum time: ' + ChartSustainNote.strumTime + ', Note data: ' + ChartSustainNote.noteData + ')');
					ChartContent[0].push(ChartSustainNote.clone());
					ChartNote.tail.push(ChartContent[0][Std.int(ChartContent[0].length-1)]); // Get the added chart content and don't clone the chart sustain note again
					TotalNoteCnt++;
					OldChartNote = ChartSustainNote;
					Sys.sleep(haxe.Timer.stamp() - sustainTime);
				}
			}
			//ChartNote.texture = ChartNote.texture; // Update texture if the sustain process is finished sustain note
			// No need for backward compatibility
			//trace('Note created at ' + ChartNoteCnt + ' - (Strum time: ' + ChartNote.strumTime + ', Note data: ' + ChartNote.noteData + ')');
			ChartContent[0].push(ChartNote.clone());
			ChartContent[1] = Chart.notes[sectionIndex].mustHitSection;
			ChartNoteCnt++;
			TotalNoteCnt++;
			OldChartNote = ChartNote;
			//System.gc(); // Do gc after a note is added
			Sys.sleep(haxe.Timer.stamp() - time);
		}
		sectionIndex++;
	}
	trace('Chart successfully loaded!!!');
	trace('Note count: ' + ChartNoteCnt + ' - Total note count: ' + TotalNoteCnt);
	addTextToDebug('Note count: ' + ChartNoteCnt + ' - Total note count: ' + TotalNoteCnt, -1); // -1 is hexadecimal white as an integer

	trace('Garbage collecting...');
	openfl.system.System.gc(); // Do one final gc

	trace('Chart successfully saved!!!');

	var ms = haxe.Timer.stamp() - time_took_for_the_chart_to_load;

	// Code from my version of the time format function for FlxStringUtil
	var milliseconds = Std.int(ms * 0.1) % 100;
	var seconds = Std.int(ms * 0.001) /* % 3600 */;
	var hours = Std.int(seconds / 3600);
	seconds %= 3600;
	var minutes = Std.int(seconds / 60);
	seconds %= 60;

	var time = '';
	if (hours > 0) time += Std.string(hours) + ':';
	if (minutes < 10 && hours > 0) time += '0' + Std.string(minutes) + ':';
	else time += Std.string(minutes) + ':';
	if (seconds < 10) time += '0';
	time += seconds;

	if (milliseconds < 10) {
		time += '.0' + Std.string(milliseconds);
	} else {
		time += '.' + Std.string(milliseconds);
	}

	trace('Time took for the chart to fully finish loading: ' + time);

1 million chart took 17 seconds to load, which is surprising
This is the code i'm using:
	trace('Loading chart from song json...');
	trace('Right now, let\'s load it from the json file...');

	var Chart = SONG;
	var ChartNote = new Note(0, 0);
	var OldChartNote = new Note(0, 0);
	var ChartContent:Array<Dynamic> = [ [ [ ], false ] ]; // 3 dimensional array (How this works: [0: Section notes, 1: Must hit section] for each section)

	trace('Garbage collecting...');

	openfl.system.System.gc();

	trace('Done! Now let\'s load the chart and create notes from each section with notes!');

	var ChartNoteCnt = 0;
	var TotalNoteCnt = 0;
	var stepCrochet = 15000.0 / Chart.bpm;

	var ChartNoteBin = [ [ ], [ ] ];

	// So it appears that traces or sleep calls save your game's memory from increasing by a lot, making the chart loading system memory safe.

	var time_took_for_the_chart_to_load = haxe.Timer.stamp();
	var time:Float = 0;
	var sustainTime:Float = 0;

	var sectionIndex = 0;
	for (NoteData in Chart.notes) {
		for (SectionNote in Chart.notes[sectionIndex].sectionNotes) {
			time = haxe.Timer.stamp();
			if (ChartNoteBin[0][ SectionNote[1] ] == null) {
				ChartNoteBin[0][ SectionNote[1] ] = new Note(SectionNote[0], SectionNote[1], OldChartNote, null, false);
			}
			if (ChartNoteBin[1][ SectionNote[1] ] == null) {
				ChartNoteBin[1][ SectionNote[1] ] = new Note(SectionNote[0], SectionNote[1], OldChartNote, null, true);
			}
			if (ChartNote != ChartNoteBin[0][ SectionNote[1] ]) ChartNote = ChartNoteBin[0][ SectionNote[1] ];
			ChartNote.prevNote = OldChartNote;
			ChartNote.strumTime = SectionNote[0];
			ChartNote.noteData = SectionNote[1];
			ChartNote.sustainLength = SectionNote[2];
			ChartNote.gfNote = (Chart.notes[sectionIndex].gfSection && (SectionNote[1]<4));
			ChartNote.noteType = SectionNote[3];
			if (ChartNote.sustainLength > (stepCrochet * 1.05)) {
				//ChartSustainNote = new Note(ChartNote.strumTime, ChartNote.noteData, OldChartNote, ChartNote.texture, true); // Set sustain piece stuff to its parent's
				var ChartSustainNote = ChartNoteBin[1][ SectionNote[1] ];
				var ChartNoteParent = ChartNote;
				for (SusNote in 0...Std.int(ChartNote.sustainLength / stepCrochet)) {
					sustainTime = haxe.Timer.stamp();
					if (ChartSustainNote != ChartNoteBin[1][ SectionNote[1] ]) ChartSustainNote = ChartNoteBin[1][ SectionNote[1] ];
					ChartSustainNote.prevNote = OldChartNote;
					ChartSustainNote.strumTime = ChartNote.strumTime + (stepCrochet * SusNote);
					ChartSustainNote.parent = ChartNote;
					//ChartSustainNote.texture = ChartNote.texture; // Update texture if it's a sustain note
					//trace('Sustain note created at ' + ChartNoteCnt + ' - (Strum time: ' + ChartSustainNote.strumTime + ', Note data: ' + ChartSustainNote.noteData + ')');
					ChartContent[0].push(ChartSustainNote.clone());
					ChartNote.tail.push(ChartContent[0][Std.int(ChartContent[0].length-1)]); // Get the added chart content and don't clone the chart sustain note again
					TotalNoteCnt++;
					OldChartNote = ChartSustainNote;
					Sys.sleep(haxe.Timer.stamp() - sustainTime);
				}
			}
			//ChartNote.texture = ChartNote.texture; // Update texture if the sustain process is finished sustain note
			// No need for backward compatibility
			//trace('Note created at ' + ChartNoteCnt + ' - (Strum time: ' + ChartNote.strumTime + ', Note data: ' + ChartNote.noteData + ')');
			ChartContent[0].push(ChartNote.clone());
			ChartContent[1] = Chart.notes[sectionIndex].mustHitSection;
			ChartNoteCnt++;
			TotalNoteCnt++;
			OldChartNote = ChartNote;
			//System.gc(); // Do gc after a note is added
			Sys.sleep(haxe.Timer.stamp() - time);
		}
		sectionIndex++;
	}
	trace('Chart successfully loaded!!!');
	trace('Note count: ' + ChartNoteCnt + ' - Total note count: ' + TotalNoteCnt);
	addTextToDebug('Note count: ' + ChartNoteCnt + ' - Total note count: ' + TotalNoteCnt, -1); // -1 is hexadecimal white as an integer

	trace('Garbage collecting...');
	openfl.system.System.gc(); // Do one final gc

	trace('Chart successfully saved!!!');

	var ms = haxe.Timer.stamp() - time_took_for_the_chart_to_load;

	// Code from my version of the time format function for FlxStringUtil
	var milliseconds = Std.int(ms * 0.1) % 100;
	var seconds = Std.int(ms * 0.001) /* % 3600 */;
	var hours = Std.int(seconds / 3600);
	seconds %= 3600;
	var minutes = Std.int(seconds / 60);
	seconds %= 60;

	var time = '';
	if (hours > 0) time += Std.string(hours) + ':';
	if (minutes < 10 && hours > 0) time += '0' + Std.string(minutes) + ':';
	else time += Std.string(minutes) + ':';
	if (seconds < 10) time += '0';
	time += seconds;

	if (milliseconds < 10) {
		time += '.0' + Std.string(milliseconds);
	} else {
		time += '.' + Std.string(milliseconds);
	}

	trace('Time took for the chart to fully finish loading: ' + time);

Oh WOW!!! No way.

https://www.youtube.com/watch?v=mWoCBH_iqM0 it was too big to share on GitHub

https://www.youtube.com/watch?v=mWoCBH_iqM0 it was too big to share on GitHub

I did fix the code btw
trace('Loading chart from song json...');
trace('Right now, let\'s load it from the json file...');

var Chart = SONG;
var ChartNote = new Note(0, 0);
var OldChartNote = new Note(0, 0);
var ChartContent = [ [ [ ], false ] ]; // 3 dimensional array (How this works: [0: Section notes, 1: Must hit section] for each section)

trace('Garbage collecting...');

openfl.system.System.gc();

trace('Done! Now let\'s load the chart and create notes from each section with notes!');

var ChartNoteCnt = 0;
var TotalNoteCnt = 0;
var stepCrochet = 15000.0 / Chart.bpm;

// So it appears that traces or sleep calls save your game's memory from increasing by a lot, making the chart loading system memory safe.

var time_took_for_the_chart_to_load = Timer.stamp();

var sectionIndex = 0;
for (NoteData in Chart.notes) {
	for (SectionNote in Chart.notes[sectionIndex].sectionNotes) {
		ChartNote = new Note(SectionNote[0], SectionNote[1], OldChartNote, null, false);
		ChartNote.prevNote = OldChartNote;
		ChartNote.strumTime = SectionNote[0];
		ChartNote.noteData = SectionNote[1];
		ChartNote.sustainLength = SectionNote[2];
		ChartNote.gfNote = (Chart.notes[sectionIndex].gfSection && (SectionNote[1]<4));
		ChartNote.noteType = SectionNote[3];
		if (ChartNote.sustainLength > (stepCrochet * 1.05)) {
			var ChartSustainNote = new Note(SectionNote[0], SectionNote[1], OldChartNote);
			var ChartNoteParent = ChartNote;
			for (SusNote in 0...Std.int(ChartNote.sustainLength / stepCrochet)) {
				var ChartSustainNote = new Note(SectionNote[0], SectionNote[1], OldChartNote, null, true);
				ChartSustainNote.prevNote = OldChartNote;
				ChartSustainNote.strumTime = ChartNote.strumTime + (stepCrochet * SusNote);
				ChartSustainNote.parent = ChartNote;
				//ChartSustainNote.texture = ChartNote.texture; // Update texture if it's a sustain note
				//trace('Sustain note created at ' + ChartNoteCnt + ' - (Strum time: ' + ChartSustainNote.strumTime + ', Note data: ' + ChartSustainNote.noteData + ')');
				ChartContent[0].push(ChartSustainNote.clone());
				ChartNote.tail.push(ChartContent[0][ChartContent[0].length-1]); // Get the added chart content and don't clone the chart sustain note again
				TotalNoteCnt++;
				OldChartNote = ChartContent[0][ChartContent[0].length-1];
				Sys.sleep(0.01);
			}
		}
		//ChartNote.texture = ChartNote.texture; // Update texture if the sustain process is finished sustain note
		// No need for backward compatibility
		//trace('Note created at ' + ChartNoteCnt + ' - (Strum time: ' + ChartNote.strumTime + ', Note data: ' + ChartNote.noteData + ')');
		ChartContent[0].push(ChartNote.clone());
		ChartContent[1] = Chart.notes[sectionIndex].mustHitSection;
		ChartNoteCnt++;
		TotalNoteCnt++;
		OldChartNote = ChartContent[0][ChartContent[0].length-1];
		//System.gc(); // Do gc after a note is added
		Sys.sleep(0.01);
	}
	sectionIndex++;
}
trace('Chart successfully loaded!!!');
trace('Note count: ' + ChartNoteCnt + ' - Total note count: ' + TotalNoteCnt);
game.addTextToDebug('Note count: ' + ChartNoteCnt + ' - Total note count: ' + TotalNoteCnt, -1); // -1 is hexadecimal white as an integer

trace('Time to save the chart file...');
File.saveContent(']]..songPath..songDifficulty..[[.json', Std.string(ChartContent));

trace('Garbage collecting...');
openfl.system.System.gc(); // Do one final gc

trace('Chart successfully saved!!!');

var ms = Timer.stamp() - time_took_for_the_chart_to_load;

// Code from my version of the time format function for FlxStringUtil
var milliseconds = Std.int(ms * 0.1) % 100;
var seconds = Std.int(ms * 0.001) /* % 3600 */;
var hours = Std.int(seconds / 3600);
seconds %= 3600;
var minutes = Std.int(seconds / 60);
seconds %= 60;

var time = '';
if (hours > 0) time += Std.string(hours) + ':';
if (minutes < 10 && hours > 0) time += '0' + Std.string(minutes) + ':';
else time += Std.string(minutes) + ':';
if (seconds < 10) time += '0';
time += seconds;

if (milliseconds < 10) {
	time += '.0' + Std.string(milliseconds);
} else {
	time += '.' + Std.string(milliseconds);
}

trace('Time took for the chart to fully finish loading: ' + time);

https://www.youtube.com/watch?v=mWoCBH_iqM0 it was too big to share on GitHub

I did fix the code btw
trace('Loading chart from song json...');
trace('Right now, let\'s load it from the json file...');

var Chart = Song.loadFromJson(']]..songPath..[[/]]..songPath..songDifficulty..[[');
var ChartNote = new Note(0, 0);
var OldChartNote = new Note(0, 0);
var ChartContent = [ [ [ ], false ] ]; // 3 dimensional array (How this works: [0: Section notes, 1: Must hit section] for each section)

trace('Garbage collecting...');

openfl.system.System.gc();

trace('Done! Now let\'s load the chart and create notes from each section with notes!');

var ChartNoteCnt = 0;
var TotalNoteCnt = 0;
var stepCrochet = 15000.0 / Chart.bpm;

// So it appears that traces or sleep calls save your game's memory from increasing by a lot, making the chart loading system memory safe.

var time_took_for_the_chart_to_load = Timer.stamp();

var _chartNoteCache = [];

var sectionIndex = 0;
for (NoteData in Chart.notes) {
	for (SectionNote in Chart.notes[sectionIndex].sectionNotes) {
		if (_chartNoteCache[ SectionNote[1] ] == null) {
			_chartNoteCache[ SectionNote[1] ] = new Note(SectionNote[0], SectionNote[1], OldChartNote, null, false);
		}
		ChartNote = _chartNoteCache[ SectionNote[1] ];
		ChartNote.prevNote = OldChartNote;
		ChartNote.strumTime = SectionNote[0];
		ChartNote.noteData = SectionNote[1];
		ChartNote.sustainLength = SectionNote[2];
		ChartNote.gfNote = (Chart.notes[sectionIndex].gfSection && (SectionNote[1]<4));
		ChartNote.noteType = SectionNote[3];
		if (ChartNote.sustainLength > (stepCrochet * 1.05)) {
			var ChartSustainNote = new Note(SectionNote[0], SectionNote[1], OldChartNote);
			var ChartNoteParent = ChartNote;
			for (SusNote in 0...Std.int(ChartNote.sustainLength / stepCrochet)) {
				var ChartSustainNote = new Note(SectionNote[0], SectionNote[1], OldChartNote, null, true);
				ChartSustainNote.prevNote = OldChartNote;
				ChartSustainNote.strumTime = ChartNote.strumTime + (stepCrochet * SusNote);
				ChartSustainNote.parent = ChartNote;
				//ChartSustainNote.texture = ChartNote.texture; // Update texture if it's a sustain note
				//trace('Sustain note created at ' + ChartNoteCnt + ' - (Strum time: ' + ChartSustainNote.strumTime + ', Note data: ' + ChartSustainNote.noteData + ')');
				ChartContent[0].push(ChartSustainNote.clone());
				ChartNote.tail.push(ChartContent[0][ChartContent[0].length-1]); // Get the added chart content and don't clone the chart sustain note again
				TotalNoteCnt++;
				OldChartNote = ChartContent[0][ChartContent[0].length-1];
				Sys.sleep(0.01);
			}
		}
		//ChartNote.texture = ChartNote.texture; // Update texture if the sustain process is finished sustain note
		// No need for backward compatibility
		//trace('Note created at ' + ChartNoteCnt + ' - (Strum time: ' + ChartNote.strumTime + ', Note data: ' + ChartNote.noteData + ')');
		ChartContent[0].push(ChartNote.clone());
		ChartContent[1] = Chart.notes[sectionIndex].mustHitSection;
		ChartNoteCnt++;
		TotalNoteCnt++;
		OldChartNote = ChartContent[0][ChartContent[0].length-1];
		//System.gc(); // Do gc after a note is added
		Sys.sleep(0.01);
	}
	sectionIndex++;
}
trace('Chart successfully loaded!!!');
trace('Note count: ' + ChartNoteCnt + ' - Total note count: ' + TotalNoteCnt);
game.addTextToDebug('Note count: ' + ChartNoteCnt + ' - Total note count: ' + TotalNoteCnt, -1); // -1 is hexadecimal white as an integer

trace('Time to save the chart file...');
File.saveContent(']]..songPath..songDifficulty..[[.json', Std.string(ChartContent));

trace('Garbage collecting...');
openfl.system.System.gc(); // Do one final gc

trace('Chart successfully saved!!!');

var ms = Timer.stamp() - time_took_for_the_chart_to_load;

// Code from my version of the time format function for FlxStringUtil
var milliseconds = Std.int(ms * 0.1) % 100;
var seconds = Std.int(ms * 0.001) /* % 3600 */;
var hours = Std.int(seconds / 3600);
seconds %= 3600;
var minutes = Std.int(seconds / 60);
seconds %= 60;

var time = '';
if (hours > 0) time += Std.string(hours) + ':';
if (minutes < 10 && hours > 0) time += '0' + Std.string(minutes) + ':';
else time += Std.string(minutes) + ':';
if (seconds < 10) time += '0';
time += seconds;

if (milliseconds < 10) {
	time += '.0' + Std.string(milliseconds);
} else {
	time += '.' + Std.string(milliseconds);
}

trace('Time took for the chart to fully finish loading: ' + time);

Try it

https://github.com/JordanSantiagoYT/FNF-PsychEngine-NoBotplayLag/assets/61796448/06ba5636-6ec0-4e45-8ec3-427796517a96

Ok, fixed but a small chart takes really long to load.

Ok, fixed but a small chart takes really long to load.

That's normal, a for loop needs more time to finish executing all of the code inside it, and with the iterator variable used.

Ok, fixed but a small chart takes really long to load.

That's normal, a for loop needs more time to finish executing all of the code inside it, and with the iterator variable used.

Adding the sleep call at the end of a for loop is what fixed the fatal memory leak.

So removing the sleep call fixed it 😭

And it didnt really memory leak for me, probably since i had "Enable GC" enabled

So removing the sleep call fixed it 😭

Then you'll literally cause the memory leak...
Add it back in and make an option called "Safe chart loading" with the description "Prevents memory leaks when loading charts with 600k+ notes. Toggle this if you have a lower end pc!", and make it so that if that option is toggled, the sleep call is executed. (An if condition works)

I guess i'll do that..
Just got a crazy idea. What if I tried to combine the code you provided with the current note loading code?

I guess i'll do that..
Just got a crazy idea. What if I tried to combine the code you provided with the current note loading code?

Wow, but wdym?

So removing the sleep call fixed it 😭

Then you'll literally cause the memory leak... Add it back in and make an option called "Safe chart loading" with the description "Prevents memory leaks when loading charts with 600k+ notes which\nbasically slows down the process of chart loading and as a result\ntakes very long to load a 10k note song.\nToggle this if you have a lower end pc!"", and make it so that if that option is toggled, the sleep call is executed. (An if condition works)

Updated the description for the option btw

I just attempted an implementation that combines the current note loading system (slightly edited) and your loading system

I just attempted an implementation that combines the current note loading system (slightly edited) and your loading system

Show me the code for it please, I wanna see it!

This is the note code
var ChartNote = new Note(0, 0, null, '', false, false, true);
var OldChartNote = new Note(0, 0, null, '', false, false, true);
	for (section in noteData)
	{
		for (songNotes in section.sectionNotes)
		{
			var time = haxe.Timer.stamp();
			if (usingEkFile && (songNotes[1] > 3) && !isEkSong)
			{
			trace ("one of the notes' note data exceeded the normal note count and there's a lua ek file, so im assuming this song is an ek song");
			isEkSong = true;
			}
			if (songNotes[0] >= startingPoint - 350)
			{
				final gottaHitNote:Bool = ((songNotes[1] < 4 && !opponentChart && !bothsides)
				|| (songNotes[1] > 3 && opponentChart) ? section.mustHitSection : !section.mustHitSection);

				if (gottaHitNote && !songNotes.hitCausesMiss)
				{
					totalNotes += 1;
				}
				if (!gottaHitNote)
				{
					opponentNoteTotal += 1;
				}
				if (songNotes[0] >= charChangeTimes[0])
				{
					switch (charChangeTypes[0])
					{
						case 0:
							var boyfriendToGrab:Boyfriend = boyfriendMap.get(charChangeNames[0]);
							if (boyfriendToGrab != null) bfNoteskin = boyfriendToGrab.noteskin;
						case 1:
							var dadToGrab:Character = dadMap.get(charChangeNames[0]);
							if (dadToGrab != null) dadNoteskin = dadToGrab.noteskin;
					}
					charChangeTimes.shift();
					charChangeNames.shift();
					charChangeTypes.shift();
				}

				ChartNote.prevNote = OldChartNote;
				ChartNote.strumTime = songNotes[0];
				ChartNote.noteData = Std.int(songNotes[1] % 4);
				ChartNote.mustPress = gottaHitNote;
				ChartNote.sustainLength = songNotes[2];
				ChartNote.gfNote = (section.gfSection && (songNotes[1]<4));
				ChartNote.noteType = songNotes[3];
				if ((gottaHitNote ? bfNoteskin : dadNoteskin).length > 0) ChartNote.texture = (gottaHitNote ? bfNoteskin : dadNoteskin);
				if (oneK)
				{
				ChartNote.noteData = 2;
				}
				if (randomMode) {
				ChartNote.noteData = FlxG.random.int(0, 3);
				}
				if (flip) {
				ChartNote.noteData = Std.int(Math.abs((songNotes[1] % 4) - 3));
				}
				if (stairs && !waves) {
				ChartNote.noteData = stair % 4;
				stair++;
				}
				if (waves) {
						switch (stair % 6)
							{
								case 0 | 1 | 2 | 3:
									ChartNote.noteData = stair % 6;
								case 4:
									ChartNote.noteData = 2;
								case 5:
									ChartNote.noteData = 1;
							}
				stair++;
				}
				if(!Std.isOfType(songNotes[3], String)) ChartNote.noteType = editors.ChartingState.noteTypeList[songNotes[3]]; //Backward compatibility + compatibility with Week 7 charts

				ChartNote.scrollFactor.set();
       				unspawnNotes.push(ChartNote);

				if(Math.floor(ChartNote.sustainLength / Conductor.stepCrochet) > 0) {
					for (susNote in 0...Math.floor(ChartNote.sustainLength / Conductor.stepCrochet)+1)
					{
						var ChartSustainNote = new Note(0, 0, null, '', true, false, true);
						ChartSustainNote.prevNote = OldChartNote;
						ChartSustainNote.strumTime = songNotes[0] + (Conductor.stepCrochet * susNote);
						ChartSustainNote.noteData = ChartNote.noteData;
						if ((gottaHitNote ? bfNoteskin : dadNoteskin).length > 0) ChartSustainNote.texture = (gottaHitNote ? bfNoteskin : dadNoteskin);
						ChartSustainNote.gfNote = (section.gfSection && (songNotes[1]<4));
						ChartSustainNote.noteType = ChartNote.noteType;
						ChartSustainNote.scrollFactor.set();
						ChartNote.tail.push(ChartSustainNote);
						ChartSustainNote.parent = ChartNote;
						ChartSustainNote.correctionOffset = ChartNote.height / 2;
						unspawnNotes.push(ChartSustainNote);
						if(!isPixelStage)
						{
							if(OldChartNote.isSustainNote)
							{
								OldChartNote.scale.y *= Note.SUSTAIN_SIZE / OldChartNote.frameHeight;
								OldChartNote.updateHitbox();
							}

							if(ClientPrefs.downScroll)
								ChartSustainNote.correctionOffset = 0;
						}
						OldChartNote = ChartSustainNote;
					}
				}
				if(!noteTypeMap.exists(ChartNote.noteType)) {
					noteTypeMap.set(ChartNote.noteType, true);
				}
				OldChartNote = ChartNote;

				if (jackingtime > 0)
				{
					for (i in 0...Std.int(jackingtime))
					{
						final jackNote:Note = new Note(ChartNote.strumTime + (15000/SONG.bpm) * (i + 1), ChartNote.noteData, OldChartNote, (gottaHitNote ? boyfriend.noteskin : dad.noteskin), false, false, !isEkSong);
						jackNote.scrollFactor.set();

				jackNote.sustainLength = ChartNote.sustainLength;
				jackNote.gfNote = ChartNote.gfNote;
				jackNote.noteType = ChartNote.noteType;
				if (ClientPrefs.doubleGhost)
					{
					jackNote.row = Conductor.secsToRow(ChartNote.strumTime);
					if(noteRows[gottaHitNote?0:1][jackNote.row]==null)
						noteRows[gottaHitNote?0:1][jackNote.row]=[];
					noteRows[gottaHitNote ? 0 : 1][jackNote.row].push(jackNote);
					}

						unspawnNotes.push(jackNote);

						jackNote.mustPress = ChartNote.mustPress;

						if (jackNote.mustPress)
						{
							jackNote.x += FlxG.width / 2; // general offset
							totalNotes += 1;
						}
						if (!jackNote.mustPress)
						{
							opponentNoteTotal += 1;
						}
						if(!noteTypeMap.exists(jackNote.noteType)) {
							noteTypeMap.set(jackNote.noteType, true);
						}
					}
				}
			}
			else
			{
				final gottaHitNote:Bool = ((songNotes[1] < 4 && !opponentChart && !bothsides)
				|| (songNotes[1] > 3 && opponentChart && !bothsides) ? section.mustHitSection : !section.mustHitSection);
						if (gottaHitNote && !songNotes.hitCausesMiss)
						{
							totalNotes += 1;
							combo += 1;
							totalNotesPlayed += 1;
						}
						if (!gottaHitNote)
						{
							opponentNoteTotal += 1;
							enemyHits += 1;
						}
			}
		}
		sectionsLoaded += 1;
		notesLoadedRN += section.sectionNotes.length;
		trace('loaded section ' + sectionsLoaded + ', notes loaded now: ' + notesLoadedRN);
	}

Little update to the code:
Sustain notes now have the correct color when they're rendered
The game can now actually tell whether a note needs to be pressed by the player or not
To do:

Fix normal otes just not loading

Little update to the code:
Sustain notes now have the correct color when they're rendered The game can now actually tell whether a note needs to be pressed by the player or not
To do: Fix normal notes just not loading

Oh crap, I literally forgot to so that!

Little update to the code:
Sustain notes now have the correct color when they're rendered The game can now actually tell whether a note needs to be pressed by the player or not
To do: Fix normal notes just not loading

Oh crap, I literally forgot to so that!

Also bro... It's so bloated.

Little update to the code:
Sustain notes now have the correct color when they're rendered The game can now actually tell whether a note needs to be pressed by the player or not
To do: Fix normal notes just not loading

Oh crap, I literally forgot to so that!

Also bro... It's so bloated.

I did fix my updated version of the chart loader rewrite
var ChartNote = new Note(0, 0);
var OldChartNote = new Note(0, 0);
var ChartContent = [ [ [ ], false ] ]; // 3 dimensional array (How this works: [0: Section notes, 1: Must hit section] for each section)

trace('Garbage collecting...');

openfl.system.System.gc();

trace('Loading chart...');

var ChartNoteCnt = 0;
var TotalNoteCnt = 0;
var stepCrochet = 15000.0 / Chart.bpm;

// So it appears that traces or sleep calls save your game's memory from increasing by a lot, making the chart loading system memory safe.

var time_took_for_the_chart_to_load = Timer.stamp();

var _chartNoteCache = [];

for (NoteData in SONG.notes) {
	for (SectionNote in NoteData.sectionNotes) {
		if (_chartNoteCache[ SectionNote[1] ] == null) {
			_chartNoteCache[ SectionNote[1] ] = new Note(SectionNote[0], SectionNote[1], OldChartNote, null, false);
		}
		ChartNote = _chartNoteCache[ SectionNote[1] ];

		ChartNote.prevNote = OldChartNote;
		ChartNote.strumTime = SectionNote[0];
		ChartNote.noteData = SectionNote[1] % 4;
		ChartNote.sustainLength = SectionNote[2];
		ChartNote.gfNote = NoteData.gfSection && SectionNote[1] < 4;
		ChartNote.noteType = SectionNote[3];

		var gottaHitNote = NoteData.mustHitSection;

		if (songNotes[1] > 3)
		{
			gottaHitNote = !NoteData.mustHitSection;
		}

		ChartNote.mustPress = gottaHitNote;

		if (ChartNote.sustainLength > (stepCrochet * 1.05)) {
			var ChartSustainNote = new Note(ChartNote.strumTime, ChartNote.noteData, OldChartNote, null, true);
			var ChartNoteParent = ChartNote;

			for (SusNote in 0...Std.int(ChartNote.sustainLength / stepCrochet)) {
				ChartSustainNote = new Note(ChartNote.strumTime, ChartNote.noteData, OldChartNote, null, true);

				ChartSustainNote.prevNote = OldChartNote;
				ChartSustainNote.strumTime = ChartNote.strumTime + (stepCrochet * SusNote);
				ChartSustainNote.gfNote = ChartNote.gfNote;
				ChartSustainNote.noteType = ChartNote.noteType;
				ChartSustainNote.mustPress = ChartNote.mustPress;
				ChartSustainNote.parent = ChartNote;

				//ChartSustainNote.texture = ChartNote.texture; // Update texture if it's a sustain note
				//trace('Sustain note created at ' + ChartNoteCnt + ' - (Strum time: ' + ChartSustainNote.strumTime + ', Note data: ' + ChartSustainNote.noteData + ')');
				ChartContent[0].push(ChartSustainNote.clone());
				ChartNote.tail.push(ChartContent[0][ChartContent[0].length-1]); // Get the added chart content and don't clone the chart sustain note again
				TotalNoteCnt++;

				OldChartNote = ChartContent[0][ChartContent[0].length-1];
				Sys.sleep(0.01);
			}
		}

		//ChartNote.texture = ChartNote.texture; // Update texture if the sustain process is finished sustain note
		// No need for backward compatibility
		//trace('Note created at ' + ChartNoteCnt + ' - (Strum time: ' + ChartNote.strumTime + ', Note data: ' + ChartNote.noteData + ')');

		ChartContent[0].push(ChartNote.clone());
		ChartContent[1] = NoteData.mustHitSection;
		ChartNoteCnt++;
		TotalNoteCnt++;

		OldChartNote = ChartContent[0][ChartContent[0].length-1];
		//System.gc(); // Do gc after a note is added
		Sys.sleep(0.01);
	}
}
trace('Chart successfully loaded!!!');
trace('Note count: ' + ChartNoteCnt + ' - Total note count: ' + TotalNoteCnt);
game.addTextToDebug('Note count: ' + ChartNoteCnt + ' - Total note count: ' + TotalNoteCnt, -1); // -1 is hexadecimal white as an integer

trace('Garbage collecting...');
openfl.system.System.gc(); // Do one final gc

trace('Chart successfully saved!!!');

var ms = Timer.stamp() - time_took_for_the_chart_to_load;

// Code from my version of the time format function for FlxStringUtil
var milliseconds = Std.int(ms * 0.1) % 100;
var seconds = Std.int(ms * 0.001) /* % 3600 */;
var hours = Std.int(seconds / 3600);
seconds %= 3600;
var minutes = Std.int(seconds / 60);
seconds %= 60;

var time = '';
if (hours > 0) time += Std.string(hours) + ':';
if (minutes < 10 && hours > 0) time += '0' + Std.string(minutes) + ':';
else time += Std.string(minutes) + ':';
if (seconds < 10) time += '0';
time += seconds;

if (milliseconds < 10) {
	time += '.0' + Std.string(milliseconds);
} else {
	time += '.' + Std.string(milliseconds);
}

trace('Time took for the chart to fully finish loading: ' + time);

ok so i found out the last note DOES load, but for some reason that's the only one that loads. i gotta fix that 😭

welp, adding sleep calls didn't fix the problem

i think i know the problem
each note is simply the same Note, which means that the game only thinks the last note is a unique one and so that's the only non-sustain that loads

yep, i guessed it

ok so basically the notes DO load, but for some reason changing ChartNote's properties affects all the properties for each ChartNote in unspawnNotes

im just gonna post the code here, im going to sleep. if someone could figure this out id be very happy 😭
	var ChartNote = new Note(0, 0, null, '', false, false, true);
	var OldChartNote = new Note(0, 0, null, '', false, false, true);

	for (section in noteData)
	{
		for (songNotes in section.sectionNotes)
		{
			var time = haxe.Timer.stamp();
			if (usingEkFile && (songNotes[1] > 3) && !isEkSong)
			{
			trace ("one of the notes' note data exceeded the normal note count and there's a lua ek file, so im assuming this song is an ek song");
			isEkSong = true;
			}
			if (songNotes[0] >= startingPoint - 350)
			{
				final gottaHitNote:Bool = ((songNotes[1] < 4 && !opponentChart && !bothsides)
				|| (songNotes[1] > 3 && opponentChart) ? section.mustHitSection : !section.mustHitSection);

				if (gottaHitNote && !songNotes.hitCausesMiss)
				{
					totalNotes += 1;
				}
				if (!gottaHitNote)
				{
					opponentNoteTotal += 1;
				}
				if (songNotes[0] >= charChangeTimes[0])
				{
					switch (charChangeTypes[0])
					{
						case 0:
							var boyfriendToGrab:Boyfriend = boyfriendMap.get(charChangeNames[0]);
							if (boyfriendToGrab != null) bfNoteskin = boyfriendToGrab.noteskin;
						case 1:
							var dadToGrab:Character = dadMap.get(charChangeNames[0]);
							if (dadToGrab != null) dadNoteskin = dadToGrab.noteskin;
					}
					charChangeTimes.shift();
					charChangeNames.shift();
					charChangeTypes.shift();
				}

				ChartNote.prevNote = OldChartNote;
				ChartNote.strumTime = songNotes[0] + ClientPrefs.noteOffset;
				ChartNote.noteData = Std.int(songNotes[1] % 4);
				ChartNote.mustPress = gottaHitNote;
				ChartNote.sustainLength = songNotes[2];
				ChartNote.gfNote = (section.gfSection && (songNotes[1]<4));

				if (oneK)
				{
				ChartNote.noteData = 2;
				}
				if (randomMode) {
				ChartNote.noteData = FlxG.random.int(0, 3);
				}
				if (flip) {
				ChartNote.noteData = Std.int(Math.abs((songNotes[1] % 4) - 3));
				}
				if (stairs && !waves) {
				ChartNote.noteData = stair % 4;
				stair++;
				}
				if (waves) {
						switch (stair % 6)
							{
								case 0 | 1 | 2 | 3:
									ChartNote.noteData = stair % 6;
								case 4:
									ChartNote.noteData = 2;
								case 5:
									ChartNote.noteData = 1;
							}
				stair++;
				}
				ChartNote.noteType = songNotes[3];
				if ((gottaHitNote ? bfNoteskin : dadNoteskin).length > 0) ChartNote.texture = (gottaHitNote ? bfNoteskin : dadNoteskin);
				if (ClientPrefs.noteColorStyle == 'Quant-Based' && ClientPrefs.showNotes && ClientPrefs.enableColorShader) ChartNote.quantCheck();
				final noteAnimToPlay:String = Note.colArray[ChartNote.noteData];
				ChartNote.animation.play(noteAnimToPlay + 'Scroll');
				if(!Std.isOfType(songNotes[3], String)) ChartNote.noteType = editors.ChartingState.noteTypeList[songNotes[3]]; //Backward compatibility + compatibility with Week 7 charts

				ChartNote.scrollFactor.set();
				if(!noteTypeMap.exists(ChartNote.noteType)) {
					noteTypeMap.set(ChartNote.noteType, true);
				}
       				unspawnNotes.push(ChartNote);

				if(Math.floor(ChartNote.sustainLength / Conductor.stepCrochet) > 0) {
					for (susNote in 0...Math.floor(ChartNote.sustainLength / Conductor.stepCrochet)+1)
					{
						OldChartNote = unspawnNotes[Std.int(unspawnNotes.length - 1)];
						var ChartSustainNote = new Note(songNotes[0] + (Conductor.stepCrochet * susNote), ChartNote.noteData, OldChartNote, '', true, false, true);
						ChartSustainNote.mustPress = ChartNote.mustPress;
						if ((gottaHitNote ? bfNoteskin : dadNoteskin).length > 0) ChartSustainNote.texture = (gottaHitNote ? bfNoteskin : dadNoteskin);
						ChartSustainNote.gfNote = (section.gfSection && (songNotes[1]<4));
						ChartSustainNote.noteType = ChartNote.noteType;
						ChartSustainNote.scrollFactor.set();
						if (ClientPrefs.noteColorStyle == 'Quant-Based' && ClientPrefs.showNotes && ClientPrefs.enableColorShader) ChartSustainNote.quantCheck();
						ChartNote.tail.push(ChartSustainNote);
						ChartSustainNote.parent = ChartNote;
						ChartSustainNote.correctionOffset = ChartNote.height / 2;
						unspawnNotes.push(ChartSustainNote);
						if(!isPixelStage)
						{
							if(OldChartNote.isSustainNote)
							{
								OldChartNote.scale.y *= Note.SUSTAIN_SIZE / OldChartNote.frameHeight;
								OldChartNote.updateHitbox();
							}

							if(ClientPrefs.downScroll)
								ChartSustainNote.correctionOffset = 0;
						}
					}
				}

				if (jackingtime > 0)
				{
					for (i in 0...Std.int(jackingtime))
					{
						final jackNote:Note = new Note(ChartNote.strumTime + (15000/SONG.bpm) * (i + 1), ChartNote.noteData, OldChartNote, (gottaHitNote ? boyfriend.noteskin : dad.noteskin), false, false, !isEkSong);
						jackNote.scrollFactor.set();

				jackNote.sustainLength = ChartNote.sustainLength;
				jackNote.gfNote = ChartNote.gfNote;
				jackNote.noteType = ChartNote.noteType;
				if (ClientPrefs.doubleGhost)
					{
					jackNote.row = Conductor.secsToRow(ChartNote.strumTime);
					if(noteRows[gottaHitNote?0:1][jackNote.row]==null)
						noteRows[gottaHitNote?0:1][jackNote.row]=[];
					noteRows[gottaHitNote ? 0 : 1][jackNote.row].push(jackNote);
					}

						unspawnNotes.push(jackNote);

						jackNote.mustPress = ChartNote.mustPress;

						if (jackNote.mustPress)
						{
							jackNote.x += FlxG.width / 2; // general offset
							totalNotes += 1;
						}
						if (!jackNote.mustPress)
						{
							opponentNoteTotal += 1;
						}
						if(!noteTypeMap.exists(jackNote.noteType)) {
							noteTypeMap.set(jackNote.noteType, true);
						}
					}
				}
			}
			else
			{
				final gottaHitNote:Bool = ((songNotes[1] < 4 && !opponentChart && !bothsides)
				|| (songNotes[1] > 3 && opponentChart && !bothsides) ? section.mustHitSection : !section.mustHitSection);
						if (gottaHitNote && !songNotes.hitCausesMiss)
						{
							totalNotes += 1;
							combo += 1;
							totalNotesPlayed += 1;
						}
						if (!gottaHitNote)
						{
							opponentNoteTotal += 1;
							enemyHits += 1;
						}
			}
		}
		sectionsLoaded += 1;
		notesLoadedRN += section.sectionNotes.length;
		trace('loaded section ' + sectionsLoaded + ', notes loaded now: ' + notesLoadedRN);
	}

Ooh! I have an idea! Let's remove preallocation and preallocate notes as they progress. It'll disable troll mode though, but it's worth loading a 2.35 million note chart!

im just gonna post the code here, im going to sleep. if someone could figure this out id be very happy 😭
	var ChartNote = new Note(0, 0, null, '', false, false, true);
	var OldChartNote = new Note(0, 0, null, '', false, false, true);

	for (section in noteData)
	{
		for (songNotes in section.sectionNotes)
		{
			var time = haxe.Timer.stamp();
			if (usingEkFile && (songNotes[1] > 3) && !isEkSong)
			{
			trace ("one of the notes' note data exceeded the normal note count and there's a lua ek file, so im assuming this song is an ek song");
			isEkSong = true;
			}
			if (songNotes[0] >= startingPoint - 350)
			{
				final gottaHitNote:Bool = ((songNotes[1] < 4 && !opponentChart && !bothsides)
				|| (songNotes[1] > 3 && opponentChart) ? section.mustHitSection : !section.mustHitSection);

				if (gottaHitNote && !songNotes.hitCausesMiss)
				{
					totalNotes += 1;
				}
				if (!gottaHitNote)
				{
					opponentNoteTotal += 1;
				}
				if (songNotes[0] >= charChangeTimes[0])
				{
					switch (charChangeTypes[0])
					{
						case 0:
							var boyfriendToGrab:Boyfriend = boyfriendMap.get(charChangeNames[0]);
							if (boyfriendToGrab != null) bfNoteskin = boyfriendToGrab.noteskin;
						case 1:
							var dadToGrab:Character = dadMap.get(charChangeNames[0]);
							if (dadToGrab != null) dadNoteskin = dadToGrab.noteskin;
					}
					charChangeTimes.shift();
					charChangeNames.shift();
					charChangeTypes.shift();
				}

				ChartNote.prevNote = OldChartNote;
				ChartNote.strumTime = songNotes[0] + ClientPrefs.noteOffset;
				ChartNote.noteData = Std.int(songNotes[1] % 4);
				ChartNote.mustPress = gottaHitNote;
				ChartNote.sustainLength = songNotes[2];
				ChartNote.gfNote = (section.gfSection && (songNotes[1]<4));

				if (oneK)
				{
				ChartNote.noteData = 2;
				}
				if (randomMode) {
				ChartNote.noteData = FlxG.random.int(0, 3);
				}
				if (flip) {
				ChartNote.noteData = Std.int(Math.abs((songNotes[1] % 4) - 3));
				}
				if (stairs && !waves) {
				ChartNote.noteData = stair % 4;
				stair++;
				}
				if (waves) {
						switch (stair % 6)
							{
								case 0 | 1 | 2 | 3:
									ChartNote.noteData = stair % 6;
								case 4:
									ChartNote.noteData = 2;
								case 5:
									ChartNote.noteData = 1;
							}
				stair++;
				}
				ChartNote.noteType = songNotes[3];
				if ((gottaHitNote ? bfNoteskin : dadNoteskin).length > 0) ChartNote.texture = (gottaHitNote ? bfNoteskin : dadNoteskin);
				if (ClientPrefs.noteColorStyle == 'Quant-Based' && ClientPrefs.showNotes && ClientPrefs.enableColorShader) ChartNote.quantCheck();
				final noteAnimToPlay:String = Note.colArray[ChartNote.noteData];
				ChartNote.animation.play(noteAnimToPlay + 'Scroll');
				if(!Std.isOfType(songNotes[3], String)) ChartNote.noteType = editors.ChartingState.noteTypeList[songNotes[3]]; //Backward compatibility + compatibility with Week 7 charts

				ChartNote.scrollFactor.set();
				if(!noteTypeMap.exists(ChartNote.noteType)) {
					noteTypeMap.set(ChartNote.noteType, true);
				}
       				unspawnNotes.push(ChartNote);

				if(Math.floor(ChartNote.sustainLength / Conductor.stepCrochet) > 0) {
					for (susNote in 0...Math.floor(ChartNote.sustainLength / Conductor.stepCrochet)+1)
					{
						OldChartNote = unspawnNotes[Std.int(unspawnNotes.length - 1)];
						var ChartSustainNote = new Note(songNotes[0] + (Conductor.stepCrochet * susNote), ChartNote.noteData, OldChartNote, '', true, false, true);
						ChartSustainNote.mustPress = ChartNote.mustPress;
						if ((gottaHitNote ? bfNoteskin : dadNoteskin).length > 0) ChartSustainNote.texture = (gottaHitNote ? bfNoteskin : dadNoteskin);
						ChartSustainNote.gfNote = (section.gfSection && (songNotes[1]<4));
						ChartSustainNote.noteType = ChartNote.noteType;
						ChartSustainNote.scrollFactor.set();
						if (ClientPrefs.noteColorStyle == 'Quant-Based' && ClientPrefs.showNotes && ClientPrefs.enableColorShader) ChartSustainNote.quantCheck();
						ChartNote.tail.push(ChartSustainNote);
						ChartSustainNote.parent = ChartNote;
						ChartSustainNote.correctionOffset = ChartNote.height / 2;
						unspawnNotes.push(ChartSustainNote);
						if(!isPixelStage)
						{
							if(OldChartNote.isSustainNote)
							{
								OldChartNote.scale.y *= Note.SUSTAIN_SIZE / OldChartNote.frameHeight;
								OldChartNote.updateHitbox();
							}

							if(ClientPrefs.downScroll)
								ChartSustainNote.correctionOffset = 0;
						}
					}
				}

				if (jackingtime > 0)
				{
					for (i in 0...Std.int(jackingtime))
					{
						final jackNote:Note = new Note(ChartNote.strumTime + (15000/SONG.bpm) * (i + 1), ChartNote.noteData, OldChartNote, (gottaHitNote ? boyfriend.noteskin : dad.noteskin), false, false, !isEkSong);
						jackNote.scrollFactor.set();

				jackNote.sustainLength = ChartNote.sustainLength;
				jackNote.gfNote = ChartNote.gfNote;
				jackNote.noteType = ChartNote.noteType;
				if (ClientPrefs.doubleGhost)
					{
					jackNote.row = Conductor.secsToRow(ChartNote.strumTime);
					if(noteRows[gottaHitNote?0:1][jackNote.row]==null)
						noteRows[gottaHitNote?0:1][jackNote.row]=[];
					noteRows[gottaHitNote ? 0 : 1][jackNote.row].push(jackNote);
					}

						unspawnNotes.push(jackNote);

						jackNote.mustPress = ChartNote.mustPress;

						if (jackNote.mustPress)
						{
							jackNote.x += FlxG.width / 2; // general offset
							totalNotes += 1;
						}
						if (!jackNote.mustPress)
						{
							opponentNoteTotal += 1;
						}
						if(!noteTypeMap.exists(jackNote.noteType)) {
							noteTypeMap.set(jackNote.noteType, true);
						}
					}
				}
			}
			else
			{
				final gottaHitNote:Bool = ((songNotes[1] < 4 && !opponentChart && !bothsides)
				|| (songNotes[1] > 3 && opponentChart && !bothsides) ? section.mustHitSection : !section.mustHitSection);
						if (gottaHitNote && !songNotes.hitCausesMiss)
						{
							totalNotes += 1;
							combo += 1;
							totalNotesPlayed += 1;
						}
						if (!gottaHitNote)
						{
							opponentNoteTotal += 1;
							enemyHits += 1;
						}
			}
		}
		sectionsLoaded += 1;
		notesLoadedRN += section.sectionNotes.length;
		trace('loaded section ' + sectionsLoaded + ', notes loaded now: ' + notesLoadedRN);
	}

Ooh! I have an idea! Let's remove preallocation and preallocate notes as they progress. It'll disable troll mode though, but it's worth loading a 2.35 million note chart!

It'll disable jacks as well, because you're literally gonna spawn notes at runtime. It'll still have colors though.

im just gonna post the code here, im going to sleep. if someone could figure this out id be very happy 😭
	var ChartNote = new Note(0, 0, null, '', false, false, true);
	var OldChartNote = new Note(0, 0, null, '', false, false, true);

	for (section in noteData)
	{
		for (songNotes in section.sectionNotes)
		{
			var time = haxe.Timer.stamp();
			if (usingEkFile && (songNotes[1] > 3) && !isEkSong)
			{
			trace ("one of the notes' note data exceeded the normal note count and there's a lua ek file, so im assuming this song is an ek song");
			isEkSong = true;
			}
			if (songNotes[0] >= startingPoint - 350)
			{
				final gottaHitNote:Bool = ((songNotes[1] < 4 && !opponentChart && !bothsides)
				|| (songNotes[1] > 3 && opponentChart) ? section.mustHitSection : !section.mustHitSection);

				if (gottaHitNote && !songNotes.hitCausesMiss)
				{
					totalNotes += 1;
				}
				if (!gottaHitNote)
				{
					opponentNoteTotal += 1;
				}
				if (songNotes[0] >= charChangeTimes[0])
				{
					switch (charChangeTypes[0])
					{
						case 0:
							var boyfriendToGrab:Boyfriend = boyfriendMap.get(charChangeNames[0]);
							if (boyfriendToGrab != null) bfNoteskin = boyfriendToGrab.noteskin;
						case 1:
							var dadToGrab:Character = dadMap.get(charChangeNames[0]);
							if (dadToGrab != null) dadNoteskin = dadToGrab.noteskin;
					}
					charChangeTimes.shift();
					charChangeNames.shift();
					charChangeTypes.shift();
				}

				ChartNote.prevNote = OldChartNote;
				ChartNote.strumTime = songNotes[0] + ClientPrefs.noteOffset;
				ChartNote.noteData = Std.int(songNotes[1] % 4);
				ChartNote.mustPress = gottaHitNote;
				ChartNote.sustainLength = songNotes[2];
				ChartNote.gfNote = (section.gfSection && (songNotes[1]<4));

				if (oneK)
				{
				ChartNote.noteData = 2;
				}
				if (randomMode) {
				ChartNote.noteData = FlxG.random.int(0, 3);
				}
				if (flip) {
				ChartNote.noteData = Std.int(Math.abs((songNotes[1] % 4) - 3));
				}
				if (stairs && !waves) {
				ChartNote.noteData = stair % 4;
				stair++;
				}
				if (waves) {
						switch (stair % 6)
							{
								case 0 | 1 | 2 | 3:
									ChartNote.noteData = stair % 6;
								case 4:
									ChartNote.noteData = 2;
								case 5:
									ChartNote.noteData = 1;
							}
				stair++;
				}
				ChartNote.noteType = songNotes[3];
				if ((gottaHitNote ? bfNoteskin : dadNoteskin).length > 0) ChartNote.texture = (gottaHitNote ? bfNoteskin : dadNoteskin);
				if (ClientPrefs.noteColorStyle == 'Quant-Based' && ClientPrefs.showNotes && ClientPrefs.enableColorShader) ChartNote.quantCheck();
				final noteAnimToPlay:String = Note.colArray[ChartNote.noteData];
				ChartNote.animation.play(noteAnimToPlay + 'Scroll');
				if(!Std.isOfType(songNotes[3], String)) ChartNote.noteType = editors.ChartingState.noteTypeList[songNotes[3]]; //Backward compatibility + compatibility with Week 7 charts

				ChartNote.scrollFactor.set();
				if(!noteTypeMap.exists(ChartNote.noteType)) {
					noteTypeMap.set(ChartNote.noteType, true);
				}
       				unspawnNotes.push(ChartNote);

				if(Math.floor(ChartNote.sustainLength / Conductor.stepCrochet) > 0) {
					for (susNote in 0...Math.floor(ChartNote.sustainLength / Conductor.stepCrochet)+1)
					{
						OldChartNote = unspawnNotes[Std.int(unspawnNotes.length - 1)];
						var ChartSustainNote = new Note(songNotes[0] + (Conductor.stepCrochet * susNote), ChartNote.noteData, OldChartNote, '', true, false, true);
						ChartSustainNote.mustPress = ChartNote.mustPress;
						if ((gottaHitNote ? bfNoteskin : dadNoteskin).length > 0) ChartSustainNote.texture = (gottaHitNote ? bfNoteskin : dadNoteskin);
						ChartSustainNote.gfNote = (section.gfSection && (songNotes[1]<4));
						ChartSustainNote.noteType = ChartNote.noteType;
						ChartSustainNote.scrollFactor.set();
						if (ClientPrefs.noteColorStyle == 'Quant-Based' && ClientPrefs.showNotes && ClientPrefs.enableColorShader) ChartSustainNote.quantCheck();
						ChartNote.tail.push(ChartSustainNote);
						ChartSustainNote.parent = ChartNote;
						ChartSustainNote.correctionOffset = ChartNote.height / 2;
						unspawnNotes.push(ChartSustainNote);
						if(!isPixelStage)
						{
							if(OldChartNote.isSustainNote)
							{
								OldChartNote.scale.y *= Note.SUSTAIN_SIZE / OldChartNote.frameHeight;
								OldChartNote.updateHitbox();
							}

							if(ClientPrefs.downScroll)
								ChartSustainNote.correctionOffset = 0;
						}
					}
				}

				if (jackingtime > 0)
				{
					for (i in 0...Std.int(jackingtime))
					{
						final jackNote:Note = new Note(ChartNote.strumTime + (15000/SONG.bpm) * (i + 1), ChartNote.noteData, OldChartNote, (gottaHitNote ? boyfriend.noteskin : dad.noteskin), false, false, !isEkSong);
						jackNote.scrollFactor.set();

				jackNote.sustainLength = ChartNote.sustainLength;
				jackNote.gfNote = ChartNote.gfNote;
				jackNote.noteType = ChartNote.noteType;
				if (ClientPrefs.doubleGhost)
					{
					jackNote.row = Conductor.secsToRow(ChartNote.strumTime);
					if(noteRows[gottaHitNote?0:1][jackNote.row]==null)
						noteRows[gottaHitNote?0:1][jackNote.row]=[];
					noteRows[gottaHitNote ? 0 : 1][jackNote.row].push(jackNote);
					}

						unspawnNotes.push(jackNote);

						jackNote.mustPress = ChartNote.mustPress;

						if (jackNote.mustPress)
						{
							jackNote.x += FlxG.width / 2; // general offset
							totalNotes += 1;
						}
						if (!jackNote.mustPress)
						{
							opponentNoteTotal += 1;
						}
						if(!noteTypeMap.exists(jackNote.noteType)) {
							noteTypeMap.set(jackNote.noteType, true);
						}
					}
				}
			}
			else
			{
				final gottaHitNote:Bool = ((songNotes[1] < 4 && !opponentChart && !bothsides)
				|| (songNotes[1] > 3 && opponentChart && !bothsides) ? section.mustHitSection : !section.mustHitSection);
						if (gottaHitNote && !songNotes.hitCausesMiss)
						{
							totalNotes += 1;
							combo += 1;
							totalNotesPlayed += 1;
						}
						if (!gottaHitNote)
						{
							opponentNoteTotal += 1;
							enemyHits += 1;
						}
			}
		}
		sectionsLoaded += 1;
		notesLoadedRN += section.sectionNotes.length;
		trace('loaded section ' + sectionsLoaded + ', notes loaded now: ' + notesLoadedRN);
	}

Ooh! I have an idea! Let's remove preallocation and preallocate notes as they progress. It'll disable troll mode though, but it's worth loading a 2.35 million note chart!

It'll disable jacks as well, because you're literally gonna spawn notes at runtime. It'll still have colors though.

Oh and also it'll cost you to rewrite the sustain input system when that option is toggled because it'll have smooth sustains!!!

Actually, I'm gonna scratch the idea for smooth sustains. I'll try to code in sustains that spawn like psych engine's sustains.

Little update to the code:
Sustain notes now have the correct color when they're rendered The game can now actually tell whether a note needs to be pressed by the player or not
To do: Fix normal notes just not loading

Oh crap, I literally forgot to so that!

Also bro... It's so bloated.

I did fix my updated version of the chart loader rewrite
var ChartNote = new Note(0, 0);
var OldChartNote = new Note(0, 0);
var ChartContent = [ [ [ ], false ] ]; // 3 dimensional array (How this works: [0: Section notes, 1: Must hit section] for each section)

trace('Garbage collecting...');

openfl.system.System.gc();

trace('Loading chart...');

var ChartNoteCnt = 0;
var TotalNoteCnt = 0;
var stepCrochet = 15000.0 / Chart.bpm;

// So it appears that traces or sleep calls save your game's memory from increasing by a lot, making the chart loading system memory safe.

var time_took_for_the_chart_to_load = haxe.Timer.stamp();

var _chartNoteCache = [];

for (NoteData in SONG.notes) {
	for (SectionNote in NoteData.sectionNotes) {
		if (_chartNoteCache[ SectionNote[1] ] == null) {
			_chartNoteCache[ SectionNote[1] ] = new Note(SectionNote[0], SectionNote[1], OldChartNote, null, false);
		}
		ChartNote = _chartNoteCache[ SectionNote[1] ];

		ChartNote.prevNote = OldChartNote;
		ChartNote.strumTime = SectionNote[0];
		ChartNote.noteData = SectionNote[1] % 4;
		ChartNote.sustainLength = SectionNote[2];
		ChartNote.gfNote = NoteData.gfSection && SectionNote[1] < 4;
		ChartNote.noteType = SectionNote[3];

		var gottaHitNote = NoteData.mustHitSection;

		if (songNotes[1] > 3)
		{
			gottaHitNote = !NoteData.mustHitSection;
		}

		ChartNote.mustPress = gottaHitNote;

		if (ChartNote.sustainLength > (stepCrochet * 1.05)) {
			var ChartSustainNote = new Note(ChartNote.strumTime, ChartNote.noteData, OldChartNote, null, true);
			var ChartNoteParent = ChartNote;

			for (SusNote in 0...Std.int(ChartNote.sustainLength / stepCrochet)) {
				ChartSustainNote = new Note(ChartNote.strumTime, ChartNote.noteData, OldChartNote, null, true);

				ChartSustainNote.prevNote = OldChartNote;
				ChartSustainNote.strumTime = ChartNote.strumTime + (stepCrochet * SusNote);
				ChartSustainNote.gfNote = ChartNote.gfNote;
				ChartSustainNote.noteType = ChartNote.noteType;
				ChartSustainNote.mustPress = ChartNote.mustPress;
				ChartSustainNote.parent = ChartNote;

				//ChartSustainNote.texture = ChartNote.texture; // Update texture if it's a sustain note
				//trace('Sustain note created at ' + ChartNoteCnt + ' - (Strum time: ' + ChartSustainNote.strumTime + ', Note data: ' + ChartSustainNote.noteData + ')');
				ChartContent[0].push(ChartSustainNote.clone());
				ChartNote.tail.push(ChartContent[0][ChartContent[0].length-1]); // Get the added chart content and don't clone the chart sustain note again
				TotalNoteCnt++;

				OldChartNote = ChartContent[0][ChartContent[0].length-1];
				Sys.sleep(0.01);
			}
		}

		//ChartNote.texture = ChartNote.texture; // Update texture if the sustain process is finished sustain note
		// No need for backward compatibility
		//trace('Note created at ' + ChartNoteCnt + ' - (Strum time: ' + ChartNote.strumTime + ', Note data: ' + ChartNote.noteData + ')');

		ChartContent[0].push(ChartNote.clone());
		ChartContent[1] = NoteData.mustHitSection;
		ChartNoteCnt++;
		TotalNoteCnt++;

		OldChartNote = ChartContent[0][ChartContent[0].length-1];
		//System.gc(); // Do gc after a note is added
		Sys.sleep(0.01);
	}
}
trace('Chart successfully loaded!!!');
trace('Note count: ' + ChartNoteCnt + ' - Total note count: ' + TotalNoteCnt);
game.addTextToDebug('Note count: ' + ChartNoteCnt + ' - Total note count: ' + TotalNoteCnt, -1); // -1 is hexadecimal white as an integer

trace('Garbage collecting...');
openfl.system.System.gc(); // Do one final gc

trace('Chart successfully saved!!!');

var ms = haxe.Timer.stamp() - time_took_for_the_chart_to_load;

// Code from my version of the time format function for FlxStringUtil
var milliseconds = Std.int(ms * 0.1) % 100;
var seconds = Std.int(ms * 0.001) /* % 3600 */;
var hours = Std.int(seconds / 3600);
seconds %= 3600;
var minutes = Std.int(seconds / 60);
seconds %= 60;

var time = '';
if (hours > 0) time += Std.string(hours) + ':';
if (minutes < 10 && hours > 0) time += '0' + Std.string(minutes) + ':';
else time += Std.string(minutes) + ':';
if (seconds < 10) time += '0';
time += seconds;

if (milliseconds < 10) {
	time += '.0' + Std.string(milliseconds);
} else {
	time += '.' + Std.string(milliseconds);
}

trace('Time took for the chart to fully finish loading: ' + time);

also this kinda has to be updated to work with the note spawning system 😭

Little update to the code:
Sustain notes now have the correct color when they're rendered The game can now actually tell whether a note needs to be pressed by the player or not
To do: Fix normal notes just not loading

Oh crap, I literally forgot to so that!

Also bro... It's so bloated.

I did fix my updated version of the chart loader rewrite
var ChartNote = new Note(0, 0);
var OldChartNote = new Note(0, 0);
var ChartContent = [ [ [ ], false ] ]; // 3 dimensional array (How this works: [0: Section notes, 1: Must hit section] for each section)

trace('Garbage collecting...');

openfl.system.System.gc();

trace('Loading chart...');

var ChartNoteCnt = 0;
var TotalNoteCnt = 0;
var stepCrochet = 15000.0 / Chart.bpm;

// So it appears that traces or sleep calls save your game's memory from increasing by a lot, making the chart loading system memory safe.

var time_took_for_the_chart_to_load = haxe.Timer.stamp();

var _chartNoteCache = [];

for (NoteData in SONG.notes) {
	for (SectionNote in NoteData.sectionNotes) {
		if (_chartNoteCache[ SectionNote[1] ] == null) {
			_chartNoteCache[ SectionNote[1] ] = new Note(SectionNote[0], SectionNote[1], OldChartNote, null, false);
		}
		ChartNote = _chartNoteCache[ SectionNote[1] ];

		ChartNote.prevNote = OldChartNote;
		ChartNote.strumTime = SectionNote[0];
		ChartNote.noteData = SectionNote[1] % 4;
		ChartNote.sustainLength = SectionNote[2];
		ChartNote.gfNote = NoteData.gfSection && SectionNote[1] < 4;
		ChartNote.noteType = SectionNote[3];

		var gottaHitNote = NoteData.mustHitSection;

		if (songNotes[1] > 3)
		{
			gottaHitNote = !NoteData.mustHitSection;
		}

		ChartNote.mustPress = gottaHitNote;

		if (ChartNote.sustainLength > (stepCrochet * 1.05)) {
			var ChartSustainNote = new Note(ChartNote.strumTime, ChartNote.noteData, OldChartNote, null, true);
			var ChartNoteParent = ChartNote;

			for (SusNote in 0...Std.int(ChartNote.sustainLength / stepCrochet)) {
				ChartSustainNote = new Note(ChartNote.strumTime, ChartNote.noteData, OldChartNote, null, true);

				ChartSustainNote.prevNote = OldChartNote;
				ChartSustainNote.strumTime = ChartNote.strumTime + (stepCrochet * SusNote);
				ChartSustainNote.gfNote = ChartNote.gfNote;
				ChartSustainNote.noteType = ChartNote.noteType;
				ChartSustainNote.mustPress = ChartNote.mustPress;
				ChartSustainNote.parent = ChartNote;

				//ChartSustainNote.texture = ChartNote.texture; // Update texture if it's a sustain note
				//trace('Sustain note created at ' + ChartNoteCnt + ' - (Strum time: ' + ChartSustainNote.strumTime + ', Note data: ' + ChartSustainNote.noteData + ')');
				ChartContent[0].push(ChartSustainNote.clone());
				ChartNote.tail.push(ChartContent[0][ChartContent[0].length-1]); // Get the added chart content and don't clone the chart sustain note again
				TotalNoteCnt++;

				OldChartNote = ChartContent[0][ChartContent[0].length-1];
				Sys.sleep(0.01);
			}
		}

		//ChartNote.texture = ChartNote.texture; // Update texture if the sustain process is finished sustain note
		// No need for backward compatibility
		//trace('Note created at ' + ChartNoteCnt + ' - (Strum time: ' + ChartNote.strumTime + ', Note data: ' + ChartNote.noteData + ')');

		ChartContent[0].push(ChartNote.clone());
		ChartContent[1] = NoteData.mustHitSection;
		ChartNoteCnt++;
		TotalNoteCnt++;

		OldChartNote = ChartContent[0][ChartContent[0].length-1];
		//System.gc(); // Do gc after a note is added
		Sys.sleep(0.01);
	}
}
trace('Chart successfully loaded!!!');
trace('Note count: ' + ChartNoteCnt + ' - Total note count: ' + TotalNoteCnt);
game.addTextToDebug('Note count: ' + ChartNoteCnt + ' - Total note count: ' + TotalNoteCnt, -1); // -1 is hexadecimal white as an integer

trace('Garbage collecting...');
openfl.system.System.gc(); // Do one final gc

trace('Chart successfully saved!!!');

var ms = haxe.Timer.stamp() - time_took_for_the_chart_to_load;

// Code from my version of the time format function for FlxStringUtil
var milliseconds = Std.int(ms * 0.1) % 100;
var seconds = Std.int(ms * 0.001) /* % 3600 */;
var hours = Std.int(seconds / 3600);
seconds %= 3600;
var minutes = Std.int(seconds / 60);
seconds %= 60;

var time = '';
if (hours > 0) time += Std.string(hours) + ':';
if (minutes < 10 && hours > 0) time += '0' + Std.string(minutes) + ':';
else time += Std.string(minutes) + ':';
if (seconds < 10) time += '0';
time += seconds;

if (milliseconds < 10) {
	time += '.0' + Std.string(milliseconds);
} else {
	time += '.' + Std.string(milliseconds);
}

trace('Time took for the chart to fully finish loading: ' + time);

also this kinda has to be updated to work with the note spawning system 😭

What did you even change?

What did you even change?

oh, i added the following:
				final noteAnimToPlay:String = Note.colArray[ChartNote.noteData];
				ChartNote.animation.play(noteAnimToPlay + 'Scroll'); //for notes

and then I added a mustPress line (the one thing i forgot to add initially 😭)

Oh yeah, what was the problem before you fixed it?

oh, i still haven't gotten the code fixed.
the issue currently is still that only the last note has its properties.
I'm still working on fixing that. I have began to implement some more of your code and now more than 1 non-sustain note is actually present

I actually made it ao that you don't have to preallocate all the notes in the chart. You can just set up the note data from the chart's section note. (Currently a WIP)

I actually made it ao that you don't have to preallocate all the notes in the chart. You can just set up the note data from the chart's section note. (Currently a WIP)

A

Also Note extends FlxSprite, so cloning a note returns a FlxSprite instance instead

Okay, for now I'll revert my note spawning code

Okay, for now I'll revert my chart loading code

https://github.com/JordanSantiagoYT/FNF-PsychEngine-NoBotplayLag/assets/99929173/364955a3-210f-4525-a27c-f89c620beb3c
I did finish the chart loading rewrite, but I ran into a huge problem.
The notes don't show.

Okay, for now I'll revert my chart loading code

2024-03-01.10-00-29.mp4
I did finish the chart loading rewrite, but I ran into a huge problem. The notes don't show.

Here's the current playstate:
PlayState.txt

Merged in the latest commit. THANK YOU SO MUCH BRO 😭


Bitbucket 7.2.x compatibility

We have been hit by this problem after upgrading from Bitbucket Server 6 to 7.2.5.
Now our Concourse PR builds fail in the pipes as the bitbucket pull request resource (https://github.com/mmb/concourse-bitbucket-pullrequest-resource) also relies onto the internal refs.
As a workaround I tried to use this plugin, but I did not manage to get it working.
Can you please confirm the plugin is compatible with Bitbucket 7.2(.5) or provide a release that is?

Our production instance is Bitbucket 7.2.1 and we've been running using this plugin as a workaround for a couple of months without issue. I've looked at the changelog between 7.2.1 & 7.2.5, there are no obvious changes which would affect the functionality of this plugin, but of course I have not tried it on 7.2.5 - it should still work.
Important to note, as mentioned in the README & Atlassian's jira ticket: BSERV-12284. This plugin updates the refs/pull-requests/*/from internal ref immediately on certain pull-request events (otherwise you need to query an API / browse it in the UI for that ref to refreshed.
This plugin does not bring back the internal ref: refs/pull-requests/*/merge, which does not exist in Bitbucket 7+ due to the switch to a two-way diff.
Perhaps you could expand on 'not manage to get it working'?

Okay thanks for the clarification. I missed the interesting part:

This plugin does not bring back the internal ref: refs/pull-requests/*/merge, which does not exist in Bitbucket 7+ due to the switch to a two-way diff.

For us that means will still have to update the affected Concourse Ressource if when using the plugin, which is kinda around the corner. It looks like we have to go the API path with the resource.
Thanks for the quick answer.


Issue with scraping programatically using provided code sample

Hi there,
When I run the sample code provided for scraping programmatically:
from jisho_api.word import Word
from jisho_api.cli import scrape

word_requests = scrape(Word, ['water', 'fire'], '~/japanese/test')

I get this error:
Traceback (most recent call last):
  File "/home/frank/scripts/scrape_from_jisho.py", line 7, in <module>
    word_requests = scrape(Word, ['water', 'fire'], '~/japanese/test')
  File "/home/frank/dev/venv/lib/python3.8/site-packages/click/core.py", line 1128, in __call__
    return self.main(*args, **kwargs)
  File "/home/frank/dev/venv/lib/python3.8/site-packages/click/core.py", line 1042, in main
    args = list(args)
TypeError: 'type' object is not iterable

Help is appreciated. Thanks.

Thanks for bringing this to attention.
I have taken care of the issue.
First, the README was wrongly written, secondly there was a bug in the correct call, which was solved as well.
You can now
from jisho_api import scrape
from jisho_api.word import Word

word_requests = scrape(Word, ['water', 'fire'], 'to/path/')

only the import has changed.
Cheers


The Eco-Score logo appears on top of the "Add new product card"

The Eco-Score logo appears on top of the "Add new product card"

Fixed by 3dc2eef7cc16a4e6dd9fa0ef3110c864b5c0d29c

Fixed by 3dc2eef7cc16a4e6dd9fa0ef3110c864b5c0d29c


fix(model): fix errant inference_forward

Motivation
Fix errant inference_forward.
Now inferencing is correct.
Modification
Edit multiheadattention module.

Normal Batchsize=1 Result:

Dynamic NTK Result:

Batch Result:


[FALSE-POSITIVE] change.org www.change.com

Hi guys,
I think a false positive made it on the list.
change.org www.change.com
This is a petition signing website- not malicious
I checked the platform, and couldn't find it

.

Its working now. https://github.com/mitchellkrogza/Phishing.Database/issues/82

@p1r473 I'm aware of the problem with the platform :disappointed: I'll look into it in the coming weeks...


CONSTANTLY logging me off....

Every couple minutes or less it logs me off and I'm forced to log back in - 30 to 40 times in the course of 30 minutes. Completely unacceptable.

Same here and for many of my corpmates. (using pathfinder.bravecollective.com)


Update pricing vectors

Update pricing vector content:
https://docs.influxdata.com/influxdb/v2.0/account-management/pricing-plans/#pricing-vectors

Add the following to reflect all four pricing vectors:

Query count is the total number of individual query operations. Each individual operation—including queries, tasks, alerts, notifications, and Data Explorer activity—is one billable query operation. Refreshing a dashboard with multiple cells will incur multiple query operations. Failed operations aren’t counted.
Data In  is the amount of data you’re writing into InfluxDB (measured in MB).
Storage is the amount of data you’re storing in InfluxDB (measured in GB).


Add panics section to docs

I've made the suggested change, but I'm going to roll this up with some other documentation suggestions.


Overall architecture picture on EnMasse web site

The landing page of the enmasse.io web site, should have a overall 40000 feet view of the EnMasse architecture other than a list of features. I'm going to propose one potential picture starting from one of those I used for a demo here https://github.com/ppatierno/enmasse-iot-demo.

Fixed, yeah?


include: zephyr: drivers: modify SPI_CONFIG_DT to add CPOL, CPHA, HOLD_CS

Expose SPI device hardware characteristics: clock polarity, phase, and ability to control the chip select in application via DeviceTree files.
This allows users to define these SPI hardware characteristics in dts, overlay, etc. files without the need to modify the C code.

Linux is using flags for spi-cpol and spi-cpha, not enums, and we try to preserve compatibility with linux for standard properties. If there is no strong justification for doing this differently, please match Linux. If there is a strong justification, please state it.

@mbolivar-ampere, I don't have a strong reason, just I did that to follow the same style in spi-device.yaml, and I was not aware of the Linux style, so I will change them to boolean.

Regarding spi-hold-cs, is this really necessary at the spi-device.yaml level, and why must it be an enum when it is essentially a flag also?

Some products in the market, such as ST BlueNRG series require hold-cs feature. According to Zephyr policy, hardware configurations should be in devicetree files, and in order to use it in dts, overlay, etc. files, it is necessary to be defined as a property in a yaml file.
In my opinion, since spi-device.yaml has fundamental SPI properties, it's the best file to include these flags in comparison to other files, like zephyr,bt-hci-spi.yaml.
In addition, the purpose of using enum was the same as above, so I will also change this to boolean.

In addition, the purpose of using enum was the same as above, so I will also change this to boolean.

Ack, thanks!


how does one call eglGetPlatformDisplayEXT on the EGL context created by GLFW, I need to specify custom display attributes

Hi I am using ANGLE and I am required to call eglGetPlatformDisplayEXT with a custom attribute set for selecting a specific backend (d3d, opengl, vulkan, etc). I can't find a way to use this function in the EGL environment created by GLFW because it appears to be hard coded somewhere in the glfwCreateWindow function with no customization available

Currently yes, that is true. The main branch has the GLFW_ANGLE_PLATFORM_TYPE init hint for selecting the ANGLE backend but the full range of options from the ANGLE EGL extensions is not currently supported.

than you, GLFW_ANGLE_PLATFORM_TYPE is what I needed


Is there a way to use my GPU to apply a color transform to an image?

I'm using python 3.10 and I'd like to apply a color transform to an image. I've followed the code example and got everything set up as below. When I execute my program it loads in an EXR image, converts it to Numpy Array, and then passes it into the 'applyColorTransformToImage' function. In it, I do the config and env setup then set up the processor and apply the transform.
I was expecting to return either an ndarray or a python list but this returns None. I saw that applyRGB returns a list when a list is fed in, so I tried converting my ndarray to a list so that I can feed it into the applyRGB function but it is unreasonably slow to the point that I end up canceling the application.
def applyColorTransformToImage(imageToTransform):

iconfig_file_path = ('./opencolorio/nuke-default/config.ocio')
OCIO.SetEnvVariable('OCIO', config_file_path)
config = OCIO.GetCurrentConfig()

processor = config.getProcessor('linear','sRGB')
cpu = processor.getDefaultCPUProcessor()

transformedImage = imageToTransform
transformedImage = cpu.applyRGB(transformedImage)

return transformedImage

I got around this bottleneck by using cupy to offload the process onto my GPU which was orders of magnitude faster. Finally, with my list in hand I passed it into the applyRGB function and then I get the same deathly slow speed as when converting the ndarray to list mentioned previously.
Is there a faster way to apply a color transform that I'm just not seeing/finding in the documentation? Is it possible to use my GPU to apply a color transform instead of my CPU? If so, could someone kindly point me in the right direction with a code example?

We have a function in Colour that uses the CPU but is decently fast: https://colour.readthedocs.io/en/develop/generated/colour.io.process_image_OpenColorIO.html, you could give it a go! Using the GPU required such a significant amount of boiler plate code that we have not bothered implementing support for it yet.

Hello, the issue in your snippet is that the ndarray instance passed is modified directly by OCIO and is as such not returned.
You can just :
# ...
cpu = processor.getDefaultCPUProcessor()
# transformedImage doesn't seems to be useful
# if you don't want to modify the passed array, you can copy it like :
# newArray = imageToTransform.copy()
cpu.applyRGB(imageToTransform)
return imageToTransform

@MrLixm Absolute legend. Thank you!


openapi_3 to 2: Skip readOnly formData params

The readOnly property in OAS3 declares that a schema property

MAY be sent as part of a response but SHOULD NOT be sent as part of the request

When converting properties to formData parameters, skip readOnly properties, since they should not be sent as parameters.
Add a test to cover this.
Note: This PR should apply after #230.  Only the last commit is specific to this PR.
Thanks for considering,
Kevin

I used squash to merge #230 unfortunately - mind rebasing?

Sure thing.  No worries.  Thanks for reviewing and merging #230!

Thanks again!

Thanks @rbren!


Rebuild for osx-arm64

Checklist

[x] Used a personal fork of the feedstock to propose changes
[x] Bumped the build number (if the version is unchanged)
[ ] Reset the build number to 0 (if the version changed)
[x] Re-rendered with the latest conda-smithy (Use the phrase @conda-forge-admin, please rerender in a comment in this PR for automated rerendering)
[x] Ensured the license file is being packaged.

@conda-forge/libtasn1 osx-arm64 CI passed, PTAL

btw this PR blocks two downstream PRs (see the links above), so it'd be nice to get it in sooner 🙂

Something is still wrong on OS X:
checking for LIBTASN1... no
configure: error: libtasn1 not found. Building without it results in significant loss of functionality. To proceed use --without-libtasn1

Will look into it...

Sorry for the noise, posted in the wrong PR 😅

ppc64le CI hangs... let's retry
@conda-forge-admin, please restart ci

@conda-forge-admin, please rerender

@conda-forge-admin, please rerender

@ocefpaf The CI is green 🙂

Thanks, @gillins!


apex infra does not pass the function name with -var

According to documentation, running apex infra plan or apex infra apply should pass a variable to terraform with the ARN of the functions, for example ${var.apex_function_xxx} should be defined in TF.
According to my tests - it isn't.
Here's a repo with a simple repro: https://github.com/rantav/apex-bug-repro-335
When running apex infra plan you'd notice that TF asks for a value for the var apex_function_hello. To my understanding, this shouldn't happen if apex had passed the value for the var.
Here are two examples. The first demonstrates the issue (TF asks for my input)
$ apex infra plan
var.apex_function_hello
  Enter a value: xxx       <<<---- TF asks for my input

Refreshing Terraform state prior to plan...

No changes. Infrastructure is up-to-date. This means that Terraform
could not detect any differences between your configuration and
the real physical resources that exist. As a result, Terraform
doesn't need to do anything.

The second shows that using env variables, TF shuts up....
$ TF_VAR_apex_function_hello=xxx apex infra plan
Refreshing Terraform state prior to plan...

No changes. Infrastructure is up-to-date. This means that Terraform
could not detect any differences between your configuration and
the real physical resources that exist. As a result, Terraform
doesn't need to do anything.

My hope is that - I'm not not using it correctly. Did I get the correct var name? Is there something wrong with my TF code? Or is this a bug?

@rantav is it still an issue? I guess the problem was that you didn't defined empty variable in TF(?).

Yes it is still an issue.
I did add an empty variable in TF, see https://github.com/rantav/apex-bug-repro-335/blob/master/infrastructure/main.tf#L5
Did I do this incorrectly?

Looks fine, could you run apex infra plan --log-level debug and paste output here.

hmm that's kind of annoying if TF makes you use variable {} for that. I have my fn ARNs hard-coded in ATM

Running apex infra plan (or apply) requires providing the value for the variable apex_function_hello:
$ apex infra plan --log-level debug
   • couldn't read role from infrastructure: exit status 1
   • loading functions in functions
   • loading function in functions/hello
   • inferring runtime         function=hello
   • inferred runtime          function=hello runtime=nodejs
   • terraform                 args=[plan]
var.apex_function_hello
  Enter a value:

(I stopped here)

And BTW:
$ terraform -v
Terraform v0.6.12

and
$ apex version
Apex version 0.7.0

Just to make sure, have you deployed functions before using functions' ARNs in TF configs?

Hi @mthenw yes, the function had been deployed.
Look, I'm sure it's just a simple oversight from my end, but beats me, I can't figure out what I'm doing wrong... Does the -var work for you?
Also, if seems that the output of --log-level debug includes the line • terraform                 args=[plan] so does that mean that the -var is indeed not passed?

OK I figured out what is wrong. Based on your repro repo there is no role passed. If there is no role apex doesn't load functions. Not sure how you created infrastructure folder but that wasn't generated with apex init. apex init inits infrastructure repo with TF module responsible for creating IAM role that is read by apex to deploy functions.
Basically the flow should look like this:

apex init
apex infra apply
apex deploy
some changes to TF configs using functions arns
apex infra apply
...

For sure we need to work on better docs about that.

Hmm, I apologize, I did add a role later in development, but I did not push the commit. I did push it just now though.
However, even after having added the role (I can't deploy without a role, BTW) - I still can't get the ARNs passed to TF. Did you?
BTW - the flow is a bit perplexed. As someone that now understands the implemantation details I can see why you need init and then infra apply and then deploy and then some changes and then again infra apply however, as a noob - this still seems somewhat confusing, usability wise...
Anyway, bottom line for me - this still isn't working. Does it work for you? (as mentioned, I added the role but this role only makes sense under my AWS account not yours ;))

OK, I found the problem, it was my bad, thanks @mthenw for your help!
One has to remember a few things:

You have to deploy the function before it's ARN can be used. (ARNs are created only after a resource actually exists in AWS)
One of the errors that stumbled me was that at some point I did not provide the region, so even though apex was going to fail on that if I was going to run apex deploy without a region - running apex infra does not fail, but it also does not pass the -var ARN as expected. Fixing this was easy - just add the aws region, for example AWS_REGION=us-west-2 apex infra plan

My suggestion would be though @mthenw to check for missing region (and other required params such as aws key) before calling to TF, similar to the way you check when running apex deploy. I'm happy to open a bug to track this issue if you agree.
I'm going to go ahead and close this issue right now.


edit Netplugin license info so that GitHub recognizes it

Hello! 👋
(CCing @dankohn who has requested this work so that the license will appear correctly in https://landscape.cncf.io/selected=contiv)
Description of the changes
Type of fix: LICENSE doc fix
Fixes # (N/A)
GitHub uses a library called Licensee to identify a project's license
type. It shows this information in the status bar and via the API if it
can unambiguously identify the license.
This commit updates the LICENSE file so that it contains the full text
of the Apache 2.0 license. This allows Licensee to successfully
identify the license type of Netplugin's codebase as Apache 2.0.

Thanks! 👍


[OP] Enable register via match tag

enables register attribute to a group of ops

NNVM_REGISTER_OP(add)
.set_attr<std::string>("OpType", "Elementwise");

// register same attributes to all the ops that matchs the attribute condition.
NNVM_OP_GROUP_BY_MATCH_ATTR(OpType, "Elementwise")
.set_attr<FInferShape>("FInferShape", ElementwiseInferShape);

// mul will also have the ElementwiseInferShape tag
NNVM_REGISTER_OP(mul)
.set_attr<std::string>("TagType", "Elementwise");

@jermainewang @piiswrong

please see if the name  NNVM_REGISTER_BY_MATCH_ATTR makes sense to you, I think it is an OK name and cannot come up with a shorter version for now

NNVM_REGISTER_OP(add)
.set_attr<std::string>("OpType", "Elementwise");

// register same attributes to all the ops that matchs the attribute condition.
NNVM_REGISTER_OP_GROUP(OpType, "Elementwise")
.set_attr<FInferShape>("FInferShape", ElementwiseInferShape);

// mul will also have the ElementwiseInferShape tag
NNVM_REGISTER_OP(mul)
.set_attr<std::string>("OpGroup", "Elementwise");

looks better

BTW, what's the relation between OpType and TagType? It's confusing

This makes it even harder to figure out where things are registered.
It would be MUCH easier to document and understand if you use a different interface for setting tags:
NNVM_REGISTER_OP(mul)
.add_to_group("Elementwise");

also instead of using names like Elementwise, it should be something unique so that a search in the code base will point to the registration point

Actually I think
NNVM_REGISTER_OP(mul)
.include("ElemwiseOpAttrs");

Makes more sense

The idea is that we don't want to specialize the field group or tag. But simply use attribute. There can be multiple attributes that corresponding to a tag.
For example
NNVM_REGISTER_OP(add)
.set_attr<std::string>("OpType", "Elementwise")
.set_attr<std::string>("FuncType", "BinaryOp");

// register same attributes to all the ops that matchs the attribute condition.
NNVM_OP_GROUP_BY_MATCH_ATTR(OpType, "Elementwise")
.set_attr<FInferShape>("FInferShape", ElementwiseInferShape);

NNVM_OP_GROUP_BY_MATCH_ATTR(FuncType, "UnaryOp")
.set_attr<FXX>("FXX", UnaryFXX);

// mul will also have the ElementwiseInferShape tag
NNVM_REGISTER_OP(mul)
.set_attr<std::string>("OpType", "Elementwise");

NNVM_REGISTER_OP(exp)
.set_attr<std::string>("OpType", "Elementwise")
.set_attr<std::string>("FuncType", "Unary");

That makes it more complicated but doesn't add much utility. include(OpType:Elementwise) would to the same thing.
I think it definitely need a different api. you can still implement it via attrs internally.

Consider doing it this way: an op can include another op and copy all it's attrs. This can be done recursively and groups can also be registered as ops

Group is definitely different from what op is(they have incomplete information, and partial info about something), so it does not make sense to do so.
NNVM_OP_GROUP_BY_MATCH_ATTR provides a semantics like
NNVM_FOR_EACH_OP_WHOSE_ATTR_EQ(AttrName, Attr_Value)
DO
op.set_attr<bla>()
END

Which is quite clear,

consider ops as classes. an incomplete abstract class is still a class

There are two semantics, here, both are valid, the difference is like follows

Inheritate provides a pull semantics, operators pull things from its parents,

There could be confusion about multiple inheritance in here
The recursive inheritance seems to be a overkill feature that is a bit hard to reason
It is not easy to tell from an abstract class from normal one, especially when multiple inheritance happen.

Match and set provides a push semantics, which means find the ops that satisfies the condition and set the corresponding attribute.

Personally I prefer not introducing group as op, but simply as a returning result of some matching conditions on the operator set, which is aligned with push semantics. It also avoid introducing additional concept for specially handle groups.

@piiswrong changed API to include