* well boys I fixed it. you can now have Zipped Mods!!!!! * comment update * quick fixes + optimizations * fixed stream audio bug???? * found the issue ffs * removing traces oops * fixed videos from not being able to play. Inspired from VideoCutscene's fix for ZIP videos, and also removed that fix in favor for just fixing the issue entirely * oop just in case no special characters that kill themself on other shit * Implemented preloading every video (caching) when loading a ZipFolderLibrary. Since videos have to be decompressed and be saved as a file anyways this reduces the time to do that, and what not. * [UNTESTED] Allowed Zip Extensions for allowing any extension in the list to be passed as a `.zip` * After some more testing loading Zip Addons works as well. * Added the long awaited .cnemod file type!!!!! (it's just a folder with .cnemod with a .zip inside LMAO) * Chalking up the Streamed Audio Bug to a mod issue, and also added capabilites to detect if a library is considered compressed * Added warning to those who try to use the editor with compressed libraries * ok instead of making it a .cnemod, the zip name will be `cnemod.zip` or what not. * removing unnessesary traces oops * clean Library accessor ig then * fixed small issues and removed an idiot idea * writing todos and fixing some context that left the room in comments * Fixed an issue where if you had a file of 0 bytes (nothing) in a zipped library it would FUCKING CRASH the game * Actually fixed the issue of decompressing 0 byte files Also stopped saving the data for Folders in Zipped files, as they are 0 bytes anyways. * Added the features that needed to exist, and removed a stupid line I saw in `ModsFolder` lol For some reason animation offsets for characters are breaking and I can't tell if its my drive killing itself or cne so uh * fix an issue that will force the game to crash if first ever mod being loaded is a ZipModLibrary
170 lines
5.2 KiB
Haxe
170 lines
5.2 KiB
Haxe
package funkin.backend.assets;
|
|
|
|
import flixel.util.FlxSignal.FlxTypedSignal;
|
|
import funkin.backend.system.MainState;
|
|
import haxe.io.Path;
|
|
import lime.text.Font;
|
|
import openfl.text.Font as OpenFLFont;
|
|
import openfl.utils.AssetLibrary;
|
|
import openfl.utils.AssetManifest;
|
|
|
|
using StringTools;
|
|
#if MOD_SUPPORT
|
|
import sys.FileSystem;
|
|
#end
|
|
|
|
|
|
class ModsFolder {
|
|
/**
|
|
* INTERNAL - Only use when editing source mods!!
|
|
*/
|
|
@:dox(hide) public static var onModSwitch:FlxTypedSignal<String->Void> = new FlxTypedSignal<String->Void>();
|
|
|
|
/**
|
|
* Current mod folder. Will affect `Paths`.
|
|
*/
|
|
public static var currentModFolder:String = null;
|
|
/**
|
|
* Path to the `mods` folder.
|
|
*/
|
|
public static var modsPath:String = "./mods/";
|
|
/**
|
|
* Path to the `addons` folder.
|
|
*/
|
|
public static var addonsPath:String = "./addons/";
|
|
|
|
/**
|
|
* If accessing a file as assets/data/global/LIB_mymod.hx should redirect to mymod:assets/data/global.hx
|
|
*/
|
|
public static var useLibFile:Bool = true;
|
|
|
|
/**
|
|
* Whenever its the first time mods has been reloaded.
|
|
*/
|
|
private static var __firstTime:Bool = true;
|
|
|
|
/**
|
|
* Initializes `mods` folder.
|
|
*/
|
|
public static function init() {
|
|
if(!getModsList().contains(Options.lastLoadedMod)) {
|
|
if(Options.lastLoadedMod != null)
|
|
Logs.warn("Mod \"" + Options.lastLoadedMod + "\" not found in mods list, switching to base game!");
|
|
Options.lastLoadedMod = null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Switches mod - unloads all the other mods, then load this one.
|
|
* @param libName
|
|
*/
|
|
public static function switchMod(mod:String) {
|
|
Options.lastLoadedMod = currentModFolder = mod;
|
|
reloadMods();
|
|
if(mod == null) {
|
|
mod = "(default)";
|
|
}
|
|
Logs.traceColored([
|
|
Logs.logText('Switched to mod: '),
|
|
Logs.logText(mod, GREEN)
|
|
], VERBOSE);
|
|
}
|
|
|
|
public static function reloadMods() {
|
|
if (!__firstTime)
|
|
FlxG.switchState(new MainState());
|
|
__firstTime = false;
|
|
}
|
|
|
|
/**
|
|
* Loads a mod library from the specified path. Supports folders and zips.
|
|
* @param modName Name of the mod
|
|
* @param force Whenever the mod should be reloaded if it has already been loaded
|
|
*/
|
|
public static function loadModLib(path:String, force:Bool = false, ?modName:String) {
|
|
#if MOD_SUPPORT
|
|
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;
|
|
#end
|
|
}
|
|
|
|
public static function getModsList():Array<String> {
|
|
var mods:Array<String> = [];
|
|
#if MOD_SUPPORT
|
|
// Mods directory does not exist yet, create it
|
|
if (!FileSystem.exists(modsPath)) FileSystem.createDirectory(modsPath);
|
|
|
|
final modsList:Array<String> = FileSystem.readDirectory(modsPath);
|
|
|
|
if (modsList == null || modsList.length <= 0) return mods;
|
|
|
|
for (modFolder in modsList) {
|
|
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;
|
|
}
|
|
public static function getLoadedModsLibs(skipTranslated:Bool = false):Array<IModsAssetLibrary> {
|
|
var libs = [];
|
|
for (i in Paths.assetsTree.libraries) {
|
|
var l = AssetsLibraryList.getCleanLibrary(i);
|
|
#if TRANSLATIONS_SUPPORT
|
|
if(skipTranslated && (l is TranslatedAssetLibrary)) continue;
|
|
#end
|
|
// No need to check for it being a `ScriptedAssetLibrary`, if `ScriptedAssetLibrary` extends ModsFolderLibrary, which implements `IModsAssetLibrary`
|
|
// If you have to revert this change then uhhhhh wasn't me, trust 🙏
|
|
if (/*l is ScriptedAssetLibrary ||*/ l is IModsAssetLibrary) libs.push(cast(l, IModsAssetLibrary));
|
|
}
|
|
return libs;
|
|
}
|
|
public static function getLoadedMods(skipTranslated:Bool = false):Array<String>
|
|
return [for (modLib in getLoadedModsLibs(skipTranslated)) modLib.modName];
|
|
|
|
public static function prepareLibrary(libName:String, force:Bool = false) {
|
|
var assets:AssetManifest = new AssetManifest();
|
|
assets.name = libName;
|
|
assets.version = 2;
|
|
assets.libraryArgs = [];
|
|
assets.assets = [];
|
|
|
|
return AssetLibrary.fromManifest(assets);
|
|
}
|
|
|
|
public static function registerFont(font:Font) {
|
|
var openflFont = new OpenFLFont();
|
|
@:privateAccess
|
|
openflFont.__fromLimeFont(font);
|
|
OpenFLFont.registerFont(openflFont);
|
|
return font;
|
|
}
|
|
|
|
public static function prepareModLibrary(libName:String, lib:IModsAssetLibrary, force:Bool = false, ?tag:AssetSource) {
|
|
var openLib = prepareLibrary(libName, force);
|
|
lib.prefix = 'assets/';
|
|
@:privateAccess
|
|
openLib.__proxy = cast(lib, lime.utils.AssetLibrary);
|
|
if (tag != null) {
|
|
openLib.tag = tag;
|
|
cast(lib, lime.utils.AssetLibrary).tag = tag;
|
|
}
|
|
return openLib;
|
|
}
|
|
|
|
#if MOD_SUPPORT
|
|
public static function loadLibraryFromFolder(libName:String, folder:String, force:Bool = false, ?modName:String, ?tag:AssetSource = MODS) {
|
|
return prepareModLibrary(libName, new ModsFolderLibrary(folder, libName, modName), force, tag);
|
|
}
|
|
|
|
public static function loadLibraryFromZip(libName:String, zipPath:String, force:Bool = false, ?modName:String, ?tag:AssetSource = MODS) {
|
|
return prepareModLibrary(libName, new ZipFolderLibrary(zipPath, libName, modName), force, tag);
|
|
}
|
|
#end
|
|
}
|