diff --git a/source/funkin/InitState.hx b/source/funkin/InitState.hx index 28d8db6b5..bda2f5113 100644 --- a/source/funkin/InitState.hx +++ b/source/funkin/InitState.hx @@ -267,7 +267,7 @@ class InitState extends FlxState // Move it to use a BaseRegistry. CharacterDataParser.loadCharacterCache(); - NoteKindManager.loadScripts(); + NoteKindManager.initialize(); ModuleHandler.buildModuleCallbacks(); ModuleHandler.loadModuleCache(); diff --git a/source/funkin/data/event/SongEventRegistry.hx b/source/funkin/data/event/SongEventRegistry.hx index 33b86ec56..918715f9d 100644 --- a/source/funkin/data/event/SongEventRegistry.hx +++ b/source/funkin/data/event/SongEventRegistry.hx @@ -13,7 +13,7 @@ class SongEventRegistry { /** * Every built-in event class must be added to this list. - * Thankfully, with the power of `SongEventMacro`, this is done automatically. + * Thankfully, with the power of `ClassMacro`, this is done automatically. */ static final BUILTIN_EVENTS:List> = ClassMacro.listSubclassesOf(SongEvent); diff --git a/source/funkin/modding/PolymodHandler.hx b/source/funkin/modding/PolymodHandler.hx index a09267d99..0b37812ca 100644 --- a/source/funkin/modding/PolymodHandler.hx +++ b/source/funkin/modding/PolymodHandler.hx @@ -587,7 +587,7 @@ class PolymodHandler FreeplayStyleRegistry.instance.loadEntries(); CharacterDataParser.loadCharacterCache(); // TODO: Migrate characters to BaseRegistry. - NoteKindManager.loadScripts(); + NoteKindManager.initialize(); ModuleHandler.loadModuleCache(); ModuleHandler.callOnCreate(); } diff --git a/source/funkin/play/character/BaseCharacter.hx b/source/funkin/play/character/BaseCharacter.hx index d5f774641..ba9b3cd6b 100644 --- a/source/funkin/play/character/BaseCharacter.hx +++ b/source/funkin/play/character/BaseCharacter.hx @@ -7,6 +7,8 @@ import funkin.data.character.CharacterData.CharacterDataParser; import funkin.data.character.CharacterData.CharacterRenderType; import funkin.play.stage.Bopper; import funkin.play.notes.NoteDirection; +import funkin.play.notes.notekind.NoteKind; +import funkin.play.notes.notekind.NoteKindManager; /** * A Character is a stage prop which bops to the music as well as controlled by the strumlines. diff --git a/source/funkin/play/notes/notekind/NoAnimNoteKind.hx b/source/funkin/play/notes/notekind/NoAnimNoteKind.hx new file mode 100644 index 000000000..73bd66aa5 --- /dev/null +++ b/source/funkin/play/notes/notekind/NoAnimNoteKind.hx @@ -0,0 +1,14 @@ +package funkin.play.notes.notekind; + +/** + * A custom note kind which has custom functionality, preventing singing animations from playing. + */ +class NoAnimNoteKind extends NoteKind +{ + static final DISABLE_ANIMATIONS:Bool = true; + + public function new() + { + super("noanim", "Disables singing animations", null, [], DISABLE_ANIMATIONS, null); + } +} diff --git a/source/funkin/play/notes/notekind/NoteKind.hx b/source/funkin/play/notes/notekind/NoteKind.hx index f472def3b..8b2197e7e 100644 --- a/source/funkin/play/notes/notekind/NoteKind.hx +++ b/source/funkin/play/notes/notekind/NoteKind.hx @@ -45,13 +45,13 @@ class NoteKind implements INoteScriptedClass */ public var scoreable:Bool = true; - public function new(noteKind:String, description:String = "", ?noteStyleId:String, ?params:Array, ?anim:Bool, ?suffix:String) + public function new(noteKind:String, description:String = "", ?noteStyleId:String, ?params:Array, ?noanim:Bool, ?suffix:String) { this.noteKind = noteKind; this.description = description; this.noteStyleId = noteStyleId; this.params = params ?? []; - this.noanim = anim ?? false; + this.noanim = noanim ?? false; this.suffix = suffix ?? ''; } diff --git a/source/funkin/play/notes/notekind/NoteKindManager.hx b/source/funkin/play/notes/notekind/NoteKindManager.hx index 829615933..deb7248be 100644 --- a/source/funkin/play/notes/notekind/NoteKindManager.hx +++ b/source/funkin/play/notes/notekind/NoteKindManager.hx @@ -8,9 +8,16 @@ import funkin.data.notestyle.NoteStyleRegistry; import funkin.play.notes.notestyle.NoteStyle; import funkin.play.notes.notekind.ScriptedNoteKind; import funkin.play.notes.notekind.NoteKind.NoteKindParam; +import funkin.util.macro.ClassMacro; class NoteKindManager { + /** + * Every built-in note kind class must be added to this list. + * Thankfully, with the power of `ClassMacro`, this is done automatically. + */ + static final BUILTIN_KINDS:List> = ClassMacro.listSubclassesOf(NoteKind); + /** * A map of all note kinds, keyed by their name. * This is used to retrieve note kinds by their name. @@ -22,12 +29,56 @@ class NoteKindManager * @param noteKind The name of the note kind. * @return The note kind, or null if it doesn't exist. */ - public static function getNoteKind(noteKind:String):Null + public static function getNoteKind(?noteKind:String):Null { + if (noteKind == null) return null; return noteKinds.get(noteKind); } - public static function loadScripts():Void + /** + * Initialize custom behavior for note kinds. + */ + public static function initialize():Void + { + clearNoteKindCache(); + + // + // BASE GAME EVENTS + // + registerBaseNoteKinds(); + registerScriptedNoteKinds(); + } + + /** + * Register the hard-coded note kinds. + */ + public static function registerBaseNoteKinds():Void + { + trace('Instantiating ${BUILTIN_KINDS.length} built-in note kinds...'); + for (noteKindCls in BUILTIN_KINDS) + { + var noteKindClsName:String = Type.getClassName(noteKindCls); + if (noteKindClsName == 'funkin.play.notes.notekind.NoteKind' + || noteKindClsName == 'funkin.play.notes.notekind.ScriptedNoteKind') continue; + + var kind:NoteKind = Type.createInstance(noteKindCls, ["UNKNOWN"]); + + if (kind != null) + { + trace(' Loaded built-in note kind: ${kind.noteKind}'); + noteKinds.set(kind.noteKind, kind); + } + else + { + trace(' Failed to load built-in note kind: ${noteKindClsName}'); + } + } + } + + /** + * Register the scripted note kinds provided by mods. + */ + public static function registerScriptedNoteKinds():Void { var scriptedClassName:Array = ScriptedNoteKind.listScriptClasses(); if (scriptedClassName.length > 0) @@ -97,12 +148,22 @@ class NoteKindManager return NoteStyleRegistry.instance.fetchEntry(noteStyleId); } - public static function listNoteStyles(songNoteDatas:Array):Array + /** + * Get a list of all the note styles used by the given notes. + * Great for preloading. + * @param songNoteDatas The notes to query for note styles. + * @return The note styles to load. + */ + public static function listNoteStylesByNoteData(songNoteDatas:Array):Array { var results:Array = []; for (songNoteData in songNoteDatas) { var noteStyle:NoteStyle = getNoteStyle(songNoteData.kind, null); + if (noteStyle != null && !results.contains(noteStyle)) + { + results.push(noteStyle); + } } return results; } @@ -129,23 +190,6 @@ class NoteKindManager return noteStyleId; } - /** - * Retrieve custom params of the given note kind - * @param noteKind Name of the note kind - * @return Array - */ - public static function getNoteKind(noteKind:Null):Null - { - if (noteKind == null) - { - return null; - } - else - { - return noteKinds.get(noteKind); - } - } - /** * Retrive custom params of the given note kind * @param noteKind Name of the note kind @@ -160,4 +204,13 @@ class NoteKindManager return noteKinds.get(noteKind)?.params ?? []; } + + /** + * Clear the note kind cache. + * Be sure to register the note kinds again before trying to use them. + */ + public static function clearNoteKindCache():Void + { + noteKinds.clear(); + } } diff --git a/source/funkin/ui/debug/charting/util/ChartEditorDropdowns.hx b/source/funkin/ui/debug/charting/util/ChartEditorDropdowns.hx index 75246c9ee..1cc872959 100644 --- a/source/funkin/ui/debug/charting/util/ChartEditorDropdowns.hx +++ b/source/funkin/ui/debug/charting/util/ChartEditorDropdowns.hx @@ -157,6 +157,7 @@ class ChartEditorDropdowns // Base "" => "Default", "~CUSTOM~" => "Custom", + "noanim" => "No Animation", // Weeks 1-7 "censor" => "[UH-OH!] Censor Bar", "mom" => "Mom Sings (Week 5)",