From 787d77601936e64d5bfd0b65f68e9f5d94533587 Mon Sep 17 00:00:00 2001 From: lemz1 Date: Sun, 13 Oct 2024 16:39:45 +0200 Subject: [PATCH 01/13] not at all finished --- source/funkin/data/song/SongRegistry.hx | 1 + source/funkin/util/macro/RegistryMacro.hx | 56 +++++++++++++++++++++++ 2 files changed, 57 insertions(+) create mode 100644 source/funkin/util/macro/RegistryMacro.hx diff --git a/source/funkin/data/song/SongRegistry.hx b/source/funkin/data/song/SongRegistry.hx index e7cab246c..4aed0bc40 100644 --- a/source/funkin/data/song/SongRegistry.hx +++ b/source/funkin/data/song/SongRegistry.hx @@ -13,6 +13,7 @@ import funkin.util.VersionUtil; using funkin.data.song.migrator.SongDataMigrator; @:nullSafety +@:build(funkin.util.macro.RegistryMacro.build()) class SongRegistry extends BaseRegistry { /** diff --git a/source/funkin/util/macro/RegistryMacro.hx b/source/funkin/util/macro/RegistryMacro.hx new file mode 100644 index 000000000..77337e7eb --- /dev/null +++ b/source/funkin/util/macro/RegistryMacro.hx @@ -0,0 +1,56 @@ +package funkin.util.macro; + +import haxe.macro.Context; +import haxe.macro.Expr; +import haxe.macro.Type; + +using StringTools; + +class RegistryMacro +{ + public static macro function build():Array + { + var fields = Context.getBuildFields(); + + var cls = Context.getLocalClass().get(); + var clsName = cls.pack.join('.') + '.' + cls.name; + + var typeParams = getTypeParams(cls); + + var entryCls = typeParams[0]; + var entryClsName = entryCls.pack.join('.') + '.' + entryCls.name; + + var jsonCls = typeParams[1]; + var jsonClsName = jsonCls.pack.join('.') + '.' + jsonCls.name; + + trace('ENTRY', entryClsName); + trace('JSON', jsonClsName); + + return fields; + } + + #if macro + static function getTypeParams(cls:ClassType):Array + { + switch (cls.superClass.t.get().kind) + { + case KGenericInstance(t, params): + var typeParams = []; + for (param in params) + { + switch (param) + { + case TInst(t, _params): + typeParams.push(t.get()); + default: + throw 'Not a class'; + } + } + return typeParams; + default: + throw 'Not in the correct format'; + } + return []; + } + #end +} From 31f2e6597cc25fee775dfb7c4b5550d18f371a9d Mon Sep 17 00:00:00 2001 From: lemz1 Date: Sun, 13 Oct 2024 19:39:34 +0200 Subject: [PATCH 02/13] testing --- .../data/notestyle/NoteStyleRegistry.hx | 33 ++- source/funkin/data/song/SongRegistry.hx | 1 - source/funkin/util/macro/RegistryMacro.hx | 201 ++++++++++++++++-- 3 files changed, 204 insertions(+), 31 deletions(-) diff --git a/source/funkin/data/notestyle/NoteStyleRegistry.hx b/source/funkin/data/notestyle/NoteStyleRegistry.hx index 36d1b9200..051aa1072 100644 --- a/source/funkin/data/notestyle/NoteStyleRegistry.hx +++ b/source/funkin/data/notestyle/NoteStyleRegistry.hx @@ -4,6 +4,7 @@ import funkin.play.notes.notestyle.NoteStyle; import funkin.play.notes.notestyle.ScriptedNoteStyle; import funkin.data.notestyle.NoteStyleData; +@:build(funkin.util.macro.RegistryMacro.build()) class NoteStyleRegistry extends BaseRegistry { /** @@ -15,14 +16,13 @@ class NoteStyleRegistry extends BaseRegistry public static final NOTE_STYLE_DATA_VERSION_RULE:thx.semver.VersionRule = "1.1.x"; - public static var instance(get, never):NoteStyleRegistry; - static var _instance:Null = null; - - static function get_instance():NoteStyleRegistry - { - if (_instance == null) _instance = new NoteStyleRegistry(); - return _instance; - } + // public static var instance(get, never):NoteStyleRegistry; + // static var _instance:Null = null; + // static function get_instance():NoteStyleRegistry + // { + // if (_instance == null) _instance = new NoteStyleRegistry(); + // return _instance; + // } public function new() { @@ -81,13 +81,12 @@ class NoteStyleRegistry extends BaseRegistry return parser.value; } - function createScriptedEntry(clsName:String):NoteStyle - { - return ScriptedNoteStyle.init(clsName, "unknown"); - } - - function getScriptedClassNames():Array - { - return ScriptedNoteStyle.listScriptClasses(); - } + // function createScriptedEntry(clsName:String):NoteStyle + // { + // return ScriptedNoteStyle.init(clsName, "unknown"); + // } + // function getScriptedClassNames():Array + // { + // return ScriptedNoteStyle.listScriptClasses(); + // } } diff --git a/source/funkin/data/song/SongRegistry.hx b/source/funkin/data/song/SongRegistry.hx index 4aed0bc40..e7cab246c 100644 --- a/source/funkin/data/song/SongRegistry.hx +++ b/source/funkin/data/song/SongRegistry.hx @@ -13,7 +13,6 @@ import funkin.util.VersionUtil; using funkin.data.song.migrator.SongDataMigrator; @:nullSafety -@:build(funkin.util.macro.RegistryMacro.build()) class SongRegistry extends BaseRegistry { /** diff --git a/source/funkin/util/macro/RegistryMacro.hx b/source/funkin/util/macro/RegistryMacro.hx index 77337e7eb..e337fbe72 100644 --- a/source/funkin/util/macro/RegistryMacro.hx +++ b/source/funkin/util/macro/RegistryMacro.hx @@ -13,44 +13,219 @@ class RegistryMacro var fields = Context.getBuildFields(); var cls = Context.getLocalClass().get(); - var clsName = cls.pack.join('.') + '.' + cls.name; var typeParams = getTypeParams(cls); + var entryCls = typeParams.entryCls; + var jsonCls = typeParams.jsonCls; + var scriptedEntryCls = getScriptedEntryClass(entryCls); - var entryCls = typeParams[0]; - var entryClsName = entryCls.pack.join('.') + '.' + entryCls.name; + // fields = fields.concat(buildInstanceField(cls)); - var jsonCls = typeParams[1]; - var jsonClsName = jsonCls.pack.join('.') + '.' + jsonCls.name; + // fields.push(buildGetScriptedClassNamesField(scriptedEntryClsName)); - trace('ENTRY', entryClsName); - trace('JSON', jsonClsName); + // fields.push(buildCreateScriptedEntryField(entryCls, scriptedEntryClsName)); return fields; } #if macro - static function getTypeParams(cls:ClassType):Array + static function getTypeParams(cls:ClassType):RegistryTypeParams { switch (cls.superClass.t.get().kind) { - case KGenericInstance(t, params): - var typeParams = []; + case KGenericInstance(_, params): + var typeParams:Array = []; for (param in params) { switch (param) { - case TInst(t, _params): + case TInst(t, _): + typeParams.push(t.get()); + case TType(t, _): typeParams.push(t.get()); default: throw 'Not a class'; } } - return typeParams; + return {entryCls: typeParams[0], jsonCls: typeParams[1]}; default: throw 'Not in the correct format'; } - return []; + } + + static function getScriptedEntryClass(entryCls:ClassType):ClassType + { + var scriptedEntryClsName = entryCls.pack.join('.') + '.Scripted' + entryCls.name; + switch (Context.getType(scriptedEntryClsName)) + { + case Type.TInst(t, _): + return t.get(); + default: + throw 'Not A Class (${scriptedEntryClsName})'; + }; + } + + static function buildInstanceField(cls:ClassType):Array + { + var fields = []; + + fields.push( + { + name: '_instance', + access: [Access.APrivate, Access.AStatic], + kind: FieldType.FVar(ComplexType.TPath( + { + pack: [], + name: 'Null', + params: [ + TypeParam.TPType(ComplexType.TPath( + { + pack: cls.pack, + name: cls.name, + params: [] + })) + ] + })), + pos: Context.currentPos() + }); + + fields.push( + { + name: 'instance', + access: [Access.APublic, Access.AStatic], + kind: FieldType.FProp("get", "never", ComplexType.TPath( + { + pack: cls.pack, + name: cls.name, + params: [] + })), + pos: Context.currentPos() + }); + + var newStrExpr = 'new ${cls.pack.join('.')}.${cls.name}()'; + var newExpr = Context.parse(newStrExpr, Context.currentPos()); + + fields.push( + { + name: 'get_instance', + access: [Access.APrivate, Access.AStatic], + kind: FFun( + { + args: [], + expr: macro + { + if (_instance == null) + { + _instance = ${newExpr}; + } + return _instance; + }, + params: [], + ret: ComplexType.TPath( + { + pack: cls.pack, + name: cls.name, + params: [] + }) + }), + pos: Context.currentPos() + }); + + return fields; + } + + static function buildGetScriptedClassNamesField(scriptedEntryCls:ClassType):Field + { + var scriptedEntryExpr = Context.parse('${scriptedEntryCls.pack.join('.')}.${scriptedEntryCls.name}', Context.currentPos()); + + return { + name: 'getScriptedClassNames', + access: [Access.APrivate], + kind: FieldType.FFun( + { + args: [], + expr: macro + { + return ${scriptedEntryExpr}.listScriptClasses(); + }, + params: [], + ret: (macro :Array) + }), + pos: Context.currentPos() + }; + } + + static function buildCreateScriptedEntryField(entryCls:ClassType, scriptedEntryCls:ClassType):Field + { + var scriptedStrExpr = '${scriptedEntryCls.pack.join('.')}.${scriptedEntryCls.name}.init(clsName, ${buildNullArgs(entryCls.constructor.get())})'; + var scriptedInitExpr = Context.parse(scriptedStrExpr, Context.currentPos()); + + return { + name: 'createScriptedEntry', + access: [Access.APrivate], + kind: FieldType.FFun( + { + args: [ + { + name: 'clsName', + type: (macro :String) + } + ], + expr: macro + { + return ${scriptedInitExpr}; + }, + params: [], + ret: ComplexType.TPath( + { + pack: [], + name: 'Null', + params: [ + TypeParam.TPType(ComplexType.TPath( + { + pack: entryCls.pack, + name: entryCls.name + })) + ] + }) + }), + pos: Context.currentPos() + }; + } + + static function buildNullArgs(fun:ClassField):String + { + var amount:Int = 0; + switch (fun.type) + { + case Type.TFun(args, _): + amount = args.length; + case Type.TLazy(f): + switch (f()) + { + case Type.TFun(args, _): + amount = args.length; + default: + throw 'Not a function'; + } + default: + throw 'Not a function'; + } + + var args = []; + for (i in 0...amount) + { + args.push('null'); + } + return args.join(', '); } #end } + +#if macro +typedef RegistryTypeParams = +{ + var entryCls:ClassType; + var jsonCls:Dynamic; // DefType or ClassType +} +#end From e54269700e284828d85d323cbfa4d51c3a011e98 Mon Sep 17 00:00:00 2001 From: lemz1 Date: Sun, 13 Oct 2024 20:30:58 +0200 Subject: [PATCH 03/13] i think i found the solution --- .../funkin/play/notes/notestyle/NoteStyle.hx | 32 ++++---- source/funkin/util/macro/EntryMacro.hx | 74 +++++++++++++++++++ source/funkin/util/macro/RegistryMacro.hx | 35 +-------- 3 files changed, 95 insertions(+), 46 deletions(-) create mode 100644 source/funkin/util/macro/EntryMacro.hx diff --git a/source/funkin/play/notes/notestyle/NoteStyle.hx b/source/funkin/play/notes/notestyle/NoteStyle.hx index dd0885751..c47245939 100644 --- a/source/funkin/play/notes/notestyle/NoteStyle.hx +++ b/source/funkin/play/notes/notestyle/NoteStyle.hx @@ -18,6 +18,7 @@ using funkin.data.animation.AnimationData.AnimationDataUtil; * and provides convenience methods for building sprites based on them. */ @:nullSafety +@:build(funkin.util.macro.EntryMacro.build(funkin.data.notestyle.NoteStyleRegistry)) class NoteStyle implements IRegistryEntry { /** @@ -36,9 +37,11 @@ class NoteStyle implements IRegistryEntry */ var fallback(get, never):Null; - function get_fallback():Null { + function get_fallback():Null + { if (_data == null || _data.fallback == null) return null; - return NoteStyleRegistry.instance.fetchEntry(_data.fallback); + return null; + // return NoteStyleRegistry.instance.fetchEntry(_data.fallback); } /** @@ -887,17 +890,16 @@ class NoteStyle implements IRegistryEntry return 'NoteStyle($id)'; } - static function _fetchData(id:String):NoteStyleData - { - var result = NoteStyleRegistry.instance.parseEntryDataWithMigration(id, NoteStyleRegistry.instance.fetchEntryVersion(id)); - - if (result == null) - { - throw 'Could not parse note style data for id: $id'; - } - else - { - return result; - } - } + // static function _fetchData(id:String):NoteStyleData + // { + // var result = NoteStyleRegistry.instance.parseEntryDataWithMigration(id, NoteStyleRegistry.instance.fetchEntryVersion(id)); + // if (result == null) + // { + // throw 'Could not parse note style data for id: $id'; + // } + // else + // { + // return result; + // } + // } } diff --git a/source/funkin/util/macro/EntryMacro.hx b/source/funkin/util/macro/EntryMacro.hx new file mode 100644 index 000000000..0692bf95e --- /dev/null +++ b/source/funkin/util/macro/EntryMacro.hx @@ -0,0 +1,74 @@ +package funkin.util.macro; + +import haxe.macro.Context; +import haxe.macro.Expr; +import haxe.macro.Type; + +using StringTools; + +class EntryMacro +{ + public static macro function build(registryExpr:ExprOf>):Array + { + var fields = Context.getBuildFields(); + + var cls = Context.getLocalClass().get(); + + var registryCls = MacroUtil.getClassTypeFromExpr(registryExpr); + + fields.push(build_fetchDataField(registryExpr)); + + return fields; + } + + #if macro + static function build_fetchDataField(registryExpr:ExprOf>):Field + { + return { + name: '_fetchData', + access: [Access.APrivate], + kind: FieldType.FFun( + { + args: [ + { + name: 'id', + type: (macro :String) + } + ], + expr: macro + { + var result = ${registryExpr}.instance.parseEntryDataWithMigration(id, ${registryExpr}.instance.fetchEntryVersion(id)); + + if (result == null) + { + throw 'Could not parse note style data for id: ' + id; + } + else + { + return result; + } + }, + params: [], + ret: (macro :funkin.data.notestyle.NoteStyleData) + }), + pos: Context.currentPos() + }; + + /** + * static function _fetchData(id:String):NoteStyleData + { + var result = NoteStyleRegistry.instance.parseEntryDataWithMigration(id, NoteStyleRegistry.instance.fetchEntryVersion(id)); + + if (result == null) + { + throw 'Could not parse note style data for id: $id'; + } + else + { + return result; + } + } + */ + } + #end +} diff --git a/source/funkin/util/macro/RegistryMacro.hx b/source/funkin/util/macro/RegistryMacro.hx index e337fbe72..39173be74 100644 --- a/source/funkin/util/macro/RegistryMacro.hx +++ b/source/funkin/util/macro/RegistryMacro.hx @@ -19,11 +19,11 @@ class RegistryMacro var jsonCls = typeParams.jsonCls; var scriptedEntryCls = getScriptedEntryClass(entryCls); - // fields = fields.concat(buildInstanceField(cls)); + fields = fields.concat(buildInstanceField(cls)); - // fields.push(buildGetScriptedClassNamesField(scriptedEntryClsName)); + fields.push(buildGetScriptedClassNamesField(scriptedEntryCls)); - // fields.push(buildCreateScriptedEntryField(entryCls, scriptedEntryClsName)); + fields.push(buildCreateScriptedEntryField(entryCls, scriptedEntryCls)); return fields; } @@ -157,7 +157,7 @@ class RegistryMacro static function buildCreateScriptedEntryField(entryCls:ClassType, scriptedEntryCls:ClassType):Field { - var scriptedStrExpr = '${scriptedEntryCls.pack.join('.')}.${scriptedEntryCls.name}.init(clsName, ${buildNullArgs(entryCls.constructor.get())})'; + var scriptedStrExpr = '${scriptedEntryCls.pack.join('.')}.${scriptedEntryCls.name}.init(clsName, null)'; var scriptedInitExpr = Context.parse(scriptedStrExpr, Context.currentPos()); return { @@ -192,33 +192,6 @@ class RegistryMacro pos: Context.currentPos() }; } - - static function buildNullArgs(fun:ClassField):String - { - var amount:Int = 0; - switch (fun.type) - { - case Type.TFun(args, _): - amount = args.length; - case Type.TLazy(f): - switch (f()) - { - case Type.TFun(args, _): - amount = args.length; - default: - throw 'Not a function'; - } - default: - throw 'Not a function'; - } - - var args = []; - for (i in 0...amount) - { - args.push('null'); - } - return args.join(', '); - } #end } From 54f6ca5cbf562631ba30c2b7fdcb81502c021f77 Mon Sep 17 00:00:00 2001 From: lemz1 Date: Sun, 13 Oct 2024 20:44:14 +0200 Subject: [PATCH 04/13] registryInstance field --- .../funkin/play/notes/notestyle/NoteStyle.hx | 27 +++--- source/funkin/util/macro/EntryMacro.hx | 85 +++++++++---------- 2 files changed, 51 insertions(+), 61 deletions(-) diff --git a/source/funkin/play/notes/notestyle/NoteStyle.hx b/source/funkin/play/notes/notestyle/NoteStyle.hx index c47245939..9c9617741 100644 --- a/source/funkin/play/notes/notestyle/NoteStyle.hx +++ b/source/funkin/play/notes/notestyle/NoteStyle.hx @@ -40,8 +40,7 @@ class NoteStyle implements IRegistryEntry function get_fallback():Null { if (_data == null || _data.fallback == null) return null; - return null; - // return NoteStyleRegistry.instance.fetchEntry(_data.fallback); + return registryInstance.fetchEntry(_data.fallback); } /** @@ -890,16 +889,16 @@ class NoteStyle implements IRegistryEntry return 'NoteStyle($id)'; } - // static function _fetchData(id:String):NoteStyleData - // { - // var result = NoteStyleRegistry.instance.parseEntryDataWithMigration(id, NoteStyleRegistry.instance.fetchEntryVersion(id)); - // if (result == null) - // { - // throw 'Could not parse note style data for id: $id'; - // } - // else - // { - // return result; - // } - // } + static function _fetchData(id:String):NoteStyleData + { + var result = registryInstance.parseEntryDataWithMigration(id, registryInstance.fetchEntryVersion(id)); + if (result == null) + { + throw 'Could not parse note style data for id: $id'; + } + else + { + return result; + } + } } diff --git a/source/funkin/util/macro/EntryMacro.hx b/source/funkin/util/macro/EntryMacro.hx index 0692bf95e..25495760d 100644 --- a/source/funkin/util/macro/EntryMacro.hx +++ b/source/funkin/util/macro/EntryMacro.hx @@ -12,63 +12,54 @@ class EntryMacro { var fields = Context.getBuildFields(); - var cls = Context.getLocalClass().get(); - - var registryCls = MacroUtil.getClassTypeFromExpr(registryExpr); - - fields.push(build_fetchDataField(registryExpr)); + fields = fields.concat(buildRegistryInstanceField(registryExpr)); return fields; } #if macro - static function build_fetchDataField(registryExpr:ExprOf>):Field + static function buildRegistryInstanceField(registryExpr:ExprOf>):Array { - return { - name: '_fetchData', - access: [Access.APrivate], - kind: FieldType.FFun( - { - args: [ - { - name: 'id', - type: (macro :String) - } - ], - expr: macro - { - var result = ${registryExpr}.instance.parseEntryDataWithMigration(id, ${registryExpr}.instance.fetchEntryVersion(id)); + var fields = []; - if (result == null) - { - throw 'Could not parse note style data for id: ' + id; - } - else - { - return result; - } - }, - params: [], - ret: (macro :funkin.data.notestyle.NoteStyleData) - }), - pos: Context.currentPos() - }; + var registryCls = MacroUtil.getClassTypeFromExpr(registryExpr); - /** - * static function _fetchData(id:String):NoteStyleData + fields.push( { - var result = NoteStyleRegistry.instance.parseEntryDataWithMigration(id, NoteStyleRegistry.instance.fetchEntryVersion(id)); + name: 'registryInstance', + access: [Access.APrivate, Access.AStatic], + kind: FieldType.FProp("get", "never", ComplexType.TPath( + { + pack: registryCls.pack, + name: registryCls.name, + params: [] + })), + pos: Context.currentPos() + }); - if (result == null) - { - throw 'Could not parse note style data for id: $id'; - } - else - { - return result; - } - } - */ + fields.push( + { + name: 'get_registryInstance', + access: [Access.APrivate, Access.AStatic], + kind: FFun( + { + args: [], + expr: macro + { + return ${registryExpr}.instance; + }, + params: [], + ret: ComplexType.TPath( + { + pack: registryCls.pack, + name: registryCls.name, + params: [] + }) + }), + pos: Context.currentPos() + }); + + return fields; } #end } From 1031c5c3e5ed2a9ded2bf0cc419323ecff8e232e Mon Sep 17 00:00:00 2001 From: lemz1 Date: Sun, 13 Oct 2024 21:56:01 +0200 Subject: [PATCH 05/13] fetch data field --- .../data/notestyle/NoteStyleRegistry.hx | 33 ++++++------ source/funkin/data/song/SongRegistry.hx | 26 +-------- .../funkin/play/notes/notestyle/NoteStyle.hx | 6 +-- source/funkin/play/song/Song.hx | 25 ++++----- source/funkin/util/macro/EntryMacro.hx | 54 +++++++++++++++++++ source/funkin/util/macro/RegistryMacro.hx | 2 +- 6 files changed, 86 insertions(+), 60 deletions(-) diff --git a/source/funkin/data/notestyle/NoteStyleRegistry.hx b/source/funkin/data/notestyle/NoteStyleRegistry.hx index 051aa1072..36d1b9200 100644 --- a/source/funkin/data/notestyle/NoteStyleRegistry.hx +++ b/source/funkin/data/notestyle/NoteStyleRegistry.hx @@ -4,7 +4,6 @@ import funkin.play.notes.notestyle.NoteStyle; import funkin.play.notes.notestyle.ScriptedNoteStyle; import funkin.data.notestyle.NoteStyleData; -@:build(funkin.util.macro.RegistryMacro.build()) class NoteStyleRegistry extends BaseRegistry { /** @@ -16,13 +15,14 @@ class NoteStyleRegistry extends BaseRegistry public static final NOTE_STYLE_DATA_VERSION_RULE:thx.semver.VersionRule = "1.1.x"; - // public static var instance(get, never):NoteStyleRegistry; - // static var _instance:Null = null; - // static function get_instance():NoteStyleRegistry - // { - // if (_instance == null) _instance = new NoteStyleRegistry(); - // return _instance; - // } + public static var instance(get, never):NoteStyleRegistry; + static var _instance:Null = null; + + static function get_instance():NoteStyleRegistry + { + if (_instance == null) _instance = new NoteStyleRegistry(); + return _instance; + } public function new() { @@ -81,12 +81,13 @@ class NoteStyleRegistry extends BaseRegistry return parser.value; } - // function createScriptedEntry(clsName:String):NoteStyle - // { - // return ScriptedNoteStyle.init(clsName, "unknown"); - // } - // function getScriptedClassNames():Array - // { - // return ScriptedNoteStyle.listScriptClasses(); - // } + function createScriptedEntry(clsName:String):NoteStyle + { + return ScriptedNoteStyle.init(clsName, "unknown"); + } + + function getScriptedClassNames():Array + { + return ScriptedNoteStyle.listScriptClasses(); + } } diff --git a/source/funkin/data/song/SongRegistry.hx b/source/funkin/data/song/SongRegistry.hx index e7cab246c..3e9f88453 100644 --- a/source/funkin/data/song/SongRegistry.hx +++ b/source/funkin/data/song/SongRegistry.hx @@ -13,6 +13,7 @@ import funkin.util.VersionUtil; using funkin.data.song.migrator.SongDataMigrator; @:nullSafety +@:build(funkin.util.macro.RegistryMacro.build()) class SongRegistry extends BaseRegistry { /** @@ -39,19 +40,6 @@ class SongRegistry extends BaseRegistry return '${Constants.TITLE} - ${Constants.VERSION}'; } - /** - * TODO: What if there was a Singleton macro which automatically created the property for us? - */ - public static var instance(get, never):SongRegistry; - - static var _instance:Null = null; - - static function get_instance():SongRegistry - { - if (_instance == null) _instance = new SongRegistry(); - return _instance; - } - public function new() { super('SONG', 'songs', SONG_METADATA_VERSION_RULE); @@ -69,7 +57,7 @@ class SongRegistry extends BaseRegistry for (entryCls in scriptedEntryClassNames) { - var entry:Song = createScriptedEntry(entryCls); + var entry:Null = createScriptedEntry(entryCls); if (entry != null) { @@ -417,16 +405,6 @@ class SongRegistry extends BaseRegistry } } - function createScriptedEntry(clsName:String):Song - { - return ScriptedSong.init(clsName, "unknown"); - } - - function getScriptedClassNames():Array - { - return ScriptedSong.listScriptClasses(); - } - function loadEntryMetadataFile(id:String, ?variation:String):Null { variation = variation == null ? Constants.DEFAULT_VARIATION : variation; diff --git a/source/funkin/play/notes/notestyle/NoteStyle.hx b/source/funkin/play/notes/notestyle/NoteStyle.hx index 9c9617741..5d5478ce0 100644 --- a/source/funkin/play/notes/notestyle/NoteStyle.hx +++ b/source/funkin/play/notes/notestyle/NoteStyle.hx @@ -18,7 +18,6 @@ using funkin.data.animation.AnimationData.AnimationDataUtil; * and provides convenience methods for building sprites based on them. */ @:nullSafety -@:build(funkin.util.macro.EntryMacro.build(funkin.data.notestyle.NoteStyleRegistry)) class NoteStyle implements IRegistryEntry { /** @@ -40,7 +39,7 @@ class NoteStyle implements IRegistryEntry function get_fallback():Null { if (_data == null || _data.fallback == null) return null; - return registryInstance.fetchEntry(_data.fallback); + return NoteStyleRegistry.instance.fetchEntry(_data.fallback); } /** @@ -891,7 +890,8 @@ class NoteStyle implements IRegistryEntry static function _fetchData(id:String):NoteStyleData { - var result = registryInstance.parseEntryDataWithMigration(id, registryInstance.fetchEntryVersion(id)); + var result = NoteStyleRegistry.instance.parseEntryDataWithMigration(id, NoteStyleRegistry.instance.fetchEntryVersion(id)); + if (result == null) { throw 'Could not parse note style data for id: $id'; diff --git a/source/funkin/play/song/Song.hx b/source/funkin/play/song/Song.hx index 20d2f75a4..534281cb0 100644 --- a/source/funkin/play/song/Song.hx +++ b/source/funkin/play/song/Song.hx @@ -28,6 +28,7 @@ import funkin.util.SortUtil; * can be used to perform custom gameplay behaviors only on specific songs. */ @:nullSafety +@:build(funkin.util.macro.EntryMacro.build(funkin.data.song.SongRegistry)) class Song implements IPlayStateScriptedClass implements IRegistryEntry { /** @@ -209,17 +210,17 @@ class Song implements IPlayStateScriptedClass implements IRegistryEntry; - if (includeScript && SongRegistry.instance.isScriptedEntry(songId)) + if (includeScript && registryInstance.isScriptedEntry(songId)) { - var songClassName:String = SongRegistry.instance.getScriptedEntryClassName(songId); + var songClassName:String = registryInstance.getScriptedEntryClassName(songId); @:privateAccess - result = SongRegistry.instance.createScriptedEntry(songClassName); + result = registryInstance.createScriptedEntry(songClassName); } else { @:privateAccess - result = SongRegistry.instance.createEntry(songId); + result = registryInstance.createEntry(songId); } if (result == null) throw 'ERROR: Could not build Song instance ($songId), is the attached script bad?'; @@ -356,9 +357,9 @@ class Song implements IPlayStateScriptedClass implements IRegistryEntry = SongRegistry.instance.fetchEntryChartVersion(id, variation); + var version:Null = registryInstance.fetchEntryChartVersion(id, variation); if (version == null) continue; - var chart:Null = SongRegistry.instance.parseEntryChartDataWithMigration(id, variation, version); + var chart:Null = registryInstance.parseEntryChartDataWithMigration(id, variation, version); if (chart == null) continue; applyChartData(chart, variation); } @@ -673,19 +674,11 @@ class Song implements IPlayStateScriptedClass implements IRegistryEntry - { - trace('Fetching song metadata for $id'); - var version:Null = SongRegistry.instance.fetchEntryMetadataVersion(id); - if (version == null) return null; - return SongRegistry.instance.parseEntryMetadataWithMigration(id, Constants.DEFAULT_VARIATION, version); - } - function fetchVariationMetadata(id:String, vari:String):Null { - var version:Null = SongRegistry.instance.fetchEntryMetadataVersion(id, vari); + var version:Null = registryInstance.fetchEntryMetadataVersion(id, vari); if (version == null) return null; - var meta:Null = SongRegistry.instance.parseEntryMetadataWithMigration(id, vari, version); + var meta:Null = registryInstance.parseEntryMetadataWithMigration(id, vari, version); return meta; } diff --git a/source/funkin/util/macro/EntryMacro.hx b/source/funkin/util/macro/EntryMacro.hx index 25495760d..0138d3385 100644 --- a/source/funkin/util/macro/EntryMacro.hx +++ b/source/funkin/util/macro/EntryMacro.hx @@ -12,12 +12,31 @@ class EntryMacro { var fields = Context.getBuildFields(); + var cls = Context.getLocalClass().get(); + + var entryData = getEntryData(cls); + fields = fields.concat(buildRegistryInstanceField(registryExpr)); + fields.push(build_fetchDataField(entryData, registryExpr)); + return fields; } #if macro + static function getEntryData(cls:ClassType):Dynamic // DefType or ClassType + { + switch (cls.interfaces[0].params[0]) + { + case Type.TInst(t, _): + return t.get(); + case Type.TType(t, _): + return t.get(); + default: + throw 'Entry Data is not a class or typedef'; + } + } + static function buildRegistryInstanceField(registryExpr:ExprOf>):Array { var fields = []; @@ -61,5 +80,40 @@ class EntryMacro return fields; } + + static function build_fetchDataField(entryData:Dynamic, registryExpr:ExprOf>):Field + { + return { + name: '_fetchData', + access: [Access.AStatic, Access.APrivate], + kind: FieldType.FFun( + { + args: [ + { + name: 'id', + type: (macro :String) + } + ], + expr: macro + { + return ${registryExpr}.instance.parseEntryDataWithMigration(id, ${registryExpr}.instance.fetchEntryVersion(id)); + }, + params: [], + ret: ComplexType.TPath( + { + pack: [], + name: 'Null', + params: [ + TypeParam.TPType(ComplexType.TPath( + { + pack: entryData.pack, + name: entryData.name + })) + ] + }) + }), + pos: Context.currentPos() + }; + } #end } diff --git a/source/funkin/util/macro/RegistryMacro.hx b/source/funkin/util/macro/RegistryMacro.hx index 39173be74..3294be404 100644 --- a/source/funkin/util/macro/RegistryMacro.hx +++ b/source/funkin/util/macro/RegistryMacro.hx @@ -157,7 +157,7 @@ class RegistryMacro static function buildCreateScriptedEntryField(entryCls:ClassType, scriptedEntryCls:ClassType):Field { - var scriptedStrExpr = '${scriptedEntryCls.pack.join('.')}.${scriptedEntryCls.name}.init(clsName, null)'; + var scriptedStrExpr = '${scriptedEntryCls.pack.join('.')}.${scriptedEntryCls.name}.init(clsName, \'unknown\')'; var scriptedInitExpr = Context.parse(scriptedStrExpr, Context.currentPos()); return { From e5165b04f12dd0657200143eb40c04a45fe28e8e Mon Sep 17 00:00:00 2001 From: lemz1 Date: Sun, 13 Oct 2024 22:11:38 +0200 Subject: [PATCH 06/13] id and _data --- source/funkin/play/song/Song.hx | 13 ---------- source/funkin/util/macro/EntryMacro.hx | 35 ++++++++++++++++++++++++++ 2 files changed, 35 insertions(+), 13 deletions(-) diff --git a/source/funkin/play/song/Song.hx b/source/funkin/play/song/Song.hx index 534281cb0..f0db694b3 100644 --- a/source/funkin/play/song/Song.hx +++ b/source/funkin/play/song/Song.hx @@ -66,19 +66,6 @@ class Song implements IPlayStateScriptedClass implements IRegistryEntry; - // key = variation id, value = metadata final _metadata:Map; diff --git a/source/funkin/util/macro/EntryMacro.hx b/source/funkin/util/macro/EntryMacro.hx index 0138d3385..082f6a281 100644 --- a/source/funkin/util/macro/EntryMacro.hx +++ b/source/funkin/util/macro/EntryMacro.hx @@ -16,6 +16,10 @@ class EntryMacro var entryData = getEntryData(cls); + fields.push(buildIdField()); + + fields.push(build_dataField(entryData)); + fields = fields.concat(buildRegistryInstanceField(registryExpr)); fields.push(build_fetchDataField(entryData, registryExpr)); @@ -37,6 +41,37 @@ class EntryMacro } } + static function buildIdField():Field + { + return { + name: 'id', + access: [Access.APublic, Access.AFinal], + kind: FieldType.FVar((macro :String)), + pos: Context.currentPos() + }; + } + + static function build_dataField(entryData:Dynamic):Field + { + return { + name: '_data', + access: [Access.APublic, Access.AFinal], + kind: FieldType.FVar(ComplexType.TPath( + { + pack: [], + name: 'Null', + params: [ + TypeParam.TPType(ComplexType.TPath( + { + pack: entryData.pack, + name: entryData.name + })) + ] + })), + pos: Context.currentPos() + }; + } + static function buildRegistryInstanceField(registryExpr:ExprOf>):Array { var fields = []; From 1226dee1737cb37467243c63f2b6c0b1561eb982 Mon Sep 17 00:00:00 2001 From: lemz1 Date: Sun, 13 Oct 2024 22:59:18 +0200 Subject: [PATCH 07/13] fix crash --- source/funkin/play/song/Song.hx | 8 ++ source/funkin/util/macro/EntryMacro.hx | 157 +++++++++++++++---------- 2 files changed, 102 insertions(+), 63 deletions(-) diff --git a/source/funkin/play/song/Song.hx b/source/funkin/play/song/Song.hx index f0db694b3..818c1602e 100644 --- a/source/funkin/play/song/Song.hx +++ b/source/funkin/play/song/Song.hx @@ -661,6 +661,14 @@ class Song implements IPlayStateScriptedClass implements IRegistryEntry + { + trace('Fetching song metadata for $id'); + var version:Null = registryInstance.fetchEntryMetadataVersion(id); + if (version == null) return null; + return registryInstance.parseEntryMetadataWithMigration(id, Constants.DEFAULT_VARIATION, version); + } + function fetchVariationMetadata(id:String, vari:String):Null { var version:Null = registryInstance.fetchEntryMetadataVersion(id, vari); diff --git a/source/funkin/util/macro/EntryMacro.hx b/source/funkin/util/macro/EntryMacro.hx index 082f6a281..7bf8797ec 100644 --- a/source/funkin/util/macro/EntryMacro.hx +++ b/source/funkin/util/macro/EntryMacro.hx @@ -16,18 +16,30 @@ class EntryMacro var entryData = getEntryData(cls); - fields.push(buildIdField()); + buildIdField(fields); - fields.push(build_dataField(entryData)); + build_dataField(entryData, fields); - fields = fields.concat(buildRegistryInstanceField(registryExpr)); + buildRegistryInstanceField(registryExpr, fields); - fields.push(build_fetchDataField(entryData, registryExpr)); + build_fetchDataField(entryData, registryExpr, fields); return fields; } #if macro + static function shouldBuildField(name:String, fields:Array):Bool + { + for (field in fields) + { + if (field.name == name) + { + return false; + } + } + return true; + } + static function getEntryData(cls:ClassType):Dynamic // DefType or ClassType { switch (cls.interfaces[0].params[0]) @@ -41,40 +53,55 @@ class EntryMacro } } - static function buildIdField():Field + static function buildIdField(fields:Array):Void { - return { - name: 'id', - access: [Access.APublic, Access.AFinal], - kind: FieldType.FVar((macro :String)), - pos: Context.currentPos() - }; + if (!shouldBuildField('id', fields)) + { + return; + } + + fields.push( + { + name: 'id', + access: [Access.APublic, Access.AFinal], + kind: FieldType.FVar((macro :String)), + pos: Context.currentPos() + }); } - static function build_dataField(entryData:Dynamic):Field + static function build_dataField(entryData:Dynamic, fields:Array):Void { - return { - name: '_data', - access: [Access.APublic, Access.AFinal], - kind: FieldType.FVar(ComplexType.TPath( - { - pack: [], - name: 'Null', - params: [ - TypeParam.TPType(ComplexType.TPath( - { - pack: entryData.pack, - name: entryData.name - })) - ] - })), - pos: Context.currentPos() - }; + if (!shouldBuildField('_data', fields)) + { + return; + } + + fields.push( + { + name: '_data', + access: [Access.APublic, Access.AFinal], + kind: FieldType.FVar(ComplexType.TPath( + { + pack: [], + name: 'Null', + params: [ + TypeParam.TPType(ComplexType.TPath( + { + pack: entryData.pack, + name: entryData.name + })) + ] + })), + pos: Context.currentPos() + }); } - static function buildRegistryInstanceField(registryExpr:ExprOf>):Array + static function buildRegistryInstanceField(registryExpr:ExprOf>, fields:Array):Void { - var fields = []; + if (!shouldBuildField('registryInstance', fields)) + { + return; + } var registryCls = MacroUtil.getClassTypeFromExpr(registryExpr); @@ -112,43 +139,47 @@ class EntryMacro }), pos: Context.currentPos() }); - - return fields; } - static function build_fetchDataField(entryData:Dynamic, registryExpr:ExprOf>):Field + static function build_fetchDataField(entryData:Dynamic, registryExpr:ExprOf>, fields:Array):Void { - return { - name: '_fetchData', - access: [Access.AStatic, Access.APrivate], - kind: FieldType.FFun( - { - args: [ - { - name: 'id', - type: (macro :String) - } - ], - expr: macro + if (!shouldBuildField('_fetchData', fields)) + { + return; + } + + fields.push( + { + name: '_fetchData', + access: [Access.AStatic, Access.APrivate], + kind: FieldType.FFun( { - return ${registryExpr}.instance.parseEntryDataWithMigration(id, ${registryExpr}.instance.fetchEntryVersion(id)); - }, - params: [], - ret: ComplexType.TPath( + args: [ + { + name: 'id', + type: (macro :String) + } + ], + expr: macro { - pack: [], - name: 'Null', - params: [ - TypeParam.TPType(ComplexType.TPath( - { - pack: entryData.pack, - name: entryData.name - })) - ] - }) - }), - pos: Context.currentPos() - }; + return ${registryExpr}.instance.parseEntryDataWithMigration(id, ${registryExpr}.instance.fetchEntryVersion(id)); + }, + params: [], + ret: ComplexType.TPath( + { + pack: [], + name: 'Null', + params: [ + TypeParam.TPType(ComplexType.TPath( + { + pack: entryData.pack, + name: entryData.name + })) + ] + }) + }), + pos: Context.currentPos() + }); } #end } From 73d35343096affc6d95c54989e1dd19ef44d38f4 Mon Sep 17 00:00:00 2001 From: lemz1 Date: Sun, 13 Oct 2024 23:19:31 +0200 Subject: [PATCH 08/13] Update RegistryMacro.hx --- source/funkin/util/macro/RegistryMacro.hx | 129 +++++++++++++--------- 1 file changed, 77 insertions(+), 52 deletions(-) diff --git a/source/funkin/util/macro/RegistryMacro.hx b/source/funkin/util/macro/RegistryMacro.hx index 3294be404..9da9ddee6 100644 --- a/source/funkin/util/macro/RegistryMacro.hx +++ b/source/funkin/util/macro/RegistryMacro.hx @@ -19,16 +19,28 @@ class RegistryMacro var jsonCls = typeParams.jsonCls; var scriptedEntryCls = getScriptedEntryClass(entryCls); - fields = fields.concat(buildInstanceField(cls)); + buildInstanceField(cls, fields); - fields.push(buildGetScriptedClassNamesField(scriptedEntryCls)); + buildGetScriptedClassNamesField(scriptedEntryCls, fields); - fields.push(buildCreateScriptedEntryField(entryCls, scriptedEntryCls)); + buildCreateScriptedEntryField(entryCls, scriptedEntryCls, fields); return fields; } #if macro + static function shouldBuildField(name:String, fields:Array):Bool + { + for (field in fields) + { + if (field.name == name) + { + return false; + } + } + return true; + } + static function getTypeParams(cls:ClassType):RegistryTypeParams { switch (cls.superClass.t.get().kind) @@ -65,9 +77,12 @@ class RegistryMacro }; } - static function buildInstanceField(cls:ClassType):Array + static function buildInstanceField(cls:ClassType, fields:Array):Void { - var fields = []; + if (!shouldBuildField('instasnce', fields)) + { + return; + } fields.push( { @@ -130,67 +145,77 @@ class RegistryMacro }), pos: Context.currentPos() }); - - return fields; } - static function buildGetScriptedClassNamesField(scriptedEntryCls:ClassType):Field + static function buildGetScriptedClassNamesField(scriptedEntryCls:ClassType, fields:Array):Void { + if (!shouldBuildField('getScriptedClassNames', fields)) + { + return; + } + var scriptedEntryExpr = Context.parse('${scriptedEntryCls.pack.join('.')}.${scriptedEntryCls.name}', Context.currentPos()); - return { - name: 'getScriptedClassNames', - access: [Access.APrivate], - kind: FieldType.FFun( - { - args: [], - expr: macro + fields.push( + { + name: 'getScriptedClassNames', + access: [Access.APrivate], + kind: FieldType.FFun( { - return ${scriptedEntryExpr}.listScriptClasses(); - }, - params: [], - ret: (macro :Array) - }), - pos: Context.currentPos() - }; + args: [], + expr: macro + { + return ${scriptedEntryExpr}.listScriptClasses(); + }, + params: [], + ret: (macro :Array) + }), + pos: Context.currentPos() + }); } - static function buildCreateScriptedEntryField(entryCls:ClassType, scriptedEntryCls:ClassType):Field + static function buildCreateScriptedEntryField(entryCls:ClassType, scriptedEntryCls:ClassType, fields:Array):Void { + if (!shouldBuildField('createScriptedEntry', fields)) + { + return; + } + var scriptedStrExpr = '${scriptedEntryCls.pack.join('.')}.${scriptedEntryCls.name}.init(clsName, \'unknown\')'; var scriptedInitExpr = Context.parse(scriptedStrExpr, Context.currentPos()); - return { - name: 'createScriptedEntry', - access: [Access.APrivate], - kind: FieldType.FFun( - { - args: [ - { - name: 'clsName', - type: (macro :String) - } - ], - expr: macro + fields.push( + { + name: 'createScriptedEntry', + access: [Access.APrivate], + kind: FieldType.FFun( { - return ${scriptedInitExpr}; - }, - params: [], - ret: ComplexType.TPath( + args: [ + { + name: 'clsName', + type: (macro :String) + } + ], + expr: macro { - pack: [], - name: 'Null', - params: [ - TypeParam.TPType(ComplexType.TPath( - { - pack: entryCls.pack, - name: entryCls.name - })) - ] - }) - }), - pos: Context.currentPos() - }; + return ${scriptedInitExpr}; + }, + params: [], + ret: ComplexType.TPath( + { + pack: [], + name: 'Null', + params: [ + TypeParam.TPType(ComplexType.TPath( + { + pack: entryCls.pack, + name: entryCls.name + })) + ] + }) + }), + pos: Context.currentPos() + }); } #end } From 3b3134a6f822144bfd24b4ab0325c365f7d81380 Mon Sep 17 00:00:00 2001 From: lemz1 Date: Mon, 14 Oct 2024 18:19:50 +0200 Subject: [PATCH 09/13] some more stuff --- source/funkin/play/song/Song.hx | 7 --- source/funkin/util/macro/EntryMacro.hx | 63 ++++++++++++++++++++++++-- 2 files changed, 58 insertions(+), 12 deletions(-) diff --git a/source/funkin/play/song/Song.hx b/source/funkin/play/song/Song.hx index 818c1602e..9b7a3bb69 100644 --- a/source/funkin/play/song/Song.hx +++ b/source/funkin/play/song/Song.hx @@ -612,13 +612,6 @@ class Song implements IPlayStateScriptedClass implements IRegistryEntry):Void + static function buildDataField(entryData:Dynamic, fields:Array):Void { if (!shouldBuildField('_data', fields)) { @@ -141,7 +145,7 @@ class EntryMacro }); } - static function build_fetchDataField(entryData:Dynamic, registryExpr:ExprOf>, fields:Array):Void + static function buildFetchDataField(entryData:Dynamic, fields:Array):Void { if (!shouldBuildField('_fetchData', fields)) { @@ -162,7 +166,7 @@ class EntryMacro ], expr: macro { - return ${registryExpr}.instance.parseEntryDataWithMigration(id, ${registryExpr}.instance.fetchEntryVersion(id)); + return registryInstance.parseEntryDataWithMigration(id, registryInstance.fetchEntryVersion(id)); }, params: [], ret: ComplexType.TPath( @@ -181,5 +185,54 @@ class EntryMacro pos: Context.currentPos() }); } + + static function buildToStringField(cls:ClassType, fields:Array):Void + { + if (!shouldBuildField('toString', fields)) + { + return; + } + + fields.push( + { + name: 'toString', + access: [Access.APublic], + kind: FieldType.FFun( + { + args: [], + expr: macro + { + return $v{cls.name} + '(' + id + ')'; + }, + params: [], + ret: (macro :String) + }), + pos: Context.currentPos() + }); + } + + static function buildDestroyField(fields:Array):Void + { + if (!shouldBuildField('destroy', fields)) + { + return; + } + + fields.push( + { + name: 'destroy', + access: [Access.APublic], + kind: FieldType.FFun( + { + args: [], + expr: macro + { + return; + }, + params: [] + }), + pos: Context.currentPos() + }); + } #end } From 9660982403b4316c597167bab4c86bbcd6864633 Mon Sep 17 00:00:00 2001 From: lemz1 Date: Mon, 14 Oct 2024 19:13:03 +0200 Subject: [PATCH 10/13] parseentrydata and update notestyleregistry --- .../data/notestyle/NoteStyleRegistry.hx | 67 +--------- .../funkin/play/notes/notestyle/NoteStyle.hx | 17 +-- source/funkin/util/macro/RegistryMacro.hx | 124 +++++++++++++++++- 3 files changed, 127 insertions(+), 81 deletions(-) diff --git a/source/funkin/data/notestyle/NoteStyleRegistry.hx b/source/funkin/data/notestyle/NoteStyleRegistry.hx index 36d1b9200..43dbd41f7 100644 --- a/source/funkin/data/notestyle/NoteStyleRegistry.hx +++ b/source/funkin/data/notestyle/NoteStyleRegistry.hx @@ -4,6 +4,7 @@ import funkin.play.notes.notestyle.NoteStyle; import funkin.play.notes.notestyle.ScriptedNoteStyle; import funkin.data.notestyle.NoteStyleData; +@:build(funkin.util.macro.RegistryMacro.build()) class NoteStyleRegistry extends BaseRegistry { /** @@ -15,15 +16,6 @@ class NoteStyleRegistry extends BaseRegistry public static final NOTE_STYLE_DATA_VERSION_RULE:thx.semver.VersionRule = "1.1.x"; - public static var instance(get, never):NoteStyleRegistry; - static var _instance:Null = null; - - static function get_instance():NoteStyleRegistry - { - if (_instance == null) _instance = new NoteStyleRegistry(); - return _instance; - } - public function new() { super('NOTESTYLE', 'notestyles', NOTE_STYLE_DATA_VERSION_RULE); @@ -33,61 +25,4 @@ class NoteStyleRegistry extends BaseRegistry { return fetchEntry(Constants.DEFAULT_NOTE_STYLE); } - - /** - * Read, parse, and validate the JSON data and produce the corresponding data object. - */ - public function parseEntryData(id:String):Null - { - // JsonParser does not take type parameters, - // otherwise this function would be in BaseRegistry. - var parser = new json2object.JsonParser(); - parser.ignoreUnknownVariables = false; - - switch (loadEntryFile(id)) - { - case {fileName: fileName, contents: contents}: - parser.fromJson(contents, fileName); - default: - return null; - } - - if (parser.errors.length > 0) - { - printErrors(parser.errors, id); - return null; - } - return parser.value; - } - - /** - * Parse and validate the JSON data and produce the corresponding data object. - * - * NOTE: Must be implemented on the implementation class. - * @param contents The JSON as a string. - * @param fileName An optional file name for error reporting. - */ - public function parseEntryDataRaw(contents:String, ?fileName:String):Null - { - var parser = new json2object.JsonParser(); - parser.ignoreUnknownVariables = false; - parser.fromJson(contents, fileName); - - if (parser.errors.length > 0) - { - printErrors(parser.errors, fileName); - return null; - } - return parser.value; - } - - function createScriptedEntry(clsName:String):NoteStyle - { - return ScriptedNoteStyle.init(clsName, "unknown"); - } - - function getScriptedClassNames():Array - { - return ScriptedNoteStyle.listScriptClasses(); - } } diff --git a/source/funkin/play/notes/notestyle/NoteStyle.hx b/source/funkin/play/notes/notestyle/NoteStyle.hx index 5d5478ce0..0bdc507e8 100644 --- a/source/funkin/play/notes/notestyle/NoteStyle.hx +++ b/source/funkin/play/notes/notestyle/NoteStyle.hx @@ -18,13 +18,9 @@ using funkin.data.animation.AnimationData.AnimationDataUtil; * and provides convenience methods for building sprites based on them. */ @:nullSafety +@:build(funkin.util.macro.EntryMacro.build(funkin.data.notestyle.NoteStyleRegistry)) class NoteStyle implements IRegistryEntry { - /** - * The ID of the note style. - */ - public final id:String; - /** * Note style data as parsed from the JSON file. */ @@ -39,7 +35,7 @@ class NoteStyle implements IRegistryEntry function get_fallback():Null { if (_data == null || _data.fallback == null) return null; - return NoteStyleRegistry.instance.fetchEntry(_data.fallback); + return registryInstance.fetchEntry(_data.fallback); } /** @@ -881,16 +877,9 @@ class NoteStyle implements IRegistryEntry } } - public function destroy():Void {} - - public function toString():String - { - return 'NoteStyle($id)'; - } - static function _fetchData(id:String):NoteStyleData { - var result = NoteStyleRegistry.instance.parseEntryDataWithMigration(id, NoteStyleRegistry.instance.fetchEntryVersion(id)); + var result = registryInstance.parseEntryDataWithMigration(id, registryInstance.fetchEntryVersion(id)); if (result == null) { diff --git a/source/funkin/util/macro/RegistryMacro.hx b/source/funkin/util/macro/RegistryMacro.hx index 9da9ddee6..364a7fcb5 100644 --- a/source/funkin/util/macro/RegistryMacro.hx +++ b/source/funkin/util/macro/RegistryMacro.hx @@ -25,6 +25,10 @@ class RegistryMacro buildCreateScriptedEntryField(entryCls, scriptedEntryCls, fields); + buildParseEntryDataField(jsonCls, fields); + + buildParseEntryDataRawField(jsonCls, fields); + return fields; } @@ -79,7 +83,7 @@ class RegistryMacro static function buildInstanceField(cls:ClassType, fields:Array):Void { - if (!shouldBuildField('instasnce', fields)) + if (!shouldBuildField('instance', fields)) { return; } @@ -217,6 +221,124 @@ class RegistryMacro pos: Context.currentPos() }); } + + static function buildParseEntryDataField(jsonCls:Dynamic, fields:Array):Void + { + if (!shouldBuildField('parseEntryData', fields)) + { + return; + } + + var jsonParserNewStrExpr = 'new json2object.JsonParser<${jsonCls.pack.join('.')}.${jsonCls.name}>()'; + var jsonParserNewExpr = Context.parse(jsonParserNewStrExpr, Context.currentPos()); + + fields.push( + { + name: 'parseEntryData', + access: [Access.APublic], + kind: FieldType.FFun( + { + args: [ + { + name: 'id', + type: (macro :String) + } + ], + expr: macro + { + var parser = ${jsonParserNewExpr}; + parser.ignoreUnknownVariables = false; + + switch (loadEntryFile(id)) + { + case {fileName: fileName, contents: contents}: + parser.fromJson(contents, fileName); + default: + return null; + } + + if (parser.errors.length > 0) + { + printErrors(parser.errors, id); + return null; + } + return parser.value; + }, + params: [], + ret: ComplexType.TPath( + { + pack: [], + name: 'Null', + params: [ + TypeParam.TPType(ComplexType.TPath( + { + pack: jsonCls.pack, + name: jsonCls.name + })) + ] + }) + }), + pos: Context.currentPos() + }); + } + + static function buildParseEntryDataRawField(jsonCls:Dynamic, fields:Array):Void + { + if (!shouldBuildField('parseEntryDataRaw', fields)) + { + return; + } + + var jsonParserNewStrExpr = 'new json2object.JsonParser<${jsonCls.pack.join('.')}.${jsonCls.name}>()'; + var jsonParserNewExpr = Context.parse(jsonParserNewStrExpr, Context.currentPos()); + + fields.push( + { + name: 'parseEntryDataRaw', + access: [Access.APublic], + kind: FieldType.FFun( + { + args: [ + { + name: 'contents', + type: (macro :String) + }, + { + name: 'fileName', + type: (macro :Null), + opt: true + } + ], + expr: macro + { + var parser = ${jsonParserNewExpr}; + parser.ignoreUnknownVariables = false; + parser.fromJson(contents, fileName); + + if (parser.errors.length > 0) + { + printErrors(parser.errors, fileName); + return null; + } + return parser.value; + }, + params: [], + ret: ComplexType.TPath( + { + pack: [], + name: 'Null', + params: [ + TypeParam.TPType(ComplexType.TPath( + { + pack: jsonCls.pack, + name: jsonCls.name + })) + ] + }) + }), + pos: Context.currentPos() + }); + } #end } From 930d7d5989d0f6c230256ba364117250971e33ae Mon Sep 17 00:00:00 2001 From: lemz1 Date: Mon, 14 Oct 2024 20:52:27 +0200 Subject: [PATCH 11/13] player registry --- .../data/freeplay/player/PlayerRegistry.hx | 67 +------------------ .../freeplay/charselect/PlayableCharacter.hx | 1 + 2 files changed, 2 insertions(+), 66 deletions(-) diff --git a/source/funkin/data/freeplay/player/PlayerRegistry.hx b/source/funkin/data/freeplay/player/PlayerRegistry.hx index 76b1c25c1..c14849bc4 100644 --- a/source/funkin/data/freeplay/player/PlayerRegistry.hx +++ b/source/funkin/data/freeplay/player/PlayerRegistry.hx @@ -5,6 +5,7 @@ import funkin.ui.freeplay.charselect.PlayableCharacter; import funkin.ui.freeplay.charselect.ScriptedPlayableCharacter; import funkin.save.Save; +@:build(funkin.util.macro.RegistryMacro.build()) class PlayerRegistry extends BaseRegistry { /** @@ -16,15 +17,6 @@ class PlayerRegistry extends BaseRegistry public static final PLAYER_DATA_VERSION_RULE:thx.semver.VersionRule = "1.0.x"; - public static var instance(get, never):PlayerRegistry; - static var _instance:Null = null; - - static function get_instance():PlayerRegistry - { - if (_instance == null) _instance = new PlayerRegistry(); - return _instance; - } - /** * A mapping between stage character IDs and Freeplay playable character IDs. */ @@ -131,63 +123,6 @@ class PlayerRegistry extends BaseRegistry return ownedCharacterIds.exists(characterId); } - /** - * Read, parse, and validate the JSON data and produce the corresponding data object. - */ - public function parseEntryData(id:String):Null - { - // JsonParser does not take type parameters, - // otherwise this function would be in BaseRegistry. - var parser = new json2object.JsonParser(); - parser.ignoreUnknownVariables = false; - - switch (loadEntryFile(id)) - { - case {fileName: fileName, contents: contents}: - parser.fromJson(contents, fileName); - default: - return null; - } - - if (parser.errors.length > 0) - { - printErrors(parser.errors, id); - return null; - } - return parser.value; - } - - /** - * Parse and validate the JSON data and produce the corresponding data object. - * - * NOTE: Must be implemented on the implementation class. - * @param contents The JSON as a string. - * @param fileName An optional file name for error reporting. - */ - public function parseEntryDataRaw(contents:String, ?fileName:String):Null - { - var parser = new json2object.JsonParser(); - parser.ignoreUnknownVariables = false; - parser.fromJson(contents, fileName); - - if (parser.errors.length > 0) - { - printErrors(parser.errors, fileName); - return null; - } - return parser.value; - } - - function createScriptedEntry(clsName:String):PlayableCharacter - { - return ScriptedPlayableCharacter.init(clsName, "unknown"); - } - - function getScriptedClassNames():Array - { - return ScriptedPlayableCharacter.listScriptClasses(); - } - /** * A list of all the playable characters from the base game, in order. */ diff --git a/source/funkin/ui/freeplay/charselect/PlayableCharacter.hx b/source/funkin/ui/freeplay/charselect/PlayableCharacter.hx index 408a91672..4dd60faf3 100644 --- a/source/funkin/ui/freeplay/charselect/PlayableCharacter.hx +++ b/source/funkin/ui/freeplay/charselect/PlayableCharacter.hx @@ -10,6 +10,7 @@ import funkin.play.scoring.Scoring.ScoringRank; * Can be scripted to override each function, for custom behavior. */ @:nullSafety +@:build(funkin.util.macro.EntryMacro.build(funkin.data.freeplay.player.PlayerRegistry)) class PlayableCharacter implements IRegistryEntry { /** From 940c52ed46f2937bea47f3a040f906c86f302b86 Mon Sep 17 00:00:00 2001 From: lemz1 Date: Mon, 14 Oct 2024 21:39:00 +0200 Subject: [PATCH 12/13] check superclass for destroy field --- .../freeplay/charselect/PlayableCharacter.hx | 31 ------------------- source/funkin/util/macro/EntryMacro.hx | 8 ++--- source/funkin/util/macro/RegistryMacro.hx | 2 +- 3 files changed, 5 insertions(+), 36 deletions(-) diff --git a/source/funkin/ui/freeplay/charselect/PlayableCharacter.hx b/source/funkin/ui/freeplay/charselect/PlayableCharacter.hx index 4dd60faf3..6215a64bd 100644 --- a/source/funkin/ui/freeplay/charselect/PlayableCharacter.hx +++ b/source/funkin/ui/freeplay/charselect/PlayableCharacter.hx @@ -13,16 +13,6 @@ import funkin.play.scoring.Scoring.ScoringRank; @:build(funkin.util.macro.EntryMacro.build(funkin.data.freeplay.player.PlayerRegistry)) class PlayableCharacter implements IRegistryEntry { - /** - * The ID of the playable character. - */ - public final id:String; - - /** - * Playable character data as parsed from the JSON file. - */ - public final _data:Null; - /** * @param id The ID of the JSON file to parse. */ @@ -157,25 +147,4 @@ class PlayableCharacter implements IRegistryEntry { return _data?.unlocked ?? true; } - - /** - * Called when the character is destroyed. - * TODO: Document when this gets called - */ - public function destroy():Void {} - - public function toString():String - { - return 'PlayableCharacter($id)'; - } - - /** - * Retrieve and parse the JSON data for a playable character by ID. - * @param id The ID of the character - * @return The parsed player data, or null if not found or invalid - */ - static function _fetchData(id:String):Null - { - return PlayerRegistry.instance.parseEntryDataWithMigration(id, PlayerRegistry.instance.fetchEntryVersion(id)); - } } diff --git a/source/funkin/util/macro/EntryMacro.hx b/source/funkin/util/macro/EntryMacro.hx index d3e66b590..3e4937292 100644 --- a/source/funkin/util/macro/EntryMacro.hx +++ b/source/funkin/util/macro/EntryMacro.hx @@ -26,13 +26,13 @@ class EntryMacro buildToStringField(cls, fields); - buildDestroyField(fields); + buildDestroyField(cls, fields); return fields; } #if macro - static function shouldBuildField(name:String, fields:Array):Bool + static function shouldBuildField(name:String, fields:Array):Bool // fields can be Array or Array { for (field in fields) { @@ -211,9 +211,9 @@ class EntryMacro }); } - static function buildDestroyField(fields:Array):Void + static function buildDestroyField(cls:ClassType, fields:Array):Void { - if (!shouldBuildField('destroy', fields)) + if (!shouldBuildField('destroy', fields) || !shouldBuildField('destroy', cls.superClass?.t.get().fields.get() ?? [])) { return; } diff --git a/source/funkin/util/macro/RegistryMacro.hx b/source/funkin/util/macro/RegistryMacro.hx index 364a7fcb5..5aba301bc 100644 --- a/source/funkin/util/macro/RegistryMacro.hx +++ b/source/funkin/util/macro/RegistryMacro.hx @@ -33,7 +33,7 @@ class RegistryMacro } #if macro - static function shouldBuildField(name:String, fields:Array):Bool + static function shouldBuildField(name:String, fields:Array):Bool // fields can be Array or Array { for (field in fields) { From 90c15fe542a3a812785956207e7d42d7e882304a Mon Sep 17 00:00:00 2001 From: lemz1 Date: Tue, 5 Nov 2024 22:05:17 +0100 Subject: [PATCH 13/13] hmm, testing stuff out --- source/funkin/play/song/Song.hx | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/source/funkin/play/song/Song.hx b/source/funkin/play/song/Song.hx index 9b7a3bb69..40d4cb789 100644 --- a/source/funkin/play/song/Song.hx +++ b/source/funkin/play/song/Song.hx @@ -197,17 +197,17 @@ class Song implements IPlayStateScriptedClass implements IRegistryEntry; - if (includeScript && registryInstance.isScriptedEntry(songId)) + if (includeScript && SongRegistry.instance.isScriptedEntry(songId)) { - var songClassName:String = registryInstance.getScriptedEntryClassName(songId); + var songClassName:String = SongRegistry.instance.getScriptedEntryClassName(songId); @:privateAccess - result = registryInstance.createScriptedEntry(songClassName); + result = SongRegistry.instance.createScriptedEntry(songClassName); } else { @:privateAccess - result = registryInstance.createEntry(songId); + result = SongRegistry.instance.createEntry(songId); } if (result == null) throw 'ERROR: Could not build Song instance ($songId), is the attached script bad?'; @@ -344,9 +344,9 @@ class Song implements IPlayStateScriptedClass implements IRegistryEntry = registryInstance.fetchEntryChartVersion(id, variation); + var version:Null = SongRegistry.instance.fetchEntryChartVersion(id, variation); if (version == null) continue; - var chart:Null = registryInstance.parseEntryChartDataWithMigration(id, variation, version); + var chart:Null = SongRegistry.instance.parseEntryChartDataWithMigration(id, variation, version); if (chart == null) continue; applyChartData(chart, variation); } @@ -657,16 +657,16 @@ class Song implements IPlayStateScriptedClass implements IRegistryEntry { trace('Fetching song metadata for $id'); - var version:Null = registryInstance.fetchEntryMetadataVersion(id); + var version:Null = SongRegistry.instance.fetchEntryMetadataVersion(id); if (version == null) return null; - return registryInstance.parseEntryMetadataWithMigration(id, Constants.DEFAULT_VARIATION, version); + return SongRegistry.instance.parseEntryMetadataWithMigration(id, Constants.DEFAULT_VARIATION, version); } function fetchVariationMetadata(id:String, vari:String):Null { - var version:Null = registryInstance.fetchEntryMetadataVersion(id, vari); + var version:Null = SongRegistry.instance.fetchEntryMetadataVersion(id, vari); if (version == null) return null; - var meta:Null = registryInstance.parseEntryMetadataWithMigration(id, vari, version); + var meta:Null = SongRegistry.instance.parseEntryMetadataWithMigration(id, vari, version); return meta; }