diff --git a/hmm.json b/hmm.json index 0dfe88ded..641ef1bbd 100644 --- a/hmm.json +++ b/hmm.json @@ -139,7 +139,7 @@ "name": "openfl", "type": "git", "dir": null, - "ref": "f229d76361c7e31025a048fe7909847f75bb5d5e", + "ref": "228c1b5063911e2ad75cef6e3168ef0a4b9f9134", "url": "https://github.com/FunkinCrew/openfl" }, { diff --git a/source/funkin/play/PauseSubState.hx b/source/funkin/play/PauseSubState.hx index f1375cc63..fc1d01377 100644 --- a/source/funkin/play/PauseSubState.hx +++ b/source/funkin/play/PauseSubState.hx @@ -441,7 +441,7 @@ class PauseSubState extends MusicBeatSubState var entries:Array = []; if (PlayState.instance.currentChart != null) { - var difficultiesInVariation = PlayState.instance.currentSong.listDifficulties(PlayState.instance.currentChart.variation); + var difficultiesInVariation = PlayState.instance.currentSong.listDifficulties(PlayState.instance.currentChart.variation, true); trace('DIFFICULTIES: ${difficultiesInVariation}'); for (difficulty in difficultiesInVariation) { diff --git a/source/funkin/play/PlayState.hx b/source/funkin/play/PlayState.hx index e3e1f974d..cb1cacbc1 100644 --- a/source/funkin/play/PlayState.hx +++ b/source/funkin/play/PlayState.hx @@ -2576,7 +2576,7 @@ class PlayState extends MusicBeatSubState // If daRating is 'miss', that means we made a mistake and should not continue. FlxG.log.warn('popUpScore judged a note as a miss!'); // TODO: Remove this. - comboPopUps.displayRating('miss'); + // comboPopUps.displayRating('miss'); return; } @@ -2857,7 +2857,7 @@ class PlayState extends MusicBeatSubState FlxTransitionableState.skipNextTransIn = true; FlxTransitionableState.skipNextTransOut = true; - FlxG.sound.music.stop(); + if (FlxG.sound.music != null) FlxG.sound.music.stop(); vocals.stop(); // TODO: Softcode this cutscene. diff --git a/source/funkin/play/song/Song.hx b/source/funkin/play/song/Song.hx index 0248e09ee..d219dc2f6 100644 --- a/source/funkin/play/song/Song.hx +++ b/source/funkin/play/song/Song.hx @@ -404,11 +404,12 @@ class Song implements IPlayStateScriptedClass implements IRegistryEntry, showHidden:Bool = false):Array + public function listDifficulties(?variationId:String, ?variationIds:Array, showLocked:Bool = false, showHidden:Bool = false):Array { if (variationIds == null) variationIds = []; if (variationId != null) variationIds.push(variationId); diff --git a/source/funkin/save/Save.hx b/source/funkin/save/Save.hx index dc7c5f989..af2730ddd 100644 --- a/source/funkin/save/Save.hx +++ b/source/funkin/save/Save.hx @@ -9,6 +9,7 @@ import funkin.save.migrator.SaveDataMigrator; import funkin.ui.debug.charting.ChartEditorState.ChartEditorLiveInputStyle; import funkin.ui.debug.charting.ChartEditorState.ChartEditorTheme; import thx.semver.Version; +import funkin.util.SerializerUtil; @:nullSafety class Save @@ -391,6 +392,22 @@ class Save */ public function getLevelScore(levelId:String, difficultyId:String = 'normal'):Null { + if (data.scores?.levels == null) + { + if (data.scores == null) + { + data.scores = + { + songs: [], + levels: [] + }; + } + else + { + data.scores.levels = []; + } + } + var level = data.scores.levels.get(levelId); if (level == null) { @@ -641,6 +658,9 @@ class Save { trace("[SAVE] Loading save from slot " + slot + "..."); + // Prevent crashes if the save data is corrupted. + SerializerUtil.initSerializer(); + FlxG.save.bind('$SAVE_NAME${slot}', SAVE_PATH); if (FlxG.save.isEmpty()) diff --git a/source/funkin/ui/debug/charting/handlers/ChartEditorImportExportHandler.hx b/source/funkin/ui/debug/charting/handlers/ChartEditorImportExportHandler.hx index 557875596..0308cd871 100644 --- a/source/funkin/ui/debug/charting/handlers/ChartEditorImportExportHandler.hx +++ b/source/funkin/ui/debug/charting/handlers/ChartEditorImportExportHandler.hx @@ -73,7 +73,7 @@ class ChartEditorImportExportHandler state.loadInstFromAsset(Paths.inst(songId, '-$variation'), variation); } - for (difficultyId in song.listDifficulties(variation)) + for (difficultyId in song.listDifficulties(variation, true, true)) { var diff:Null = song.getDifficulty(difficultyId, variation); if (diff == null) continue; diff --git a/source/funkin/ui/debug/charting/handlers/ChartEditorToolboxHandler.hx b/source/funkin/ui/debug/charting/handlers/ChartEditorToolboxHandler.hx index 8c7b1a8c1..f82bc3c1f 100644 --- a/source/funkin/ui/debug/charting/handlers/ChartEditorToolboxHandler.hx +++ b/source/funkin/ui/debug/charting/handlers/ChartEditorToolboxHandler.hx @@ -308,16 +308,6 @@ class ChartEditorToolboxHandler state.playtestBotPlayMode = checkboxBotPlay.selected; }; - var checkboxDebugger:Null = toolbox.findComponent('playtestDebuggerCheckbox', CheckBox); - - if (checkboxDebugger == null) throw 'ChartEditorToolboxHandler.buildToolboxPlaytestPropertiesLayout() - Could not find playtestDebuggerCheckbox component.'; - - state.enabledDebuggerPopup = checkboxDebugger.selected; - - checkboxDebugger.onClick = _ -> { - state.enabledDebuggerPopup = checkboxDebugger.selected; - }; - var checkboxSongScripts:Null = toolbox.findComponent('playtestSongScriptsCheckbox', CheckBox); if (checkboxSongScripts == null) diff --git a/source/funkin/ui/debug/latency/LatencyState.hx b/source/funkin/ui/debug/latency/LatencyState.hx index 7b2eabb1c..620f0edd7 100644 --- a/source/funkin/ui/debug/latency/LatencyState.hx +++ b/source/funkin/ui/debug/latency/LatencyState.hx @@ -171,10 +171,7 @@ class LatencyState extends MusicBeatSubState trace(FlxG.sound.music._channel.position); */ - #if FLX_DEBUG - funnyStatsGraph.update(FlxG.sound.music.time % 500); - realStats.update(swagSong.getTimeWithDiff() % 500); - #end + // localConductor.update(swagSong.time, false); if (FlxG.keys.justPressed.S) { diff --git a/source/funkin/ui/freeplay/FreeplayState.hx b/source/funkin/ui/freeplay/FreeplayState.hx index 10a582728..0724ad022 100644 --- a/source/funkin/ui/freeplay/FreeplayState.hx +++ b/source/funkin/ui/freeplay/FreeplayState.hx @@ -195,7 +195,7 @@ class FreeplayState extends MusicBeatSubState var song:Song = SongRegistry.instance.fetchEntry(songId); // Only display songs which actually have available charts for the current character. - var availableDifficultiesForSong:Array = song.listDifficulties(displayedVariations); + var availableDifficultiesForSong:Array = song.listDifficulties(displayedVariations, false); if (availableDifficultiesForSong.length == 0) continue; songs.push(new FreeplaySongData(levelId, songId, song, displayedVariations)); @@ -1400,7 +1400,7 @@ class FreeplaySongData function updateValues(variations:Array):Void { - this.songDifficulties = song.listDifficulties(variations); + this.songDifficulties = song.listDifficulties(variations, false, false); if (!this.songDifficulties.contains(currentDifficulty)) currentDifficulty = Constants.DEFAULT_DIFFICULTY; var songDifficulty:SongDifficulty = song.getDifficulty(currentDifficulty, variations); diff --git a/source/funkin/ui/freeplay/SongMenuItem.hx b/source/funkin/ui/freeplay/SongMenuItem.hx index bffa821b3..f8b3d7ac3 100644 --- a/source/funkin/ui/freeplay/SongMenuItem.hx +++ b/source/funkin/ui/freeplay/SongMenuItem.hx @@ -83,10 +83,10 @@ class SongMenuItem extends FlxSpriteGroup diffRatingSprite = new FlxSprite(145, 90).loadGraphic(Paths.image('freeplay/diffRatings/diff00')); diffRatingSprite.shader = grayscaleShader; + diffRatingSprite.origin.set(capsule.origin.x - diffRatingSprite.x, capsule.origin.y - diffRatingSprite.y); // TODO: Readd once ratings are fully implemented // add(diffRatingSprite); - diffRatingSprite.origin.set(capsule.origin.x - diffRatingSprite.x, capsule.origin.y - diffRatingSprite.y); - grpHide.add(diffRatingSprite); + // grpHide.add(diffRatingSprite); songText = new CapsuleText(capsule.width * 0.26, 45, 'Random', Std.int(40 * realScaled)); add(songText); diff --git a/source/funkin/ui/story/Level.hx b/source/funkin/ui/story/Level.hx index 626fb8e52..8f454aa1a 100644 --- a/source/funkin/ui/story/Level.hx +++ b/source/funkin/ui/story/Level.hx @@ -169,7 +169,7 @@ class Level implements IRegistryEntry if (firstSong != null) { // Don't display alternate characters in Story Mode. Only show `default` and `erect` variations. - for (difficulty in firstSong.listDifficulties([Constants.DEFAULT_VARIATION, 'erect'])) + for (difficulty in firstSong.listDifficulties([Constants.DEFAULT_VARIATION, 'erect'], false, false)) { difficulties.push(difficulty); } diff --git a/source/funkin/ui/transition/LoadingState.hx b/source/funkin/ui/transition/LoadingState.hx index e4f4bf004..af8798ae2 100644 --- a/source/funkin/ui/transition/LoadingState.hx +++ b/source/funkin/ui/transition/LoadingState.hx @@ -222,7 +222,7 @@ class LoadingState extends MusicBeatSubState #if NO_PRELOAD_ALL // Switch to loading state while we load assets (default on HTML5 target). - var loadStateCtor:NextState = function() { + var loadStateCtor = function() { var result = new LoadingState(playStateCtor, shouldStopMusic, params); @:privateAccess result.asSubState = asSubState; @@ -230,7 +230,7 @@ class LoadingState extends MusicBeatSubState } if (asSubState) { - FlxG.state.openSubState(loadStateCtor); + FlxG.state.openSubState(cast loadStateCtor()); } else { diff --git a/source/funkin/ui/transition/preload/FunkinPreloader.hx b/source/funkin/ui/transition/preload/FunkinPreloader.hx index 89a8c1140..2e8e0c319 100644 --- a/source/funkin/ui/transition/preload/FunkinPreloader.hx +++ b/source/funkin/ui/transition/preload/FunkinPreloader.hx @@ -1,5 +1,10 @@ package funkin.ui.transition.preload; +import openfl.filters.GlowFilter; +import openfl.display.SpreadMethod; +import openfl.display.GradientType; +import openfl.geom.Matrix; +import openfl.filters.BlurFilter; import openfl.events.MouseEvent; import flash.display.Bitmap; import flash.display.BitmapData; @@ -46,7 +51,7 @@ class FunkinPreloader extends FlxBasePreloader */ static final BAR_PADDING:Float = 20; - static final BAR_HEIGHT:Int = 20; + static final BAR_HEIGHT:Int = 12; /** * Logo takes this long (in seconds) to fade in. @@ -108,10 +113,19 @@ class FunkinPreloader extends FlxBasePreloader #if TOUCH_HERE_TO_PLAY var touchHereToPlay:Bitmap; #end + var progressBarPieces:Array; var progressBar:Bitmap; var progressLeftText:TextField; var progressRightText:TextField; + var dspText:TextField; + var enhancedText:TextField; + var stereoText:TextField; + + var vfdShader:VFDOverlay; + var box:Sprite; + var progressLines:Sprite; + public function new() { super(Constants.PRELOADER_MIN_STAGE_TIME, Constants.SITE_LOCK); @@ -146,7 +160,7 @@ class FunkinPreloader extends FlxBasePreloader bmp.x = (this._width - bmp.width) / 2; bmp.y = (this._height - bmp.height) / 2; }); - addChild(logo); + // addChild(logo); #if TOUCH_HERE_TO_PLAY touchHereToPlay = createBitmap(TouchHereToPlayImage, function(bmp:Bitmap) { @@ -160,16 +174,48 @@ class FunkinPreloader extends FlxBasePreloader addChild(touchHereToPlay); #end + var amountOfPieces:Int = 16; + progressBarPieces = []; + var maxBarWidth = this._width - BAR_PADDING * 2; + var pieceWidth = maxBarWidth / amountOfPieces; + var pieceGap:Int = 8; + + progressLines = new openfl.display.Sprite(); + progressLines.graphics.lineStyle(2, Constants.COLOR_PRELOADER_BAR); + progressLines.graphics.drawRect(-2, 480, this._width + 4, 30); + addChild(progressLines); + + var progressBarPiece = new Sprite(); + progressBarPiece.graphics.beginFill(Constants.COLOR_PRELOADER_BAR); + progressBarPiece.graphics.drawRoundRect(0, 0, pieceWidth - pieceGap, BAR_HEIGHT, 4, 4); + progressBarPiece.graphics.endFill(); + + for (i in 0...amountOfPieces) + { + var piece = new Sprite(); + piece.graphics.beginFill(Constants.COLOR_PRELOADER_BAR); + piece.graphics.drawRoundRect(0, 0, pieceWidth - pieceGap, BAR_HEIGHT, 4, 4); + piece.graphics.endFill(); + + piece.x = i * (piece.width + pieceGap); + piece.y = this._height - BAR_PADDING - BAR_HEIGHT - 200; + addChild(piece); + progressBarPieces.push(piece); + } + // Create the progress bar. - progressBar = new Bitmap(new BitmapData(1, BAR_HEIGHT, true, Constants.COLOR_PRELOADER_BAR)); - progressBar.x = BAR_PADDING; - progressBar.y = this._height - BAR_PADDING - BAR_HEIGHT; - addChild(progressBar); + // progressBar = new Bitmap(new BitmapData(1, BAR_HEIGHT, true, Constants.COLOR_PRELOADER_BAR)); + // progressBar.x = BAR_PADDING; + // progressBar.y = this._height - BAR_PADDING - BAR_HEIGHT; + // addChild(progressBar); // Create the progress message. progressLeftText = new TextField(); + dspText = new TextField(); + enhancedText = new TextField(); + stereoText = new TextField(); - var progressLeftTextFormat = new TextFormat("VCR OSD Mono", 16, Constants.COLOR_PRELOADER_BAR, true); + var progressLeftTextFormat = new TextFormat("DS-Digital", 32, Constants.COLOR_PRELOADER_BAR, true); progressLeftTextFormat.align = TextFormatAlign.LEFT; progressLeftText.defaultTextFormat = progressLeftTextFormat; @@ -177,13 +223,14 @@ class FunkinPreloader extends FlxBasePreloader progressLeftText.width = this._width - BAR_PADDING * 2; progressLeftText.text = 'Downloading assets...'; progressLeftText.x = BAR_PADDING; - progressLeftText.y = this._height - BAR_PADDING - BAR_HEIGHT - 16 - 4; + progressLeftText.y = this._height - BAR_PADDING - BAR_HEIGHT - 290; + // progressLeftText.shader = new VFDOverlay(); addChild(progressLeftText); // Create the progress %. progressRightText = new TextField(); - var progressRightTextFormat = new TextFormat("VCR OSD Mono", 16, Constants.COLOR_PRELOADER_BAR, true); + var progressRightTextFormat = new TextFormat("DS-Digital", 16, Constants.COLOR_PRELOADER_BAR, true); progressRightTextFormat.align = TextFormatAlign.RIGHT; progressRightText.defaultTextFormat = progressRightTextFormat; @@ -193,6 +240,60 @@ class FunkinPreloader extends FlxBasePreloader progressRightText.x = BAR_PADDING; progressRightText.y = this._height - BAR_PADDING - BAR_HEIGHT - 16 - 4; addChild(progressRightText); + + box = new Sprite(); + box.graphics.beginFill(Constants.COLOR_PRELOADER_BAR, 1); + box.graphics.drawRoundRect(0, 0, 64, 20, 5, 5); + box.graphics.drawRoundRect(70, 0, 58, 20, 5, 5); + box.graphics.endFill(); + box.graphics.beginFill(Constants.COLOR_PRELOADER_BAR, 0.1); + box.graphics.drawRoundRect(0, 0, 128, 20, 5, 5); + box.graphics.endFill(); + box.x = 880; + box.y = 440; + addChild(box); + + dspText.selectable = false; + dspText.textColor = 0x000000; + dspText.width = this._width; + dspText.height = 20; + dspText.text = 'DSP'; + dspText.x = 10; + dspText.y = -5; + box.addChild(dspText); + + enhancedText.selectable = false; + enhancedText.textColor = Constants.COLOR_PRELOADER_BAR; + enhancedText.width = this._width; + enhancedText.height = 100; + enhancedText.text = 'ENHANCED'; + enhancedText.x = -100; + enhancedText.y = 0; + box.addChild(enhancedText); + + stereoText.selectable = false; + stereoText.textColor = Constants.COLOR_PRELOADER_BAR; + stereoText.width = this._width; + stereoText.height = 100; + stereoText.text = 'STEREO'; + stereoText.x = 0; + stereoText.y = -40; + box.addChild(stereoText); + + // var dummyMatrix:openfl.geom.Matrix = new Matrix(); + // dummyMatrix.createGradientBox(this._width, this._height * 0.1, 90 * Math.PI / 180); + + // var gradient:Sprite = new Sprite(); + // gradient.graphics.beginGradientFill(GradientType.LINEAR, [0xFFFFFF, 0x000000], [1, 1], [0, 255], dummyMatrix, SpreadMethod.REFLECT); + // gradient.graphics.drawRect(0, 0, this._width, this._height); + // gradient.graphics.endFill(); + // addChild(gradient); + + var vfdBitmap:Bitmap = new Bitmap(new BitmapData(this._width, this._height, true, 0xFFFFFFFF)); + addChild(vfdBitmap); + + vfdShader = new VFDOverlay(); + vfdBitmap.shader = vfdShader; } var lastElapsed:Float = 0.0; @@ -200,6 +301,8 @@ class FunkinPreloader extends FlxBasePreloader override function update(percent:Float):Void { var elapsed:Float = (Date.now().getTime() - this._startTime) / 1000.0; + + vfdShader.update(elapsed * 100); // trace('Time since last frame: ' + (lastElapsed - elapsed)); downloadingAssetsPercent = percent; @@ -748,12 +851,19 @@ class FunkinPreloader extends FlxBasePreloader else { renderLogoFadeIn(elapsed); + + // Render progress bar + var maxWidth = this._width - BAR_PADDING * 2; + var barWidth = maxWidth * percent; + var piecesToRender:Int = Std.int(percent * progressBarPieces.length); + + for (i => piece in progressBarPieces) + { + piece.alpha = i <= piecesToRender ? 0.9 : 0.1; + } } - // Render progress bar - var maxWidth = this._width - BAR_PADDING * 2; - var barWidth = maxWidth * percent; - progressBar.width = barWidth; + // progressBar.width = barWidth; // Cycle ellipsis count to show loading var ellipsisCount:Int = Std.int(elapsed / ELLIPSIS_TIME) % 3 + 1; @@ -766,29 +876,29 @@ class FunkinPreloader extends FlxBasePreloader { // case FunkinPreloaderState.NotStarted: default: - updateProgressLeftText('Loading (0/$TOTAL_STEPS)$ellipsis'); + updateProgressLeftText('Loading \n0/$TOTAL_STEPS $ellipsis'); case FunkinPreloaderState.DownloadingAssets: - updateProgressLeftText('Downloading assets (1/$TOTAL_STEPS)$ellipsis'); + updateProgressLeftText('Downloading assets \n1/$TOTAL_STEPS $ellipsis'); case FunkinPreloaderState.PreloadingPlayAssets: - updateProgressLeftText('Preloading assets (2/$TOTAL_STEPS)$ellipsis'); + updateProgressLeftText('Preloading assets \n2/$TOTAL_STEPS $ellipsis'); case FunkinPreloaderState.InitializingScripts: - updateProgressLeftText('Initializing scripts (3/$TOTAL_STEPS)$ellipsis'); + updateProgressLeftText('Initializing scripts \n3/$TOTAL_STEPS $ellipsis'); case FunkinPreloaderState.CachingGraphics: - updateProgressLeftText('Caching graphics (4/$TOTAL_STEPS)$ellipsis'); + updateProgressLeftText('Caching graphics \n4/$TOTAL_STEPS $ellipsis'); case FunkinPreloaderState.CachingAudio: - updateProgressLeftText('Caching audio (5/$TOTAL_STEPS)$ellipsis'); + updateProgressLeftText('Caching audio \n5/$TOTAL_STEPS $ellipsis'); case FunkinPreloaderState.CachingData: - updateProgressLeftText('Caching data (6/$TOTAL_STEPS)$ellipsis'); + updateProgressLeftText('Caching data \n6/$TOTAL_STEPS $ellipsis'); case FunkinPreloaderState.ParsingSpritesheets: - updateProgressLeftText('Parsing spritesheets (7/$TOTAL_STEPS)$ellipsis'); + updateProgressLeftText('Parsing spritesheets \n7/$TOTAL_STEPS $ellipsis'); case FunkinPreloaderState.ParsingStages: - updateProgressLeftText('Parsing stages (8/$TOTAL_STEPS)$ellipsis'); + updateProgressLeftText('Parsing stages \n8/$TOTAL_STEPS $ellipsis'); case FunkinPreloaderState.ParsingCharacters: - updateProgressLeftText('Parsing characters (9/$TOTAL_STEPS)$ellipsis'); + updateProgressLeftText('Parsing characters \n9/$TOTAL_STEPS $ellipsis'); case FunkinPreloaderState.ParsingSongs: - updateProgressLeftText('Parsing songs (10/$TOTAL_STEPS)$ellipsis'); + updateProgressLeftText('Parsing songs \n10/$TOTAL_STEPS $ellipsis'); case FunkinPreloaderState.Complete: - updateProgressLeftText('Finishing up ($TOTAL_STEPS/$TOTAL_STEPS)$ellipsis'); + updateProgressLeftText('Finishing up \n$TOTAL_STEPS/$TOTAL_STEPS $ellipsis'); #if TOUCH_HERE_TO_PLAY case FunkinPreloaderState.TouchHereToPlay: updateProgressLeftText(null); @@ -815,10 +925,21 @@ class FunkinPreloader extends FlxBasePreloader else if (progressLeftText.text != text) { // We have to keep updating the text format, because the font can take a frame or two to load. - var progressLeftTextFormat = new TextFormat("VCR OSD Mono", 16, Constants.COLOR_PRELOADER_BAR, true); + var progressLeftTextFormat = new TextFormat("DS-Digital", 32, Constants.COLOR_PRELOADER_BAR, true); progressLeftTextFormat.align = TextFormatAlign.LEFT; progressLeftText.defaultTextFormat = progressLeftTextFormat; progressLeftText.text = text; + + dspText.defaultTextFormat = new TextFormat("Quantico", 20, 0x000000, false); + dspText.text = 'DSP\t\t\t\t\tFNF'; // fukin dum.... + dspText.textColor = 0x000000; + + enhancedText.defaultTextFormat = new TextFormat("Inconsolata Black", 16, Constants.COLOR_PRELOADER_BAR, false); + enhancedText.text = 'ENHANCED'; + enhancedText.textColor = Constants.COLOR_PRELOADER_BAR; + + stereoText.defaultTextFormat = new TextFormat("Inconsolata Bold", 36, Constants.COLOR_PRELOADER_BAR, false); + stereoText.text = 'NATURAL STEREO'; } } } @@ -845,9 +966,17 @@ class FunkinPreloader extends FlxBasePreloader logo.y = (this._height - logo.height) / 2; // Fade out progress bar too. - progressBar.alpha = logo.alpha; + // progressBar.alpha = logo.alpha; progressLeftText.alpha = logo.alpha; progressRightText.alpha = logo.alpha; + box.alpha = logo.alpha; + dspText.alpha = logo.alpha; + enhancedText.alpha = logo.alpha; + stereoText.alpha = logo.alpha; + progressLines.alpha = logo.alpha; + + for (piece in progressBarPieces) + piece.alpha = logo.alpha; return elapsedFinished; } @@ -901,8 +1030,8 @@ class FunkinPreloader extends FlxBasePreloader { // Ensure the graphics are properly destroyed and GC'd. removeChild(logo); - removeChild(progressBar); - logo = progressBar = null; + // removeChild(progressBar); + logo = null; super.destroy(); } diff --git a/source/funkin/ui/transition/preload/VFDOverlay.hx b/source/funkin/ui/transition/preload/VFDOverlay.hx new file mode 100644 index 000000000..1792c56ec --- /dev/null +++ b/source/funkin/ui/transition/preload/VFDOverlay.hx @@ -0,0 +1,70 @@ +package funkin.ui.transition.preload; + +import flixel.tweens.FlxEase; +import flixel.tweens.FlxTween; +import openfl.display.GraphicsShader; + +class VFDOverlay extends GraphicsShader +{ + public var elapsedTime(default, set):Float = 0; + + function set_elapsedTime(value:Float):Float + { + u_time.value = [value]; + return value; + } + + @:glFragmentSource('#pragma header + const vec2 s = vec2(1, 1.7320508); + + uniform float u_time; + + float rand(float co) { return fract(sin(co*(91.3458)) * 47453.5453); } + float rand(vec2 co){ return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453); } + + void main(void) { + vec4 col = texture2D (bitmap, openfl_TextureCoordv); + vec2 game_res = vec2(1280.0, 720.0); + const float tileAmount = 10.; + + vec2 uv = (2. * openfl_TextureCoordv.xy * -1.); + uv *= 50.; + + vec4 hexCenter = floor(vec4(uv, uv - vec2(0.5, 1.0)) / s.xyxy) + 0.5; + vec4 offset = vec4(uv - hexCenter.xy * s, uv - (hexCenter.zw + 0.5) * s) + 0.0; + vec4 hexInfo = dot(offset.xy, offset.xy) < dot(offset.zw, offset.zw) ? vec4(offset.xy, hexCenter.xy) : vec4(offset.zw, hexCenter.zw); + + // Distance to the nearest edge of a hexagon + vec2 p = abs(hexInfo.xy) ; + float edgeDist = max(dot(p, normalize(vec2(1.0, sqrt(3.0)))), p.x); + float edgeWidth = 0.05 * tileAmount; // Adjust edge width based on tile amount + float edgeSharpness = 0.011 * tileAmount; + + float outline = smoothstep(edgeWidth - edgeSharpness, edgeWidth, edgeDist); + float color_mix = mix(0.0, 0.3, outline); // Mix black outline with white fill + + float flicker = (sin(u_time) * 0.05) + 1.0; + float sinshit = smoothstep(-3.0, 1.0, sin(uv.y * 3.)); + + col = vec4(vec3(0.0), color_mix); + col = mix(col, vec4(0., 0., 0., sinshit), 0.5 * flicker); + + float specs = rand(uv.xy); + vec4 noise = vec4(0., 0., 0., specs); + col = mix(col, noise, 0.1); + + gl_FragColor = col; + } + ') + public function new() + { + super(); + + this.elapsedTime = 0; + } + + public function update(elapsed:Float):Void + { + this.elapsedTime += elapsed; + } +} diff --git a/source/funkin/util/Constants.hx b/source/funkin/util/Constants.hx index 2f5a4ca16..47410b9c5 100644 --- a/source/funkin/util/Constants.hx +++ b/source/funkin/util/Constants.hx @@ -140,7 +140,7 @@ class Constants /** * Color for the preloader progress bar */ - public static final COLOR_PRELOADER_BAR:FlxColor = 0xFF00FF00; + public static final COLOR_PRELOADER_BAR:FlxColor = 0xFFA4FF11; /** * Color for the preloader site lock background @@ -357,7 +357,7 @@ class Constants * The progress bare is automatically rescaled to match. */ #if debug - public static final PRELOADER_MIN_STAGE_TIME:Float = 1.0; + public static final PRELOADER_MIN_STAGE_TIME:Float = 0.0; #else public static final PRELOADER_MIN_STAGE_TIME:Float = 0.1; #end diff --git a/source/funkin/util/SerializerUtil.hx b/source/funkin/util/SerializerUtil.hx index c87d3f6c0..fa602cc73 100644 --- a/source/funkin/util/SerializerUtil.hx +++ b/source/funkin/util/SerializerUtil.hx @@ -63,6 +63,31 @@ class SerializerUtil } } + public static function initSerializer():Void + { + haxe.Unserializer.DEFAULT_RESOLVER = new FunkinTypeResolver(); + } + + /** + * Serialize a Haxe object using the built-in Serializer. + * @param input The object to serialize + * @return The serialized object as a string + */ + public static function fromHaxeObject(input:Dynamic):String + { + return haxe.Serializer.run(input); + } + + /** + * Convert a serialized Haxe object back into a Haxe object. + * @param input The serialized object as a string + * @return The deserialized object + */ + public static function toHaxeObject(input:String):Dynamic + { + return haxe.Unserializer.run(input); + } + /** * Customize how certain types are serialized when converting to JSON. */ @@ -90,3 +115,26 @@ class SerializerUtil return result; } } + +class FunkinTypeResolver +{ + public function new() + { + // Blank constructor. + } + + public function resolveClass(name:String):Class + { + if (name == 'Dynamic') + { + FlxG.log.warn('Found invalid class type in save data, indicates partial save corruption.'); + return null; + } + return Type.resolveClass(name); + }; + + public function resolveEnum(name:String):Enum + { + return Type.resolveEnum(name); + }; +} diff --git a/source/funkin/util/StructureUtil.hx b/source/funkin/util/StructureUtil.hx index 92d4e61fb..2f0c3818a 100644 --- a/source/funkin/util/StructureUtil.hx +++ b/source/funkin/util/StructureUtil.hx @@ -39,6 +39,45 @@ class StructureUtil return result; } + public static function isMap(a:Dynamic):Bool + { + return Std.isOfType(a, haxe.Constraints.IMap); + } + + public static function isObject(a:Dynamic):Bool + { + switch (Type.typeof(a)) + { + case TObject: + return true; + default: + return false; + } + } + + public static function isPrimitive(a:Dynamic):Bool + { + switch (Type.typeof(a)) + { + case TInt | TFloat | TBool: + return true; + case TClass(c): + return false; + case TEnum(e): + return false; + case TObject: + return false; + case TFunction: + return false; + case TNull: + return true; + case TUnknown: + return false; + default: + return false; + } + } + /** * Merge two structures, with the second overwriting the first. * Performs a DEEP clone, where child structures are also merged recursively. @@ -50,6 +89,18 @@ class StructureUtil { if (a == null) return b; if (b == null) return null; + if (isPrimitive(a) && isPrimitive(b)) return b; + if (isMap(b)) + { + if (isMap(a)) + { + return MapTools.merge(a, b); + } + else + { + return StructureUtil.toMap(a).merge(b); + } + } if (!Reflect.isObject(a) || !Reflect.isObject(b)) return b; if (Std.isOfType(b, haxe.ds.StringMap)) { diff --git a/source/funkin/util/tools/MapTools.hx b/source/funkin/util/tools/MapTools.hx index 029ea4978..beee1219b 100644 --- a/source/funkin/util/tools/MapTools.hx +++ b/source/funkin/util/tools/MapTools.hx @@ -45,6 +45,24 @@ class MapTools return result; } + /** + * Create a new map which is a combination of the two given maps. + * @param a The base map. + * @param b The other map. The values from this take precedence. + * @return The combined map. + */ + public static function merge(a:Map, b:Map):Map + { + var result = a.copy(); + + for (pair in b.keyValueIterator()) + { + result.set(pair.key, pair.value); + } + + return result; + } + /** * Create a new array with clones of all elements of the given array, to prevent modifying the original. */