Merge branch 'main' into new-editors-conductor

# Conflicts:
#	source/funkin/backend/utils/CoolUtil.hx
#	source/funkin/backend/utils/IniUtil.hx
#	source/funkin/editors/character/CharacterEditor.hx
#	source/funkin/editors/ui/UIWarningSubstate.hx
This commit is contained in:
Ralty
2025-07-19 23:51:52 +07:00
9 changed files with 184 additions and 113 deletions
+13 -21
View File
@@ -449,30 +449,22 @@ final class CoolUtil
FlxG.sound.music.persist = Persist;
}
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}'
]);
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;
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 (FlxG.sound.music != null)
FlxG.sound.music.loopTime = Std.parseFloat(musicInfo["LoopTime"]) * 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];
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, floorInt(stepsPerBeat));
} else
var bpm:Float = Std.parseFloat(musicData["BPM"]).getDefault(DefaultBPM);
Conductor.changeBPM(bpm, beatsPerMeasure, Math.floor(stepsPerBeat));
}
else
Conductor.changeBPM(DefaultBPM);
}
@@ -89,6 +89,10 @@ final 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
}
+25 -31
View File
@@ -1,39 +1,33 @@
package funkin.backend.utils;
/**
* DOESN'T SUPPORT CATEGORIES YET!!
*/
final class IniUtil {
public static inline function parseAsset(assetPath:String, ?defaultVariables:Map<String, String>)
return parseString(Assets.getText(assetPath), defaultVariables);
class IniUtil {
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);
}
}