diff --git a/source/backend/assets/FunkinCache.hx b/source/backend/assets/FunkinCache.hx index a52c431..d526efc 100644 --- a/source/backend/assets/FunkinCache.hx +++ b/source/backend/assets/FunkinCache.hx @@ -6,11 +6,13 @@ import flixel.graphics.FlxGraphic; import flash.media.Sound; import lime.utils.Assets; +import openfl.utils.ByteArray; + class FunkinCache { public var graphicCache:Map = []; + var backupGraphicCache:Map = []; public var soundCache:Map = []; - public var backupGraphicCache:Map = []; - public var backupSoundCache:Map = []; + var backupSoundCache:Map = []; public function new() { graphicCache = new Map(); @@ -76,9 +78,45 @@ class FunkinCache { } } + // experimental + public function cacheGraphicByte(key:String) { + var bitmap:BitmapData; + var bytes:ByteArray = new ByteArray(); + + if (graphicCache.exists(key)) { + trace('Graphic already cached'); + return; + } + + if (backupGraphicCache.exists(key)) { + var graphic = backupGraphicCache.get(key); + backupGraphicCache.remove(key); + graphicCache.set(key, graphic); + return; + } + + try (bytes = ByteArray.fromFile(key)) + catch (e) { + trace('Graphic not loaded: ' + key); + return; + } + + // bytes.deflate(); + try (bitmap = BitmapData.fromBytes(bytes)) + catch (e) { + trace('ByteArray cannot be read'); + return; + } + + var graphic:FlxGraphic = FlxGraphic.fromBitmapData(bitmap, false, key); + graphic.persist = true; + graphicCache.set(key, graphic); + trace('Graphic cached: ' + key); + } + public function getGraphic(key:String) { if (!graphicCache.exists(key)) - cacheGraphic(key); + cacheGraphicByte(key); return graphicCache.get(key); } diff --git a/source/backend/assets/Paths.hx b/source/backend/assets/Paths.hx index ad4f031..b37e5ee 100644 --- a/source/backend/assets/Paths.hx +++ b/source/backend/assets/Paths.hx @@ -12,7 +12,8 @@ import openfl.utils.Assets as OpenFlAssets; import openfl.system.System; import lime.utils.Assets; -// caching system is like a mix of funkin and flashcache so credits to them i guess +// caching system is like a mix of funkin and flashcache/psych so credits to them i guess +@:access(openfl.display.BitmapData) class Paths { inline public static var SOUND_EXT = #if web "mp3" #else "ogg" #end; // Sound file type @@ -30,8 +31,16 @@ class Paths { assetCache = new FunkinCache(); } + @:access(flixel.system.frontEnds.BitmapFrontEnd._cache) public static function clearCaches() { OpenFlAssets.cache.clear('assets/songs'); + for (key in FlxG.bitmap._cache.keys()) { + if (!assetCache.graphicCache.exists(key)) { + if (FlxG.bitmap.get(key).bitmap.__texture != null) + FlxG.bitmap.get(key).bitmap.__texture.dispose(); + FlxG.bitmap.remove(FlxG.bitmap.get(key)); + } + } FlxG.bitmap.dumpCache(); // i am desperate to clean memory assetCache.clearCaches(); System.gc(); @@ -130,7 +139,27 @@ class Paths { inline public static function noteSkin(key:String, ?library:String) return dataFile('skins/$key.json', library); - // im gonna make these all into one function later + inline public static function getAtlas(key:String, ?ext:String = 'xml', ?library:String) { + var path:String = file('images/$key', library); + path = OpenFlAssets.exists('$path.$ext') ? path : file('$key'); + var graphic:FlxGraphic = image(key, library); + if (OpenFlAssets.exists('$path.$ext')) { + if (ext == 'xml') { + return FlxAtlasFrames.fromSparrow(graphic, '$path.$ext'); + } else if (ext == 'txt') { + return FlxAtlasFrames.fromSpriteSheetPacker(graphic, '$path.$ext'); + } else if (ext == 'json') { + return FlxAtlasFrames.fromAseprite(graphic, '$path.$ext'); + } else { + trace('${ext.toUpperCase()} files are not supported'); + return null; + } + } else { + trace('File not found: $path.$ext'); + return null; + } + } + inline public static function getSparrowAtlas(key:String, ?library:String) { var ext:String = 'xml'; var path:String = file('images/$key.$ext', library); @@ -176,7 +205,7 @@ class Paths { // multiple spritesheet support (credits to NeeEoo for base code) // this assumes all your spritesheet file types are the same inline public static function getMultiSpritesheetFrames(keys:Array, ?type:String = 'xml', ?library:String) { - var framesToReturn:FlxAtlasFrames; + var framesToReturn:FlxFramesCollection = new FlxFramesCollection(null); for (i in 0...keys.length) { switch (type) { case 'xml' | 'sparrow': diff --git a/source/funkin/modding/FunkinScript.hx b/source/funkin/modding/FunkinScript.hx new file mode 100644 index 0000000..440539e --- /dev/null +++ b/source/funkin/modding/FunkinScript.hx @@ -0,0 +1,8 @@ +package funkin.modding; + +/** + * The basics for a modded script, both Lua AND HScript + */ +class FunkinScript { + +} \ No newline at end of file diff --git a/source/funkin/modding/hscript/FunkinScript.hx b/source/funkin/modding/hscript/FunkinScript.hx deleted file mode 100644 index 8ba8609..0000000 --- a/source/funkin/modding/hscript/FunkinScript.hx +++ /dev/null @@ -1,5 +0,0 @@ -package funkin.modding.hscript; - -class FunkinScript { - -} \ No newline at end of file diff --git a/source/funkin/objects/notes/Note.hx b/source/funkin/objects/notes/Note.hx index 56abedf..340efeb 100644 --- a/source/funkin/objects/notes/Note.hx +++ b/source/funkin/objects/notes/Note.hx @@ -78,7 +78,7 @@ class Note extends FlxSprite { updateHitbox(); default: - frames = Paths.getSparrowAtlas('NOTE_assets'); + frames = Paths.getAtlas('NOTE_assets'); animation.addByPrefix('greenScroll', 'green instance'); animation.addByPrefix('redScroll', 'red instance'); diff --git a/source/funkin/objects/notes/NoteBasic.hx b/source/funkin/objects/notes/NoteBasic.hx index a2e6dd9..fc87516 100644 --- a/source/funkin/objects/notes/NoteBasic.hx +++ b/source/funkin/objects/notes/NoteBasic.hx @@ -4,7 +4,7 @@ interface NoteBasic { public var strumTime:Float; public var noteType:String; public var noteTypeID:Int; - public var noteData:Direction; + public var noteDirection:Direction; public var strumLine:StrumLine; public var noteSkin:NoteSkin; } \ No newline at end of file diff --git a/source/funkin/objects/notes/NoteNew.hx b/source/funkin/objects/notes/NoteNew.hx index 469441a..525ad94 100644 --- a/source/funkin/objects/notes/NoteNew.hx +++ b/source/funkin/objects/notes/NoteNew.hx @@ -6,7 +6,7 @@ class NoteNew extends FlxSprite implements NoteBasic { public var noteType:String = ''; // The name of the note type (Nothing for default) public var noteTypeID:Int = 0; // The ID of the note type (0 is default) public var noteSkin:NoteSkin; // Self explanatory, note type skin overrides this - public var noteData:Direction = 0; // 0 = Left, 1 = Down, 2 = Up, 3 = Right, can add more in NoteData + public var noteDirection:Direction = 0; // 0 = Left, 1 = Down, 2 = Up, 3 = Right, can add more in NoteData public var strumLine:StrumLine; // The strum line the note is assigned to public var hasSustain:Bool; // If the note has a sustain trail or not @@ -23,7 +23,7 @@ class NoteNew extends FlxSprite implements NoteBasic { public static var swagWidth:Float = 160 * 0.7; // Used for positioning the note - public function new(strumTime:Float, noteData:Direction, ?hasSustain:Bool = false, ?noteType:Int = 0, strumLine:StrumLine) { + public function new(strumTime:Float, noteDirection:Direction, ?hasSustain:Bool = false, ?noteType:Int = 0, strumLine:StrumLine) { super(); x += 50; @@ -32,7 +32,7 @@ class NoteNew extends FlxSprite implements NoteBasic { this.hasSustain = hasSustain; this.strumTime = strumTime; - this.noteData = noteData; + this.noteDirection = noteDirection; this.strumLine = strumLine; noteSkin.parse(); @@ -48,7 +48,7 @@ class NoteNew extends FlxSprite implements NoteBasic { antialiasing = noteSkin.antialiasing; - var color:String = noteData.getColor(); + var color:String = noteDirection.getColor(); if (noteSkin.atlasIncluded) { frames = Paths.getSparrowAtlas(noteSkin.path); animation.addByPrefix('scroll', '$color instance'); @@ -56,12 +56,12 @@ class NoteNew extends FlxSprite implements NoteBasic { updateHitbox(); } else { loadGraphic(Paths.image(noteSkin.path), true, noteSkin.extraData[0], noteSkin.extraData[1]); - animation.add('scroll', [4 + noteData]); + animation.add('scroll', [4 + noteDirection]); setGraphicSize(Std.int(width * noteSkin.extraData[4])); updateHitbox(); } - x += swagWidth * noteData; + x += swagWidth * noteDirection; animation.play('scroll'); } diff --git a/source/funkin/objects/notes/StrumLine.hx b/source/funkin/objects/notes/StrumLine.hx index 4125a17..f900ed5 100644 --- a/source/funkin/objects/notes/StrumLine.hx +++ b/source/funkin/objects/notes/StrumLine.hx @@ -1,5 +1,61 @@ package funkin.objects.notes; +import funkin.objects.notes.NoteBasic; +import funkin.objects.notes.NoteNew as Note; +import funkin.objects.notes.SustainTrail; +import flixel.util.FlxSort; + class StrumLine extends FlxSpriteGroup { - public var scrollSpeed:Float = 1.0; + public var scrollSpeed:Float; + public var playerStrum:Bool; + public var downScroll:Bool; + + public var strumNotes:FlxTypedGroup; + public var notes:FlxTypedGroup; + public var unspawnNotes:Array; + + public function new(scrollSpeed:Float = 1.0, playerStrum:Bool = false, ?downScroll:Bool) { + this.scrollSpeed = scrollSpeed; + this.playerStrum = playerStrum; + this.downScroll = downScroll != null ? downScroll : FunkinData.data.get('downScroll'); + + unspawnNotes = new Array(); + + strumNotes = new FlxTypedGroup(); + add(strumNotes); + + notes = new FlxTypedGroup(); + add(notes); + } + + public function sortNotes() { + notes.sort(sortNotesByTime, downScroll ? FlxSort.ASCENDING : FlxSort.DESCENDING); + } + + public function addNotes(notes:Array) { + for (note in notes) { // this is just to make sure none of the data is like fucked up or smth + var strumTime:Float = note.strumTime; + var noteDirection:Direction = note.noteDirection; + var playerNote:Bool = note.playerNote; + var hasSustain:Bool = note.hasSustain; + var sustainLength:Float = note.sustainLength; + var noteType:Int = note.noteType; + + // player note? in MY cpu strum? + // im the old strum, i want normal notes! + if (playerNote != playerStrum) playerNote = playerStrum; + + // cant have a sustain note with no length + if (hasSustain && sustainLength == 0) hasSustain = false; + sustainLength = sustainLength / Conductor.stepCrochet; + + // not sure if this causes like memory leaks or anything + var newNote:Note = new Note(strumTime, noteDirection, hasSustain, noteType, this); + newNote.scrollFactor.set(); + unspawnNotes.push(newNote); + } + } + + function sortNotesByTime(order:Int = FlxSort.ASCENDING, Obj1:Note, Obj2:Note) + return FlxSort.byValues(order, Obj1.strumTime, Obj2.strumTime); } \ No newline at end of file diff --git a/source/funkin/objects/notes/SustainTrail.hx b/source/funkin/objects/notes/SustainTrail.hx index c7437df..41ef671 100644 --- a/source/funkin/objects/notes/SustainTrail.hx +++ b/source/funkin/objects/notes/SustainTrail.hx @@ -10,7 +10,7 @@ class SustainTrail extends FlxStrip implements NoteBasic { public var noteType:String = ''; // The name of the note type (Nothing for default) public var noteTypeID:Int = 0; // The ID of the note type (0 is default) public var noteSkin:NoteSkin; // Self explanatory, note type skin overrides this - public var noteData:Direction = 0; // 0 = Left, 1 = Down, 2 = Up, 3 = Right, can add more in NoteData + public var noteDirection:Direction = 0; // 0 = Left, 1 = Down, 2 = Up, 3 = Right, can add more in NoteData public var strumLine:StrumLine; // The strum line the note is assigned to public var parentNote:NoteNew; // The note the sustain trail belongs to @@ -18,11 +18,11 @@ class SustainTrail extends FlxStrip implements NoteBasic { // loadGraphic(Paths.image(noteSkin.extraPaths[0]), true, noteSkin.extraData[2], noteSkin.extraData[3]); - public function new(strumLine:StrumLine, noteData:Int, sustainLength:Float) { + public function new(strumLine:StrumLine, noteDirection:Int, sustainLength:Float) { super(); this.strumLine = strumLine; - this.noteData = noteData; + this.noteDirection = noteDirection; this.sustainLength = sustainLength; alpha = FunkinData.data.get('sustainAlpha'); diff --git a/source/funkin/sound/FunkinSound.hx b/source/funkin/sound/FunkinSound.hx new file mode 100644 index 0000000..50cd986 --- /dev/null +++ b/source/funkin/sound/FunkinSound.hx @@ -0,0 +1,32 @@ +package funkin.sound; + +import flixel.sound.FlxSound; + +@:structInit +class SoundParams { + // Parameters + var looped:Bool; + var forceRestart:Bool; + var partialParams:Array; + var autoDestroy:Bool; + var persist:Bool; + + // Callbacks + var onComplete:Void->Void; + var onStart:Void->Void; + var onPause:Void->Void; + var onResume:Void->Void; +} + +/** + * FlxSound with some extra features + */ +@:access(flixel.sound.FlxSound) +class FunkinSound { + var _sound:FlxSound; + + public function play(path:String, params:SoundParams) { + _sound = new FlxSound(); + _sound.play(params.forceRestart); + } +} \ No newline at end of file diff --git a/source/funkin/states/PlayState.hx b/source/funkin/states/PlayState.hx index d653edd..39df4e1 100644 --- a/source/funkin/states/PlayState.hx +++ b/source/funkin/states/PlayState.hx @@ -154,7 +154,7 @@ class PlayState extends MusicBeatState Conductor.mapBPMChanges(SONG); Conductor.changeBPM(SONG.bpm); - + Paths.clearCaches(); foregroundSprites = new FlxTypedGroup(); @@ -1331,13 +1331,16 @@ class PlayState extends MusicBeatState video.screenCenter(); } }); + video.bitmap.onEndReached.add(onComplete); video.bitmap.onEndReached.add(video.destroy); add(video); - if (video.load(Paths.video(videoPath))) + if (video.load(Paths.video(videoPath))) { new FlxTimer().start(0.001, (t) -> video.play()); - else + } else { trace('Video not loaded!'); + onComplete(); + } } #end diff --git a/source/funkin/states/debug/TestPlayState.hx b/source/funkin/states/debug/TestPlayState.hx new file mode 100644 index 0000000..6b033aa --- /dev/null +++ b/source/funkin/states/debug/TestPlayState.hx @@ -0,0 +1,12 @@ +package funkin.states.debug; + +import funkin.objects.Song.SwagSong; + +class TestPlayState extends MusicBeatState { + public var strumLines:FlxTypedGroup; + public static var SONG:SwagSong; + + override function create() { + + } +} \ No newline at end of file