Merge branch 'main' into raltyro-audio-rewrite
# Conflicts: # source/funkin/backend/utils/CoolUtil.hx
This commit is contained in:
@@ -1,9 +1,11 @@
|
||||
package funkin.backend.system;
|
||||
|
||||
import flixel.util.FlxColor;
|
||||
import funkin.backend.assets.ModsFolder;
|
||||
import funkin.backend.assets.IModsAssetLibrary;
|
||||
import funkin.backend.assets.ScriptedAssetLibrary;
|
||||
import funkin.backend.system.macros.GitCommitMacro;
|
||||
import funkin.backend.utils.IniUtil;
|
||||
import lime.app.Application;
|
||||
import lime.utils.AssetLibrary as LimeAssetLibrary;
|
||||
import lime.utils.AssetType;
|
||||
@@ -13,7 +15,26 @@ import lime.utils.AssetType;
|
||||
*/
|
||||
@:build(funkin.backend.system.macros.FlagMacro.build())
|
||||
class Flags {
|
||||
// -- Codename's Addon Config --
|
||||
@:bypass public static var addonFlags:Map<String, Dynamic> = [];
|
||||
|
||||
// -- Codename's Mod Config --
|
||||
public static var MOD_NAME:String = "";
|
||||
public static var MOD_DESCRIPTION:String = "";
|
||||
public static var MOD_API_VERSION:Int = 1;
|
||||
public static var MOD_DOWNLOAD_LINK:String = "";
|
||||
public static var MOD_DEPENDENCIES:Array<String> = [];
|
||||
|
||||
public static var MOD_ICON64:String = "";
|
||||
public static var MOD_ICON32:String = "";
|
||||
public static var MOD_ICON16:String = "";
|
||||
public static var MOD_ICON:String = "";
|
||||
|
||||
public static var MOD_DISCORD_CLIENT_ID:String = "";
|
||||
public static var MOD_DISCORD_LOGO_KEY:String = "";
|
||||
public static var MOD_DISCORD_LOGO_TEXT:String = "";
|
||||
// -- Codename's Default Flags --
|
||||
public static var CURRENT_API_VERSION:Int = 1;
|
||||
public static var COMMIT_NUMBER:Int = GitCommitMacro.commitNumber;
|
||||
public static var COMMIT_HASH:String = GitCommitMacro.commitHash;
|
||||
public static var COMMIT_MESSAGE:String = 'Commit $COMMIT_NUMBER ($COMMIT_HASH)';
|
||||
@@ -159,29 +180,9 @@ class Flags {
|
||||
@:bypass public static var customFlags:Map<String, String> = [];
|
||||
|
||||
public static function loadFromData(flags:Map<String, String>, data:String) {
|
||||
var trimmed:String;
|
||||
var splitContent = [for(e in data.split("\n")) if ((trimmed = e.trim()) != "") trimmed];
|
||||
var res = IniUtil.parseString(data);
|
||||
|
||||
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();
|
||||
|
||||
var wasQuoted = value.length > 1 && value.charCodeAt(0) == '"'.code && value.charCodeAt(value.length-1) == '"'.code;
|
||||
if(wasQuoted) value = value.substr(1, value.length - 2);
|
||||
if((!wasQuoted && value.length == 0) || name.length == 0)
|
||||
continue;
|
||||
|
||||
if(!flags.exists(name))
|
||||
flags[name] = value;
|
||||
}
|
||||
for (section in res) for (key => value in section) flags[key] = value;
|
||||
}
|
||||
|
||||
public static function loadFromDatas(datas:Array<String>) {
|
||||
@@ -205,16 +206,42 @@ class Flags {
|
||||
* Loads the flags from the assets.
|
||||
**/
|
||||
public static function load(?libs:Array<LimeAssetLibrary> = null) {
|
||||
if (libs == null)
|
||||
libs = Paths.assetsTree.libraries;
|
||||
final flagsPath = Paths.getPath("flags.ini");
|
||||
var datas:Array<String> = [
|
||||
for(lib in libs)
|
||||
if(lib.exists(flagsPath, AssetType.TEXT))
|
||||
lib.getAsset(flagsPath, AssetType.TEXT)
|
||||
];
|
||||
if (libs == null) {
|
||||
libs = Paths.assetsTree.libraries.copy();
|
||||
libs.reverse();
|
||||
}
|
||||
for(lib in libs) {
|
||||
var l = lib;
|
||||
if (l is openfl.utils.AssetLibrary) {
|
||||
@:privateAccess
|
||||
l = cast(l, openfl.utils.AssetLibrary).__proxy;
|
||||
}
|
||||
|
||||
var flags:Map<String, String> = loadFromDatas(datas);
|
||||
parseFlags(flags);
|
||||
if (l is IModsAssetLibrary) {
|
||||
var flagsTxt = "";
|
||||
if (l.exists(Paths.ini("config/modpack"), AssetType.TEXT))
|
||||
flagsTxt = l.getAsset(Paths.ini("config/modpack"), AssetType.TEXT);
|
||||
if (cast(l, IModsAssetLibrary).modName == "assets") continue;
|
||||
|
||||
if (cast(l, IModsAssetLibrary).modName == ModsFolder.currentModFolder) {
|
||||
var flags:Map<String, String> = [];
|
||||
loadFromData(flags, flagsTxt);
|
||||
parseFlags(flags);
|
||||
}
|
||||
else {
|
||||
var flags:Map<String, String> = [];
|
||||
loadFromData(flags, flagsTxt);
|
||||
addonFlags.set(cast(l, IModsAssetLibrary).modName.toLowerCase().replace(" ", "").trim(), flags);
|
||||
}
|
||||
}
|
||||
else {
|
||||
var flagsTxt = "";
|
||||
if (l.exists(Paths.getPath("data/config/flags.ini"), AssetType.TEXT))
|
||||
flagsTxt = l.getAsset(Paths.getPath("data/config/flags.ini"), AssetType.TEXT);
|
||||
var flags:Map<String, String> = [];
|
||||
loadFromData(flags, flagsTxt);
|
||||
parseFlags(flags);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,8 +5,10 @@ import sys.FileSystem;
|
||||
#end
|
||||
import flixel.FlxState;
|
||||
import funkin.backend.assets.ModsFolder;
|
||||
import funkin.backend.assets.ModsFolderLibrary;
|
||||
import funkin.backend.chart.EventsData;
|
||||
import funkin.backend.system.framerate.Framerate;
|
||||
import funkin.editors.ModConfigWarning;
|
||||
import funkin.menus.TitleState;
|
||||
import haxe.io.Path;
|
||||
|
||||
@@ -112,10 +114,23 @@ class MainState extends FlxState {
|
||||
if (Framerate.isLoaded)
|
||||
Framerate.instance.reload();
|
||||
|
||||
FlxG.switchState(new TitleState());
|
||||
|
||||
#if sys
|
||||
CoolUtil.safeAddAttributes('./.temp/', NativeAPI.FileAttribute.HIDDEN);
|
||||
#end
|
||||
|
||||
if (Options.devMode) {
|
||||
var lib:ModsFolderLibrary;
|
||||
for (e in Paths.assetsTree.libraries) {
|
||||
@:privateAccess if (!(e is openfl.utils.AssetLibrary) || !((lib = cast cast(e, openfl.utils.AssetLibrary).__proxy) is ModsFolderLibrary)) continue;
|
||||
if (lib.modName == ModsFolder.currentModFolder) {
|
||||
if (lib.exists(Paths.ini("config/modpack"), lime.utils.AssetType.TEXT)) break;
|
||||
|
||||
FlxG.switchState(new ModConfigWarning(lib));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FlxG.switchState(new TitleState());
|
||||
}
|
||||
}
|
||||
@@ -422,33 +422,24 @@ class CoolUtil
|
||||
FlxG.sound.music.persist = Persist;
|
||||
FlxG.sound.defaultMusicGroup.add(FlxG.sound.music);
|
||||
|
||||
var infoPath = '${Path.withoutExtension(path)}.ini';
|
||||
if (Assets.exists(infoPath)) {
|
||||
var musicInfo = IniUtil.parseAsset(infoPath, [
|
||||
"BPM" => null,
|
||||
"TimeSignature" => Flags.DEFAULT_BEATS_PER_MEASURE + "/" + Flags.DEFAULT_STEPS_PER_BEAT,
|
||||
"LoopTime" => '${Flags.DEFAULT_LOOP_TIME}',
|
||||
"EndTime" => null,
|
||||
"Offset" => '0'
|
||||
]);
|
||||
var iniPath = '${Path.withoutExtension(path)}.ini';
|
||||
var musicData = Assets.exists(iniPath) ? IniUtil.parseAsset(iniPath)["Global"] : null;
|
||||
if (musicData != null) {
|
||||
if (musicData["LoopTime"] != null) FlxG.sound.music.loopTime = Std.parseFloat(musicData["LoopTime"]) * 1000;
|
||||
if (musicData["EndTime"] != null) FlxG.sound.music.endTime = Std.parseFloat(musicData["EndTime"]) * 1000;
|
||||
if (musicData["Offset"] != null) FlxG.sound.music.endTime = Std.parseFloat(musicData["Offset"]) * 1000;
|
||||
|
||||
FlxG.sound.music.loopTime = Std.parseFloat(musicInfo["LoopTime"]) * 1000;
|
||||
if (musicInfo["EndTime"] != null) FlxG.sound.music.endTime = Std.parseFloat(musicInfo["EndTime"]) * 1000;
|
||||
FlxG.sound.music.offset = Std.parseFloat(musicInfo["Offset"]) * 1000;
|
||||
|
||||
var timeSignParsed:Array<Null<Float>> = musicInfo["TimeSignature"] == null ? [] : [for(s in musicInfo["TimeSignature"].split("/")) Std.parseFloat(s)];
|
||||
var beatsPerMeasure:Float = Flags.DEFAULT_BEATS_PER_MEASURE;
|
||||
var stepsPerBeat:Int = Flags.DEFAULT_STEPS_PER_BEAT;
|
||||
|
||||
// Check later, i don't think timeSignParsed can contain null, only nan
|
||||
if (timeSignParsed.length == 2 && !timeSignParsed.contains(null)) {
|
||||
beatsPerMeasure = timeSignParsed[0] == null || timeSignParsed[0] <= 0 ? Flags.DEFAULT_BEATS_PER_MEASURE : cast timeSignParsed[0];
|
||||
stepsPerBeat = timeSignParsed[1] == null || timeSignParsed[1] <= 0 ? Flags.DEFAULT_STEPS_PER_BEAT : cast timeSignParsed[1];
|
||||
var timeSignParsed:Array<Null<Float>> = musicData["TimeSignature"] == null ? [] : [for(s in musicData["TimeSignature"].split("/")) Std.parseFloat(s)];
|
||||
var beatsPerMeasure:Float = Flags.DEFAULT_BEATS_PER_MEASURE, stepsPerBeat:Float = Flags.DEFAULT_STEPS_PER_BEAT;
|
||||
if (timeSignParsed.length == 2) {
|
||||
beatsPerMeasure = Math.isNaN(timeSignParsed[0]) ? Flags.DEFAULT_BEATS_PER_MEASURE : timeSignParsed[0];
|
||||
stepsPerBeat = Math.isNaN(timeSignParsed[1]) ? Flags.DEFAULT_STEPS_PER_BEAT : (16 / timeSignParsed[1]); // from denominator
|
||||
}
|
||||
|
||||
var bpm:Null<Float> = Std.parseFloat(musicInfo["BPM"]).getDefault(DefaultBPM);
|
||||
Conductor.changeBPM(bpm, beatsPerMeasure, stepsPerBeat);
|
||||
} else
|
||||
var bpm:Float = Std.parseFloat(musicData["BPM"]).getDefault(DefaultBPM);
|
||||
Conductor.changeBPM(bpm, beatsPerMeasure, Math.floor(stepsPerBeat));
|
||||
}
|
||||
else
|
||||
Conductor.changeBPM(DefaultBPM);
|
||||
|
||||
FlxG.sound.music.play();
|
||||
|
||||
@@ -89,6 +89,10 @@ class DiscordUtil
|
||||
config.logoKey = config.logoKey.getDefault(Flags.DEFAULT_DISCORD_LOGO_KEY);
|
||||
config.logoText = config.logoText.getDefault(Flags.DEFAULT_DISCORD_LOGO_TEXT);
|
||||
config.clientID = config.clientID.getDefault(Flags.DEFAULT_DISCORD_CLIENT_ID);
|
||||
|
||||
if (Flags.MOD_DISCORD_CLIENT_ID.length > 0) config.clientID = Flags.MOD_DISCORD_CLIENT_ID;
|
||||
if (Flags.MOD_DISCORD_LOGO_KEY.length > 0) config.logoKey = Flags.MOD_DISCORD_LOGO_KEY;
|
||||
if (Flags.MOD_DISCORD_LOGO_TEXT.length > 0) config.logoText = Flags.MOD_DISCORD_LOGO_TEXT;
|
||||
currentID = config.clientID;
|
||||
#end
|
||||
}
|
||||
|
||||
@@ -1,39 +1,33 @@
|
||||
package funkin.backend.utils;
|
||||
|
||||
/**
|
||||
* DOESN'T SUPPORT CATEGORIES YET!!
|
||||
*/
|
||||
class IniUtil {
|
||||
public static inline function parseAsset(assetPath:String, ?defaultVariables:Map<String, String>)
|
||||
return parseString(Assets.getText(assetPath), defaultVariables);
|
||||
public static inline function parseAsset(assetPath:String)
|
||||
return parseString(Assets.getText(assetPath));
|
||||
|
||||
public static function parseString(data:String, ?defaultVariables:Map<String, String>) {
|
||||
var trimmed:String;
|
||||
var splitContent = [for(e in data.split("\n")) if ((trimmed = e.trim()) != "") trimmed];
|
||||
public static function parseString(data:String):Map<String, Map<String, String>> {
|
||||
var res:Map<String, Map<String, String>> = [];
|
||||
parseStringToMap(res, data);
|
||||
return res;
|
||||
}
|
||||
|
||||
var finalMap:Map<String, String> = [];
|
||||
if (defaultVariables != null)
|
||||
for(k=>e in defaultVariables)
|
||||
finalMap[k] = e;
|
||||
public static function parseStringToMap(map:Map<String, Map<String, String>>, data:String) {
|
||||
var section:Map<String, String> = null;
|
||||
|
||||
for(line in splitContent) {
|
||||
// comment
|
||||
if (line.startsWith(";")) continue;
|
||||
// categories; not supported yet
|
||||
if (line.startsWith("[") && line.endsWith("]")) continue;
|
||||
var regexSec = ~/\\[(.+)\\]/g, regexVal = ~/(.+)=(.+)/g, quote = ~/[\\'"](.+)[\\'"]/g, iln = 0;
|
||||
do {
|
||||
var line = data.substring(iln, ((iln = data.indexOf('\n', iln) + 1) == 0 ? data.length : iln - 1));
|
||||
if (regexSec.match(line)) {
|
||||
if ((section = map.get(regexSec.matched(1))) == null) map.set(regexSec.matched(1), section = []);
|
||||
}
|
||||
else if (regexVal.match(line)) {
|
||||
var s = regexVal.matched(2).trim();
|
||||
if (quote.match(s)) s = quote.matched(1);
|
||||
|
||||
var index = line.indexOf("=");
|
||||
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;
|
||||
|
||||
finalMap[name] = value;
|
||||
}
|
||||
return finalMap;
|
||||
if (section == null) {
|
||||
if ((section = map.get("Global")) == null) map.set("Global", section = []);
|
||||
}
|
||||
section.set(regexVal.matched(1).trim(), s);
|
||||
}
|
||||
} while (iln != 0);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
package funkin.editors;
|
||||
|
||||
import funkin.backend.assets.ModsFolderLibrary;
|
||||
import flixel.FlxState;
|
||||
|
||||
class ModConfigWarning extends UIState {
|
||||
public static var hadPopup:Bool = false;
|
||||
|
||||
var library:ModsFolderLibrary = null;
|
||||
var goToState:Class<FlxState>;
|
||||
|
||||
public static inline var defaultModConfigText =
|
||||
'[Common]
|
||||
MOD_NAME="YOUR MOD NAME HERE"
|
||||
MOD_DESCRIPTION="YOUR MOD DESCRIPTION HERE"
|
||||
|
||||
# DO NOT EDIT!! this is used to check for version compatibility!
|
||||
MOD_API_VERSION=1
|
||||
|
||||
MOD_DOWNLOAD_LINK="YOUR MOD PAGE LINK HERE"
|
||||
|
||||
# Not supported yet
|
||||
;MOD_ICON64="path/to/icon64.png"
|
||||
;MOD_ICON32="path/to/icon32.png"
|
||||
;MOD_ICON16="path/to/icon16.png"
|
||||
;MOD_ICON="path/to/icon.ico"
|
||||
|
||||
[Flags]
|
||||
DISABLE_BETA_WARNING_SCREEN=true
|
||||
|
||||
[Discord]
|
||||
MOD_DISCORD_CLIENT_ID=""
|
||||
MOD_DISCORD_LOGO_KEY=""
|
||||
MOD_DISCORD_LOGO_TEXT=""';
|
||||
|
||||
public function new(library:ModsFolderLibrary, ?goToState:Class<FlxState>) {
|
||||
super();
|
||||
this.library = library;
|
||||
this.goToState = goToState != null ? goToState : funkin.menus.TitleState;
|
||||
}
|
||||
|
||||
override function createPost() {
|
||||
super.createPost();
|
||||
hadPopup = true;
|
||||
|
||||
var substate = new UIWarningSubstate("Missing mod folder configuration!", "Your mod is currently missing a mod config file!\n\n\nWould you like to automatically generate one?\n\n(PS: If this is not your mod please disable Developer mode to stop this popup from appearing.)", [
|
||||
{
|
||||
label: "Not Now",
|
||||
color: 0x969533,
|
||||
onClick: function (_) {
|
||||
MusicBeatState.skipTransOut = MusicBeatState.skipTransIn = false;
|
||||
FlxG.switchState(cast Type.createInstance(goToState, []));
|
||||
}
|
||||
},
|
||||
{
|
||||
label: "Yes",
|
||||
onClick: function(_) {
|
||||
var path = '${library.folderPath}/data/config/modpack.ini';
|
||||
CoolUtil.safeSaveFile(path, defaultModConfigText);
|
||||
openSubState(new UIWarningSubstate("Created mod config!", "Your mod config file has been created at " + path + "!", [
|
||||
{
|
||||
label: "Ok",
|
||||
onClick: function (_) {
|
||||
MusicBeatState.skipTransOut = MusicBeatState.skipTransIn = false;
|
||||
FlxG.switchState(cast Type.createInstance(goToState, []));
|
||||
}
|
||||
},
|
||||
], false));
|
||||
}
|
||||
}
|
||||
], false);
|
||||
substate.bHeight = 300;
|
||||
openSubState(substate);
|
||||
}
|
||||
}
|
||||
@@ -361,8 +361,19 @@ class CharacterEditor extends UIState {
|
||||
if (charXML.exists("flipX") && !character.flipX) charXML.remove("flipX");
|
||||
if (charXML.exists("scale") && character.scale.x == 1) charXML.remove("scale");
|
||||
if (charXML.exists("antialiasing") && character.antialiasing) charXML.remove("antialiasing");
|
||||
if (charXML.exists("sprite") && character.sprite == character.curCharacter) charXML.remove("sprite");
|
||||
if (charXML.exists("icon") && character.icon == character.curCharacter) charXML.remove("icon");
|
||||
|
||||
return "<!DOCTYPE codename-engine-character>\n" + Printer.print(charXML, true);
|
||||
for (a in charXML.elements())
|
||||
if (a.nodeName == "anim") {
|
||||
if (a.exists("x") && a.get("x") == "0") a.remove("x");
|
||||
if (a.exists("y") && a.get("y") == "0") a.remove("y");
|
||||
if (a.exists("fps") && a.get("fps") == "24") a.remove("fps");
|
||||
if (a.exists("loop") && a.get("loop") == "false") a.remove("loop");
|
||||
}
|
||||
|
||||
var xmlThingYea:String = "<!DOCTYPE codename-engine-character>\n" + Printer.print(charXML, Options.editorPrettyPrint);
|
||||
return Options.editorPrettyPrint ? xmlThingYea : xmlThingYea.replace("\n", "");
|
||||
}
|
||||
|
||||
function _edit_undo(_) {
|
||||
@@ -654,4 +665,4 @@ enum CharacterChange {
|
||||
CDeleteAnim(animID:Int, animData:AnimData);
|
||||
CChangeOffset(name:String, change:FlxPoint);
|
||||
CResetOffsets(oldOffsets:Map<String, FlxPoint>);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,6 +32,8 @@ class UIWarningSubstate extends MusicBeatSubstate {
|
||||
|
||||
var warnCam:FlxCamera;
|
||||
|
||||
public var bHeight:Int = 232;
|
||||
|
||||
public override function onSubstateOpen() {
|
||||
super.onSubstateOpen();
|
||||
parent.persistentUpdate = false;
|
||||
@@ -69,7 +71,7 @@ class UIWarningSubstate extends MusicBeatSubstate {
|
||||
warnCam.zoom = 0.1;
|
||||
FlxG.cameras.add(warnCam, false);
|
||||
|
||||
var spr = new UISliceSprite(0, 0, CoolUtil.maxInt(560, 30 + (170 * buttons.length)), 232, 'editors/ui/${isError ? "normal" : "grayscale"}-popup');
|
||||
var spr = new UISliceSprite(0, 0, CoolUtil.maxInt(560, 30 + (170 * buttons.length)), bHeight, 'editors/ui/${isError ? "normal" : "grayscale"}-popup');
|
||||
spr.x = (FlxG.width - spr.bWidth) / 2;
|
||||
spr.y = (FlxG.height - spr.bHeight) / 2;
|
||||
spr.color = isError ? 0xFFFF0000 : 0xFFFFFF00;
|
||||
|
||||
@@ -29,6 +29,7 @@ class MainMenuState extends MusicBeatState
|
||||
|
||||
override function create()
|
||||
{
|
||||
|
||||
super.create();
|
||||
|
||||
DiscordUtil.call("onMenuLoaded", ["Main Menu"]);
|
||||
|
||||
@@ -128,9 +128,9 @@ class Options
|
||||
// Misc
|
||||
public static var P2_RESET:Array<FlxKey> = [];
|
||||
public static var P2_SWITCHMOD:Array<FlxKey> = [];
|
||||
public static var P2_VOLUME_UP:Array<FlxKey> = [NUMPADPLUS];
|
||||
public static var P2_VOLUME_DOWN:Array<FlxKey> = [NUMPADMINUS];
|
||||
public static var P2_VOLUME_MUTE:Array<FlxKey> = [NUMPADZERO];
|
||||
public static var P2_VOLUME_UP:Array<FlxKey> = [PLUS];
|
||||
public static var P2_VOLUME_DOWN:Array<FlxKey> = [MINUS];
|
||||
public static var P2_VOLUME_MUTE:Array<FlxKey> = [ZERO];
|
||||
|
||||
// Debugs
|
||||
public static var P2_DEV_ACCESS:Array<FlxKey> = [];
|
||||
|
||||
Reference in New Issue
Block a user