From 467ee623f12b27a881cd868ed1f4b21f0a188f64 Mon Sep 17 00:00:00 2001 From: Xeight Date: Wed, 8 Apr 2026 00:14:26 +0500 Subject: [PATCH 1/9] Freeplay tabs --- source/funkin/Mods.hx | 16 ++ source/funkin/data/Metadata.hx | 7 +- source/funkin/states/FreeplayState.hx | 275 +++++++++++++++++++------- 3 files changed, 228 insertions(+), 70 deletions(-) diff --git a/source/funkin/Mods.hx b/source/funkin/Mods.hx index 165ddde4..80e830e2 100644 --- a/source/funkin/Mods.hx +++ b/source/funkin/Mods.hx @@ -83,6 +83,11 @@ typedef ModMeta = var ?comboPrefix:String; var ?ratingsPrefix:String; var ?countdownPrefix:String; + + /** + * Mod's Freeplay data + **/ + var ?freeplayData:FreeplayData; } typedef ModsList = @@ -92,6 +97,17 @@ typedef ModsList = var all:Array; } +typedef FreeplayData = +{ + var tabs:Array; +} + +typedef FreeplayTab = +{ + var title:String; + var songs:Array; +} + // add docs later class Mods diff --git a/source/funkin/data/Metadata.hx b/source/funkin/data/Metadata.hx index edd1ef48..199bba37 100644 --- a/source/funkin/data/Metadata.hx +++ b/source/funkin/data/Metadata.hx @@ -10,7 +10,12 @@ typedef MetaVariables = ?composers:Array, ?charters:Array, ?artists:Array, - ?coders:Array + ?coders:Array, + + ?displayName:String, + + ?freeplayColor:String, + ?freeplayIcon:String, } // if u want to do to it hardcoded u can just fuckin go var meta:Metadata = {composers: 'penis'}; //blalblalbla diff --git a/source/funkin/states/FreeplayState.hx b/source/funkin/states/FreeplayState.hx index 8b0d4d16..ed142c90 100644 --- a/source/funkin/states/FreeplayState.hx +++ b/source/funkin/states/FreeplayState.hx @@ -13,6 +13,8 @@ import flixel.util.FlxColor; import flixel.tweens.FlxTween; import funkin.backend.Difficulty; +import funkin.Mods; +import funkin.data.Metadata; import funkin.states.editors.ChartEditorState; import funkin.data.WeekData; import funkin.states.*; @@ -30,6 +32,10 @@ class FreeplayState extends MusicBeatState public var songs:Array = []; + public var freeplayTabs:Array = []; + + public static var currentTab:Int = 0; + public var selector:FlxText; public static var curSelected:Int = 0; @@ -41,6 +47,7 @@ class FreeplayState extends MusicBeatState public var scoreBG:FlxSprite; public var scoreText:FlxText; public var diffText:FlxText; + public var tabText:FlxText; public var lerpScore:Int = 0; public var lerpRating:Float = 0; public var intendedScore:Int = 0; @@ -66,39 +73,18 @@ class FreeplayState extends MusicBeatState DiscordClient.changePresence("In the Menus"); - if (WeekData.weeksList.length == 0) + loadFreeplayData(); + + if (WeekData.weeksList.length == 0 && freeplayTabs.length == 0) { CoolUtil.setTransSkip(true, false); persistentUpdate = false; - FlxG.switchState(() -> new FallbackState('Cannot load Freeplay as there are no weeks loaded.', () -> FlxG.switchState(MainMenuState.new))); + FlxG.switchState(() -> new FallbackState('Cannot load Freeplay as there are no weeks or tabs loaded.', () -> FlxG.switchState(MainMenuState.new))); return; } - for (i in 0...WeekData.weeksList.length) - { - if (weekIsLocked(WeekData.weeksList[i])) continue; - - var leWeek:WeekData = WeekData.weeksLoaded.get(WeekData.weeksList[i]); - var leSongs:Array = []; - var leChars:Array = []; - - for (j in 0...leWeek.songs.length) - { - leSongs.push(leWeek.songs[j][0]); - leChars.push(leWeek.songs[j][1]); - } - - WeekData.setDirectoryFromWeek(leWeek); - for (song in leWeek.songs) - { - var colors:Array = song[2]; - if (colors == null || colors.length < 3) - { - colors = [146, 113, 253]; - } - addSong(song[0], i, song[1], FlxColor.fromRGB(colors[0], colors[1], colors[2])); - } - } + if (freeplayTabs.length == 0) loadFreeplayFromWeeks(); + initStateScript(); scriptGroup.set('SongMetadata', SongMetadata); @@ -111,38 +97,11 @@ class FreeplayState extends MusicBeatState grpSongs = new FlxTypedGroup(); add(grpSongs); - for (i in 0...songs.length) - { - var songText:Alphabet = new Alphabet(0, (70 * i) + 30, songs[i].songName, true, false); - songText.isMenuItem = true; - songText.targetY = i; - grpSongs.add(songText); - - if (songText.width > 980) - { - var textScale:Float = 980 / songText.width; - songText.scale.x = textScale; - for (letter in songText.lettersArray) - { - letter.x *= textScale; - letter.offset.x *= textScale; - } - } - - Mods.currentModDirectory = songs[i].folder; - var icon:HealthIcon = new HealthIcon(songs[i].songCharacter); - icon.sprTracker = songText; - - // using a FlxGroup is too much fuss! - iconArray.push(icon); - add(icon); - } - WeekData.setDirectoryFromWeek(); - scoreText = new FlxText(0, 5, FlxG.width - 6, "", 32); scoreText.setFormat(Paths.DEFAULT_FONT, 32, FlxColor.WHITE, RIGHT); - scoreBG = new FlxSprite(scoreText.x - 6, 0).makeGraphic(1, 66, 0xFF000000); + var scoreBGSize:Int = freeplayTabs.length > 0 ? 99 : 66; + scoreBG = new FlxSprite(scoreText.x - 6, 0).makeGraphic(1, scoreBGSize, 0xFF000000); scoreBG.alpha = 0.6; add(scoreBG); @@ -150,17 +109,11 @@ class FreeplayState extends MusicBeatState diffText.font = scoreText.font; add(diffText); - add(scoreText); - - if (curSelected >= songs.length) curSelected = 0; - bg.color = songs[curSelected].color; - intendedColor = bg.color; + tabText = new FlxText(diffText.x, diffText.y + 32, 0, 24); + tabText.font = scoreText.font; + if (freeplayTabs.length > 0) add(tabText); - if (lastDifficultyName == '') - { - lastDifficultyName = Difficulty.defaultDifficulty; - } - curDifficulty = Math.round(Math.max(0, Difficulty.defaultDifficulties.indexOf(lastDifficultyName))); + add(scoreText); var textBG:FlxSprite = new FlxSprite(0, FlxG.height - 26).makeGraphic(FlxG.width, 26, 0xFF000000); textBG.alpha = 0.6; @@ -184,9 +137,25 @@ class FreeplayState extends MusicBeatState debugTxt.screenCenter(Y); add(debugTxt); + if (freeplayTabs.length > 0) loadTab(0); + else createSongs(); + WeekData.setDirectoryFromWeek(); + + if (freeplayTabs.length > 0) changeTab(); + changeSelection(); changeDiff(); + if (curSelected >= songs.length) curSelected = 0; + bg.color = songs[curSelected].color; + intendedColor = bg.color; + + if (lastDifficultyName == '') + { + lastDifficultyName = Difficulty.defaultDifficulty; + } + curDifficulty = Math.round(Math.max(0, Difficulty.defaultDifficulties.indexOf(lastDifficultyName))); + super.create(); scriptGroup.call('onCreate', []); } @@ -198,9 +167,39 @@ class FreeplayState extends MusicBeatState super.closeSubState(); } - public function addSong(songName:String, weekNum:Int, songCharacter:String, color:Int) + function createSongs() { - songs.push(new SongMetadata(songName, weekNum, songCharacter, color)); + for (i in 0...songs.length) + { + var songText:Alphabet = new Alphabet(0, (70 * i) + 30, songs[i].displayName, true, false); + songText.isMenuItem = true; + songText.targetY = i; + grpSongs.add(songText); + + if (songText.width > 980) + { + var textScale:Float = 980 / songText.width; + songText.scale.x = textScale; + for (letter in songText.lettersArray) + { + letter.x *= textScale; + letter.offset.x *= textScale; + } + } + + Mods.currentModDirectory = songs[i].folder; + var icon:HealthIcon = new HealthIcon(songs[i].songCharacter); + icon.sprTracker = songText; + + // using a FlxGroup is too much fuss! + iconArray.push(icon); + add(icon); + } + } + + public function addSong(songName:String, displayName:String, weekNum:Int, songCharacter:String, color:Int) + { + songs.push(new SongMetadata(songName, displayName, weekNum, songCharacter, color)); } function weekIsLocked(name:String):Bool @@ -247,6 +246,17 @@ class FreeplayState extends MusicBeatState var shiftMult:Int = 1; if (FlxG.keys.pressed.SHIFT) shiftMult = 3; + if (freeplayTabs.length > 1) + { + if (FlxG.keys.justPressed.TAB) + { + if (FlxG.keys.pressed.SHIFT) changeTab(-1); + else changeTab(1); + + changeSelection(); + } + } + if (songs.length > 1) { if (controls.UI_UP_P) @@ -395,6 +405,93 @@ class FreeplayState extends MusicBeatState vocals = null; } + function loadFreeplayData() + { + var mods:Array<{folder:String, enabled:Bool}> = Mods.getListAsArray(); + + for (i in mods) + { + if (!i.enabled) continue; + + var modMeta:ModMeta = Mods.getPack(i.folder); + + if (modMeta.freeplayData != null) + { + for (i in 0...modMeta.freeplayData.tabs.length) + { + freeplayTabs.push(modMeta.freeplayData.tabs[i]); + } + } + } + } + + function loadFreeplayFromWeeks() + { + for (i in 0...WeekData.weeksList.length) + { + if (weekIsLocked(WeekData.weeksList[i])) continue; + + var leWeek:WeekData = WeekData.weeksLoaded.get(WeekData.weeksList[i]); + var leSongs:Array = []; + var leChars:Array = []; + + for (j in 0...leWeek.songs.length) + { + leSongs.push(leWeek.songs[j][0]); + leChars.push(leWeek.songs[j][1]); + } + + WeekData.setDirectoryFromWeek(leWeek); + for (song in leWeek.songs) + { + var colors:Array = song[2]; + if (colors == null || colors.length < 3) + { + colors = [146, 113, 253]; + } + addSong(song[0], song[0], i, song[1], FlxColor.fromRGB(colors[0], colors[1], colors[2])); + } + } + } + + function getSongMeta(song:String) + { + var songMeta:Metadata.MetaVariables = null; + + // For some reason Metadata.getDirect() only accepts a path without the .json suffix + // Which is kinda hard to get without jank, so this is just easier at this point + var songMetaPath:String = Paths.json('$song/data/meta'); + if (FunkinAssets.exists(songMetaPath)) + { + songMeta = FunkinAssets.parseJson(FunkinAssets.getContent(songMetaPath)); + return songMeta; + } + + return null; + } + + function loadTab(tab:Int) + { + var tab = freeplayTabs[tab]; + for (song in tab.songs) + { + var displayName:String = song; + var icon:String = "face"; + var weekNum:Int = 0; + var color:String = "#8DA399"; + + var songMeta = getSongMeta(song); + if (songMeta != null) + { + if (songMeta.displayName != null) displayName = songMeta.displayName; + if (songMeta.freeplayIcon != null) icon = songMeta.freeplayIcon; + if (songMeta.freeplayColor != null) color = songMeta.freeplayColor; + } + + addSong(song, displayName, weekNum, icon, FlxColor.fromString(color)); + } + } + function changeDiff(change:Int = 0) { debugBG.alpha = 0; @@ -495,26 +592,66 @@ class FreeplayState extends MusicBeatState } } + function changeTab(diff:Int = 0) + { + if (diff != 0) FlxG.sound.play(Paths.sound('scrollMenu'), 0.4); + + currentTab = FlxMath.wrap(currentTab + diff, 0, freeplayTabs.length - 1); + tabText.text = "[ " + freeplayTabs[currentTab].title + " ]"; + + clearSongs(); + + loadTab(currentTab); + + curSelected = Std.int(Math.min(curSelected, freeplayTabs[currentTab].songs.length - 1)); + + createSongs(); + } + + function clearSongs() + { + songs = []; + + if (grpSongs != null) + { + grpSongs.forEach((t) -> { + t.destroy(); + }); + grpSongs.clear(); + } + + if (iconArray != null && iconArray.length != 0) + { + for (i in iconArray) + i.kill(); + } + iconArray = []; + } + private function positionHighscore() { scoreBG.scale.x = scoreText.textField.textWidth + 12 + 6; scoreBG.x = FlxG.width - (scoreBG.scale.x / 2); diffText.x = Std.int(scoreBG.x + (scoreBG.width / 2)); diffText.x -= diffText.textField.textWidth / 2; + tabText.x = Std.int(scoreBG.x + (scoreBG.width / 2)); + tabText.x -= tabText.textField.textWidth / 2; } } class SongMetadata { + public var displayName:String = ""; public var songName:String = ""; public var week:Int = 0; public var songCharacter:String = ""; public var color:Int = -7179779; public var folder:String = ""; - public function new(song:String, week:Int, songCharacter:String, color:Int) + public function new(song:String, displayName:String, week:Int, songCharacter:String, color:Int) { this.songName = song; + this.displayName = displayName; this.week = week; this.songCharacter = songCharacter; this.color = color; From eacf5920f5e91327d9fd6f453de2d5b3066caf54 Mon Sep 17 00:00:00 2001 From: Xeight Date: Wed, 8 Apr 2026 13:48:32 +0500 Subject: [PATCH 2/9] made it grab data from a freeplay.json file --- source/funkin/Mods.hx | 16 ---------- source/funkin/states/FreeplayState.hx | 43 ++++++++++++++++++++------- 2 files changed, 32 insertions(+), 27 deletions(-) diff --git a/source/funkin/Mods.hx b/source/funkin/Mods.hx index 80e830e2..165ddde4 100644 --- a/source/funkin/Mods.hx +++ b/source/funkin/Mods.hx @@ -83,11 +83,6 @@ typedef ModMeta = var ?comboPrefix:String; var ?ratingsPrefix:String; var ?countdownPrefix:String; - - /** - * Mod's Freeplay data - **/ - var ?freeplayData:FreeplayData; } typedef ModsList = @@ -97,17 +92,6 @@ typedef ModsList = var all:Array; } -typedef FreeplayData = -{ - var tabs:Array; -} - -typedef FreeplayTab = -{ - var title:String; - var songs:Array; -} - // add docs later class Mods diff --git a/source/funkin/states/FreeplayState.hx b/source/funkin/states/FreeplayState.hx index ed142c90..39ae7f38 100644 --- a/source/funkin/states/FreeplayState.hx +++ b/source/funkin/states/FreeplayState.hx @@ -139,6 +139,7 @@ class FreeplayState extends MusicBeatState if (freeplayTabs.length > 0) loadTab(0); else createSongs(); + WeekData.setDirectoryFromWeek(); if (freeplayTabs.length > 0) changeTab(); @@ -413,14 +414,13 @@ class FreeplayState extends MusicBeatState { if (!i.enabled) continue; - var modMeta:ModMeta = Mods.getPack(i.folder); + var freeplayData = getFreeplayData(i.folder); + Mods.currentModDirectory = i.folder; - if (modMeta.freeplayData != null) + if (freeplayData == null) continue; + for (i in 0...freeplayData.tabs.length) { - for (i in 0...modMeta.freeplayData.tabs.length) - { - freeplayTabs.push(modMeta.freeplayData.tabs[i]); - } + freeplayTabs.push(freeplayData.tabs[i]); } } } @@ -456,21 +456,31 @@ class FreeplayState extends MusicBeatState function getSongMeta(song:String) { - var songMeta:Metadata.MetaVariables = null; - // For some reason Metadata.getDirect() only accepts a path without the .json suffix // Which is kinda hard to get without jank, so this is just easier at this point - var songMetaPath:String = Paths.json('$song/data/meta'); + final songMetaPath:String = Paths.json('$song/data/meta'); if (FunkinAssets.exists(songMetaPath)) { - songMeta = FunkinAssets.parseJson(FunkinAssets.getContent(songMetaPath)); + var songMeta:Metadata.MetaVariables = FunkinAssets.parseJson(FunkinAssets.getContent(songMetaPath)); return songMeta; } return null; } - function loadTab(tab:Int) + function getFreeplayData(modFolder:String):FreeplayData + { + final freeplayDataPath = Paths.getPath('data/freeplay.json', modFolder, true); + if (FunkinAssets.exists(freeplayDataPath)) + { + var freeplayData:FreeplayData = FunkinAssets.parseJson(FunkinAssets.getContent(freeplayDataPath)); + return freeplayData; + } + + return null; + } + + function loadTab(tab:Int):Void { var tab = freeplayTabs[tab]; for (song in tab.songs) @@ -659,3 +669,14 @@ class SongMetadata if (this.folder == null) this.folder = ''; } } + +typedef FreeplayData = +{ + var tabs:Array; +} + +typedef FreeplayTab = +{ + var title:String; + var songs:Array; +} From 9343cf8cb4b67e179586ce8a74a6df3c0f75dbae Mon Sep 17 00:00:00 2001 From: Xeight Date: Wed, 8 Apr 2026 14:19:57 +0500 Subject: [PATCH 3/9] fix crash if freeplay json is formatted incorrectly + move tab name a bit up to look better --- source/funkin/states/FreeplayState.hx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/source/funkin/states/FreeplayState.hx b/source/funkin/states/FreeplayState.hx index 39ae7f38..b9330344 100644 --- a/source/funkin/states/FreeplayState.hx +++ b/source/funkin/states/FreeplayState.hx @@ -109,7 +109,7 @@ class FreeplayState extends MusicBeatState diffText.font = scoreText.font; add(diffText); - tabText = new FlxText(diffText.x, diffText.y + 32, 0, 24); + tabText = new FlxText(diffText.x, diffText.y + 28, 0, 24); tabText.font = scoreText.font; if (freeplayTabs.length > 0) add(tabText); @@ -418,6 +418,7 @@ class FreeplayState extends MusicBeatState Mods.currentModDirectory = i.folder; if (freeplayData == null) continue; + if (freeplayData.tabs == null) continue; for (i in 0...freeplayData.tabs.length) { freeplayTabs.push(freeplayData.tabs[i]); From 881a18b356292a2075217c6cdf690d05a5a940b9 Mon Sep 17 00:00:00 2001 From: Xeight Date: Wed, 8 Apr 2026 18:32:31 +0500 Subject: [PATCH 4/9] add tab keybind hint to freeplay --- source/funkin/states/FreeplayState.hx | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/source/funkin/states/FreeplayState.hx b/source/funkin/states/FreeplayState.hx index b9330344..ae0e4cae 100644 --- a/source/funkin/states/FreeplayState.hx +++ b/source/funkin/states/FreeplayState.hx @@ -48,6 +48,7 @@ class FreeplayState extends MusicBeatState public var scoreText:FlxText; public var diffText:FlxText; public var tabText:FlxText; + public var tabHint:FlxText; public var lerpScore:Int = 0; public var lerpRating:Float = 0; public var intendedScore:Int = 0; @@ -100,7 +101,7 @@ class FreeplayState extends MusicBeatState scoreText = new FlxText(0, 5, FlxG.width - 6, "", 32); scoreText.setFormat(Paths.DEFAULT_FONT, 32, FlxColor.WHITE, RIGHT); - var scoreBGSize:Int = freeplayTabs.length > 0 ? 99 : 66; + var scoreBGSize:Int = freeplayTabs.length > 0 ? 132 : 66; scoreBG = new FlxSprite(scoreText.x - 6, 0).makeGraphic(1, scoreBGSize, 0xFF000000); scoreBG.alpha = 0.6; add(scoreBG); @@ -113,6 +114,12 @@ class FreeplayState extends MusicBeatState tabText.font = scoreText.font; if (freeplayTabs.length > 0) add(tabText); + tabHint = new FlxText(tabText.x, tabText.y + 28, 0, 24); + tabHint.font = scoreText.font; + tabHint.text = "Press TAB to switch tabs."; + tabHint.color = FlxColor.GRAY; + if (freeplayTabs.length > 0) add(tabHint); + add(scoreText); var textBG:FlxSprite = new FlxSprite(0, FlxG.height - 26).makeGraphic(FlxG.width, 26, 0xFF000000); @@ -647,6 +654,8 @@ class FreeplayState extends MusicBeatState diffText.x -= diffText.textField.textWidth / 2; tabText.x = Std.int(scoreBG.x + (scoreBG.width / 2)); tabText.x -= tabText.textField.textWidth / 2; + tabHint.x = Std.int(scoreBG.x + (scoreBG.width / 2)); + tabHint.x -= tabHint.textField.textWidth / 2; } } From 1ea6240acb929d6dfe7738592cef7746e2abc103 Mon Sep 17 00:00:00 2001 From: data5 <99661153+FixedData@users.noreply.github.com> Date: Wed, 8 Apr 2026 15:15:46 -0600 Subject: [PATCH 5/9] add these but kill them if the length is 0 --- source/funkin/states/FreeplayState.hx | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/source/funkin/states/FreeplayState.hx b/source/funkin/states/FreeplayState.hx index ae0e4cae..3a79d269 100644 --- a/source/funkin/states/FreeplayState.hx +++ b/source/funkin/states/FreeplayState.hx @@ -112,13 +112,19 @@ class FreeplayState extends MusicBeatState tabText = new FlxText(diffText.x, diffText.y + 28, 0, 24); tabText.font = scoreText.font; - if (freeplayTabs.length > 0) add(tabText); + add(tabText); tabHint = new FlxText(tabText.x, tabText.y + 28, 0, 24); tabHint.font = scoreText.font; tabHint.text = "Press TAB to switch tabs."; tabHint.color = FlxColor.GRAY; - if (freeplayTabs.length > 0) add(tabHint); + add(tabHint); + + if (freeplayTabs.length == 0) + { + tabText.kill(); + tabHint.kill(); + } add(scoreText); @@ -654,8 +660,8 @@ class FreeplayState extends MusicBeatState diffText.x -= diffText.textField.textWidth / 2; tabText.x = Std.int(scoreBG.x + (scoreBG.width / 2)); tabText.x -= tabText.textField.textWidth / 2; - tabHint.x = Std.int(scoreBG.x + (scoreBG.width / 2)); - tabHint.x -= tabHint.textField.textWidth / 2; + tabHint.x = Std.int(scoreBG.x + (scoreBG.width / 2)); + tabHint.x -= tabHint.textField.textWidth / 2; } } From 675011d686eae4ae031ef2f6a029c661d1427f7b Mon Sep 17 00:00:00 2001 From: data5 <99661153+FixedData@users.noreply.github.com> Date: Wed, 8 Apr 2026 15:17:30 -0600 Subject: [PATCH 6/9] tabs title can be null --- source/funkin/states/FreeplayState.hx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/funkin/states/FreeplayState.hx b/source/funkin/states/FreeplayState.hx index 3a79d269..09257083 100644 --- a/source/funkin/states/FreeplayState.hx +++ b/source/funkin/states/FreeplayState.hx @@ -621,7 +621,7 @@ class FreeplayState extends MusicBeatState if (diff != 0) FlxG.sound.play(Paths.sound('scrollMenu'), 0.4); currentTab = FlxMath.wrap(currentTab + diff, 0, freeplayTabs.length - 1); - tabText.text = "[ " + freeplayTabs[currentTab].title + " ]"; + tabText.text = "[ " + (freeplayTabs[currentTab].title ?? 'Unknown') + " ]"; clearSongs(); @@ -693,6 +693,6 @@ typedef FreeplayData = typedef FreeplayTab = { - var title:String; + var ?title:String; var songs:Array; } From 2a7d271d15825b532e5536b14647752e21ae0bfe Mon Sep 17 00:00:00 2001 From: data5 <99661153+FixedData@users.noreply.github.com> Date: Wed, 8 Apr 2026 15:20:41 -0600 Subject: [PATCH 7/9] updatefreeplaydata mark them as potentially nullable and use json5 parsing --- source/funkin/states/FreeplayState.hx | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/source/funkin/states/FreeplayState.hx b/source/funkin/states/FreeplayState.hx index 09257083..370944d4 100644 --- a/source/funkin/states/FreeplayState.hx +++ b/source/funkin/states/FreeplayState.hx @@ -468,30 +468,20 @@ class FreeplayState extends MusicBeatState } } - function getSongMeta(song:String) + function getSongMeta(song:String):Null { // For some reason Metadata.getDirect() only accepts a path without the .json suffix // Which is kinda hard to get without jank, so this is just easier at this point final songMetaPath:String = Paths.json('$song/data/meta'); - if (FunkinAssets.exists(songMetaPath)) - { - var songMeta:Metadata.MetaVariables = FunkinAssets.parseJson(FunkinAssets.getContent(songMetaPath)); - return songMeta; - } - return null; + return FunkinAssets.exists(songMetaPath) ? FunkinAssets.parseJson5(FunkinAssets.getContent(songMetaPath)) : null; } - function getFreeplayData(modFolder:String):FreeplayData + function getFreeplayData(modFolder:String):Null { final freeplayDataPath = Paths.getPath('data/freeplay.json', modFolder, true); - if (FunkinAssets.exists(freeplayDataPath)) - { - var freeplayData:FreeplayData = FunkinAssets.parseJson(FunkinAssets.getContent(freeplayDataPath)); - return freeplayData; - } - return null; + return FunkinAssets.exists(freeplayDataPath) ? FunkinAssets.parseJson5(FunkinAssets.getContent(freeplayDataPath)) : null; } function loadTab(tab:Int):Void From 5dbf35cfbda7d22320d938a9d305989b8a603408 Mon Sep 17 00:00:00 2001 From: data5 <99661153+FixedData@users.noreply.github.com> Date: Wed, 8 Apr 2026 15:22:07 -0600 Subject: [PATCH 8/9] Update FreeplayState.hx --- source/funkin/states/FreeplayState.hx | 8 -------- 1 file changed, 8 deletions(-) diff --git a/source/funkin/states/FreeplayState.hx b/source/funkin/states/FreeplayState.hx index 370944d4..aa6d0ef9 100644 --- a/source/funkin/states/FreeplayState.hx +++ b/source/funkin/states/FreeplayState.hx @@ -446,14 +446,6 @@ class FreeplayState extends MusicBeatState if (weekIsLocked(WeekData.weeksList[i])) continue; var leWeek:WeekData = WeekData.weeksLoaded.get(WeekData.weeksList[i]); - var leSongs:Array = []; - var leChars:Array = []; - - for (j in 0...leWeek.songs.length) - { - leSongs.push(leWeek.songs[j][0]); - leChars.push(leWeek.songs[j][1]); - } WeekData.setDirectoryFromWeek(leWeek); for (song in leWeek.songs) From 2baa0f6ab749594c18fd6500f0caffebe5e80abf Mon Sep 17 00:00:00 2001 From: data5 <99661153+FixedData@users.noreply.github.com> Date: Wed, 8 Apr 2026 15:43:37 -0600 Subject: [PATCH 9/9] update freeplay improve the cleanup only show tabHint if there is more than 1 tab --- source/funkin/states/FreeplayState.hx | 25 ++++++++++--------------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/source/funkin/states/FreeplayState.hx b/source/funkin/states/FreeplayState.hx index aa6d0ef9..f10ca9f9 100644 --- a/source/funkin/states/FreeplayState.hx +++ b/source/funkin/states/FreeplayState.hx @@ -101,8 +101,9 @@ class FreeplayState extends MusicBeatState scoreText = new FlxText(0, 5, FlxG.width - 6, "", 32); scoreText.setFormat(Paths.DEFAULT_FONT, 32, FlxColor.WHITE, RIGHT); - var scoreBGSize:Int = freeplayTabs.length > 0 ? 132 : 66; - scoreBG = new FlxSprite(scoreText.x - 6, 0).makeGraphic(1, scoreBGSize, 0xFF000000); + final scoreBGSize = 66 + 33 * (Math.min(freeplayTabs.length, 2)); + + scoreBG = new FlxSprite(scoreText.x - 6, 0).makeScaledGraphic(1, scoreBGSize, 0xFF000000); scoreBG.alpha = 0.6; add(scoreBG); @@ -120,11 +121,9 @@ class FreeplayState extends MusicBeatState tabHint.color = FlxColor.GRAY; add(tabHint); - if (freeplayTabs.length == 0) - { - tabText.kill(); - tabHint.kill(); - } + if (freeplayTabs.length <= 1) tabHint.kill(); + + if (freeplayTabs.length == 0) tabText.kill(); add(scoreText); @@ -620,17 +619,13 @@ class FreeplayState extends MusicBeatState if (grpSongs != null) { - grpSongs.forEach((t) -> { - t.destroy(); - }); + grpSongs.forEach(song -> song?.destroy()); + grpSongs.clear(); } - if (iconArray != null && iconArray.length != 0) - { - for (i in iconArray) - i.kill(); - } + iconArray = FlxDestroyUtil.destroyArray(iconArray); + iconArray = []; }