mirror of
https://github.com/FunkinCrew/Funkin.git
synced 2024-11-14 11:15:24 -05:00
Merge 90c15fe542
into 0d8e4a5330
This commit is contained in:
commit
1f7bffe3af
8 changed files with 600 additions and 222 deletions
|
@ -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<PlayableCharacter, PlayerData>
|
||||
{
|
||||
/**
|
||||
|
@ -16,15 +17,6 @@ class PlayerRegistry extends BaseRegistry<PlayableCharacter, PlayerData>
|
|||
|
||||
public static final PLAYER_DATA_VERSION_RULE:thx.semver.VersionRule = "1.0.x";
|
||||
|
||||
public static var instance(get, never):PlayerRegistry;
|
||||
static var _instance:Null<PlayerRegistry> = 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<PlayableCharacter, PlayerData>
|
|||
return ownedCharacterIds.exists(characterId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read, parse, and validate the JSON data and produce the corresponding data object.
|
||||
*/
|
||||
public function parseEntryData(id:String):Null<PlayerData>
|
||||
{
|
||||
// JsonParser does not take type parameters,
|
||||
// otherwise this function would be in BaseRegistry.
|
||||
var parser = new json2object.JsonParser<PlayerData>();
|
||||
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<PlayerData>
|
||||
{
|
||||
var parser = new json2object.JsonParser<PlayerData>();
|
||||
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<String>
|
||||
{
|
||||
return ScriptedPlayableCharacter.listScriptClasses();
|
||||
}
|
||||
|
||||
/**
|
||||
* A list of all the playable characters from the base game, in order.
|
||||
*/
|
||||
|
|
|
@ -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<NoteStyle, NoteStyleData>
|
||||
{
|
||||
/**
|
||||
|
@ -15,15 +16,6 @@ class NoteStyleRegistry extends BaseRegistry<NoteStyle, NoteStyleData>
|
|||
|
||||
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<NoteStyleRegistry> = 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<NoteStyle, NoteStyleData>
|
|||
{
|
||||
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<NoteStyleData>
|
||||
{
|
||||
// JsonParser does not take type parameters,
|
||||
// otherwise this function would be in BaseRegistry.
|
||||
var parser = new json2object.JsonParser<NoteStyleData>();
|
||||
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<NoteStyleData>
|
||||
{
|
||||
var parser = new json2object.JsonParser<NoteStyleData>();
|
||||
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<String>
|
||||
{
|
||||
return ScriptedNoteStyle.listScriptClasses();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<Song, SongMetadata>
|
||||
{
|
||||
/**
|
||||
|
@ -39,19 +40,6 @@ class SongRegistry extends BaseRegistry<Song, SongMetadata>
|
|||
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<SongRegistry> = 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<Song, SongMetadata>
|
|||
|
||||
for (entryCls in scriptedEntryClassNames)
|
||||
{
|
||||
var entry:Song = createScriptedEntry(entryCls);
|
||||
var entry:Null<Song> = createScriptedEntry(entryCls);
|
||||
|
||||
if (entry != null)
|
||||
{
|
||||
|
@ -417,16 +405,6 @@ class SongRegistry extends BaseRegistry<Song, SongMetadata>
|
|||
}
|
||||
}
|
||||
|
||||
function createScriptedEntry(clsName:String):Song
|
||||
{
|
||||
return ScriptedSong.init(clsName, "unknown");
|
||||
}
|
||||
|
||||
function getScriptedClassNames():Array<String>
|
||||
{
|
||||
return ScriptedSong.listScriptClasses();
|
||||
}
|
||||
|
||||
function loadEntryMetadataFile(id:String, ?variation:String):Null<JsonFile>
|
||||
{
|
||||
variation = variation == null ? Constants.DEFAULT_VARIATION : variation;
|
||||
|
|
|
@ -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<NoteStyleData>
|
||||
{
|
||||
/**
|
||||
* The ID of the note style.
|
||||
*/
|
||||
public final id:String;
|
||||
|
||||
/**
|
||||
* Note style data as parsed from the JSON file.
|
||||
*/
|
||||
|
@ -36,9 +32,10 @@ class NoteStyle implements IRegistryEntry<NoteStyleData>
|
|||
*/
|
||||
var fallback(get, never):Null<NoteStyle>;
|
||||
|
||||
function get_fallback():Null<NoteStyle> {
|
||||
function get_fallback():Null<NoteStyle>
|
||||
{
|
||||
if (_data == null || _data.fallback == null) return null;
|
||||
return NoteStyleRegistry.instance.fetchEntry(_data.fallback);
|
||||
return registryInstance.fetchEntry(_data.fallback);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -880,16 +877,9 @@ class NoteStyle implements IRegistryEntry<NoteStyleData>
|
|||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
|
|
|
@ -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<SongMetadata>
|
||||
{
|
||||
/**
|
||||
|
@ -65,19 +66,6 @@ class Song implements IPlayStateScriptedClass implements IRegistryEntry<SongMeta
|
|||
*/
|
||||
public static final DEFAULT_SCROLLSPEED:Float = 1.0;
|
||||
|
||||
/**
|
||||
* The internal ID of the song.
|
||||
*/
|
||||
public final id:String;
|
||||
|
||||
/**
|
||||
* Song metadata as parsed from the JSON file.
|
||||
* This is the data for the `default` variation specifically,
|
||||
* and is needed for the IRegistryEntry interface.
|
||||
* Will only be null if the song data could not be loaded.
|
||||
*/
|
||||
public final _data:Null<SongMetadata>;
|
||||
|
||||
// key = variation id, value = metadata
|
||||
final _metadata:Map<String, SongMetadata>;
|
||||
|
||||
|
@ -624,13 +612,6 @@ class Song implements IPlayStateScriptedClass implements IRegistryEntry<SongMeta
|
|||
}
|
||||
}
|
||||
|
||||
public function toString():String
|
||||
{
|
||||
return 'Song($id)';
|
||||
}
|
||||
|
||||
public function destroy():Void {}
|
||||
|
||||
public function onPause(event:PauseScriptEvent):Void {};
|
||||
|
||||
public function onResume(event:ScriptEvent):Void {};
|
||||
|
|
|
@ -10,18 +10,9 @@ 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<PlayerData>
|
||||
{
|
||||
/**
|
||||
* The ID of the playable character.
|
||||
*/
|
||||
public final id:String;
|
||||
|
||||
/**
|
||||
* Playable character data as parsed from the JSON file.
|
||||
*/
|
||||
public final _data:Null<PlayerData>;
|
||||
|
||||
/**
|
||||
* @param id The ID of the JSON file to parse.
|
||||
*/
|
||||
|
@ -156,25 +147,4 @@ class PlayableCharacter implements IRegistryEntry<PlayerData>
|
|||
{
|
||||
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<PlayerData>
|
||||
{
|
||||
return PlayerRegistry.instance.parseEntryDataWithMigration(id, PlayerRegistry.instance.fetchEntryVersion(id));
|
||||
}
|
||||
}
|
||||
|
|
238
source/funkin/util/macro/EntryMacro.hx
Normal file
238
source/funkin/util/macro/EntryMacro.hx
Normal file
|
@ -0,0 +1,238 @@
|
|||
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<Class<Dynamic>>):Array<Field>
|
||||
{
|
||||
var fields = Context.getBuildFields();
|
||||
|
||||
var cls = Context.getLocalClass().get();
|
||||
|
||||
var entryData = getEntryData(cls);
|
||||
|
||||
buildIdField(fields);
|
||||
|
||||
buildDataField(entryData, fields);
|
||||
|
||||
buildRegistryInstanceField(registryExpr, fields);
|
||||
|
||||
buildFetchDataField(entryData, fields);
|
||||
|
||||
buildToStringField(cls, fields);
|
||||
|
||||
buildDestroyField(cls, fields);
|
||||
|
||||
return fields;
|
||||
}
|
||||
|
||||
#if macro
|
||||
static function shouldBuildField(name:String, fields:Array<Dynamic>):Bool // fields can be Array<Field> or Array<ClassField>
|
||||
{
|
||||
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])
|
||||
{
|
||||
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 buildIdField(fields:Array<Field>):Void
|
||||
{
|
||||
if (!shouldBuildField('id', fields))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
fields.push(
|
||||
{
|
||||
name: 'id',
|
||||
access: [Access.APublic, Access.AFinal],
|
||||
kind: FieldType.FVar((macro :String)),
|
||||
pos: Context.currentPos()
|
||||
});
|
||||
}
|
||||
|
||||
static function buildDataField(entryData:Dynamic, fields:Array<Field>):Void
|
||||
{
|
||||
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<Class<Dynamic>>, fields:Array<Field>):Void
|
||||
{
|
||||
if (!shouldBuildField('registryInstance', fields))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var registryCls = MacroUtil.getClassTypeFromExpr(registryExpr);
|
||||
|
||||
fields.push(
|
||||
{
|
||||
name: 'registryInstance',
|
||||
access: [Access.APrivate, Access.AStatic],
|
||||
kind: FieldType.FProp("get", "never", ComplexType.TPath(
|
||||
{
|
||||
pack: registryCls.pack,
|
||||
name: registryCls.name,
|
||||
params: []
|
||||
})),
|
||||
pos: Context.currentPos()
|
||||
});
|
||||
|
||||
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()
|
||||
});
|
||||
}
|
||||
|
||||
static function buildFetchDataField(entryData:Dynamic, fields:Array<Field>):Void
|
||||
{
|
||||
if (!shouldBuildField('_fetchData', fields))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
fields.push(
|
||||
{
|
||||
name: '_fetchData',
|
||||
access: [Access.AStatic, Access.APrivate],
|
||||
kind: FieldType.FFun(
|
||||
{
|
||||
args: [
|
||||
{
|
||||
name: 'id',
|
||||
type: (macro :String)
|
||||
}
|
||||
],
|
||||
expr: macro
|
||||
{
|
||||
return registryInstance.parseEntryDataWithMigration(id, registryInstance.fetchEntryVersion(id));
|
||||
},
|
||||
params: [],
|
||||
ret: ComplexType.TPath(
|
||||
{
|
||||
pack: [],
|
||||
name: 'Null',
|
||||
params: [
|
||||
TypeParam.TPType(ComplexType.TPath(
|
||||
{
|
||||
pack: entryData.pack,
|
||||
name: entryData.name
|
||||
}))
|
||||
]
|
||||
})
|
||||
}),
|
||||
pos: Context.currentPos()
|
||||
});
|
||||
}
|
||||
|
||||
static function buildToStringField(cls:ClassType, fields:Array<Field>):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(cls:ClassType, fields:Array<Field>):Void
|
||||
{
|
||||
if (!shouldBuildField('destroy', fields) || !shouldBuildField('destroy', cls.superClass?.t.get().fields.get() ?? []))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
fields.push(
|
||||
{
|
||||
name: 'destroy',
|
||||
access: [Access.APublic],
|
||||
kind: FieldType.FFun(
|
||||
{
|
||||
args: [],
|
||||
expr: macro
|
||||
{
|
||||
return;
|
||||
},
|
||||
params: []
|
||||
}),
|
||||
pos: Context.currentPos()
|
||||
});
|
||||
}
|
||||
#end
|
||||
}
|
351
source/funkin/util/macro/RegistryMacro.hx
Normal file
351
source/funkin/util/macro/RegistryMacro.hx
Normal file
|
@ -0,0 +1,351 @@
|
|||
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<Field>
|
||||
{
|
||||
var fields = Context.getBuildFields();
|
||||
|
||||
var cls = Context.getLocalClass().get();
|
||||
|
||||
var typeParams = getTypeParams(cls);
|
||||
var entryCls = typeParams.entryCls;
|
||||
var jsonCls = typeParams.jsonCls;
|
||||
var scriptedEntryCls = getScriptedEntryClass(entryCls);
|
||||
|
||||
buildInstanceField(cls, fields);
|
||||
|
||||
buildGetScriptedClassNamesField(scriptedEntryCls, fields);
|
||||
|
||||
buildCreateScriptedEntryField(entryCls, scriptedEntryCls, fields);
|
||||
|
||||
buildParseEntryDataField(jsonCls, fields);
|
||||
|
||||
buildParseEntryDataRawField(jsonCls, fields);
|
||||
|
||||
return fields;
|
||||
}
|
||||
|
||||
#if macro
|
||||
static function shouldBuildField(name:String, fields:Array<Dynamic>):Bool // fields can be Array<Field> or Array<ClassField>
|
||||
{
|
||||
for (field in fields)
|
||||
{
|
||||
if (field.name == name)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static function getTypeParams(cls:ClassType):RegistryTypeParams
|
||||
{
|
||||
switch (cls.superClass.t.get().kind)
|
||||
{
|
||||
case KGenericInstance(_, params):
|
||||
var typeParams:Array<Dynamic> = [];
|
||||
for (param in params)
|
||||
{
|
||||
switch (param)
|
||||
{
|
||||
case TInst(t, _):
|
||||
typeParams.push(t.get());
|
||||
case TType(t, _):
|
||||
typeParams.push(t.get());
|
||||
default:
|
||||
throw 'Not a class';
|
||||
}
|
||||
}
|
||||
return {entryCls: typeParams[0], jsonCls: typeParams[1]};
|
||||
default:
|
||||
throw 'Not in the correct format';
|
||||
}
|
||||
}
|
||||
|
||||
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, fields:Array<Field>):Void
|
||||
{
|
||||
if (!shouldBuildField('instance', fields))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
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()
|
||||
});
|
||||
}
|
||||
|
||||
static function buildGetScriptedClassNamesField(scriptedEntryCls:ClassType, fields:Array<Field>):Void
|
||||
{
|
||||
if (!shouldBuildField('getScriptedClassNames', fields))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var scriptedEntryExpr = Context.parse('${scriptedEntryCls.pack.join('.')}.${scriptedEntryCls.name}', Context.currentPos());
|
||||
|
||||
fields.push(
|
||||
{
|
||||
name: 'getScriptedClassNames',
|
||||
access: [Access.APrivate],
|
||||
kind: FieldType.FFun(
|
||||
{
|
||||
args: [],
|
||||
expr: macro
|
||||
{
|
||||
return ${scriptedEntryExpr}.listScriptClasses();
|
||||
},
|
||||
params: [],
|
||||
ret: (macro :Array<String>)
|
||||
}),
|
||||
pos: Context.currentPos()
|
||||
});
|
||||
}
|
||||
|
||||
static function buildCreateScriptedEntryField(entryCls:ClassType, scriptedEntryCls:ClassType, fields:Array<Field>):Void
|
||||
{
|
||||
if (!shouldBuildField('createScriptedEntry', fields))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var scriptedStrExpr = '${scriptedEntryCls.pack.join('.')}.${scriptedEntryCls.name}.init(clsName, \'unknown\')';
|
||||
var scriptedInitExpr = Context.parse(scriptedStrExpr, Context.currentPos());
|
||||
|
||||
fields.push(
|
||||
{
|
||||
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 buildParseEntryDataField(jsonCls:Dynamic, fields:Array<Field>):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<Field>):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<String>),
|
||||
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
|
||||
}
|
||||
|
||||
#if macro
|
||||
typedef RegistryTypeParams =
|
||||
{
|
||||
var entryCls:ClassType;
|
||||
var jsonCls:Dynamic; // DefType or ClassType
|
||||
}
|
||||
#end
|
Loading…
Reference in a new issue