fixed zip mods ram usage & in general

This commit is contained in:
Yoshman29
2023-04-02 03:05:26 +02:00
parent 76cb5a256b
commit 14442ba5b5
3 changed files with 197 additions and 90 deletions
+39 -86
View File
@@ -14,6 +14,7 @@ import lime.text.Font;
import lime.utils.AssetType;
import lime.utils.Bytes;
import lime.utils.Assets as LimeAssets;
import openfl.text.Font as OpenFLFont;
#if MOD_SUPPORT
@@ -21,108 +22,60 @@ import sys.FileStat;
import sys.FileSystem;
import sys.io.File;
import haxe.zip.Reader;
import haxe.zip.Entry;
#end
import funkin.utils.SysZip;
import funkin.utils.SysZip.SysZipEntry;
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;
public var assets:Map<String, Entry> = [];
#end
public var zip:SysZip;
public var assets:Map<String, SysZipEntry> = [];
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));
var entries = zip.read();
for(entry in entries) {
zip = SysZip.openFromFile(zipPath);
zip.read();
for(entry in zip.entries)
assets[entry.fileName.toLowerCase()] = entry;
}
#end
super();
}
#if MOD_SUPPORT
public var _parsedAsset:String;
public override function getAudioBuffer(id:String):AudioBuffer {
if (__isCacheValid(LimeAssets.cache.audio, id))
return LimeAssets.cache.audio.get('$libName:$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]));
return e;
}
__parseAsset(id);
return AudioBuffer.fromBytes(unzip(assets[_parsedAsset]));
}
public override function getBytes(id:String):Bytes {
if (__isCacheValid(cachedBytes, id, true))
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;
}
__parseAsset(id);
return Bytes.fromBytes(unzip(assets[_parsedAsset]));
}
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(LimeAssets.cache.font, id))
return LimeAssets.cache.font.get('$libName:$id');
else {
if (!exists(id, "FONT")) {
Log.error('ZipFolderLibrary: Font at $id does not exist.');
return null;
}
var e = Font.fromBytes(unzip(assets[_parsedAsset]));
return e;
}
__parseAsset(id);
var font = Font.fromBytes(unzip(assets[_parsedAsset]));
var openflFont = new OpenFLFont();
@:privateAccess
openflFont.__fromLimeFont(font);
OpenFLFont.registerFont(openflFont);
return font;
}
public override function getImage(id:String):Image {
__parseAsset(id);
return Image.fromBytes(unzip(assets[_parsedAsset]));
}
public override function getImage(id:String):Image {
if (useImageCache && __isCacheValid(LimeAssets.cache.image, id))
return LimeAssets.cache.image.get('$libName:$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 inline function unzip(f:SysZipEntry)
return f == null ? null : zip.unzipEntry(f);
public function __parseAsset(asset:String):Bool {
if (!asset.startsWith(prefix)) return false;
@@ -134,8 +87,8 @@ class ZipFolderLibrary extends AssetLibrary implements ModsAssetLibrary {
if (cache.exists(isLocal ? '$libName:$asset': asset)) return true;
return false;
}
public override function exists(asset:String, type:String):Bool {
public override function exists(asset:String, type:String):Bool {
if(!__parseAsset(asset)) return false;
return assets[_parsedAsset] != null;
@@ -147,10 +100,10 @@ class ZipFolderLibrary extends AssetLibrary implements ModsAssetLibrary {
public function getFiles(folder:String):Array<String> {
var content:Array<String> = [];
if (!folder.endsWith("/")) folder = folder + "/";
if (!__parseAsset(folder)) return [];
@:privateAccess
for(k=>e in assets) {
if (k.toLowerCase().startsWith(_parsedAsset)) {
@@ -164,10 +117,10 @@ class ZipFolderLibrary extends AssetLibrary implements ModsAssetLibrary {
public function getFolders(folder:String):Array<String> {
var content:Array<String> = [];
if (!folder.endsWith("/")) folder = folder + "/";
if (!__parseAsset(folder)) return [];
@:privateAccess
for(k=>e in assets) {
if (k.toLowerCase().startsWith(_parsedAsset)) {
@@ -178,5 +131,5 @@ class ZipFolderLibrary extends AssetLibrary implements ModsAssetLibrary {
}
return content;
}
#end
}
}
#end
-4
View File
@@ -168,11 +168,7 @@ class Paths
inline static public function font(key:String)
{
#if sys
return sys.FileSystem.absolutePath(OpenFlAssets.getPath(getPath('fonts/$key', FONT, null)));
#else
return getPath('fonts/$key', FONT, null);
#end
}
inline static public function obj(key:String) {
+158
View File
@@ -0,0 +1,158 @@
package funkin.utils;
#if sys
import haxe.io.Input;
import haxe.zip.Entry;
import haxe.zip.Reader;
import sys.io.File;
import sys.io.FileInput;
import haxe.zip.InflateImpl;
/**
* 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
*/
class SysZip extends Reader {
var input:Input;
var fileInput:FileInput;
public var entries:List<SysZipEntry>;
/**
* Opens a zip from a specified path.
* @param path Path to the zip file.
*/
public static function openFromFile(path:String) {
return new SysZip(File.read(path, true));
}
/**
* Creates a new SysZip from a specified file input.
* @param input File input.
*/
public function new(input:FileInput) {
super(input);
fileInput = input;
}
/**
* 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;
}
/**
* 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);
if (!f.compressed)
return data;
var c = new haxe.zip.Uncompress(-15);
var s = haxe.io.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;
}
public override function read():List<Entry> {
if (entries != null)
return entries;
entries = new List();
while (true) {
var e = readEntryHeader();
if (e == null)
break;
var zipEntry:SysZipEntry = cast e;
zipEntry.seekPos = fileInput.tell();
entries.add(zipEntry);
fileInput.seek(e.dataSize, SeekCur);
}
return entries;
}
public function dispose() {
if (input != null)
input.close();
}
}
typedef SysZipEntry = {
> Entry,
var seekPos:Int;
}
#end