diff --git a/source/funkin/backend/assets/AssetsLibraryList.hx b/source/funkin/backend/assets/AssetsLibraryList.hx index ea3cffdc4..0dd532c80 100644 --- a/source/funkin/backend/assets/AssetsLibraryList.hx +++ b/source/funkin/backend/assets/AssetsLibraryList.hx @@ -7,7 +7,15 @@ import funkin.backend.assets.IModsAssetLibrary; import lime.utils.AssetLibrary; class AssetsLibraryList extends AssetLibrary { + public var libraries:Array = []; + + // is true if any library in `libraries` contains some kind of compressed library. + public var hasCompressedLibrary(get, never):Bool; + function get_hasCompressedLibrary():Bool { + for (l in libraries) if (getCleanLibrary(l).isCompressed) return true; + return false; + } @:allow(funkin.backend.system.Main) @:allow(funkin.backend.system.MainState) @@ -141,9 +149,7 @@ class AssetsLibraryList extends AssetLibrary { public override inline function getAsset(id:String, type:String):Dynamic return getSpecificAsset(id, type, BOTH); - public override function isLocal(id:String, type:String) { - return true; - } + public override function isLocal(id:String, type:String) return true; public function new(?base:AssetLibrary) { super(); diff --git a/source/funkin/backend/assets/ModsFolder.hx b/source/funkin/backend/assets/ModsFolder.hx index b59b605cb..328c4836b 100644 --- a/source/funkin/backend/assets/ModsFolder.hx +++ b/source/funkin/backend/assets/ModsFolder.hx @@ -83,10 +83,11 @@ class ModsFolder { */ public static function loadModLib(path:String, force:Bool = false, ?modName:String) { #if MOD_SUPPORT - if (FileSystem.exists('$path.zip')) - return loadLibraryFromZip('$path'.toLowerCase(), '$path.zip', force, modName); - else - return loadLibraryFromFolder('$path'.toLowerCase(), '$path', force, modName); + for (ext in Flags.ALLOWED_ZIP_EXTENSIONS) { + if (!FileSystem.exists('$path.$ext')) continue; + return loadLibraryFromZip('$path'.toLowerCase(), '$path.$ext', force, modName); + } + return loadLibraryFromFolder('$path'.toLowerCase(), '$path', force, modName); #else return null; @@ -96,27 +97,16 @@ class ModsFolder { public static function getModsList():Array { var mods:Array = []; #if MOD_SUPPORT - if (!FileSystem.exists(modsPath)) { - // Mods directory does not exist yet, create it - FileSystem.createDirectory(modsPath); - } + // Mods directory does not exist yet, create it + if (!FileSystem.exists(modsPath)) FileSystem.createDirectory(modsPath); final modsList:Array = FileSystem.readDirectory(modsPath); - if (modsList == null || modsList.length <= 0) - return mods; + if (modsList == null || modsList.length <= 0) return mods; for (modFolder in modsList) { - if (FileSystem.isDirectory(modsPath + modFolder)) { - mods.push(modFolder); - } else { - var ext = Path.extension(modFolder).toLowerCase(); - switch(ext) { - case 'zip': - // is a zip mod!! - mods.push(Path.withoutExtension(modFolder)); - } - } + if (FileSystem.isDirectory(modsPath + modFolder)) mods.push(modFolder); + else if (Flags.ALLOWED_ZIP_EXTENSIONS.contains(Path.extension(modFolder))) mods.push(Path.withoutExtension(modFolder)); } #end return mods; diff --git a/source/funkin/backend/assets/ZipFolderLibrary.hx b/source/funkin/backend/assets/ZipFolderLibrary.hx index 68ef537a5..de519742f 100644 --- a/source/funkin/backend/assets/ZipFolderLibrary.hx +++ b/source/funkin/backend/assets/ZipFolderLibrary.hx @@ -1,11 +1,14 @@ package funkin.backend.assets; +import funkin.backend.system.Flags; + import haxe.io.Path; import lime.graphics.Image; import lime.media.AudioBuffer; import lime.text.Font; import lime.utils.Bytes; import openfl.utils.AssetLibrary; +import sys.io.File; #if MOD_SUPPORT import funkin.backend.utils.SysZip.SysZipEntry; @@ -15,15 +18,16 @@ class ZipFolderLibrary extends AssetLibrary implements IModsAssetLibrary { public var basePath:String; public var modName:String; public var libName:String; - public var useImageCache:Bool = false; + // public var useImageCache:Bool = false; public var prefix = 'assets/'; - + public var zip:SysZip; public var assets:Map = []; public var lowerCaseAssets:Map = []; public var nameMap:Map = []; - public function new(basePath:String, libName:String, ?modName:String) { + public function new(basePath:String, libName:String, ?modName:String, ?preloadVideos:Bool = true) { + CoolUtil.debugTimeStamp(); this.libName = libName; this.basePath = basePath; @@ -31,21 +35,48 @@ class ZipFolderLibrary extends AssetLibrary implements IModsAssetLibrary { this.modName = (modName == null) ? libName : modName; zip = SysZip.openFromFile(basePath); - zip.read(); for(entry in zip.entries) { - lowerCaseAssets[entry.fileName.toLowerCase()] = assets[entry.fileName.toLowerCase()] = assets[entry.fileName] = entry; - nameMap.set(entry.fileName.toLowerCase(), entry.fileName); + var name = entry.fileName.toLowerCase(); + lowerCaseAssets[name] = assets[name] = assets[entry.fileName] = entry; + nameMap.set(name, entry.fileName); } super(); + isCompressed = true; + precacheVideos(); + CoolUtil.debugTimeStamp("ZipFolderLibrary"); + } + + public function precacheVideos() { + videoCacheRemap = []; + for (entry in zip.entries) { + var name = entry.fileName.toLowerCase(); + if (_videoExtensions.contains(Path.extension(name))) getPath(prefix+name); + } + var count = 0; + for (_ in videoCacheRemap.keys()) count++; + trace('Precached $count video${count == 1 ? "" : "s"}'); + } + + // Now we have supports for videos in ZIP!! + public var _videoExtensions:Array = [Flags.VIDEO_EXT]; + public var videoCacheRemap:Map = []; + public function getVideoRemap(originalPath:String):String { + if (!_videoExtensions.contains(Path.extension(_parsedAsset))) return originalPath; + if (videoCacheRemap.exists(originalPath)) return videoCacheRemap.get(originalPath); + + // We adding the length of the string to counteract folder in folder naming duplicates. + var newPath = './.temp/${assets[_parsedAsset].fileName.length}-zipvideo-${_parsedAsset.split("/").pop()}'; + File.saveBytes(newPath, unzip(assets[_parsedAsset])); + videoCacheRemap.set(originalPath, newPath); + return newPath; } function toString():String { - return '(ZipFolderLibrary: $libName/$modName)'; + return '(ZipFolderLibrary: $libName/$modName | ${zip.entries.length} entries | Detected Video Extensions: ${_videoExtensions.join(", ")})'; } public var _parsedAsset:String; - public override function getAudioBuffer(id:String):AudioBuffer { __parseAsset(id); return AudioBuffer.fromBytes(unzip(assets[_parsedAsset])); @@ -68,15 +99,12 @@ class ZipFolderLibrary extends AssetLibrary implements IModsAssetLibrary { return getAssetPath(); } - - - public inline function unzip(f:SysZipEntry) - return f == null ? null : zip.unzipEntry(f); + public inline function unzip(f:SysZipEntry) return (f == null) ? null : zip.unzipEntry(f); public function __parseAsset(asset:String):Bool { if (!asset.startsWith(prefix)) return false; _parsedAsset = asset.substr(prefix.length); - if(ModsFolder.useLibFile) { + if (ModsFolder.useLibFile) { var file = new haxe.io.Path(_parsedAsset); if(file.file.startsWith("LIB_")) { var library = file.file.substr(4); @@ -87,8 +115,7 @@ class ZipFolderLibrary extends AssetLibrary implements IModsAssetLibrary { } _parsedAsset = _parsedAsset.toLowerCase(); - if(nameMap.exists(_parsedAsset)) - _parsedAsset = nameMap.get(_parsedAsset); + if (nameMap.exists(_parsedAsset)) _parsedAsset = nameMap.get(_parsedAsset); return true; } @@ -104,8 +131,7 @@ class ZipFolderLibrary extends AssetLibrary implements IModsAssetLibrary { } private function getAssetPath() { - trace('[ZIP]$basePath/$_parsedAsset'); - return '[ZIP]$basePath/$_parsedAsset'; + return getVideoRemap('$basePath/$_parsedAsset'); } // TODO: rewrite this to 1 function, like ModsFolderLibrary diff --git a/source/funkin/backend/system/Flags.hx b/source/funkin/backend/system/Flags.hx index f57eb7aef..fc4d688e1 100644 --- a/source/funkin/backend/system/Flags.hx +++ b/source/funkin/backend/system/Flags.hx @@ -18,6 +18,9 @@ class Flags { // -- Codename's Addon Config -- @:bypass public static var addonFlags:Map = []; + // -- Codename's ZipFolderLibrary Config -- + public static var ALLOWED_ZIP_EXTENSIONS:Array = ["zip"]; + // -- Codename's Mod Config -- public static var MOD_NAME:String = ""; public static var MOD_DESCRIPTION:String = ""; diff --git a/source/funkin/backend/system/MainState.hx b/source/funkin/backend/system/MainState.hx index 982152d5d..d133d0101 100644 --- a/source/funkin/backend/system/MainState.hx +++ b/source/funkin/backend/system/MainState.hx @@ -57,12 +57,29 @@ class MainState extends FlxState { var _highPriorityAddons:Array = []; var _noPriorityAddons:Array = []; + var quick_modsPath = ModsFolder.modsPath + ModsFolder.currentModFolder; + + var isCneMod = false; + for (ext in Flags.ALLOWED_ZIP_EXTENSIONS) { + if (!FileSystem.exists(quick_modsPath+"/cnemod."+ext)) continue; + isCneMod = true; + break; + } + + // handing if the loading mod, before it's properly loaded, is a compressed mod + // we just need to use `Paths.assetsTree.hasCompressedLibrary` to complete valid checks for actual loaded compressed mods + var isZipMod = false; + for (ext in Flags.ALLOWED_ZIP_EXTENSIONS) { + if (!FileSystem.exists(quick_modsPath+"."+ext)) continue; + isZipMod = true; + break; + } + + // Now here is a conundrum, if it's a compressed mod you can't really uncompress it yet, since it's not loaded as a library, so we need to skip it. var addonPaths = [ ModsFolder.addonsPath, - ( - ModsFolder.currentModFolder != null ? - ModsFolder.modsPath + ModsFolder.currentModFolder + "/addons/" : - null + ( (ModsFolder.currentModFolder != null && !isZipMod) ? + quick_modsPath + "/addons/" : null ) ]; @@ -72,12 +89,8 @@ class MainState extends FlxState { for (addon in FileSystem.readDirectory(path)) { if (!FileSystem.isDirectory(path + addon)) { - switch(Path.extension(addon).toLowerCase()) { - case 'zip': - addon = Path.withoutExtension(addon); - default: - continue; - } + if (Flags.ALLOWED_ZIP_EXTENSIONS.contains(Path.extension(addon).toLowerCase())) addon = Path.withoutExtension(addon); + else continue; } var data:AddonInfo = { @@ -100,9 +113,13 @@ class MainState extends FlxState { #if MOD_SUPPORT for (addon in _lowPriorityAddons) loadLib(addon.path, ltrim(addon.name, "[LOW]")); - - if (ModsFolder.currentModFolder != null) - loadLib(ModsFolder.modsPath + ModsFolder.currentModFolder, ModsFolder.currentModFolder); + + if (ModsFolder.currentModFolder != null) { + if (isCneMod) + loadLib(quick_modsPath + "/cnemod", ModsFolder.currentModFolder); + else + loadLib(quick_modsPath, ModsFolder.currentModFolder); + } for (addon in _noPriorityAddons) loadLib(addon.path, addon.name); @@ -136,7 +153,7 @@ class MainState extends FlxState { var startState:Class = Flags.DISABLE_WARNING_SCREEN ? TitleState : funkin.menus.WarningState; - if (Options.devMode && Options.allowConfigWarning) { + if (Options.devMode && Options.allowConfigWarning && !Paths.assetsTree.hasCompressedLibrary) { // because it's a zip file, you can't edit a zip file without decompiling it var lib:ModsFolderLibrary; for (e in Paths.assetsTree.libraries) if ((lib = cast AssetsLibraryList.getCleanLibrary(e)) is ModsFolderLibrary && lib.modName == ModsFolder.currentModFolder) diff --git a/source/funkin/backend/system/macros/Macros.hx b/source/funkin/backend/system/macros/Macros.hx index f3bf4adb2..983fa9355 100644 --- a/source/funkin/backend/system/macros/Macros.hx +++ b/source/funkin/backend/system/macros/Macros.hx @@ -64,6 +64,7 @@ class Macros { final fields:Array = Context.getBuildFields(), pos:Position = Context.currentPos(); fields.push({name: 'tag', access: [APublic], pos: pos, kind: FVar(macro :funkin.backend.assets.AssetSource)}); + fields.push({name: 'isCompressed', access: [APublic], pos: pos, kind: FVar(macro :Bool, macro false)}); return fields; } diff --git a/source/funkin/backend/utils/CoolUtil.hx b/source/funkin/backend/utils/CoolUtil.hx index d06b416c3..0bdcd5836 100644 --- a/source/funkin/backend/utils/CoolUtil.hx +++ b/source/funkin/backend/utils/CoolUtil.hx @@ -1435,6 +1435,21 @@ final class CoolUtil return toProperty.setValue(fromProperty.getValue()); } + + private static var lastTimeStamp:Float = -1; + public static function debugTimeStamp(?customText:String = "Quick Debug") { + if (lastTimeStamp > 0) { + var endTimeStamp = haxe.Timer.stamp(); + Logs.traceColored([ + Logs.logText("[Haxe Time Stamp] ", YELLOW), + Logs.logText(customText), + Logs.logText(' | Time stamp took ${(endTimeStamp - lastTimeStamp)} milliseconds.'), + ], INFO); + lastTimeStamp = -1; + return; + } + lastTimeStamp = haxe.Timer.stamp(); + } } class PropertyInfo { diff --git a/source/funkin/backend/utils/SysZip.hx b/source/funkin/backend/utils/SysZip.hx index b1c013fbd..25eee0fbe 100644 --- a/source/funkin/backend/utils/SysZip.hx +++ b/source/funkin/backend/utils/SysZip.hx @@ -2,157 +2,120 @@ package funkin.backend.utils; #if sys import haxe.io.Input; -import haxe.zip.Entry; -import haxe.zip.InflateImpl; import haxe.zip.Reader; import sys.io.File; import sys.io.FileInput; +import haxe.io.Bytes; + /** * Class that extends Reader allowing you to load ZIP entries without blowing your RAM up!! - * Half of the code is taken from haxe libraries btw + * ~~Half of the code is taken from haxe libraries btw~~ Reworked by ItsLJcool to actually work for zip files. */ -class SysZip extends Reader { - var input:Input; +class SysZip { var fileInput:FileInput; + var filePath:String; public var entries:List; /** * Opens a zip from a specified path. - * @param path Path to the zip file. + * @param path Path to the zip file. (With the extension) */ - public static function openFromFile(path:String) { - - return new SysZip(File.read(path, true)); - } + public static function openFromFile(path:String) { return new SysZip(path); } // keeping for compatibility. /** - * Creates a new SysZip from a specified file input. - * @param input File input. + * Creates a new SysZip from a specified path. + * @param path Path to the zip file. (With the extension) */ - public function new(input:FileInput) { - super(input); - fileInput = input; - } + public function new(path:String) { + this.filePath = path; + fileInput = File.read(path, true); - /** - * Reads all the data present in a specified entry. - * NOTE: If the entry is compressed, the data won't be decompressed. For decompression, use `unzipEntry`. - * @param e Entry - */ - public function readEntryData(e:SysZipEntry) { - var bytes:haxe.io.Bytes = null; - var buf = null; - var tmp = null; - - fileInput.seek(e.seekPos, SeekBegin); - if (e.crc32 == null) { - if (e.compressed) { - #if neko - // enter progressive mode : we use a different input which has - // a temporary buffer, this is necessary since we have to uncompress - // progressively, and after that we might have pending read data - // that needs to be processed - var bufSize = 65536; - if (buf == null) { - buf = new haxe.io.BufferInput(i, haxe.io.Bytes.alloc(bufSize)); - tmp = haxe.io.Bytes.alloc(bufSize); - i = buf; - } - var out = new haxe.io.BytesBuffer(); - var z = new neko.zip.Uncompress(-15); - z.setFlushMode(neko.zip.Flush.SYNC); - while (true) { - if (buf.available == 0) - buf.refill(); - var p = bufSize - buf.available; - if (p != buf.pos) { - // because of lack of "srcLen" in zip api, we need to always be stuck to the buffer end - buf.buf.blit(p, buf.buf, buf.pos, buf.available); - buf.pos = p; - } - var r = z.execute(buf.buf, buf.pos, tmp, 0); - out.addBytes(tmp, 0, r.write); - buf.pos += r.read; - buf.available -= r.read; - if (r.done) - break; - } - bytes = out.getBytes(); - #else - var bufSize = 65536; - if (tmp == null) - tmp = haxe.io.Bytes.alloc(bufSize); - var out = new haxe.io.BytesBuffer(); - var z = new InflateImpl(i, false, false); - while (true) { - var n = z.readBytes(tmp, 0, bufSize); - out.addBytes(tmp, 0, n); - if (n < bufSize) - break; - } - bytes = out.getBytes(); - #end - } else - bytes = i.read(e.dataSize); - e.crc32 = i.readInt32(); - if (e.crc32 == 0x08074b50) - e.crc32 = i.readInt32(); - e.dataSize = i.readInt32(); - e.fileSize = i.readInt32(); - // set data to uncompressed - e.dataSize = e.fileSize; - e.compressed = false; - } else - bytes = i.read(e.dataSize); - return bytes; + updateEntries(); // automatic but if you feel like you don't want it to be automatic, you can remove this. } /** * Unzips and returns all of the data present in an entry. * @param f Entry to read from. */ - public function unzipEntry(f:SysZipEntry) { - var data = readEntryData(f); + public function unzipEntry(f:SysZipEntry):Bytes { + fileInput.seek(f.seekPos, SeekBegin); + var data = fileInput.read(f.compressedSize); + + if (!f.compressed) return data; - if (!f.compressed) - return data; var c = new haxe.zip.Uncompress(-15); - var s = haxe.io.Bytes.alloc(f.fileSize); + var s = Bytes.alloc(f.fileSize); var r = c.execute(data, 0, s, 0); c.close(); - if (!r.done || r.read != data.length || r.write != f.fileSize) - throw "Invalid compressed data for " + f.fileName; - data = s; - return data; + + if (!r.done || r.read != data.length || r.write != f.fileSize) throw "Invalid compressed data for " + f.fileName; + return s; } - public override function read():List { - if (entries != null) - return entries; + public function updateEntries() { entries = new List(); + + // --- locate End of Central Directory (EOCD) --- + var fileSize:Int = sys.FileSystem.stat(this.filePath).size; // probably need a better way to check the size of the file. + var scanSize:Int = (65535 < fileSize) ? 65535 : fileSize; + + fileInput.seek(fileSize - scanSize, SeekBegin); // It seems this usually ends up being 0 anyways, but for cases where it might not be?? I'd just make sure. but Someone do some digging I don't know if this required. + + var buf = fileInput.read(scanSize); + var b = new haxe.io.BytesInput(buf); + b.position = (buf.length - 22) + 16; // offset to start of central directory + + // --- read central directory --- + fileInput.seek(b.readInt32(), SeekBegin); while (true) { - var e = readEntryHeader(); - if (e == null) - break; + if (fileInput.readInt32() != 0x02014b50) break; // central dir file header signature + + fileInput.seek(6, SeekCur); // version/flags + var compMethod = fileInput.readUInt16(); + fileInput.seek(8, SeekCur); // time/date + CRC32 (4, 4) + var compSize = fileInput.readInt32(); + var uncompSize = fileInput.readInt32(); + var nameLen = fileInput.readUInt16(); + var extraLen = fileInput.readUInt16(); + var commentLen = fileInput.readUInt16(); + fileInput.seek(8, SeekCur); // skip disk number/start attrs + var localHeaderOffset = fileInput.readInt32(); + + var name = fileInput.read(nameLen).toString(); + + // skip central directory extra/comment + fileInput.seek(extraLen + commentLen, SeekCur); + + // --- compute correct seekPos using local header --- + var curPos = fileInput.tell(); + fileInput.seek(localHeaderOffset + 26, SeekBegin); + var localNameLen = fileInput.readUInt16(); + var localExtraLen = fileInput.readUInt16(); + fileInput.seek(curPos, SeekBegin); - var zipEntry:SysZipEntry = cast e; - zipEntry.seekPos = fileInput.tell(); + var zipEntry:SysZipEntry = { + fileName: name, + fileSize: uncompSize, + seekPos: (localHeaderOffset + 30 + localNameLen + localExtraLen), + compressedSize: compSize, + compressed: (compMethod == 8), + }; entries.add(zipEntry); - fileInput.seek(e.dataSize, SeekCur); } - return entries; } public function dispose() { - if (input != null) - input.close(); + if (fileInput != null) fileInput.close(); } } typedef SysZipEntry = { - > Entry, + var fileName:String; + var fileSize:Int; var seekPos:Int; + var compressedSize:Int; + var compressed:Bool; } #end \ No newline at end of file diff --git a/source/funkin/editors/EditorTreeMenu.hx b/source/funkin/editors/EditorTreeMenu.hx index 1a7a0e372..e9bb7ab37 100644 --- a/source/funkin/editors/EditorTreeMenu.hx +++ b/source/funkin/editors/EditorTreeMenu.hx @@ -20,6 +20,8 @@ class EditorTreeMenu extends funkin.options.TreeMenu { bg.antialiasing = true; setBackgroundRotation(-5); super.createPost(); + + if (Paths.assetsTree.hasCompressedLibrary) warnCompressLibrary(); } public inline function setBackgroundRotation(rotation:Float) { @@ -58,6 +60,21 @@ class EditorTreeMenu extends funkin.options.TreeMenu { bg.colorTransform.greenMultiplier = FlxMath.lerp(1, color.greenFloat, 0.25); bg.colorTransform.blueMultiplier = FlxMath.lerp(1, color.blueFloat, 0.25); } + + private function warnCompressLibrary() { + var warningMessage = "It seems you have libraries loaded that are compressed, and can not have files written to them.\n + This is just a friendly reminder that if you're loading a Mod and wish to edit files, you need to uncompress it to be able to use any editors!\n\nCompressed Libraries: "; + var compressedList = Paths.assetsTree.libraries.filter(l -> funkin.backend.assets.AssetsLibraryList.getCleanLibrary(l).isCompressed); + var modNameList = [for (l in compressedList) { + l = funkin.backend.assets.AssetsLibraryList.getCleanLibrary(l); + if (l is funkin.backend.assets.IModsAssetLibrary) cast(l, funkin.backend.assets.IModsAssetLibrary).modName; + }]; + warningMessage += modNameList.join(", "); + var zipLibraryWarning = new funkin.editors.ui.UIWarningSubstate("Compressed Library Detected!", warningMessage, [{label: "Ok", color: 0x969533, onClick: (state) -> {} }], false); + + openSubState(zipLibraryWarning); + } + } class EditorTreeMenuScreen extends funkin.options.TreeMenuScreen { diff --git a/source/funkin/game/cutscenes/VideoCutscene.hx b/source/funkin/game/cutscenes/VideoCutscene.hx index f3e3e2745..283f8e499 100644 --- a/source/funkin/game/cutscenes/VideoCutscene.hx +++ b/source/funkin/game/cutscenes/VideoCutscene.hx @@ -101,14 +101,9 @@ class VideoCutscene extends Cutscene { FlxTween.tween(loadingBackdrop, {alpha: 1}, 0.5, {ease: FlxEase.sineInOut}); Main.execAsync(function() { - if (localPath.startsWith("[ZIP]")) { - // ZIP PATH: EXPORT - // TODO: this but better and more ram friendly - localPath = './.temp/video-${curVideo++}.mp4'; - File.saveBytes(localPath, Assets.getBytes(path)); - } - - if (video.load(localPath)) new FlxTimer().start(0.001, function(_) { mutex.acquire(); onReady(); mutex.release(); }); + if (video.load(localPath)) new FlxTimer().start(0.001, function(_) { + mutex.acquire(); onReady(); mutex.release(); + }); else { mutex.acquire(); close(); mutex.release(); } }); @@ -180,6 +175,7 @@ class VideoCutscene extends Cutscene { } public inline function onReady() { + trace("VideoCutscene: Ready"); FlxTween.cancelTweensOf(loadingBackdrop); FlxTween.tween(loadingBackdrop, {alpha: 0}, 0.7, {ease: FlxEase.sineInOut, onComplete: function(_) { loadingBackdrop.destroy(); diff --git a/source/funkin/menus/ModSwitchMenu.hx b/source/funkin/menus/ModSwitchMenu.hx index 977f74fc6..3414af7f0 100644 --- a/source/funkin/menus/ModSwitchMenu.hx +++ b/source/funkin/menus/ModSwitchMenu.hx @@ -34,7 +34,7 @@ class ModSwitchMenu extends MusicBeatSubstate { alphabets = new FlxTypedGroup(); for(mod in mods) { - var a = new Alphabet(0, 0, mod == null ? TU.translate("mods.disableMods") : mod, "bold"); + var a = new Alphabet(0, 0, mod == null ? TU.translate("mods.disableMods") : Path.withoutExtension(mod), "bold"); if(mod == ModsFolder.currentModFolder) a.color = FlxColor.LIME; a.isMenuItem = true; diff --git a/source/openfl/utils/Assets.hx b/source/openfl/utils/Assets.hx index c14b9f2c9..07a6c90f5 100644 --- a/source/openfl/utils/Assets.hx +++ b/source/openfl/utils/Assets.hx @@ -249,9 +249,10 @@ class Assets } #if (lime_vorbis && lime > "7.9.0" && !macro) if (Options.streamedMusic) { - var path = getPath(id); + var bytes = getBytes(id); + if (bytes == null) return null; // TODO: What if it is a WAV or non-Vorbis file? - var vorbisFile = VorbisFile.fromFile(path); + var vorbisFile = VorbisFile.fromBytes(bytes); if (vorbisFile != null) return Sound.fromAudioBuffer(AudioBuffer.fromVorbisFile(vorbisFile)); } #end