diff --git a/buildnumber.txt b/buildnumber.txt index 5b2b555c..8fad7c29 100644 --- a/buildnumber.txt +++ b/buildnumber.txt @@ -1 +1 @@ -1340 \ No newline at end of file +1354 \ No newline at end of file diff --git a/source/funkin/menus/FreeplayState.hx b/source/funkin/menus/FreeplayState.hx index 09d2797d..99935d75 100644 --- a/source/funkin/menus/FreeplayState.hx +++ b/source/funkin/menus/FreeplayState.hx @@ -186,7 +186,7 @@ class FreeplayState extends MusicBeatState curDifficulty = FlxMath.wrap(curDifficulty + change, 0, curSong.difficulties.length-1); #if !switch - intendedScore = Highscore.getScore(songs[curSelected].songName, songs[curSelected].difficulties[curDifficulty]).score; + intendedScore = Highscore.getScore(curSong.songName, curSong.difficulties[curDifficulty]).score; #end diff --git a/source/funkin/mods/ModdableAssetsFolder.hx b/source/funkin/mods/ModdableAssetsFolder.hx index 8d593ba3..78c32d71 100644 --- a/source/funkin/mods/ModdableAssetsFolder.hx +++ b/source/funkin/mods/ModdableAssetsFolder.hx @@ -9,14 +9,18 @@ class ModdableAssetsFolder extends ModsFolderLibrary { public var oldLibrary:AssetLibrary; public override function exists(id:String, type:String) { - if (!id.startsWith("assets/")) + if (!id.startsWith("assets/") && !exists('assets/$id', type)) return oldLibrary.exists(id, type); return super.exists(id, type); } public override function getAsset(id:String, type:String) { - if (!id.startsWith("assets/")) + if (!id.startsWith("assets/")) { + var possibleReplacement = getAsset('assets/$id', type); + if (possibleReplacement != null) + return possibleReplacement; return oldLibrary.getAsset(id, type); + } return super.getAsset(id, type); } diff --git a/source/funkin/mods/ModsAssetLibrary.hx b/source/funkin/mods/ModsAssetLibrary.hx index 565d69ae..72dae58f 100644 --- a/source/funkin/mods/ModsAssetLibrary.hx +++ b/source/funkin/mods/ModsAssetLibrary.hx @@ -23,6 +23,8 @@ import sys.FileSystem; using StringTools; interface ModsAssetLibrary { + public var prefix:String; + #if MOD_SUPPORT public var _parsedAsset:String; diff --git a/source/funkin/mods/ModsFolder.hx b/source/funkin/mods/ModsFolder.hx index 7e38c298..9a638a2c 100644 --- a/source/funkin/mods/ModsFolder.hx +++ b/source/funkin/mods/ModsFolder.hx @@ -30,9 +30,9 @@ class ModsFolder { */ public static var currentModFolder:String = null; /** - * Array of all loaded mods' folder names. + * Map all loaded mods' folder libraries. */ - public static var loadedMods:Array = []; + public static var loadedMods:Map = []; /** * Path to the `mods` folder. */ @@ -54,15 +54,11 @@ class ModsFolder { #if MOD_SUPPORT if (mod == null) return null; // may be loading base game - if (FileSystem.exists('${modsPath}$mod.zip')) { - var e = loadLibraryFromZip('mods/$mod'.toLowerCase(), '${modsPath}$mod.zip', force); - loadedMods.push(mod); - return e; - } else { - var e = loadLibraryFromFolder('mods/$mod'.toLowerCase(), '${modsPath}$mod', force); - loadedMods.push(mod); - return e; - } + if (FileSystem.exists('${modsPath}$mod.zip')) + return loadedMods[mod] = loadLibraryFromZip('mods/$mod'.toLowerCase(), '${modsPath}$mod.zip', force); + else + return loadedMods[mod] = loadLibraryFromFolder('mods/$mod'.toLowerCase(), '${modsPath}$mod', force); + #else return null; #end @@ -73,16 +69,17 @@ class ModsFolder { * @param libName */ public static function switchMod(mod:String) { - for(m in loadedMods) - unloadMod(m); - - loadMod(ModsFolder.currentModFolder = mod); + unloadMod(ModsFolder.currentModFolder); + Paths.assetsTree.addLibrary(loadMod(ModsFolder.currentModFolder = mod)); + Main.refreshAssets(); onModSwitch.dispatch(ModsFolder.currentModFolder); FlxG.resetState(); } public static function unloadMod(mod:String) { + if (mod == null) return; + Paths.assetsTree.removeLibrary(loadedMods[mod]); Assets.unloadLibrary('mods/$mod'.toLowerCase()); } @@ -103,64 +100,20 @@ class ModsFolder { return AssetLibrary.fromManifest(assets); } + public static function prepareModLibrary(libName:String, lib:ModsAssetLibrary, force:Bool = false) { + var openLib = prepareLibrary(libName, force); + lib.prefix = 'assets/'; + @:privateAccess + openLib.__proxy = cast(lib, lime.utils.AssetLibrary); + Assets.registerLibrary(libName, openLib); + return openLib; + } + + public static function loadLibraryFromFolder(libName:String, folder:String, force:Bool = false) { + return prepareModLibrary(libName, new ModsFolderLibrary(folder, libName), force); + } + public static function loadLibraryFromZip(libName:String, zipPath:String, force:Bool = false) { - var lib = prepareLibrary(libName, force); - @:privateAccess - lib.__proxy = new ZipFolderLibrary(zipPath, libName); - Assets.registerLibrary(libName, lib); - return lib; - } - - public static function loadLibraryFromFolder(libName:String, folder:String, force:Bool = false, useOldWhenMissing:Bool = false) { - var oldLib = useOldWhenMissing ? Assets.getLibrary(libName) : null; - var lib = prepareLibrary(libName, force); - @:privateAccess - lib.__proxy = useOldWhenMissing ? new ModdableAssetsFolder(folder, libName, oldLib) : new ModsFolderLibrary(folder, libName); - Assets.registerLibrary(libName, lib); - return lib; - } - - /** - * Gets all assets in folders and put them in the `assets` array. - * @param assets Array of assets - * @param rootPath Root path - * @param path Path inside of the rootPath (ex: `root path/path/path2/`) - * @param libraryName Name of the library (ex: `mods/my mod/`) - * @param prefix Prefix for the asset names (ex: `assets/mods/my mod/`) - * @param addRoot Whenever the root should be added to the paths. Defaults to false - */ - public static function getAssetFiles(assets:Array, rootPath:String, path:String, libraryName:String, prefix:String = "", addRoot:Bool = false) { - #if sys - for(f in FileSystem.readDirectory('$rootPath$path')) { - if (FileSystem.isDirectory('$rootPath$path$f')) { - // fuck you git - if (f.toLowerCase() != ".git") - getAssetFiles(assets, rootPath, '$path$f/', libraryName); - } else { - var type = "BINARY"; - var useExt:Bool = true; - switch(Path.extension(f).toLowerCase()) { - case "txt" | "xml" | "json" | "hx" | "hscript" | "hsc" | "lua" | "frag" | "vert": - type = "TEXT"; - case "png": - type = "IMAGE"; - case "ogg": - type = path.toLowerCase().startsWith("music") ? "MUSIC" : "SOUND"; - case "ttf": - type = "FONT"; - useExt = false; - - } - var stat = FileSystem.stat('$rootPath$path$f'); - assets.push({ - type: type, - id: ('assets/$libraryName/$prefix$path${useExt ? f : Path.withoutExtension(f)}').toLowerCase(), // for case sensitive shit & correct linux support - path: (addRoot ? rootPath : '') + '$path$f', - size: stat.size, - edited: stat.mtime.getTime() / 1000 - }); - } - } - #end + return prepareModLibrary(libName, new ZipFolderLibrary(zipPath, libName), force); } } \ No newline at end of file diff --git a/source/funkin/mods/ModsFolderLibrary.hx b/source/funkin/mods/ModsFolderLibrary.hx index e39f8c8b..d483d01d 100644 --- a/source/funkin/mods/ModsFolderLibrary.hx +++ b/source/funkin/mods/ModsFolderLibrary.hx @@ -27,10 +27,12 @@ class ModsFolderLibrary extends AssetLibrary implements ModsAssetLibrary { public var folderPath:String; public var libName:String; public var useImageCache:Bool = true; + public var prefix = 'assets/'; public function new(folderPath:String, libName:String) { this.folderPath = folderPath; this.libName = libName; + this.prefix = 'assets/$libName/'; super(); } @@ -48,10 +50,8 @@ class ModsFolderLibrary extends AssetLibrary implements ModsAssetLibrary { return LimeAssets.cache.audio.get('$libName:$id'); } else { - if (!exists(id, "SOUND")) { - Log.error('ModsAssetLibrary: Audio Buffer at $id does not exist.'); + if (!exists(id, "SOUND")) return null; - } var path = getAssetPath(); editedTimes[id] = FileSystem.stat(path).mtime.getTime(); var e = AudioBuffer.fromFile(path); @@ -64,10 +64,8 @@ class ModsFolderLibrary extends AssetLibrary implements ModsAssetLibrary { if (__isCacheValid(cachedBytes, id, true)) return cachedBytes.get(id); else { - if (!exists(id, "BINARY")) { - Log.error('ModsAssetLibrary: Bytes at $id does not exist.'); + if (!exists(id, "BINARY")) return null; - } var path = getAssetPath(); editedTimes[id] = FileSystem.stat(path).mtime.getTime(); var e = Bytes.fromFile(path); @@ -80,10 +78,8 @@ class ModsFolderLibrary extends AssetLibrary implements ModsAssetLibrary { if (__isCacheValid(LimeAssets.cache.font, id)) return LimeAssets.cache.font.get(id); else { - if (!exists(id, "FONT")) { - Log.error('ModsAssetLibrary: Font at $id does not exist.'); + if (!exists(id, "FONT")) return null; - } var path = getAssetPath(); editedTimes[id] = FileSystem.stat(path).mtime.getTime(); var e = Font.fromFile(path); @@ -95,10 +91,8 @@ class ModsFolderLibrary extends AssetLibrary implements ModsAssetLibrary { if (useImageCache && __isCacheValid(LimeAssets.cache.image, id)) return LimeAssets.cache.image.get('$libName:$id'); else { - if (!exists(id, "IMAGE")) { - Log.error('ModsAssetLibrary: Image at $id does not exist.'); + if (!exists(id, "IMAGE")) return null; - } var path = getAssetPath(); editedTimes[id] = FileSystem.stat(path).mtime.getTime(); @@ -150,7 +144,6 @@ class ModsFolderLibrary extends AssetLibrary implements ModsAssetLibrary { } private function __parseAsset(asset:String):Bool { - var prefix = 'assets/$libName/'; if (!asset.startsWith(prefix)) return false; _parsedAsset = asset.substr(prefix.length); return true; diff --git a/source/funkin/mods/ZipFolderLibrary.hx b/source/funkin/mods/ZipFolderLibrary.hx index 72eaf56c..2c5f3412 100644 --- a/source/funkin/mods/ZipFolderLibrary.hx +++ b/source/funkin/mods/ZipFolderLibrary.hx @@ -29,6 +29,7 @@ class ZipFolderLibrary extends AssetLibrary implements ModsAssetLibrary { public var zipPath:String; public var libName:String; public var useImageCache:Bool = false; + public var prefix = 'assets/'; #if MOD_SUPPORT public var zip:Reader; @@ -38,6 +39,7 @@ class ZipFolderLibrary extends AssetLibrary implements ModsAssetLibrary { public function new(zipPath:String, libName:String) { this.zipPath = zipPath; this.libName = libName; + this.prefix = 'assets/$libName/'; #if MOD_SUPPORT zip = new Reader(File.read(zipPath, true)); @@ -124,7 +126,6 @@ class ZipFolderLibrary extends AssetLibrary implements ModsAssetLibrary { } public function __parseAsset(asset:String):Bool { - var prefix = 'assets/$libName/'; if (!asset.startsWith(prefix)) return false; _parsedAsset = asset.substr(prefix.length).toLowerCase(); return true; diff --git a/source/funkin/system/AssetsLibraryList.hx b/source/funkin/system/AssetsLibraryList.hx new file mode 100644 index 00000000..0b4358b8 --- /dev/null +++ b/source/funkin/system/AssetsLibraryList.hx @@ -0,0 +1,79 @@ +package funkin.system; + +import funkin.mods.ModsAssetLibrary; +import openfl.utils.Assets; +import lime.utils.AssetLibrary; + +class AssetsLibraryList extends AssetLibrary { + public var libraries:Array = []; + public var base:AssetLibrary; + + public function removeLibrary(lib:AssetLibrary) { + if (lib == null) return lib; + libraries.remove(lib); + return lib; + } + public override function exists(id:String, type:String) { + if (!id.startsWith("assets/") && exists('assets/$id', type)) + return true; + for(e in libraries) + if (e.exists(id, type)) + return true; + return false; + } + + public override function getPath(id:String) { + for(e in libraries) { + var path = e.getPath(id); + if (path != null) + return path; + } + return null; + } + + public function getFiles(folder:String):Array { + var content:Array = []; + for(e in libraries) { + var l = e; + + if (l is openfl.utils.AssetLibrary) { + @:privateAccess + l = cast(l, openfl.utils.AssetLibrary).__proxy; + } + + // TODO: do base folder scanning + if (l is ModsAssetLibrary) { + var lib = cast(l, ModsAssetLibrary); + for(e in lib.getFiles(folder)) + content.push(e); + } + } + return content; + } + + public override function getAsset(id:String, type:String) { + if (!id.startsWith("assets/")) { + var ass = getAsset('assets/$id', type); + if (ass != null) + return ass; + } + for(e in libraries) { + var asset = e.getAsset(id, type); + if (asset != null) + return asset; + } + return null; + } + + public function new(?base:AssetLibrary) { + super(); + if (base == null) + base = Assets.getLibrary("default"); + addLibrary(this.base = base); + } + + public function addLibrary(lib:AssetLibrary) { + libraries.insert(0, lib); + return lib; + } +} \ No newline at end of file diff --git a/source/funkin/system/Main.hx b/source/funkin/system/Main.hx index 19aadcf1..e3048d7c 100644 --- a/source/funkin/system/Main.hx +++ b/source/funkin/system/Main.hx @@ -1,5 +1,6 @@ package funkin.system; +import openfl.utils.AssetLibrary; import openfl.utils.AssetCache; import openfl.text.TextFormat; import flixel.system.ui.FlxSoundTray; @@ -111,6 +112,8 @@ class Main extends Sprite public function loadGameSettings() { + Paths.assetsTree = new AssetsLibraryList(); + Logs.init(); // TODO: Mod switching @@ -127,7 +130,9 @@ class Main extends Sprite if (Sys.args().contains("-livereload")) { #if USE_SOURCE_ASSETS trace("Used lime test windows. Switching into source assets."); - ModsFolder.loadLibraryFromFolder('default', './../../../../assets/', true, true); + Paths.assetsTree.addLibrary(ModsFolder.loadLibraryFromFolder('assets', './../../../../assets/', true)); + #else + Assets.registerLibrary('assets', Paths.assetsTree.base); #end var buildNum:Int = Std.parseInt(File.getContent("./../../../../buildnumber.txt")); @@ -135,11 +140,21 @@ class Main extends Sprite File.saveContent("./../../../../buildnumber.txt", Std.string(buildNum)); } else { #if USE_ADAPTED_ASSETS - ModsFolder.loadLibraryFromFolder('default', './assets/', true, true); + Paths.assetsTree.addLibrary(ModsFolder.loadLibraryFromFolder('assets', './assets/', true)); + #else + Assets.registerLibrary('assets', Paths.assetsTree.base); #end } + #else + Assets.registerLibrary('assets', Paths.assetsTree.base); #end + + var lib = new AssetLibrary(); + @:privateAccess + lib.__proxy = Paths.assetsTree; + Assets.registerLibrary('default', lib); + funkin.options.PlayerSettings.init(); FlxG.save.bind('Save'); Options.load(); diff --git a/source/funkin/system/Paths.hx b/source/funkin/system/Paths.hx index b7946d76..3b73b8bd 100644 --- a/source/funkin/system/Paths.hx +++ b/source/funkin/system/Paths.hx @@ -19,19 +19,14 @@ class Paths */ inline public static var SOUND_EXT = #if web "mp3" #else "ogg" #end; + public static var assetsTree:AssetsLibraryList; + public static function getPath(file:String, type:AssetType, library:Null, skipModsVerification:Bool = false) { - if (library != null && library.startsWith("mods/")) { - library = library.toLowerCase(); - } else if (!skipModsVerification && ModsFolder.currentModFolder != null) { - var modPath = getPath(file, type, 'mods/${ModsFolder.currentModFolder}'); - if (OpenFlAssets.exists(modPath)) return modPath; - } - if (library != null) return getLibraryPath(file, library); - return getAssetsPath(file); + return skipModsVerification ? 'assets:${getAssetsPath(file)}' : getAssetsPath(file); } static public function video(key:String) { @@ -188,13 +183,20 @@ class Paths static public function getFolderContent(key:String, includeSource:Bool = true, addPath:Bool = false, scanSource:Bool = false):Array { // designed to work both on windows and web - + if (!key.endsWith("/")) key += "/"; + var content = assetsTree.getFiles('assets/$key'); + if (addPath) { + for(k=>e in content) + content[k] = '$key$e'; + } + return content; + /* if (!key.endsWith("/")) key = key + "/"; if (ModsFolder.currentModFolder == null && !scanSource) return getFolderContent(key, false, addPath, true); - var folderPath:String = scanSource ? getPreloadPath(key) : getLibraryPathForce(key, 'mods/${ModsFolder.currentModFolder}'); + var folderPath:String = scanSource ? getAssetsPath(key) : getLibraryPathForce(key, 'mods/${ModsFolder.currentModFolder}'); var libThing = new LimeLibrarySymbol(folderPath); var library = libThing.library; @@ -239,5 +241,6 @@ class Paths } return content; + */ } }