Improved Macros + Libraries (WIP)

Co-Authored-By: ⍚~Nex <87421482+NexIsDumb@users.noreply.github.com>
This commit is contained in:
Ne_Eo
2024-04-09 18:32:57 +02:00
committed by ⍚~Nex
co-authored by ⍚~Nex
parent f9c74c5a2d
commit e068300cf1
18 changed files with 65 additions and 39 deletions
@@ -0,0 +1,7 @@
package funkin.backend.assets;
enum abstract AssetSource(Null<Bool>) from Bool from Null<Bool> to Null<Bool> {
var SOURCE = true;
var MODS = false;
var BOTH = null;
}
@@ -22,10 +22,10 @@ class AssetsLibraryList extends AssetLibrary {
return lib;
}
public function existsSpecific(id:String, type:String, source:AssetSource = BOTH) {
if (!id.startsWith("assets/") && exists('assets/$id', type))
if (!id.startsWith("assets/") && existsSpecific('assets/$id', type, source))
return true;
for(k=>e in libraries) {
if (shouldSkipLib(k, source)) continue;
if (shouldSkipLib(e, source)) continue;
if (e.exists(id, type))
return true;
}
@@ -36,7 +36,7 @@ class AssetsLibraryList extends AssetLibrary {
public function getSpecificPath(id:String, source:AssetSource = BOTH) {
for(k=>e in libraries) {
if (shouldSkipLib(k, source)) continue;
if (shouldSkipLib(e, source)) continue;
@:privateAccess
if (e.exists(id, e.types.get(id))) {
@@ -54,7 +54,7 @@ class AssetsLibraryList extends AssetLibrary {
public function getFiles(folder:String, source:AssetSource = BOTH):Array<String> {
var content:Array<String> = [];
for(k=>e in libraries) {
if (shouldSkipLib(k, source)) continue;
if (shouldSkipLib(e, source)) continue;
var l = e;
@@ -78,7 +78,7 @@ class AssetsLibraryList extends AssetLibrary {
public function getFolders(folder:String, source:AssetSource = BOTH):Array<String> {
var content:Array<String> = [];
for(k=>e in libraries) {
if (shouldSkipLib(k, source)) continue;
if (shouldSkipLib(e, source)) continue;
var l = e;
@@ -108,7 +108,7 @@ class AssetsLibraryList extends AssetLibrary {
}
}
for(k=>e in libraries) {
if (shouldSkipLib(k, source)) continue;
if (shouldSkipLib(e, source)) continue;
@:privateAccess
if (e.exists(id, e.types.get(id))) {
@@ -125,15 +125,9 @@ class AssetsLibraryList extends AssetLibrary {
return null;
}
private function shouldSkipLib(k:Int, source:AssetSource) {
#if TRANSLATIONS_SUPPORT
k -= libraries.indexOf(transLib) + 1;
#end
return switch(source) {
case BOTH: false;
case SOURCE: k < libraries.length - __defaultLibraries.length;
case MODS: k >= libraries.length - __defaultLibraries.length;
};
private function shouldSkipLib(lib:AssetLibrary, source:AssetSource) {
if (source == BOTH || lib.tag == BOTH) return false;
return source != lib.tag;
}
public override inline function getAsset(id:String, type:String):Dynamic
return getSpecificAsset(id, type, BOTH);
@@ -171,10 +165,4 @@ class AssetsLibraryList extends AssetLibrary {
lib.tag = tag;
return lib;
}
}
enum abstract AssetSource(Null<Bool>) from Bool from Null<Bool> to Null<Bool> {
var SOURCE = true;
var MODS = false;
var BOTH = null;
}
+7 -1
View File
@@ -48,8 +48,10 @@ class ModsFolder {
* Initialises `mods` folder.
*/
public static function init() {
if(!getModsList().contains(Options.lastLoadedMod))
if(!getModsList().contains(Options.lastLoadedMod)) {
Options.lastLoadedMod = null;
Logs.trace("Mod not found in mods list, switching to base game!", WARNING, YELLOW);
}
}
/**
@@ -59,6 +61,10 @@ class ModsFolder {
public static function switchMod(mod:String) {
Options.lastLoadedMod = currentModFolder = mod;
reloadMods();
Logs.traceColored([
Logs.logText('Switched to mod ', GRAY),
Logs.logText(mod, GREEN)
], VERBOSE);
}
public static function reloadMods() {
+2 -2
View File
@@ -236,7 +236,7 @@ class Paths
return graph.imageFrame;
}
public static function getFolderDirectories(key:String, addPath:Bool = false, source:AssetsLibraryList.AssetSource = BOTH):Array<String> {
public static function getFolderDirectories(key:String, addPath:Bool = false, source:AssetSource = BOTH):Array<String> {
if (!key.endsWith("/")) key += "/";
var content = assetsTree.getFolders('assets/$key', source);
if (addPath) {
@@ -246,7 +246,7 @@ class Paths
return content;
}
public static function getFolderContent(key:String, addPath:Bool = false, source:AssetsLibraryList.AssetSource = BOTH):Array<String> {
public static function getFolderContent(key:String, addPath:Bool = false, source:AssetSource = BOTH):Array<String> {
// designed to work both on windows and web
if (!key.endsWith("/")) key += "/";
var content = assetsTree.getFiles('assets/$key', source);
@@ -57,6 +57,16 @@ class TranslatedAssetLibrary extends AssetLibrary implements IModsAssetLibrary {
return null;
}
public override function getText(id:String):String
{
for(lib in ModsFolder.getLoadedModsLibs(true)) {
if(!(lib is AssetLibrary)) continue;
var val = cast(lib, AssetLibrary).getText(formatPath(lib.prefix, id));
if(val != null) return val;
}
return null;
}
public override function getFont(id:String):Font
{
for(lib in ModsFolder.getLoadedModsLibs(true)) {
@@ -1,52 +0,0 @@
package funkin.backend.system.macros;
#if macro
import haxe.macro.Context;
import haxe.macro.Expr;
import haxe.macro.Compiler;
using StringTools;
/**
* Macro used to add custom fields to classes without having to override the entire file.
*/
class CustomFieldMacro {
public static function init() {
Compiler.addGlobalMetadata("lime.utils", '@:build(funkin.backend.system.macros.UsingHandler.build("lime.utils.AssetLibrary", "tag", "funkin.backend.assets.AssetSource"))');
}
// TODO: Add support for default values
public static function build(lib:String, fieldName:String, type:String) {
var fields = Context.getBuildFields();
var clRef = Context.getLocalClass();
if (clRef == null) return fields;
var cl = clRef.get();
var key = cl.module;
var fkey = cl.module + "." + cl.name;
if(fkey != lib) {
return fields;
}
var fields = Context.getBuildFields();
fields.push({
name: fieldName,
access: [APublic],
kind: FVar(getTPath(type)),
pos: Context.currentPos()
});
return fields;
}
public static function getTPath(type:String) {
var arr = type.split(".");
return TPath({
pack: arr.slice(0, arr.length - 1),
name: arr[arr.length - 1]
});
}
}
#end
@@ -1,164 +0,0 @@
package funkin.backend.system.macros;
#if macro
import haxe.macro.Expr;
import haxe.macro.*;
using StringTools;
using haxe.macro.PositionTools;
class HashLinkFixer {
public static var buildMacroString = '@:build(funkin.backend.system.macros.HashLinkFixer.build())';
public static var applyOn:Array<String> = [
"lime",
"std",
"Math",
"",
];
public static var modifiedClasses:Array<String> = [];
public static function init() {
#if !display
if(Context.defined("hl")) {
for(apply in applyOn) {
compile(apply);
}
}
#end
}
public static function compile(name:String) {
#if !display
Compiler.addGlobalMetadata(name, buildMacroString);
#end
}
public static function build():Array<Field> {
var fields = Context.getBuildFields();
var clRef = Context.getLocalClass();
if (clRef == null) return fields;
var cl = clRef.get();
if (cl.isAbstract || cl.isExtern || cl.isInterface) return fields;
if (!cl.name.endsWith("_Impl_") && !cl.name.endsWith("_HSX") && !cl.name.endsWith("_HSC") && !cl.name.endsWith("_HLFHelper")) {
var metas = cl.meta.get();
if(cl.params.length > 0)
return fields;
if(cl.module == "EReg") return fields; // private typedef in same class
if(cl.module == "hl.Format") return fields; // enum in same class
var definedFields = [];
var helperClass = macro class {
};
helperClass.pos = cl.pos;
var module = cl.module + "_HLFHelper";
var hcClassName = cl.name + "_HLFHelper";
for(f in fields.copy()) {
if (f == null)
continue;
if (f.name == "new")
continue;
if(definedFields.contains(f.name)) continue; // no duplicate fields
var hasHlNative = false;
for(m in f.meta)
if (m.name == ":hlNative") {
hasHlNative = true;
break;
}
if(!hasHlNative) continue;
switch(f.kind) {
case FFun(fun):
if (fun == null)
continue;
if (fun.params != null && fun.params.length > 0) // TODO: Support for this maybe?
continue;
if(fun.params == null)
fun.params = [];
var overrideExpr:Expr;
var returns:Bool = !fun.ret.match(TPath({name: "Void"}));
var name = 'hlf_${f.name}';
var arguments = fun.args == null ? [] : [for(a in fun.args) macro $i{a.name}];
var funcExpr:Expr = returns ? {
//macro return $i{name}($a{arguments});
macro return @:privateAccess $i{hcClassName}.$name($a{arguments});
} : {
macro @:privateAccess $i{hcClassName}.$name($a{arguments});
};
var fiel:Field = {
name: name,
pos: Context.currentPos(),
kind: FFun({
ret: fun.ret,
params: fun.params.copy(),
expr: fun.expr,
args: fun.args.copy()
}),
access: f.access.copy(),
meta: f.meta.copy()
};
helperClass.fields.push(fiel);
definedFields.push(f.name);
for(m in f.meta.copy())
if (m.name == ":hlNative") {
f.meta.remove(m);
}
fun.expr = funcExpr;
default:
}
}
helperClass.pack = cl.pack.copy();
helperClass.pos = cl.pos;
helperClass.name = hcClassName;
if(definedFields.length > 0) {
trace(cl.module);
/*for(m in metas.copy()) {
trace(" " + m.name);
if(m.name == ":coreApi") {
metas.remove(m);
}
}*/
var imports = Context.getLocalImports().copy();
Context.defineModule(module, [helperClass], imports);
Context.getLocalImports().push({
path: [for(m in module.split(".")) {
name: m,
pos: Context.currentPos()
}],
mode: INormal
});
}
}
return fields;
}
}
#else
class HashLinkFixer {
}
#end
@@ -43,10 +43,6 @@ class Macros {
}
public static function initMacros() {
if(Context.defined("hl"))
HashLinkFixer.init();
CustomFieldsMacro.init();
}
}
#end
@@ -125,7 +125,7 @@ class TranslationUtil
}
if (xml == null) return [];
if (!xml.hasNode.translations) {
FlxG.log.warn("A translation xml file requires a translations root element.");
Logs.trace("A translation xml file requires a translations root element.", WARNING, YELLOW);
return [];
}
+1 -1
View File
@@ -430,7 +430,7 @@ class FreeplaySonglist {
public function new() {}
public function getSongsFromSource(source:funkin.backend.assets.AssetsLibraryList.AssetSource, useTxt:Bool = true) {
public function getSongsFromSource(source:funkin.backend.assets.AssetSource, useTxt:Bool = true) {
var path:String = Paths.txt('freeplaySonglist');
var songsFound:Array<String> = [];
if (useTxt && Paths.assetsTree.existsSpecific(path, "TEXT", source)) {
+1 -1
View File
@@ -297,7 +297,7 @@ class StoryMenuState extends MusicBeatState {
characters[charName] = charObj;
}
public function getWeeksFromSource(weeks:Array<String>, source:funkin.backend.assets.AssetsLibraryList.AssetSource) {
public function getWeeksFromSource(weeks:Array<String>, source:funkin.backend.assets.AssetSource) {
var path:String = Paths.txt('freeplaySonglist');
var weeksFound:Array<String> = [];
if (Paths.assetsTree.existsSpecific(path, "TEXT", source)) {
+1 -1
View File
@@ -20,7 +20,7 @@ class CreditsMain extends TreeMenu {
var selectables:Array<OptionType> = [];
var xmlPath = Paths.xml('config/credits');
for(source in [funkin.backend.assets.AssetsLibraryList.AssetSource.SOURCE, funkin.backend.assets.AssetsLibraryList.AssetSource.MODS]) {
for(source in [funkin.backend.assets.AssetSource.SOURCE, funkin.backend.assets.AssetSource.MODS]) {
if (Paths.assetsTree.existsSpecific(xmlPath, "TEXT", source)) {
var access:Access = null;
try {
+1 -1
View File
@@ -69,7 +69,7 @@ class OptionsMenu extends TreeMenu {
})]);
var xmlPath = Paths.xml("config/options");
for(source in [funkin.backend.assets.AssetsLibraryList.AssetSource.SOURCE, funkin.backend.assets.AssetsLibraryList.AssetSource.MODS]) {
for(source in [funkin.backend.assets.AssetSource.SOURCE, funkin.backend.assets.AssetSource.MODS]) {
if (Paths.assetsTree.existsSpecific(xmlPath, "TEXT", source)) {
var access:Access = null;
try {