diff --git a/source/flxanimate/frames/FlxAnimateFrames.hx b/source/flxanimate/frames/FlxAnimateFrames.hx deleted file mode 100644 index 0e91db5a..00000000 --- a/source/flxanimate/frames/FlxAnimateFrames.hx +++ /dev/null @@ -1,619 +0,0 @@ -package flxanimate.frames; -import flixel.graphics.frames.FlxFramesCollection; -import flxanimate.data.AnimationData.OneOfTwo; -import openfl.geom.Rectangle; -import flxanimate.data.SpriteMapData.Meta; -import haxe.io.Bytes; -import flxanimate.zip.Zip; -import haxe.io.BytesInput; -import flixel.math.FlxMatrix; -import flixel.FlxG; -import flixel.graphics.FlxGraphic; -import flixel.graphics.frames.FlxAtlasFrames; -import flixel.graphics.frames.FlxFrame.FlxFrameAngle; -import flixel.math.FlxPoint; -import flixel.math.FlxRect; -import flxanimate.data.SpriteMapData.AnimateAtlas; -import flxanimate.data.SpriteMapData.AnimateSpriteData; -import openfl.Assets; -import openfl.display.BitmapData; -import flixel.system.FlxAssets.FlxGraphicAsset; -#if haxe4 -import haxe.xml.Access; -#else -import haxe.xml.Fast as Access; -#end -import flixel.graphics.frames.FlxFrame; - -class FlxAnimateFrames extends FlxAtlasFrames -{ - public function new() - { - super(null); - parents = []; - } - static var data:AnimateAtlas = null; - static var zip:Null>; - - public var parents:Array; - /** - * Parses the spritemaps into small sprites to use in the animation. - * - * @param Path Where the Sprites are, normally you use it once when calling FlxAnimate already - * @return new sliced limbs for you to use ;) - */ - public static function fromTextureAtlas(Path:String):FlxAtlasFrames - { - var frames:FlxAnimateFrames = new FlxAnimateFrames(); - - if (zip != null || haxe.io.Path.extension(Path) == "zip") - { - #if html5 - FlxG.log.error("Zip Stuff isn't supported on Html5 since it can't transform bytes into an image"); - return null; - #end - var imagemap:Map = new Map(); - var jsonMap:Map = new Map(); - var thing = (zip != null) ? zip : Zip.unzip(Zip.readZip(Assets.getBytes(Path))); - for (list in thing) - { - if (haxe.io.Path.extension(list.fileName) == "json") - { - jsonMap.set(list.fileName,haxe.Json.parse(StringTools.replace(list.data.toString(), String.fromCharCode(0xFEFF), ""))); - } - else if (haxe.io.Path.extension(list.fileName) == "png") - { - var name = list.fileName.split("/"); - imagemap.set(name[name.length - 1], list.data); - } - } - // Assuming the json has the same stuff as the image stuff - for (curJson in jsonMap) - { - var curImage = BitmapData.fromBytes(imagemap[curJson.meta.image]); - if (curImage != null) - { - for (sprites in curJson.ATLAS.SPRITES) - { - frames.pushFrame(textureAtlasHelper(curImage, sprites.SPRITE, curJson.meta)); - } - } - else - FlxG.log.error('the Image called "${curJson.meta.image}" isnt in this zip file!'); - } - zip == null; - } - else - { - if (Assets.exists('$Path/spritemap.json')) - { - var curJson:AnimateAtlas = haxe.Json.parse(StringTools.replace(Assets.getText('$Path/spritemap.json'), String.fromCharCode(0xFEFF), "")); - var graphic = FlxG.bitmap.add('$Path/${curJson.meta.image}'); - if (graphic != null) - { - var spritemapFrames = new FlxAnimateFrames(); - spritemapFrames.parent = graphic; - for (curSprite in curJson.ATLAS.SPRITES) - spritemapFrames.pushFrame(textureAtlasHelper(graphic.bitmap,curSprite.SPRITE, curJson.meta)); - graphic.addFrameCollection(spritemapFrames); - frames.concat(spritemapFrames); - } - else - FlxG.log.error('the image called "${curJson.meta.image}" does not exist in Path $Path, maybe you changed the image Path somewhere else?'); - } - var i = 1; - while (Assets.exists('$Path/spritemap$i.json')) - { - var curJson:AnimateAtlas = haxe.Json.parse(StringTools.replace(Assets.getText('$Path/spritemap$i.json'), String.fromCharCode(0xFEFF), "")); - var graphic = FlxG.bitmap.add('$Path/${curJson.meta.image}'); - if (graphic != null) - { - var spritemapFrames = new FlxAnimateFrames(); - spritemapFrames.parent = graphic; - for (curSprite in curJson.ATLAS.SPRITES) - spritemapFrames.pushFrame(textureAtlasHelper(graphic.bitmap,curSprite.SPRITE, curJson.meta)); - graphic.addFrameCollection(spritemapFrames); - frames.concat(spritemapFrames); - } - else - FlxG.log.error('the image called "${curJson.meta.image}" does not exist in Path $Path, maybe you changed the image Path somewhere else?'); - i++; - } - } - if (frames.frames == []) - { - FlxG.log.error("the Frames parsing couldn't parse any of the frames, it's completely empty! \n Maybe you misspelled the Path?"); - return null; - } - return frames; - } - public function concat(frames:FlxFramesCollection) - { - if (parents.indexOf(frames.parent) == -1) - parents.push(frames.parent); - for (frame in frames.frames) - { - this.frames.push(frame); - framesHash.set(frame.name, frame); - } - } - /** - * Sparrow spritesheet format parser with support of both of the versions and making the image completely optional to you. - * @param Path The direction of the Xml you want to parse. - * @param Image (Optional) the image of the Xml. - * @return A new instance of `FlxAtlasFrames` - */ - public static function fromSparrow(Path:FlxSparrow, ?Image:FlxGraphicAsset):FlxAtlasFrames - { - if ((Path is String) && !Assets.exists(Path)) - return null; - - var data:Access = new Access((Path is String) ? Xml.parse(Assets.getText(Path)).firstElement() : Path.firstElement()); - if (Image == null) - { - if ((Path is String)) - { - var splitDir = Path.split("/"); - splitDir.pop(); - splitDir.push(data.att.imagePath); - Image = splitDir.join("/"); - } - else - return null; - } - var graphic:FlxGraphic = FlxG.bitmap.add(Image); - if (graphic == null) - return null; - - // No need to parse data again - var frames:FlxAtlasFrames = FlxAtlasFrames.findFrame(graphic); - if (frames != null) - return frames; - - frames = new FlxAtlasFrames(graphic); - - for (texture in data.nodes.SubTexture) - { - var version2 = texture.has.width; - var name = texture.att.name; - var trimmed = texture.has.frameX; - var width = (version2) ? texture.att.width : texture.att.w; - var height = (version2) ? texture.att.height : texture.att.h; - var rotated = (texture.has.rotated && texture.att.rotated == "true"); - var flipX = (texture.has.flipX && texture.att.flipX == "true"); - var flipY = (texture.has.flipY && texture.att.flipY == "true"); - - var rect = FlxRect.get(Std.parseFloat(texture.att.x), Std.parseFloat(texture.att.y), Std.parseFloat(width), - Std.parseFloat(height)); - - var size = (trimmed) ? new FlxRect(Std.parseInt(texture.att.frameX), Std.parseInt(texture.att.frameY), Std.parseInt(texture.att.frameWidth), - Std.parseInt(texture.att.frameHeight)) : new FlxRect(0, 0, rect.width, rect.height); - - var angle = rotated ? FlxFrameAngle.ANGLE_NEG_90 : FlxFrameAngle.ANGLE_0; - - var offset = FlxPoint.get(-size.left, -size.top); - var ImageSize = FlxPoint.get(size.width, size.height); - - if (rotated && !trimmed) - ImageSize.set(size.height, size.width); - - frames.addAtlasFrame(rect, ImageSize, offset, name, angle, flipX, flipY); - } - - return frames; - } - /** - * - * @param Path the Json in specific, can be the path of it or the actual json - * @param Image the image which the file is referencing **WARNING:** if you set the path as a json, it's obligatory to set the image! - * @return A new instance of `FlxAtlasFrames` - */ - public static function fromJson(Path:FlxJson, ?Image:FlxGraphicAsset):FlxAtlasFrames - { - if ((Path is String) && !Assets.exists(Path)) - return null; - var data:JsonNormal = (Path is String) ? haxe.Json.parse(Assets.getText(Path)) : Path; - if (Image == null) - { - if ((Path is String)) - { - var splitDir = Path.split("/"); - splitDir.pop(); - splitDir.push(data.meta.image); - Image = splitDir.join("/"); - } - else - { - FlxG.log.error("The Path isn't a String but a Json, you need to set an image if you use Jsons!"); - return null; - } - } - - var graphic:FlxGraphic = FlxG.bitmap.add(Image); - if (graphic == null) - return null; - - // No need to parse data again - var frames:FlxAtlasFrames = FlxAtlasFrames.findFrame(graphic); - if (frames != null) - return frames; - - frames = new FlxAtlasFrames(graphic); - - // JSON-Array - if ((data.frames is Array)) - { - for (frame in Lambda.array(data.frames)) - { - texturePackerHelper(frame.filename, frame, frames); - } - } - // JSON-Hash - else - { - for (frameName in Reflect.fields(data.frames)) - { - texturePackerHelper(frameName, Reflect.field(data.frames, frameName), frames); - } - } - - return frames; - } - /** - * Edge Animate - * @param Path the Path of the .eas - * @param Image (Optional) the Image - * @return Cute little Frames to use ;) - */ - public static function fromEdgeAnimate(Path:String, ?Image:FlxGraphicAsset):FlxAtlasFrames - { - return fromJson((StringTools.startsWith(Path, "{")) ? haxe.Json.parse(Path) : Path, Image); - } - /** - * Starling spritesheet format parser which uses a preference list from Mac computer shit - * @param Path the dir of the preference list - * @param Image (Optional) the Image - * @return Some recently cooked Frames for you ;) - */ - public static function fromStarling(Path:FlxPropertyList, ?Image:FlxGraphicAsset):FlxAtlasFrames - { - if ((Path is String) && !Assets.exists(Path)) - return null; - var data:Plist = (Path is String) ? PropertyList.parse(Assets.getText(Path)) : Path; - if (Image == null) - { - if ((Path is String)) - { - var splitDir = Path.split("/"); - splitDir.pop(); - splitDir.push(data.metadata.textureFileName); - Image = splitDir.join("/"); - } - else - { - return null; - } - } - - - var graphic:FlxGraphic = FlxG.bitmap.add(Image, false); - if (graphic == null) - return null; - - // No need to parse data again - var frames:FlxAtlasFrames = FlxAtlasFrames.findFrame(graphic); - if (frames != null) - return frames; - - frames = new FlxAtlasFrames(graphic); - - for (frameName in Reflect.fields(data.frames)) - { - starlingHelper(frameName, Reflect.field(data.frames, frameName), frames); - } - - return frames; - } - /** - * Cocos2D spritesheet format parser, which basically has 2 versions, - * One is basically Starling (2v) and the other one which is a more fucky and weird (3v) - * @param Path the Path of the plist - * @param Image (Optional) the image - * @return Recently made Frames for your dispose ;) - */ - public static function fromCocos2D(Path:String, ?Image:FlxGraphicAsset):FlxAtlasFrames - { - if (!Assets.exists(Path)) - return null; - var data:Plist = PropertyList.parse(Assets.getText(Path)); - if (data.metadata.format == 2) - { - return fromStarling(Path, Image); - } - else - { - if (Image == null) - { - if ((Path is String)) - { - var splitDir = Path.split("/"); - splitDir.pop(); - splitDir.push(data.metadata.target.name); - Image = splitDir.join("/"); - } - else - { - return null; - } - } - var graphic:FlxGraphic = FlxG.bitmap.add(Image); - if (graphic == null) - return null; - - // No need to parse data again - var frames:FlxAtlasFrames = FlxAtlasFrames.findFrame(graphic); - if (frames != null) - return frames; - - frames = new FlxAtlasFrames(graphic); - - for (frameName in Reflect.fields(data.frames)) - { - cocosHelper(frameName, Reflect.field(data.frames, frameName), frames); - } - - return frames; - } - } - /** - * EaselJS spritesheet format parser, pretty weird stuff. - * @param Path The Path of the jsFile - * @param Image (optional) the Path of the image - * @return New frames made for you to use ;) - */ - public static function fromEaselJS(Path:String, ?Image:FlxGraphicAsset):FlxAtlasFrames - { - var hugeFrames:FlxAtlasFrames = new FlxAtlasFrames(null); - var separatedJS = Assets.getText(Path).split("\n"); - var lines:Array = []; - for (line in separatedJS) - { - if (StringTools.contains(line, "new createjs.SpriteSheet({")) - lines.push(line); - } - var names:Array = []; - var jsons:Array = []; - for (line in lines) - { - names.push(StringTools.replace(line.split(".")[0], "_", " ")); - var curJson = StringTools.replace(StringTools.replace(line.split("(")[1], ")", ""), ";", ""); - var parsedJson = haxe.Json.parse(~/({|,\s*)(\S+)(\s*:)/g.replace(curJson, '$1\"$2"$3')); - jsons.push(parsedJson); - } - var prevName = ""; - var imagePath = Path.split("/"); - imagePath.pop(); - for (i in 0...names.length) - { - var times = 0; - var name = names[i]; - var json = jsons[i]; - var bitmap = FlxG.bitmap.add((Image == null) ? '${imagePath.join("/")}/${json.images[0]}' : Image); - var frames = new FlxAtlasFrames(bitmap); - for (frame in json.frames) - { - var frameRect:FlxRect = new FlxRect(frame[0], frame[1], frame[2], frame[3]); - var sourceSize:FlxPoint = new FlxPoint(frameRect.width, frameRect.height); - var offset = new FlxPoint(-frame[5], -frame[6]); - frames.addAtlasFrame(frameRect, sourceSize, offset, name + Std.string(times)); - times++; - } - for (frame in frames.frames) - { - hugeFrames.pushFrame(frame); - } - } - return hugeFrames; - } - - static function cocosHelper(FrameName:String, FrameData:Dynamic, Frames:FlxAtlasFrames) - { - var rotated:Bool = FrameData.textureRotated; - var name:String = FrameName; - var sourceSize:FlxPoint = FlxPoint.get(Std.parseFloat(FrameData.spriteSourceSize[0]), Std.parseFloat(FrameData.spriteSourceSize[1])); - var offset:FlxPoint = FlxPoint.get(-Std.parseFloat(FrameData.spriteOffset[0]), -Std.parseFloat(FrameData.spriteOffset[1])); - var angle:FlxFrameAngle = FlxFrameAngle.ANGLE_0; - var frameRect:FlxRect = null; - - var frame = FrameData.textureRect; - if (rotated) - { - frameRect = FlxRect.get(Std.parseFloat(frame[0]), Std.parseFloat(frame[1]), Std.parseFloat(frame[3]), Std.parseFloat(frame[2])); - angle = FlxFrameAngle.ANGLE_NEG_90; - } - else - { - frameRect = FlxRect.get(Std.parseFloat(frame[0]), Std.parseFloat(frame[1]), Std.parseFloat(frame[2]), Std.parseFloat(frame[3])); - } - - Frames.addAtlasFrame(frameRect, sourceSize, offset, name, angle); - } - - static function starlingHelper(FrameName:String, FrameData:Dynamic, Frames:FlxAtlasFrames):Void - { - var rotated:Bool = FrameData.rotated; - var name:String = FrameName; - var sourceSize:FlxPoint = FlxPoint.get(Std.parseFloat(FrameData.sourceSize[0]), Std.parseFloat(FrameData.sourceSize[1])); - var offset:FlxPoint = FlxPoint.get(-Std.parseFloat(FrameData.offset[0]), -Std.parseFloat(FrameData.offset[1])); - var angle:FlxFrameAngle = FlxFrameAngle.ANGLE_0; - var frameRect:FlxRect = null; - - var frame = FrameData.frame; - if (rotated) - { - frameRect = FlxRect.get(Std.parseFloat(frame[0]), Std.parseFloat(frame[1]), Std.parseFloat(frame[3]), Std.parseFloat(frame[2])); - angle = FlxFrameAngle.ANGLE_NEG_90; - } - else - { - frameRect = FlxRect.get(Std.parseFloat(frame[0]), Std.parseFloat(frame[1]), Std.parseFloat(frame[2]), Std.parseFloat(frame[3])); - } - - Frames.addAtlasFrame(frameRect, sourceSize, offset, name, angle); - } - - static function textureAtlasHelper(SpriteMap:BitmapData, limb:AnimateSpriteData, curMeta:Meta) - { - var width = (limb.rotated) ? limb.h : limb.w; - var height = (limb.rotated) ? limb.w : limb.h; - var sprite = new BitmapData(width, height, true, 0); - var matrix = new FlxMatrix(1,0,0,1,-limb.x,-limb.y); - if (limb.rotated) - { - matrix.rotateByNegative90(); - matrix.translate(0, height); - } - sprite.draw(SpriteMap, matrix); - - @:privateAccess - var curFrame = new FlxFrame(FlxG.bitmap.add(sprite)); - curFrame.name = limb.name; - curFrame.sourceSize.set(width, height); - curFrame.frame = new FlxRect(0,0, width, height); - return curFrame; - } - - static function texturePackerHelper(FrameName:String, FrameData:Dynamic, Frames:FlxAtlasFrames):Void - { - var rotated:Bool = FrameData.rotated; - var name:String = FrameName; - var sourceSize:FlxPoint = FlxPoint.get(FrameData.sourceSize.w, FrameData.sourceSize.h); - var offset:FlxPoint = FlxPoint.get(FrameData.spriteSourceSize.x, FrameData.spriteSourceSize.y); - var angle:FlxFrameAngle = FlxFrameAngle.ANGLE_0; - var frameRect:FlxRect = null; - - if (rotated) - { - frameRect = FlxRect.get(FrameData.frame.x, FrameData.frame.y, FrameData.frame.h, FrameData.frame.w); - angle = FlxFrameAngle.ANGLE_NEG_90; - } - else - { - frameRect = FlxRect.get(FrameData.frame.x, FrameData.frame.y, FrameData.frame.w, FrameData.frame.h); - } - - Frames.addAtlasFrame(frameRect, sourceSize, offset, name, angle); - } - static function max(a:Int, b:Int):Int - return a < b ? b : a; -} -// code made by noonat 11 years ago, not mine lol -class PropertyList -{ - static var _dateRegex:EReg = ~/(\d{4}-\d{2}-\d{2})(?:T(\d{2}:\d{2}:\d{2})Z)?/; - - /** - * Parse an Apple property list XML file into a dynamic object. If - * the property list is empty, an empty object will be returned. - * @param text Text contents of the property list file. - */ - static public function parse(text:String):Dynamic - { - var fast = new Access(Xml.parse(text).firstElement()); - return fast.hasNode.dict ? parseDict(fast.node.dict) : {}; - } - - static function parseDate(text:String):Date - { - if (!_dateRegex.match(text)) - { - throw 'Invalid date "' + text + '" (only yyyy-mm-dd and yyyy-mm-ddThh:mm:ssZ supported)'; - } - text = _dateRegex.matched(1); - if (_dateRegex.matched(2) != null) - { - text += ' ' + _dateRegex.matched(2); - } - return Date.fromString(text); - } - - static function parseDict(node:Access):Dynamic - { - var key:String = null; - var result:Dynamic = {}; - for (childNode in node.elements) - { - if (childNode.name == 'key') - { - key = childNode.innerData; - } else if (key != null) - { - Reflect.setField(result, key, parseValue(childNode)); - } - } - return result; - } - - static function parseValue(node:Access):Dynamic - { - var value:Dynamic = null; - switch (node.name) - { - case 'array': - value = new Array(); - for (childNode in node.elements) - { - value.push(parseValue(childNode)); - } - - case 'dict': - value = parseDict(node); - - case 'date': - value = parseDate(node.innerData); - - case 'string': - var thing:Dynamic = node.innerData; - if (thing.charAt(0) == "{") - { - thing = StringTools.replace(thing, "{", ""); - thing = StringTools.replace(thing, "}", ""); - thing = thing.split(","); - } - value = thing; - case 'data': - value = node.innerData; - - case 'true': - value = true; - - case 'false': - value = false; - - case 'real': - value = Std.parseFloat(node.innerData); - - case 'integer': - value = Std.parseInt(node.innerData); - } - return value; - } -} -typedef JSJson = -{ - var images:Array; - var frames:Array>; -} -typedef FlxSparrow = OneOfTwo; -typedef FlxJson = OneOfTwo; -typedef FlxPropertyList = OneOfTwo; -typedef JsonNormal = -{ - frames:Dynamic, - meta:Meta -} -typedef Plist = -{ - frames:Dynamic, - metadata:Dynamic -} \ No newline at end of file diff --git a/source/funkin/system/FlxAnimate.hx b/source/funkin/system/FlxAnimate.hx index 2e472945..3c9ccd22 100644 --- a/source/funkin/system/FlxAnimate.hx +++ b/source/funkin/system/FlxAnimate.hx @@ -19,6 +19,11 @@ class FlxAnimate extends flxanimate.FlxAnimate { FlxG.signals.preStateSwitch.add(onSwitch); } + public override function destroy() { + FlxG.bitmap.remove(graphic); + super.destroy(); + } + private static function onSwitch() { for(p in loadedPaths) { Assets.cache.clear(p); diff --git a/source/funkin/system/FunkinCache.hx b/source/funkin/system/FunkinCache.hx index 1265acd3..d2669914 100644 --- a/source/funkin/system/FunkinCache.hx +++ b/source/funkin/system/FunkinCache.hx @@ -55,6 +55,7 @@ class FunkinCache extends AssetCache { public function clearSecondLayer() { for(k=>b in bitmapData2) { + FlxG.bitmap.removeByKey(k); LimeAssets.cache.image.remove(k); } for(k=>f in font2) { @@ -69,8 +70,6 @@ class FunkinCache extends AssetCache { sound2 = []; } - - /** Retrieves a cached BitmapData. @@ -160,4 +159,45 @@ class FunkinCache extends AssetCache { { return sound.exists(id) || sound2.exists(id); } + /** + Removes a BitmapData from the cache. + + @param id The ID of a BitmapData asset + @return `true` if the asset was removed, `false` if it was not in the cache + **/ + public override function removeBitmapData(id:String):Bool + { + #if lime + LimeAssets.cache.image.remove(id); + #end + return bitmapData.remove(id) || bitmapData2.remove(id); + } + + /** + Removes a Font from the cache. + + @param id The ID of a Font asset + @return `true` if the asset was removed, `false` if it was not in the cache + **/ + public override function removeFont(id:String):Bool + { + #if lime + LimeAssets.cache.font.remove(id); + #end + return font.remove(id) || font2.remove(id); + } + + /** + Removes a Sound from the cache. + + @param id The ID of a Sound asset + @return `true` if the asset was removed, `false` if it was not in the cache + **/ + public override function removeSound(id:String):Bool + { + #if lime + LimeAssets.cache.audio.remove(id); + #end + return sound.remove(id) || sound2.remove(id); + } } \ No newline at end of file diff --git a/source/funkin/system/framerate/FlixelInfo.hx b/source/funkin/system/framerate/FlixelInfo.hx index 5ce0789c..432d415f 100644 --- a/source/funkin/system/framerate/FlixelInfo.hx +++ b/source/funkin/system/framerate/FlixelInfo.hx @@ -10,6 +10,8 @@ class FlixelInfo extends FramerateCategory { _text = 'State: ${Type.getClassName(Type.getClass(FlxG.state))}'; _text += '\nObject Count: ${FlxG.state.members.length}'; _text += '\nCamera Count: ${FlxG.cameras.list.length}'; + @:privateAccess + _text += '\nFlxG.game Childs Count: ${FlxG.game.numChildren}'; this.text.text = _text; super.__enterFrame(t);