diff --git a/assets/data/config/modpack.ini b/assets/data/config/modpack.ini deleted file mode 100644 index 313d86b2..00000000 --- a/assets/data/config/modpack.ini +++ /dev/null @@ -1,25 +0,0 @@ -[Common] -Name="baconeggandcheese" -Description="who gaf" -APIVersion="uhmmmm probs like 2" -DownloadedFrom="https://yourmom.org" -Dependencies=[ - "linkA", - "linkB", - "linkC" -] -Icon64="path/to/icon64.png" -Icon32="path/to/icon32.png" -Icon16="path/to/icon16.png" -Icon="path/to/icon.ico" - -[Flags] -UseNoteRendererV2=false -UseAway3D=false -UseDiscordRPCIntegration=true -UseLocalization=false -UseLegacyFlixelAnimateHitbox=false - -[Discord] -ClientID="1027994136193810442", -LogoKey="icon" \ No newline at end of file diff --git a/source/funkin/backend/system/Flags.hx b/source/funkin/backend/system/Flags.hx index ad824a9b..4f15bb29 100644 --- a/source/funkin/backend/system/Flags.hx +++ b/source/funkin/backend/system/Flags.hx @@ -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,11 +15,14 @@ import lime.utils.AssetType; */ @:build(funkin.backend.system.macros.FlagMacro.build()) class Flags { + // -- Codename's Addon Config -- + @:bypass public static var addonFlags:Map = []; + // -- 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_DOWNLOADED_LINK:String = ""; + public static var MOD_DOWNLOAD_LINK:String = ""; public static var MOD_DEPENDENCIES:Array = []; public static var MOD_ICON64:String = ""; @@ -27,7 +32,9 @@ class Flags { 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)'; @@ -175,29 +182,9 @@ class Flags { @:bypass public static var customFlags:Map = []; public static function loadFromData(flags:Map, 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) { @@ -221,16 +208,42 @@ class Flags { * Loads the flags from the assets. **/ public static function load(?libs:Array = null) { - if (libs == null) - libs = Paths.assetsTree.libraries; - final flagsPath = Paths.getPath("flags.ini"); - var datas:Array = [ - 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 = 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 = []; + loadFromData(flags, flagsTxt); + parseFlags(flags); + } + else { + var flags:Map = []; + 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 = []; + loadFromData(flags, flagsTxt); + parseFlags(flags); + } + } } } \ No newline at end of file diff --git a/source/funkin/backend/system/MainState.hx b/source/funkin/backend/system/MainState.hx index 1b0aea70..d4b5ef4d 100644 --- a/source/funkin/backend/system/MainState.hx +++ b/source/funkin/backend/system/MainState.hx @@ -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; @@ -114,10 +116,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()); } } \ No newline at end of file diff --git a/source/funkin/backend/utils/CoolUtil.hx b/source/funkin/backend/utils/CoolUtil.hx index 1a7ae0b2..8f083956 100644 --- a/source/funkin/backend/utils/CoolUtil.hx +++ b/source/funkin/backend/utils/CoolUtil.hx @@ -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> = 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> = 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 = 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); } diff --git a/source/funkin/backend/utils/DiscordUtil.hx b/source/funkin/backend/utils/DiscordUtil.hx index 374768e8..8a7b7658 100644 --- a/source/funkin/backend/utils/DiscordUtil.hx +++ b/source/funkin/backend/utils/DiscordUtil.hx @@ -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 } diff --git a/source/funkin/backend/utils/IniUtil.hx b/source/funkin/backend/utils/IniUtil.hx index ce1cc6e8..22cecee4 100644 --- a/source/funkin/backend/utils/IniUtil.hx +++ b/source/funkin/backend/utils/IniUtil.hx @@ -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) - 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) { - var trimmed:String; - var splitContent = [for(e in data.split("\n")) if ((trimmed = e.trim()) != "") trimmed]; + public static function parseString(data:String):Map> { + var res:Map> = []; + parseStringToMap(res, data); + return res; + } - var finalMap:Map = []; - if (defaultVariables != null) - for(k=>e in defaultVariables) - finalMap[k] = e; + public static function parseStringToMap(map:Map>, data:String) { + var section:Map = 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); } } \ No newline at end of file diff --git a/source/funkin/editors/ModConfigWarning.hx b/source/funkin/editors/ModConfigWarning.hx new file mode 100644 index 00000000..ca1fc34f --- /dev/null +++ b/source/funkin/editors/ModConfigWarning.hx @@ -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; + + 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) { + 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); + } +} \ No newline at end of file diff --git a/source/funkin/editors/ui/UIWarningSubstate.hx b/source/funkin/editors/ui/UIWarningSubstate.hx index 952290fb..4e2fd51e 100644 --- a/source/funkin/editors/ui/UIWarningSubstate.hx +++ b/source/funkin/editors/ui/UIWarningSubstate.hx @@ -22,6 +22,8 @@ class UIWarningSubstate extends MusicBeatSubstate { _; }; + public var bHeight:Int = 232; + var title:String; var message:String; var buttons:Array; @@ -70,7 +72,7 @@ class UIWarningSubstate extends MusicBeatSubstate { 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'); var sprIcon:FlxSprite = new FlxSprite(spr.x + 18, spr.y + 28 + 26).loadGraphic(Paths.image('editors/warnings/${isError ? "error" : "warning"}')); sprIcon.scale.set(1.4, 1.4); diff --git a/source/funkin/menus/MainMenuState.hx b/source/funkin/menus/MainMenuState.hx index 220bf73b..3ae6be83 100644 --- a/source/funkin/menus/MainMenuState.hx +++ b/source/funkin/menus/MainMenuState.hx @@ -29,6 +29,7 @@ class MainMenuState extends MusicBeatState override function create() { + super.create(); DiscordUtil.call("onMenuLoaded", ["Main Menu"]);