Added runtime feature flags
This commit is contained in:
@@ -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];
|
||||
|
||||
@@ -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<String, String> = [];
|
||||
|
||||
public static function load() {
|
||||
var flags:Map<String, String> = [];
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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<Field> {
|
||||
var fields = Context.getBuildFields();
|
||||
|
||||
var clRef = Context.getLocalClass();
|
||||
if (clRef == null)
|
||||
return fields;
|
||||
|
||||
var cl = clRef.get();
|
||||
|
||||
var resetExprs:Array<Expr> = [];
|
||||
var parserExprs:Array<Expr> = [];
|
||||
|
||||
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<TrimmedString>:
|
||||
field.kind = FVar(macro: Array<String>, macro expr);
|
||||
parser = macro value.split(",").map((e) -> e.trim());
|
||||
case macro: Array<String>:
|
||||
parser = macro value.split(",");
|
||||
case macro: Array<Bool>:
|
||||
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<K, V>', field.pos);
|
||||
default:
|
||||
Context.error("Flags must be either a Bool, Int, String, Array<String>, Array<Bool> or Array<TrimmedString>", field.pos);
|
||||
}
|
||||
|
||||
if(parser == null) {
|
||||
Context.error("Flags must be either a Bool, Int, String, Array<String>, Array<Bool> or Array<TrimmedString>", 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;
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user