zip mod loading

This commit is contained in:
Yoshman29
2022-11-01 17:22:14 +01:00
parent 2d06e3bb0f
commit e9c028489a
9 changed files with 346 additions and 141 deletions
+1 -1
View File
@@ -2,7 +2,7 @@
<project>
<!-- _________________________ Application Settings _________________________ -->
<app title="Friday Night Funkin' - Codename Engine" file="CodenameEngine" packageName="com.yoshman29.codenameengine" package="com.yoshman29.codenameengine" main="funkin.system.Main" version="0.2.7.1" company="ninjamuffin99" />
<app title="Friday Night Funkin' - Codename Engine" file="CodenameEngine" packageName="com.yoshman29.codenameengine" package="com.yoshman29.codenameengine" main="funkin.system.Main" version="0.0.1" company="yoshman29" />
<!--Switch Export with Unique ApplicationID and Icon-->
<set name="APP_ID" value="0x0100f6c013bbc000" />
+1 -1
View File
@@ -1 +1 @@
934
938
-1
View File
@@ -1 +0,0 @@
swagshit--moneymoney
-1
View File
@@ -1 +0,0 @@
introMod
+6 -124
View File
@@ -22,134 +22,16 @@ import sys.FileSystem;
using StringTools;
class ModsAssetLibrary extends AssetLibrary {
public var folderPath:String;
public var libName:String;
public var useImageCache:Bool = false;
public function new(folderPath:String, libName:String) {
this.folderPath = folderPath;
this.libName = libName;
super();
}
interface ModsAssetLibrary {
#if MOD_SUPPORT
private var editedTimes:Map<String, Float> = [];
var _parsedAsset:String = null;
public var _parsedAsset:String;
public function getEditedTime(asset:String):Null<Float> {
return editedTimes[asset];
}
private function getAssetPath():String;
public override function getAudioBuffer(id:String):AudioBuffer {
if (__isCacheValid(cachedAudioBuffers, id))
return cachedAudioBuffers.get(id);
else {
if (!exists(id, "SOUND")) {
Log.error('ModsAssetLibrary: Audio Buffer at $id does not exist.');
return null;
}
var path = getAssetPath();
editedTimes[id] = FileSystem.stat(path).mtime.getTime();
var e = AudioBuffer.fromFile(path);
cachedAudioBuffers.set(id, e);
return e;
}
}
private function __isCacheValid(cache:Map<String, Dynamic>, asset:String):Bool;
public override function getBytes(id:String):Bytes {
if (__isCacheValid(cachedBytes, id))
return cachedBytes.get(id);
else {
if (!exists(id, "BINARY")) {
Log.error('ModsAssetLibrary: Bytes at $id does not exist.');
return null;
}
var path = getAssetPath();
editedTimes[id] = FileSystem.stat(path).mtime.getTime();
var e = Bytes.fromFile(path);
cachedBytes.set(id, e);
return e;
}
}
private function __parseAsset(asset:String):Bool;
public override function getFont(id:String):Font {
if (__isCacheValid(cachedFonts, id))
return cachedFonts.get(id);
else {
if (!exists(id, "FONT")) {
Log.error('ModsAssetLibrary: Font at $id does not exist.');
return null;
}
var path = getAssetPath();
editedTimes[id] = FileSystem.stat(path).mtime.getTime();
var e = Font.fromFile(path);
cachedFonts.set(id, e);
return e;
}
}
public override function getImage(id:String):Image {
if (useImageCache && __isCacheValid(cachedImages, id))
return cachedImages.get(id);
else {
if (!exists(id, "IMAGE")) {
Log.error('ModsAssetLibrary: Image at $id does not exist.');
return null;
}
var path = getAssetPath();
editedTimes[id] = FileSystem.stat(path).mtime.getTime();
var e = Image.fromFile(path);
cachedImages.set(id, e);
return e;
}
}
public override function getPath(id:String):String {
if (!__parseAsset(id)) return null;
return getAssetPath();
}
public function getFiles(folder:String):Array<String> {
if (!folder.endsWith("/")) folder = folder + "/";
if (!__parseAsset(folder)) return [];
var path = getAssetPath();
try {
var result:Array<String> = [];
for(e in FileSystem.readDirectory(path))
if (!FileSystem.isDirectory('$path$e'))
result.push(e);
return result;
} catch(e) {
// woops!!
}
return [];
}
public override function exists(asset:String, type:String):Bool {
if(!__parseAsset(asset)) return false;
return FileSystem.exists(getAssetPath());
}
private function getAssetPath() {
return '$folderPath/$_parsedAsset';
}
private function __isCacheValid(cache:Map<String, Dynamic>, asset:String) {
if (!editedTimes.exists(asset))
return false;
if (editedTimes[asset] == null) return false;
if (editedTimes[asset] < FileSystem.stat(getPath(asset)).mtime.getTime()) return false;
return cache.exists(asset) && cache[asset] != null;
}
private function __parseAsset(asset:String):Bool {
var prefix = 'assets/$libName/';
if (!asset.startsWith(prefix)) return false;
_parsedAsset = asset.substr(prefix.length);
return true;
}
public function getFiles(folder:String):Array<String>;
#end
}
+28 -12
View File
@@ -49,12 +49,18 @@ class ModsFolder {
* @param force Whenever the mod should be reloaded if it has already been loaded
*/
public static function loadMod(mod:String, force:Bool = false) {
var e = loadLibraryFromFolder('mods/$mod'.toLowerCase(), '${modsPath}$mod', force);
loadedMods.push(mod);
return e;
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;
}
}
public static function loadLibraryFromFolder(libName:String, folder:String, force:Bool = false) {
public static function prepareLibrary(libName:String, force:Bool = false) {
if (Assets.hasLibrary(libName)) {
if (force)
Assets.unloadLibrary(libName);
@@ -64,15 +70,25 @@ class ModsFolder {
var assets:AssetManifest = new AssetManifest();
assets.name = libName;
assets.libraryType = 'funkin.mods.ModsAssetLibrary';
assets.version = 2;
assets.libraryArgs = [];
assets.rootPath = folder;
assets.assets = [];
var lib = AssetLibrary.fromManifest(assets);
return AssetLibrary.fromManifest(assets);
}
public static function loadLibraryFromZip(libName:String, zipPath:String, force:Bool = false) {
var lib = prepareLibrary(libName, force);
@:privateAccess
lib.__proxy = new ModsAssetLibrary(assets.rootPath, assets.name);
lib.__proxy = new ZipFolderLibrary(zipPath, libName);
Assets.registerLibrary(libName, lib);
return lib;
}
public static function loadLibraryFromFolder(libName:String, folder:String, force:Bool = false) {
var lib = prepareLibrary(libName, force);
@:privateAccess
lib.__proxy = new ModsFolderLibrary(folder, libName);
Assets.registerLibrary(libName, lib);
return lib;
}
@@ -139,8 +155,8 @@ class ModsFolder {
if (e.library is ModsAssetLibrary) {
var lib = cast(e.library, ModsAssetLibrary);
if (!lib.__parseAsset(e.symbolName)) continue;
if (!lib.__isCacheValid(lib.cachedImages, lib._parsedAsset)) {
lib.cachedImages.remove(lib._parsedAsset);
if (!lib.__isCacheValid(e.library.cachedImages, lib._parsedAsset)) {
e.library.cachedImages.remove(lib._parsedAsset);
bmapsToRemove.push(bmap);
}
}
@@ -159,9 +175,9 @@ class ModsFolder {
if (library is ModsAssetLibrary) {
var modLib = cast(library, ModsAssetLibrary);
@:privateAccess
modLib.cachedBytes = [];
library.cachedBytes = [];
@:privateAccess
for(sound in modLib.cachedAudioBuffers)
for(sound in library.cachedAudioBuffers)
sound.dispose();
}
+155
View File
@@ -0,0 +1,155 @@
package funkin.mods;
import lime.utils.Log;
import lime.utils.AssetLibrary;
import lime.utils.AssetManifest;
import haxe.io.Path;
import lime.app.Event;
import lime.app.Future;
import lime.app.Promise;
import lime.media.AudioBuffer;
import lime.graphics.Image;
import lime.net.HTTPRequest;
import lime.text.Font;
import lime.utils.AssetType;
import lime.utils.Bytes;
#if MOD_SUPPORT
import sys.FileStat;
import sys.FileSystem;
#end
using StringTools;
class ModsFolderLibrary extends AssetLibrary implements ModsAssetLibrary {
public var folderPath:String;
public var libName:String;
public var useImageCache:Bool = true;
public function new(folderPath:String, libName:String) {
this.folderPath = folderPath;
this.libName = libName;
super();
}
#if MOD_SUPPORT
private var editedTimes:Map<String, Float> = [];
public var _parsedAsset:String = null;
public function getEditedTime(asset:String):Null<Float> {
return editedTimes[asset];
}
public override function getAudioBuffer(id:String):AudioBuffer {
if (__isCacheValid(cachedAudioBuffers, id))
return cachedAudioBuffers.get(id);
else {
if (!exists(id, "SOUND")) {
Log.error('ModsAssetLibrary: Audio Buffer at $id does not exist.');
return null;
}
var path = getAssetPath();
editedTimes[id] = FileSystem.stat(path).mtime.getTime();
var e = AudioBuffer.fromFile(path);
cachedAudioBuffers.set(id, e);
return e;
}
}
public override function getBytes(id:String):Bytes {
if (__isCacheValid(cachedBytes, id))
return cachedBytes.get(id);
else {
if (!exists(id, "BINARY")) {
Log.error('ModsAssetLibrary: Bytes at $id does not exist.');
return null;
}
var path = getAssetPath();
editedTimes[id] = FileSystem.stat(path).mtime.getTime();
var e = Bytes.fromFile(path);
cachedBytes.set(id, e);
return e;
}
}
public override function getFont(id:String):Font {
if (__isCacheValid(cachedFonts, id))
return cachedFonts.get(id);
else {
if (!exists(id, "FONT")) {
Log.error('ModsAssetLibrary: Font at $id does not exist.');
return null;
}
var path = getAssetPath();
editedTimes[id] = FileSystem.stat(path).mtime.getTime();
var e = Font.fromFile(path);
cachedFonts.set(id, e);
return e;
}
}
public override function getImage(id:String):Image {
if (useImageCache && __isCacheValid(cachedImages, id))
return cachedImages.get(id);
else {
if (!exists(id, "IMAGE")) {
Log.error('ModsAssetLibrary: Image at $id does not exist.');
return null;
}
var path = getAssetPath();
editedTimes[id] = FileSystem.stat(path).mtime.getTime();
var e = Image.fromFile(path);
if (useImageCache) cachedImages.set(id, e);
return e;
}
}
public override function getPath(id:String):String {
if (!__parseAsset(id)) return null;
return getAssetPath();
}
public function getFiles(folder:String):Array<String> {
if (!folder.endsWith("/")) folder = folder + "/";
if (!__parseAsset(folder)) return [];
var path = getAssetPath();
try {
var result:Array<String> = [];
for(e in FileSystem.readDirectory(path))
if (!FileSystem.isDirectory('$path$e'))
result.push(e);
return result;
} catch(e) {
// woops!!
}
return [];
}
public override function exists(asset:String, type:String):Bool {
if(!__parseAsset(asset)) return false;
return FileSystem.exists(getAssetPath());
}
private function getAssetPath() {
return '$folderPath/$_parsedAsset';
}
private function __isCacheValid(cache:Map<String, Dynamic>, asset:String) {
if (!editedTimes.exists(asset))
return false;
if (editedTimes[asset] == null) return false;
if (editedTimes[asset] < FileSystem.stat(getPath(asset)).mtime.getTime()) return false;
return cache.exists(asset) && cache[asset] != null;
}
private function __parseAsset(asset:String):Bool {
var prefix = 'assets/$libName/';
if (!asset.startsWith(prefix)) return false;
_parsedAsset = asset.substr(prefix.length);
return true;
}
#end
}
+154
View File
@@ -0,0 +1,154 @@
package funkin.mods;
import lime.utils.Log;
import lime.utils.AssetLibrary;
import lime.utils.AssetManifest;
import haxe.io.Path;
import lime.app.Event;
import lime.app.Future;
import lime.app.Promise;
import lime.media.AudioBuffer;
import lime.graphics.Image;
import lime.net.HTTPRequest;
import lime.text.Font;
import lime.utils.AssetType;
import lime.utils.Bytes;
#if MOD_SUPPORT
import sys.FileStat;
import sys.FileSystem;
import sys.io.File;
import haxe.zip.Reader;
import haxe.zip.Entry;
#end
class ZipFolderLibrary extends AssetLibrary implements ModsAssetLibrary {
public var zipPath:String;
public var libName:String;
public var useImageCache:Bool = false;
#if MOD_SUPPORT
public var zip:Reader;
public var assets:Map<String, Entry> = [];
#end
public function new(zipPath:String, libName:String) {
this.zipPath = zipPath;
this.libName = libName;
#if MOD_SUPPORT
zip = new Reader(File.read(zipPath, true));
var entries = zip.read();
for(entry in entries) {
assets[entry.fileName.toLowerCase()] = entry;
}
#end
super();
}
#if MOD_SUPPORT
public var _parsedAsset:String;
public override function getAudioBuffer(id:String):AudioBuffer {
if (__isCacheValid(cachedAudioBuffers, id))
return cachedAudioBuffers.get(id);
else {
if (!exists(id, "SOUND")) {
Log.error('ZipFolderLibrary: Audio Buffer at $id does not exist.');
return null;
}
var e = AudioBuffer.fromBytes(unzip(assets[_parsedAsset]));
cachedAudioBuffers.set(id, e);
return e;
}
}
public override function getBytes(id:String):Bytes {
if (__isCacheValid(cachedBytes, id))
return cachedBytes.get(id);
else {
if (!exists(id, "BINARY")) {
Log.error('ZipFolderLibrary: Bytes at $id does not exist.');
return null;
}
var e = Bytes.fromBytes(unzip(assets[_parsedAsset]));
cachedBytes.set(id, e);
return e;
}
}
public static function unzip(f:Entry) {
if (!f.compressed)
return f.data;
var c = new haxe.zip.Uncompress(-15);
var s = haxe.io.Bytes.alloc(f.fileSize);
var r = c.execute(f.data, 0, s, 0);
c.close();
if (!r.done || r.read != f.data.length || r.write != f.fileSize)
throw "Invalid compressed data for " + f.fileName;
f.compressed = false;
f.dataSize = f.fileSize;
f.data = s;
return f.data;
}
public override function getFont(id:String):Font {
if (__isCacheValid(cachedFonts, id))
return cachedFonts.get(id);
else {
if (!exists(id, "FONT")) {
Log.error('ZipFolderLibrary: Font at $id does not exist.');
return null;
}
var e = Font.fromBytes(unzip(assets[_parsedAsset]));
cachedFonts.set(id, e);
return e;
}
}
public override function getImage(id:String):Image {
if (useImageCache && __isCacheValid(cachedImages, id))
return cachedImages.get(id);
else {
if (!exists(id, "IMAGE")) {
Log.error('ZipFolderLibrary: Image at $id does not exist.');
return null;
}
var e = Image.fromBytes(unzip(assets[_parsedAsset]));
if (useImageCache) cachedImages.set(id, e);
return e;
}
}
public function __parseAsset(asset:String):Bool {
var prefix = 'assets/$libName/';
if (!asset.startsWith(prefix)) return false;
_parsedAsset = asset.substr(prefix.length).toLowerCase();
return true;
}
public function __isCacheValid(cache:Map<String, Dynamic>, asset:String) {
if (cache.exists(asset)) return true;
return false;
}
public override function exists(asset:String, type:String):Bool {
if(!__parseAsset(asset)) return false;
return assets[_parsedAsset] != null;
}
private function getAssetPath() {
return _parsedAsset;
}
public function getFiles(folder:String):Array<String> {
// TODO
return [];
}
#end
}
+1 -1
View File
@@ -108,7 +108,7 @@ class Alphabet extends FlxSpriteGroup
if (library is ModsAssetLibrary) {
var modLib = cast(library, ModsAssetLibrary);
@:privateAccess
if (!modLib.__isCacheValid(modLib.cachedBytes, libThing.symbolName)) {
if (!modLib.__isCacheValid(library.cachedBytes, libThing.symbolName)) {
refreshAlphabetXML(alphabetPath);
}
}