package; import flixel.FlxG; import flixel.FlxState; import flixel.FlxSprite; import flixel.graphics.frames.FlxAtlasFrames; import flixel.util.FlxTimer; import openfl.utils.Assets; import lime.utils.Assets as LimeAssets; import lime.utils.AssetBundle; import lime.utils.AssetLibrary; import lime.utils.AssetManifest; import lime.app.Future; import lime.app.Promise; import haxe.io.Path; class LoadingState extends MusicBeatState { inline static var MIN_TIME = 1.0; var target:FlxState; var stopMusic = false; var callbacks:MultiCallback; var logo:FlxSprite; var gfDance:FlxSprite; var danceLeft = false; function new(target:FlxState, stopMusic:Bool) { super(); this.target = target; this.stopMusic = stopMusic; } override function create() { logo = new FlxSprite(-150, -100); logo.frames = FlxAtlasFrames.fromSparrow('assets/images/logoBumpin.png', 'assets/images/logoBumpin.xml'); logo.antialiasing = true; logo.animation.addByPrefix('bump', 'logo bumpin', 24); logo.animation.play('bump'); logo.updateHitbox(); // logoBl.screenCenter(); // logoBl.color = FlxColor.BLACK; gfDance = new FlxSprite(FlxG.width * 0.4, FlxG.height * 0.07); gfDance.frames = FlxAtlasFrames.fromSparrow('assets/images/gfDanceTitle.png', 'assets/images/gfDanceTitle.xml'); gfDance.animation.addByIndices('danceLeft', 'gfDance', [30, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14], "", 24, false); gfDance.animation.addByIndices('danceRight', 'gfDance', [15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29], "", 24, false); gfDance.antialiasing = true; add(gfDance); add(logo); // function onSongsManifestInit() // { callbacks = new MultiCallback(onLoad); var introComplete = callbacks.add("introComplete"); checkLoadSong(getSongPath()); checkLoadSong(getVocalPath()); checkLibrary("shared"); if (PlayState.storyWeek > 0) checkLibrary("week" + PlayState.storyWeek); else checkLibrary("tutorial"); var fadeTime = 0.5; FlxG.camera.fade(FlxG.camera.bgColor, fadeTime, true); new FlxTimer().start(fadeTime + MIN_TIME, function(_) introComplete()); // } // initSongsManifest(onSongsManifestInit); } function checkLoadSong(path:String) { if (!Assets.cache.hasSound(path)) { var library = Assets.getLibrary("songs"); final symbolPath = path.split(":").pop(); @:privateAccess library.types.set(symbolPath, SOUND); @:privateAccess library.pathGroups.set(symbolPath, [library.__cacheBreak(symbolPath)]); var callback = callbacks.add("song:" + path); Assets.loadSound(path).onComplete(function (_) { callback(); }); } } function checkLibrary(library:String) { if (Assets.getLibrary(library) == null) { var callback = callbacks.add("library:" + library); Assets.loadLibrary(library).onComplete(function (_) { callback(); }); } } override function beatHit() { super.beatHit(); logo.animation.play('bump'); danceLeft = !danceLeft; if (danceLeft) gfDance.animation.play('danceRight'); else gfDance.animation.play('danceLeft'); } override function update(elapsed:Float) { super.update(elapsed); } function onLoad() { if (stopMusic && FlxG.sound.music != null) FlxG.sound.music.stop(); FlxG.switchState(target); } static function getSongPath() { return Paths.inst(PlayState.SONG.song); } static function getVocalPath() { return Paths.voices(PlayState.SONG.song); } inline static public function loadAndSwitchState(target:FlxState, stopMusic = false) { FlxG.switchState(getNextState(target, stopMusic)); } static function getNextState(target:FlxState, stopMusic = false):FlxState { #if js var loaded = isSoundLoaded(getSongPath()) && (!PlayState.SONG.needsVoices || isSoundLoaded(getVocalPath())) && isLibraryLoaded("shared"); if (!loaded) return new LoadingState(target, stopMusic); #end if (stopMusic && FlxG.sound.music != null) FlxG.sound.music.stop(); return target; } #if js static function isSoundLoaded(path:String):Bool { return Assets.cache.hasSound(path); } static function isLibraryLoaded(library:String):Bool { return Assets.getLibrary(library) != null; } #end override function destroy() { super.destroy(); callbacks = null; } /** * creates the song manifest without loading all the songs so we can load them individually * @param onComplete called on load * @return Future */ static function initSongsManifest(onComplete:Void->Void):Future { final id = "songs"; var promise = new Promise(); // #if (tools && !display && !macro) var library = LimeAssets.getLibrary(id); if (library != null) { onComplete(); return Future.withValue(library); } var path = id; var rootPath = null; // @:privateAccess // if (LimeAssets.bundlePaths.exists(id)) // { // AssetBundle.loadFromFile(bundlePaths.get(id)).onComplete(function(bundle) // { // if (bundle == null) // { // promise.error("Cannot load bundle for library \"" + id + "\""); // return; // } // var library = AssetLibrary.fromBundle(bundle); // if (library == null) // { // promise.error("Cannot open library \"" + id + "\""); // } // else // { // libraries.set(id, library); // library.onChange.add(LimeAssets.onChange.dispatch); // promise.completeWith(Future.withValue(library)); // onComplete(); // } // }).onError(function(_) // { // promise.error("There is no asset library with an ID of \"" + id + "\""); // }); // } // else // { @:privateAccess final libraryPaths = LimeAssets.libraryPaths; if (libraryPaths.exists(id)) { path = libraryPaths[id]; rootPath = Path.directory(path); } else { if (StringTools.endsWith(path, ".bundle")) { rootPath = path; path += "/library.json"; } else { rootPath = Path.directory(path); } @:privateAccess path = LimeAssets.__cacheBreak(path); } AssetManifest.loadFromFile(path, rootPath).onComplete(function(manifest) { if (manifest == null) { promise.error("Cannot parse asset manifest for library \"" + id + "\""); return; } var library = AssetLibrary.fromManifest(manifest); if (library == null) { promise.error("Cannot open library \"" + id + "\""); } else { @:privateAccess LimeAssets.libraries.set(id, library); library.onChange.add(LimeAssets.onChange.dispatch); promise.completeWith(Future.withValue(library)); onComplete(); } }).onError(function(_) { promise.error("There is no asset library with an ID of \"" + id + "\""); }); // } // #end return promise.future; } } class MultiCallback { public var callback:Void->Void; public var logId:String = null; public var length(default, null) = 0; public var numRemaining(default, null) = 0; var unfired = new MapVoid>(); var fired = new Array(); public function new (callback:Void->Void, logId:String = null) { this.callback = callback; this.logId = logId; } public function add(id = "untitled") { id = '$length:$id'; length++; numRemaining++; var func:Void->Void = null; func = function () { if (unfired.exists(id)) { unfired.remove(id); fired.push(id); numRemaining--; if (logId != null) log('fired $id, $numRemaining remaining'); if (numRemaining == 0) { if (logId != null) log('all callbacks fired'); callback(); } } else log('already fired $id'); } unfired[id] = func; return func; } inline function log(msg):Void { if (logId != null) trace('$logId: $msg'); } public function getFired() return fired.copy(); public function getUnfired() return [for (id in unfired) id]; }