From f8d1cf08ad9f6cdda4e971a3d8adff6fce5130d2 Mon Sep 17 00:00:00 2001 From: Ne_Eo Date: Sun, 1 Sep 2024 02:31:51 +0200 Subject: [PATCH] Added runtime feature flags --- .../funkin/backend/scripting/EventManager.hx | 5 +- source/funkin/backend/system/Flags.hx | 73 ++++++++++ source/funkin/backend/system/MainState.hx | 5 + .../system/framerate/CodenameBuildField.hx | 7 +- .../backend/system/framerate/Framerate.hx | 10 ++ .../system/framerate/FramerateCategory.hx | 2 + .../system/framerate/FramerateCounter.hx | 2 + .../backend/system/framerate/MemoryCounter.hx | 2 + .../backend/system/macros/FlagMacro.macro.hx | 125 ++++++++++++++++++ source/funkin/backend/utils/IniUtil.hx | 2 +- 10 files changed, 229 insertions(+), 4 deletions(-) create mode 100644 source/funkin/backend/system/Flags.hx create mode 100644 source/funkin/backend/system/macros/FlagMacro.macro.hx diff --git a/source/funkin/backend/scripting/EventManager.hx b/source/funkin/backend/scripting/EventManager.hx index 84e7d33f..ab47bb5d 100644 --- a/source/funkin/backend/scripting/EventManager.hx +++ b/source/funkin/backend/scripting/EventManager.hx @@ -14,8 +14,9 @@ class EventManager { var index = eventKeys.indexOf(c); if (index < 0) { eventKeys.push(c); - eventValues.push(Type.createInstance(c, [])); - return cast eventValues.last(); + var ret; + eventValues.push(ret = Type.createInstance(c, [])); + return cast ret; } return cast eventValues[index]; diff --git a/source/funkin/backend/system/Flags.hx b/source/funkin/backend/system/Flags.hx new file mode 100644 index 00000000..2311ed1f --- /dev/null +++ b/source/funkin/backend/system/Flags.hx @@ -0,0 +1,73 @@ +package funkin.backend.system; + +import lime.utils.AssetLibrary; +import lime.utils.AssetType; + +import funkin.backend.assets.IModsAssetLibrary; +import funkin.backend.assets.ScriptedAssetLibrary; + +@:build(funkin.backend.system.macros.FlagMacro.build()) +class Flags { + public static var FPS_BUILD_TEXT:String = "Commit ${build} (${commit})"; + + @:bypass public static var customFlags:Map = []; + + public static function load() { + var flags:Map = []; + + final flagsPath = Paths.getPath("flags.ini"); + + for(lib in Paths.assetsTree.libraries) { + if(lib.exists(flagsPath, AssetType.TEXT)) { + var data:String = lib.getAsset(flagsPath, AssetType.TEXT); + var trimmed:String; + var splitContent = [for(e in data.split("\n")) if ((trimmed = e.trim()) != "") trimmed]; + + for(line in splitContent) { + if (line.startsWith(";")) continue; + if (line.startsWith("#")) continue; + if (line.startsWith("//")) continue; + if(line.length == 0) continue; + if(line.charAt(0) == "[" && line.charAt(line.length-1) == "]") continue; + + var index = line.indexOf("="); + if(index == -1) continue; + var name = line.substr(0, index).trim(); + var value = line.substr(index+1).trim(); + + if (value.length > 1 && value.charCodeAt(0) == '"'.code && value.charCodeAt(value.length-1) == '"'.code) + value = value.substr(1, value.length - 2); + + if (value.length == 0 || name.length == 0) + continue; + + if(!flags.exists(name)) + flags[name] = value; + } + } + } + + customFlags = []; + reset(); + for(name=>value in flags) + if(!parse(name, value)) { + customFlags.set(name, value); + } + } + + public static function getCleanLibraryName(e:AssetLibrary) { + var l = e; + if (l is openfl.utils.AssetLibrary) { + var al = cast(l, openfl.utils.AssetLibrary); + @:privateAccess + if (al.__proxy != null) l = al.__proxy; + } + + if (l is ScriptedAssetLibrary) + return '${cast(l, ScriptedAssetLibrary).scriptName} (${cast(l, ScriptedAssetLibrary).modName})'; + else if (l is IModsAssetLibrary) + return '${cast(l, IModsAssetLibrary).modName}'; + else + return Std.string(e); + } +} \ No newline at end of file diff --git a/source/funkin/backend/system/MainState.hx b/source/funkin/backend/system/MainState.hx index adc5ae00..0869fc45 100644 --- a/source/funkin/backend/system/MainState.hx +++ b/source/funkin/backend/system/MainState.hx @@ -8,6 +8,7 @@ import funkin.backend.assets.ModsFolder; import funkin.backend.chart.EventsData; import funkin.menus.BetaWarningState; import funkin.menus.TitleState; +import funkin.backend.system.framerate.Framerate; /** * Simple state used for loading the game @@ -55,10 +56,14 @@ class MainState extends FlxState { Main.refreshAssets(); ModsFolder.onModSwitch.dispatch(ModsFolder.currentModFolder); + Flags.load(); DiscordUtil.init(); EventsData.reloadEvents(); TitleState.initialized = false; + if(Framerate.isLoaded) + Framerate.instance.reload(); + if (betaWarningShown) FlxG.switchState(new TitleState()); else { diff --git a/source/funkin/backend/system/framerate/CodenameBuildField.hx b/source/funkin/backend/system/framerate/CodenameBuildField.hx index 3175a01e..092fc736 100644 --- a/source/funkin/backend/system/framerate/CodenameBuildField.hx +++ b/source/funkin/backend/system/framerate/CodenameBuildField.hx @@ -9,6 +9,11 @@ class CodenameBuildField extends TextField { defaultTextFormat = Framerate.textFormat; autoSize = LEFT; multiline = wordWrap = false; - text = 'Codename Engine ${Main.releaseCycle}\nCommit ${GitCommitMacro.commitNumber} (${GitCommitMacro.commitHash})'; + reload(); + } + + public function reload() { + var buildText = Flags.FPS_BUILD_TEXT.replace("${build}", Std.string(GitCommitMacro.commitNumber)).replace("${commit}", GitCommitMacro.commitHash); + text = 'Codename Engine ${Main.releaseCycle}\n' + buildText; } } diff --git a/source/funkin/backend/system/framerate/Framerate.hx b/source/funkin/backend/system/framerate/Framerate.hx index 8faa09ee..c321b1db 100644 --- a/source/funkin/backend/system/framerate/Framerate.hx +++ b/source/funkin/backend/system/framerate/Framerate.hx @@ -82,6 +82,16 @@ class Framerate extends Sprite { #end } + public function reload() { + for(c in categories) + c.reload(); + #if SHOW_BUILD_ON_FPS + codenameBuildField.reload(); + #end + memoryCounter.reload(); + fpsCounter.reload(); + } + private function __addCategory(category:FramerateCategory) { categories.push(category); __addToList(category); diff --git a/source/funkin/backend/system/framerate/FramerateCategory.hx b/source/funkin/backend/system/framerate/FramerateCategory.hx index f1125eb4..a862505c 100644 --- a/source/funkin/backend/system/framerate/FramerateCategory.hx +++ b/source/funkin/backend/system/framerate/FramerateCategory.hx @@ -39,6 +39,8 @@ class FramerateCategory extends Sprite { this.text.y = this.title.y + this.title.height + 2; } + public function reload() {} + public override function __enterFrame(t:Int) { if (alpha <= 0.05) return; super.__enterFrame(t); diff --git a/source/funkin/backend/system/framerate/FramerateCounter.hx b/source/funkin/backend/system/framerate/FramerateCounter.hx index e07a2e02..5658bd2b 100644 --- a/source/funkin/backend/system/framerate/FramerateCounter.hx +++ b/source/funkin/backend/system/framerate/FramerateCounter.hx @@ -37,6 +37,8 @@ class FramerateCounter extends Sprite { } } + public function reload() {} + public override function __enterFrame(t:Int) { if (alpha <= 0.05) return; super.__enterFrame(t); diff --git a/source/funkin/backend/system/framerate/MemoryCounter.hx b/source/funkin/backend/system/framerate/MemoryCounter.hx index 33efff59..f38de1d8 100644 --- a/source/funkin/backend/system/framerate/MemoryCounter.hx +++ b/source/funkin/backend/system/framerate/MemoryCounter.hx @@ -29,6 +29,8 @@ class MemoryCounter extends Sprite { memoryPeakText.alpha = 0.5; } + public function reload() {} + public override function __enterFrame(t:Int) { if (alpha <= 0.05) return; super.__enterFrame(t); diff --git a/source/funkin/backend/system/macros/FlagMacro.macro.hx b/source/funkin/backend/system/macros/FlagMacro.macro.hx new file mode 100644 index 00000000..21ff7acf --- /dev/null +++ b/source/funkin/backend/system/macros/FlagMacro.macro.hx @@ -0,0 +1,125 @@ +package funkin.backend.system.macros; + +import haxe.macro.Context; +import haxe.macro.Expr; + +using StringTools; + +using haxe.macro.Tools; + +class FlagMacro { + public static function build():Array { + var fields = Context.getBuildFields(); + + var clRef = Context.getLocalClass(); + if (clRef == null) + return fields; + + var cl = clRef.get(); + + var resetExprs:Array = []; + var parserExprs:Array = []; + + for (field in fields) { + var skip = false; + for(meta in field.meta) { + if(meta.name == ":bypass") { + skip = true; + break; + } + } + + if(skip) continue; + + switch (field.kind) { + case FVar(type, expr): + if(expr == null) + Context.error('Flags must be initialized', field.pos); + switch(expr.expr) { + case EConst(CIdent("true")) | EConst(CIdent("false")): + type = macro: Bool; + default: + if(type == null) + Context.error('Flags must have a type', field.pos); + } + + var parser:Expr = null; + + switch(type) { + case macro: Array: + field.kind = FVar(macro: Array, macro expr); + parser = macro value.split(",").map((e) -> e.trim()); + case macro: Array: + parser = macro value.split(","); + case macro: Array: + parser = macro value.split(",").map((e) -> { + e = e.trim(); + e == "true" || e == "t" || e == "1"; + }); + case macro: Int: + parser = macro Std.parseInt(value); + case macro: String: + parser = macro value; + case macro: Bool: + parser = macro value == "true" || value == "t" || value == "1"; + + case TPath({name: "Array", pack: []}): + Context.error('Flags cannot be an Array that isnt a String or Bool or TrimmedString', field.pos); + case TPath({name: "Map", pack: []}): + Context.error('Flags cannot be a Map', field.pos); + default: + Context.error("Flags must be either a Bool, Int, String, Array, Array or Array", field.pos); + } + + if(parser == null) { + Context.error("Flags must be either a Bool, Int, String, Array, Array or Array", field.pos); + continue; + } + + resetExprs.push(macro $i{field.name} = ${expr}); + + // parse(name: String, value: String) + parserExprs.push(macro @:mergeBlock { + if(name == $v{field.name}) { + $i{field.name} = $parser; + return true; + } + }); + default: + // nothing + } + } + + fields.push({ + name: "reset", + access: [APublic, AStatic], + kind: FFun({ + args: [], + expr: macro $b{resetExprs}, + ret: macro: Void + }), + pos: Context.currentPos(), + doc: null, + meta: [] + }); + + fields.push({ + name: "parse", + access: [APublic, AStatic], + kind: FFun({ + args: [{name: "name", type: macro: String}, {name: "value", type: macro: String}], + expr: macro { + @:mergeBlock $b{parserExprs}; + + return false; + }, + ret: macro: Bool + }), + pos: Context.currentPos(), + doc: null, + meta: [] + }); + + return fields; + } +} \ No newline at end of file diff --git a/source/funkin/backend/utils/IniUtil.hx b/source/funkin/backend/utils/IniUtil.hx index d7b5738e..e39d0a23 100644 --- a/source/funkin/backend/utils/IniUtil.hx +++ b/source/funkin/backend/utils/IniUtil.hx @@ -26,7 +26,7 @@ class IniUtil { var name = line.substr(0, index).trim(); var value = line.substr(index+1).trim(); - if (value.startsWith("\"") && value.endsWith("\"")) + if (value.length > 1 && value.charCodeAt(0) == '"'.code && value.charCodeAt(value.length-1) == '"'.code) value = value.substr(1, value.length - 2); if (value.length == 0 || name.length == 0)