From 6d5c5f5acb874d04534104ebcb8a479ce027ac8c Mon Sep 17 00:00:00 2001 From: EliteMasterEric <ericmyllyoja@gmail.com> Date: Mon, 26 Jun 2023 20:39:47 -0400 Subject: [PATCH] Refactor InitState plus fix a couple crash bugs --- source/Main.hx | 11 - source/funkin/InitState.hx | 375 +++++++++++++---------- source/funkin/PlayerSettings.hx | 10 +- source/funkin/TitleState.hx | 33 +- source/funkin/ui/story/StoryMenuState.hx | 2 +- 5 files changed, 224 insertions(+), 207 deletions(-) diff --git a/source/Main.hx b/source/Main.hx index 006b54e18..9b70549ab 100644 --- a/source/Main.hx +++ b/source/Main.hx @@ -77,17 +77,6 @@ class Main extends Sprite * -Eric */ - #if !debug - /** - * Someone was like "hey let's make a state that only runs code on debug builds" - * then put essential initialization code in it. - * The easiest fix is to make it run in all builds. - * -Eric - */ - // TODO: Fix this properly. - // initialState = funkin.TitleState; - #end - initHaxeUI(); addChild(new FlxGame(gameWidth, gameHeight, initialState, framerate, framerate, skipSplash, startFullscreen)); diff --git a/source/funkin/InitState.hx b/source/funkin/InitState.hx index 52bdb1015..4d74e1a05 100644 --- a/source/funkin/InitState.hx +++ b/source/funkin/InitState.hx @@ -6,52 +6,82 @@ import flixel.addons.transition.TransitionData; import flixel.graphics.FlxGraphic; import flixel.math.FlxPoint; import flixel.math.FlxRect; +import flixel.FlxSprite; import flixel.system.debug.log.LogStyle; import flixel.util.FlxColor; -import funkin.modding.module.ModuleHandler; -import funkin.play.character.CharacterData.CharacterDataParser; -import funkin.play.cutscene.dialogue.ConversationDataParser; -import funkin.play.cutscene.dialogue.DialogueBoxDataParser; -import funkin.play.cutscene.dialogue.SpeakerDataParser; -import funkin.play.event.SongEventData.SongEventParser; -import funkin.play.PlayState; -import funkin.play.song.SongData.SongDataParser; -import funkin.play.stage.StageData.StageDataParser; import funkin.ui.PreferencesMenu; import funkin.util.macro.MacroUtil; import funkin.util.WindowUtil; +import funkin.play.PlayStatePlaylist; import openfl.display.BitmapData; #if discord_rpc import Discord.DiscordClient; #end /** - * Initializes the game state using custom defines. - * Only used in Debug builds. + * The initialization state has several functions: + * - Calls code to set up the game, including loading saves and parsing game data. + * - Chooses whether to start via debug or via launching normally. */ class InitState extends FlxTransitionableState { - override public function create():Void + /** + * Perform a bunch of game setup, then immediately transition to the title screen. + */ + public override function create():Void + { + setupShit(); + + loadSaveData(); + + startGame(); + } + + /** + * Setup a bunch of important Flixel stuff. + */ + function setupShit() { // - // FLIXEL SETUP + // GAME SETUP // + + // Setup window events (like callbacks for onWindowClose) + WindowUtil.initWindowEvents(); + // Disable the thing on Windows where it tries to send a bug report to Microsoft because why do they care? + WindowUtil.disableCrashHandler(); + // This ain't a pixel art game! (most of the time) FlxSprite.defaultAntialiasing = true; - Application.current.onExit.add(function(exitCode) { - DiscordClient.shutdown(); - }); - #end + // Disable default keybinds for volume (we manually control volume in MusicBeatState with custom binds) + FlxG.sound.volumeUpKeys = []; + FlxG.sound.volumeDownKeys = []; + FlxG.sound.muteKeys = []; - // ==== flixel shit ==== // + // TODO: Make sure volume still saves/loads properly. + // if (FlxG.save.data.volume != null) FlxG.sound.volume = FlxG.save.data.volume; + // if (FlxG.save.data.mute != null) FlxG.sound.muted = FlxG.save.data.mute; + // Set the game to a lower frame rate while it is in the background. + FlxG.game.focusLostFramerate = 30; + + // + // FLIXEL DEBUG SETUP + // + #if debug + // Disable using ~ to open the console (we use that for the Editor menu) + FlxG.debugger.toggleKeys = [F2]; + + // Adds an additional Close Debugger button. // This big obnoxious white button is for MOBILE, so that you can press it // easily with your finger when debug bullshit pops up during testing lol! FlxG.debugger.addButton(LEFT, new BitmapData(200, 200), function() { FlxG.debugger.visible = false; }); + // Adds a red button to the debugger. + // This pauses the game AND the music! This ensures the Conductor stops. FlxG.debugger.addButton(CENTER, new BitmapData(20, 20, true, 0xFFCC2233), function() { if (FlxG.vcr.paused) { @@ -77,7 +107,8 @@ class InitState extends FlxTransitionableState } }); - #if FLX_DEBUG + // Adds a blue button to the debugger. + // This skips forward in the song. FlxG.debugger.addButton(CENTER, new BitmapData(20, 20, true, 0xFF2222CC), function() { FlxG.game.debugger.vcr.onStep(); @@ -90,175 +121,197 @@ class InitState extends FlxTransitionableState FlxG.sound.music.pause(); FlxG.sound.music.time += FlxG.elapsed * 1000; }); + + // Make errors and warnings less annoying. + // TODO: Disable this so we know to fix warnings. + if (false) + { + LogStyle.ERROR.openConsole = false; + LogStyle.ERROR.errorSound = null; + LogStyle.WARNING.openConsole = false; + LogStyle.WARNING.errorSound = null; + } #end - FlxG.sound.muteKeys = [ZERO]; - FlxG.game.focusLostFramerate = 60; - - // FlxG.stage.window.borderless = true; - // FlxG.stage.window.mouseLock = true; + // + // FLIXEL TRANSITIONS + // + // Diamond Transition var diamond:FlxGraphic = FlxGraphic.fromClass(GraphicTransTileDiamond); diamond.persist = true; diamond.destroyOnNoUse = false; - FlxTransitionableState.defaultTransIn = new TransitionData(FADE, FlxColor.BLACK, 1, new FlxPoint(0, -1), {asset: diamond, width: 32, height: 32}, - new FlxRect(-200, -200, FlxG.width * 1.4, FlxG.height * 1.4)); - FlxTransitionableState.defaultTransOut = new TransitionData(FADE, FlxColor.BLACK, 0.7, new FlxPoint(0, 1), {asset: diamond, width: 32, height: 32}, - new FlxRect(-200, -200, FlxG.width * 1.4, FlxG.height * 1.4)); - - // ===== save shit ===== // - - FlxG.save.bind('funkin', 'ninjamuffin99'); - - // https://github.com/HaxeFlixel/flixel/pull/2396 - // IF/WHEN MY PR GOES THRU AND IT GETS INTO MAIN FLIXEL, DELETE THIS CHUNKOF CODE, AND THEN UNCOMMENT THE LINE BELOW - // FlxG.sound.loadSavedPrefs(); - - if (FlxG.save.data.volume != null) FlxG.sound.volume = FlxG.save.data.volume; - if (FlxG.save.data.mute != null) FlxG.sound.muted = FlxG.save.data.mute; - - // Make errors and warnings less annoying. - LogStyle.ERROR.openConsole = false; - LogStyle.ERROR.errorSound = null; - LogStyle.WARNING.openConsole = false; - LogStyle.WARNING.errorSound = null; - - // FlxG.save.close(); - // FlxG.sound.loadSavedPrefs(); - WindowUtil.initWindowEvents(); - WindowUtil.disableCrashHandler(); - - PreferencesMenu.initPrefs(); - PlayerSettings.init(); - Highscore.load(); - - if (FlxG.save.data.weekUnlocked != null) - { - // FIX LATER!!! - // WEEK UNLOCK PROGRESSION!! - // StoryMenuState.weekUnlocked = FlxG.save.data.weekUnlocked; - - // if (StoryMenuState.weekUnlocked.length < 4) StoryMenuState.weekUnlocked.insert(0, true); - - // QUICK PATCH OOPS! - // if (!StoryMenuState.weekUnlocked[0]) StoryMenuState.weekUnlocked[0] = true; - } - - if (FlxG.save.data.seenVideo != null) VideoState.seenVideo = FlxG.save.data.seenVideo; - - // ===== fuck outta here ===== // - - // FlxTransitionableState.skipNextTransOut = true; + // FlxTransitionableState.defaultTransIn = new TransitionData(FADE, FlxColor.BLACK, 1, new FlxPoint(0, -1), {asset: diamond, width: 32, height: 32}, + // new FlxRect(-200, -200, FlxG.width * 1.4, FlxG.height * 1.4)); + // FlxTransitionableState.defaultTransOut = new TransitionData(FADE, FlxColor.BLACK, 0.7, new FlxPoint(0, 1), {asset: diamond, width: 32, height: 32}, + // new FlxRect(-200, -200, FlxG.width * 1.4, FlxG.height * 1.4)); + // Don't play transition in when entering the title state. FlxTransitionableState.skipNextTransIn = true; - // TODO: Register custom event callbacks here + // + // NEWGROUNDS API SETUP + // + #if newgrounds + NGio.init(); + #end + // + // DISCORD API SETUP + // + #if discord_rpc + DiscordClient.initialize(); + + Application.current.onExit.add(function(exitCode) { + DiscordClient.shutdown(); + }); + #end + + // + // ANDROID SETUP + // + #if android + FlxG.android.preventDefaultKeys = [flixel.input.android.FlxAndroidKey.BACK]; + #end + + // + // GAME DATA PARSING + // funkin.data.level.LevelRegistry.instance.loadEntries(); - SongEventParser.loadEventCache(); - ConversationDataParser.loadConversationCache(); - DialogueBoxDataParser.loadDialogueBoxCache(); - SpeakerDataParser.loadSpeakerCache(); - SongDataParser.loadSongCache(); - StageDataParser.loadStageCache(); - CharacterDataParser.loadCharacterCache(); - ModuleHandler.buildModuleCallbacks(); - ModuleHandler.loadModuleCache(); + funkin.play.event.SongEventData.SongEventParser.loadEventCache(); + funkin.play.cutscene.dialogue.ConversationDataParser.loadConversationCache(); + funkin.play.cutscene.dialogue.DialogueBoxDataParser.loadDialogueBoxCache(); + funkin.play.cutscene.dialogue.SpeakerDataParser.loadSpeakerCache(); + funkin.play.song.SongData.SongDataParser.loadSongCache(); + funkin.play.stage.StageData.StageDataParser.loadStageCache(); + funkin.play.character.CharacterData.CharacterDataParser.loadCharacterCache(); + funkin.modding.module.ModuleHandler.buildModuleCallbacks(); + funkin.modding.module.ModuleHandler.loadModuleCache(); - FlxG.debugger.toggleKeys = [F2]; + funkin.modding.module.ModuleHandler.callOnCreate(); + } - ModuleHandler.callOnCreate(); + /** + * Retrive and parse data from the user's save. + */ + function loadSaveData() + { + // Bind save data. + // TODO: Migrate save data to a better format. + FlxG.save.bind('funkin', 'ninjamuffin99'); - #if song - var song:String = getSong(); + // Load player options from save data. + PreferencesMenu.initPrefs(); + // Load controls from save data. + PlayerSettings.init(); + // Load highscores from save data. + Highscore.load(); + // TODO: Load level/character/cosmetic unlocks from save data. + } - var weeks:Array<Array<String>> = [ - ['bopeebo', 'fresh', 'dadbattle'], - ['spookeez', 'south', 'monster'], - ['spooky', 'spooky', 'monster'], - ['pico', 'philly', 'blammed'], - ['satin-panties', 'high', 'milf'], - ['cocoa', 'eggnog', 'winter-horrorland'], - ['senpai', 'roses', 'thorns'], - ['ugh', 'guns', 'stress'] - ]; - - var week:Int = 0; - for (i in 0...weeks.length) - { - if (weeks[i].contains(song)) - { - week = i + 1; - break; - } - } - - if (week == 0) throw 'Invalid -D song=$song'; - - startSong(week, song, false); - #elseif week - var week:Int = getWeek(); - - var songs:Array<String> = [ - 'bopeebo', - 'spookeez', - 'spooky', - 'pico', - 'satin-panties', - 'cocoa', - 'senpai', - 'ugh' - ]; - - if (week <= 0 || week >= songs.length) throw 'invalid -D week=' + week; - - startSong(week, songs[week - 1], true); - #elseif FREEPLAY + /** + * Start the game. + * + * By default, moves to the `TitleState`. + * But based on compile defines, the game can start immediately on a specific song, + * or immediately in a specific debug menu. + */ + function startGame():Void + { + #if SONG // -DSONG=bopeebo + startSong(defineSong(), defineDifficulty()); + #elseif LEVEL // -DLEVEL=week1 -DDIFFICULTY=hard + startLevel(defineLevel(), defineDifficulty()); + #elseif FREEPLAY // -DFREEPLAY FlxG.switchState(new FreeplayState()); - #elseif ANIMATE + #elseif ANIMATE // -DANIMATE FlxG.switchState(new funkin.ui.animDebugShit.FlxAnimateTest()); - #elseif CHARTING + #elseif CHARTING // -DCHARTING FlxG.switchState(new funkin.ui.debug.charting.ChartEditorState()); - #elseif STAGEBUILD - FlxG.switchState(new StageBuilderState()); - #elseif FIGHT - FlxG.switchState(new PicoFight()); - #elseif ANIMDEBUG + #elseif STAGEBUILD // -DSTAGEBUILD + FlxG.switchState(new funkin.ui.stageBullshit.StageBuilderState()); + #elseif ANIMDEBUG // -DANIMDEBUG FlxG.switchState(new funkin.ui.animDebugShit.DebugBoundingState()); - #elseif LATENCY - FlxG.switchState(new LatencyState()); - #elseif NETTEST - FlxG.switchState(new netTest.NetTest()); + #elseif LATENCY // -DLATENCY + FlxG.switchState(new funkin.LatencyState()); #else - FlxG.sound.cache(Paths.music('freakyMenu')); - FlxG.switchState(new TitleState()); + startGameNormally(); #end } - function startSong(week, song, isStoryMode):Void + /** + * Start the game by moving to the title state and play the game as normal. + */ + function startGameNormally():Void { - var dif:Int = getDif(); + FlxG.sound.cache(Paths.music('freakyMenu')); + FlxG.switchState(new TitleState()); + } - var targetDifficulty = switch (dif) + /** + * Start the game by directly loading into a specific song. + * @param songId + * @param difficultyId + */ + function startSong(songId:String, difficultyId:String = 'normal'):Void + { + var songData:funkin.play.song.Song = funkin.play.song.SongData.SongDataParser.fetchSong(songId); + + if (songData == null) { - case 0: 'easy'; - case 1: 'normal'; - case 2: 'hard'; - default: 'normal'; - }; - LoadingState.loadAndSwitchState(new PlayState( + startGameNormally(); + return; + } + + LoadingState.loadAndSwitchState(new funkin.play.PlayState( { - targetSong: SongDataParser.fetchSong(song), - targetDifficulty: targetDifficulty, + targetSong: songData, + targetDifficulty: difficultyId, })); } + + /** + * Start the game by directly loading into a specific story mode level. + * @param levelId + * @param difficultyId + */ + function startLevel(levelId:String, difficultyId:String = 'normal'):Void + { + var currentLevel:funkin.ui.story.Level = funkin.data.level.LevelRegistry.instance.fetchEntry(levelId); + + if (currentLevel == null) + { + startGameNormally(); + return; + } + + PlayStatePlaylist.playlistSongIds = currentLevel.getSongs(); + PlayStatePlaylist.isStoryMode = true; + PlayStatePlaylist.campaignScore = 0; + + var targetSongId:String = PlayStatePlaylist.playlistSongIds.shift(); + + var targetSong:funkin.play.song.Song = funkin.play.song.SongData.SongDataParser.fetchSong(targetSongId); + + LoadingState.loadAndSwitchState(new funkin.play.PlayState( + { + targetSong: targetSong, + targetDifficulty: difficultyId, + })); + } + + function defineSong():String + { + return MacroUtil.getDefine('SONG'); + } + + function defineLevel():String + { + return MacroUtil.getDefine('LEVEL'); + } + + function defineDifficulty():String + { + return MacroUtil.getDefine('DIFFICULTY'); + } } - -function getWeek():Int - return Std.parseInt(MacroUtil.getDefine('week')); - -function getSong():String - return MacroUtil.getDefine('song'); - -function getDif():Int - return Std.parseInt(MacroUtil.getDefine('dif', '1')); diff --git a/source/funkin/PlayerSettings.hx b/source/funkin/PlayerSettings.hx index 1b64d26c2..54fd559fb 100644 --- a/source/funkin/PlayerSettings.hx +++ b/source/funkin/PlayerSettings.hx @@ -26,8 +26,10 @@ class PlayerSettings // public var avatar:Player; // public var camera(get, never):PlayCamera; - function new(id) + function new(id:Int) { + trace('loading player settings for id: $id'); + this.id = id; this.controls = new Controls('player$id', None); @@ -52,7 +54,11 @@ class PlayerSettings } } - if (useDefault) controls.setKeyboardScheme(Solo); + if (useDefault) + { + trace("falling back to default control scheme"); + controls.setKeyboardScheme(Solo); + } // Apply loaded settings. PreciseInputManager.instance.initializeKeys(controls); diff --git a/source/funkin/TitleState.hx b/source/funkin/TitleState.hx index bd4e7084c..59845ed40 100644 --- a/source/funkin/TitleState.hx +++ b/source/funkin/TitleState.hx @@ -44,6 +44,7 @@ class TitleState extends MusicBeatState override public function create():Void { + super.create(); swagShader = new ColorSwap(); curWacky = FlxG.random.getObject(getIntroTextShit()); @@ -51,38 +52,6 @@ class TitleState extends MusicBeatState // DEBUG BULLSHIT - super.create(); - - /* - #elseif web - - - if (!initialized) - { - - video = new Video(); - FlxG.stage.addChild(video); - - var netConnection = new NetConnection(); - netConnection.connect(null); - - netStream = new NetStream(netConnection); - netStream.client = {onMetaData: client_onMetaData}; - netStream.addEventListener(AsyncErrorEvent.ASYNC_ERROR, netStream_onAsyncError); - netConnection.addEventListener(NetStatusEvent.NET_STATUS, netConnection_onNetStatus); - // netStream.addEventListener(NetStatusEvent.NET_STATUS) // netStream.play(Paths.file('music/kickstarterTrailer.mp4')); - - overlay = new Sprite(); - overlay.graphics.beginFill(0, 0.5); - overlay.graphics.drawRect(0, 0, 1280, 720); - overlay.addEventListener(MouseEvent.MOUSE_DOWN, overlay_onMouseDown); - - overlay.buttonMode = true; - // FlxG.stage.addChild(overlay); - - } - */ - // netConnection.addEventListener(MouseEvent.MOUSE_DOWN, overlay_onMouseDown); new FlxTimer().start(1, function(tmr:FlxTimer) { startIntro(); diff --git a/source/funkin/ui/story/StoryMenuState.hx b/source/funkin/ui/story/StoryMenuState.hx index d7f6db00d..f62e064e1 100644 --- a/source/funkin/ui/story/StoryMenuState.hx +++ b/source/funkin/ui/story/StoryMenuState.hx @@ -110,7 +110,7 @@ class StoryMenuState extends MusicBeatState transIn = FlxTransitionableState.defaultTransIn; transOut = FlxTransitionableState.defaultTransOut; - if (!FlxG.sound.music.playing) + if (FlxG.sound.music == null || !FlxG.sound.music.playing) { FlxG.sound.playMusic(Paths.music('freakyMenu')); FlxG.sound.music.fadeIn(4, 0, 0.7);