From e24c78ae160dbdd968ae5753f70ab5b4058b1e66 Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Thu, 15 Feb 2024 21:34:24 -0500 Subject: [PATCH 1/6] Implemented a screenshot button. FancyPreview is broken. --- source/funkin/InitState.hx | 8 +- source/funkin/Preferences.hx | 30 +- source/funkin/save/Save.hx | 6 + source/funkin/util/FileUtil.hx | 6 + .../funkin/util/plugins/ScreenshotPlugin.hx | 269 ++++++++++++++++++ 5 files changed, 312 insertions(+), 7 deletions(-) create mode 100644 source/funkin/util/plugins/ScreenshotPlugin.hx diff --git a/source/funkin/InitState.hx b/source/funkin/InitState.hx index 399f52498..ec6a4e6f0 100644 --- a/source/funkin/InitState.hx +++ b/source/funkin/InitState.hx @@ -50,11 +50,13 @@ class InitState extends FlxState */ public override function create():Void { + // Setup a bunch of important Flixel stuff. setupShit(); - // loadSaveData(); // Moved to Main.hx // Load player options from save data. + // Flixel has already loaded the save data, so we can just use it. Preferences.init(); + // Load controls from save data. PlayerSettings.init(); @@ -198,6 +200,10 @@ class InitState extends FlxState // // FLIXEL PLUGINS // + // Plugins provide a useful interface for globally active Flixel objects, + // that receive update events regardless of the current state. + // TODO: Move Module behavior to a Flixel plugin. + funkin.util.plugins.ScreenshotPlugin.initialize(); funkin.util.plugins.EvacuateDebugPlugin.initialize(); funkin.util.plugins.ReloadAssetsDebugPlugin.initialize(); funkin.util.plugins.WatchPlugin.initialize(); diff --git a/source/funkin/Preferences.hx b/source/funkin/Preferences.hx index 6b0911ede..039a4c285 100644 --- a/source/funkin/Preferences.hx +++ b/source/funkin/Preferences.hx @@ -20,7 +20,10 @@ class Preferences static function set_naughtyness(value:Bool):Bool { - return Save.get().options.naughtyness = value; + var save = Save.get(); + save.options.naughtyness = value; + save.flush(); + return value; } /** @@ -36,7 +39,10 @@ class Preferences static function set_downscroll(value:Bool):Bool { - return Save.get().options.downscroll = value; + var save = Save.get(); + save.options.downscroll = value; + save.flush(); + return value; } /** @@ -52,7 +58,10 @@ class Preferences static function set_flashingLights(value:Bool):Bool { - return Save.get().options.flashingLights = value; + var save = Save.get(); + save.options.flashingLights = value; + save.flush(); + return value; } /** @@ -68,7 +77,10 @@ class Preferences static function set_zoomCamera(value:Bool):Bool { - return Save.get().options.zoomCamera = value; + var save = Save.get(); + save.options.zoomCamera = value; + save.flush(); + return value; } /** @@ -89,7 +101,10 @@ class Preferences toggleDebugDisplay(value); } - return Save.get().options.debugDisplay = value; + var save = Save.get(); + save.options.debugDisplay = value; + save.flush(); + return value; } /** @@ -107,7 +122,10 @@ class Preferences { if (value != Save.get().options.autoPause) FlxG.autoPause = value; - return Save.get().options.autoPause = value; + var save = Save.get(); + save.options.autoPause = value; + save.flush(); + return value; } public static function init():Void diff --git a/source/funkin/save/Save.hx b/source/funkin/save/Save.hx index 6a4dd048c..5bbded231 100644 --- a/source/funkin/save/Save.hx +++ b/source/funkin/save/Save.hx @@ -113,6 +113,9 @@ abstract Save(RawSaveData) }; } + /** + * NOTE: Modifications will not be saved without calling `Save.flush()`! + */ public var options(get, never):SaveDataOptions; function get_options():SaveDataOptions @@ -120,6 +123,9 @@ abstract Save(RawSaveData) return this.options; } + /** + * NOTE: Modifications will not be saved without calling `Save.flush()`! + */ public var modOptions(get, never):Map; function get_modOptions():Map diff --git a/source/funkin/util/FileUtil.hx b/source/funkin/util/FileUtil.hx index 612737680..5d189c0e9 100644 --- a/source/funkin/util/FileUtil.hx +++ b/source/funkin/util/FileUtil.hx @@ -20,6 +20,7 @@ class FileUtil { public static final FILE_FILTER_FNFC:FileFilter = new FileFilter("Friday Night Funkin' Chart (.fnfc)", "*.fnfc"); public static final FILE_FILTER_ZIP:FileFilter = new FileFilter("ZIP Archive (.zip)", "*.zip"); + public static final FILE_FILTER_PNG:FileFilter = new FileFilter("PNG Image (.png)", "*.png"); public static final FILE_EXTENSION_INFO_FNFC:FileDialogExtensionInfo = { @@ -31,6 +32,11 @@ class FileUtil extension: 'zip', label: 'ZIP Archive', }; + public static final FILE_EXTENSION_INFO_PNG:FileDialogExtensionInfo = + { + extension: 'png', + label: 'PNG Image', + }; /** * Browses for a single file, then calls `onSelect(fileInfo)` when a file is selected. diff --git a/source/funkin/util/plugins/ScreenshotPlugin.hx b/source/funkin/util/plugins/ScreenshotPlugin.hx new file mode 100644 index 000000000..a8b494fee --- /dev/null +++ b/source/funkin/util/plugins/ScreenshotPlugin.hx @@ -0,0 +1,269 @@ +package funkin.util.plugins; + +import flixel.FlxBasic; +import flixel.FlxCamera; +import flixel.FlxG; +import flixel.FlxState; +import flixel.graphics.FlxGraphic; +import flixel.input.keyboard.FlxKey; +import flixel.tweens.FlxEase; +import flixel.tweens.FlxTween; +import flixel.util.FlxColor; +import flixel.util.FlxSignal; +import flixel.util.FlxTimer; +import funkin.graphics.FunkinSprite; +import funkin.input.Cursor; +import openfl.display.Bitmap; +import openfl.display.BitmapData; +import openfl.display.PNGEncoderOptions; +import openfl.geom.Matrix; +import openfl.geom.Rectangle; +import openfl.utils.ByteArray; + +typedef ScreenshotPluginParams = +{ + hotkeys:Array, + ?region:Rectangle, + shouldHideMouse:Bool, + flashColor:Null, + fancyPreview:Bool, +}; + +/** + * What if `flixel.addons.plugin.screengrab.FlxScreenGrab` but it's better? + * TODO: Contribute this upstream. + */ +class ScreenshotPlugin extends FlxBasic +{ + public static final SCREENSHOT_FOLDER = 'screenshots'; + + var _hotkeys:Array; + + var _region:Null; + + var _shouldHideMouse:Bool; + + var _flashColor:Null; + + var _fancyPreview:Bool; + + /** + * A signal fired before the screenshot is taken. + */ + public var onPreScreenshot(default, null):FlxTypedSignalVoid>; + + /** + * A signal fired after the screenshot is taken. + * @param bitmap The bitmap that was captured. + */ + public var onPostScreenshot(default, null):FlxTypedSignalVoid>; + + public function new(params:ScreenshotPluginParams) + { + super(); + + _hotkeys = params.hotkeys; + _region = params.region ?? null; + _shouldHideMouse = params.shouldHideMouse; + _flashColor = params.flashColor; + _fancyPreview = params.fancyPreview; + + onPreScreenshot = new FlxTypedSignalVoid>(); + onPostScreenshot = new FlxTypedSignalVoid>(); + } + + public override function update(elapsed:Float):Void + { + super.update(elapsed); + + if (FlxG.keys.anyJustReleased(_hotkeys)) + { + capture(); + } + } + + /** + * Initialize the screenshot plugin. + */ + public static function initialize():Void + { + FlxG.plugins.addPlugin(new ScreenshotPlugin( + { + flashColor: Preferences.flashingLights ? FlxColor.WHITE : null, // Was originally a black flash. + + // TODO: Add a way to configure screenshots from the options menu. + hotkeys: [FlxKey.PRINTSCREEN], + shouldHideMouse: false, + fancyPreview: true, // TODO: Fancy preview is broken on substates. + })); + } + + public function updatePreferences():Void + { + _flashColor = Preferences.flashingLights ? FlxColor.WHITE : null; + } + + /** + * Defines the region of the screen that should be captured. + * You don't need to call this method if you want to capture the entire screen, that's the default behavior. + */ + public function defineCaptureRegion(x:Int, y:Int, width:Int, height:Int):Void + { + _region = new Rectangle(x, y, width, height); + } + + /** + * Capture the game screen as a bitmap. + */ + public function capture():Void + { + onPreScreenshot.dispatch(); + + var captureRegion = _region != null ? _region : new Rectangle(0, 0, FlxG.stage.stageWidth, FlxG.stage.stageHeight); + + var wasMouseHidden = false; + if (_shouldHideMouse && FlxG.mouse.visible) + { + wasMouseHidden = true; + Cursor.hide(); + } + + // The actual work. + // var bitmap = new Bitmap(new BitmapData(Math.floor(captureRegion.width), Math.floor(captureRegion.height), true, 0x00000000)); // Create a transparent empty bitmap. + // var drawMatrix = new Matrix(1, 0, 0, 1, -captureRegion.x, -captureRegion.y); // Modifying this will scale or skew the bitmap. + // bitmap.bitmapData.draw(FlxG.stage, drawMatrix); + var bitmap = new Bitmap(BitmapData.fromImage(FlxG.stage.window.readPixels())); + + if (wasMouseHidden) + { + Cursor.show(); + } + + // Save the bitmap to a file. + saveScreenshot(bitmap); + + // Show some feedback. + showCaptureFeedback(); + if (_fancyPreview) + { + showFancyPreview(bitmap); + } + + onPostScreenshot.dispatch(bitmap); + } + + final CAMERA_FLASH_DURATION = 0.25; + + /** + * Visual (and audio?) feedback when a screenshot is taken. + */ + function showCaptureFeedback():Void + { + if (_flashColor != null) + { + for (camera in FlxG.cameras.list) + { + camera.flash(_flashColor, CAMERA_FLASH_DURATION); + } + } + } + + static final PREVIEW_INITIAL_DELAY = 0.25; // How long before the preview starts fading in. + static final PREVIEW_FADE_IN_DURATION = 0.3; // How long the preview takes to fade in. + static final PREVIEW_FADE_OUT_DELAY = 0.25; // How long the preview stays on screen. + static final PREVIEW_FADE_OUT_DURATION = 0.3; // How long the preview takes to fade out. + + function showFancyPreview(bitmap:Bitmap):Void + { + // TODO: This function looks really nice but breaks substates. + var targetCamera = new FlxCamera(); + targetCamera.bgColor.alpha = 0; // Show the scene behind the camera. + FlxG.cameras.add(targetCamera); + + var flxGraphic = FlxGraphic.fromBitmapData(bitmap.bitmapData, false, "screenshot", false); + + var preview = new FunkinSprite(0, 0); + preview.frames = flxGraphic.imageFrame; + preview.setGraphicSize(bitmap.width / 4, bitmap.height / 4); + preview.x = FlxG.width - preview.width - 10; + preview.y = FlxG.height - preview.height - 10; + + preview.alpha = 0.0; + preview.cameras = [targetCamera]; + getCurrentState().add(preview); + + // Wait to fade in. + new FlxTimer().start(PREVIEW_INITIAL_DELAY, function(_) { + // Fade in. + FlxTween.tween(preview, {alpha: 1.0}, PREVIEW_FADE_IN_DURATION, + { + ease: FlxEase.elasticOut, + onComplete: function(_) { + // Wait to fade out. + new FlxTimer().start(PREVIEW_FADE_OUT_DELAY, function(_) { + // Fade out. + FlxTween.tween(preview, {alpha: 0.0}, PREVIEW_FADE_OUT_DURATION, + { + ease: FlxEase.elasticIn, + onComplete: function(_) { + preview.kill(); + } + }); + }); + } + }); + }); + } + + static function getCurrentState():FlxState + { + var state = FlxG.state; + while (state.subState != null) + { + state = state.subState; + } + return state; + } + + static function getScreenshotPath():String + { + return '$SCREENSHOT_FOLDER/screenshot-${DateUtil.generateTimestamp()}.png'; + } + + static function makeScreenshotPath():Void + { + FileUtil.createDirIfNotExists(SCREENSHOT_FOLDER); + } + + /** + * Convert a Bitmap to a PNG ByteArray to save to a file. + */ + static function encodePNG(bitmap:Bitmap):ByteArray + { + return bitmap.bitmapData.encode(bitmap.bitmapData.rect, new PNGEncoderOptions()); + } + + /** + * Save the generated bitmap to a file. + * @param bitmap The bitmap to save. + */ + static function saveScreenshot(bitmap:Bitmap) + { + makeScreenshotPath(); + var targetPath:String = getScreenshotPath(); + + var pngData = encodePNG(bitmap); + + if (pngData == null) + { + trace('[WARN] Failed to encode PNG data.'); + return; + } + else + { + trace('Saving screenshot to: ' + targetPath); + // TODO: Make this work on browser. + FileUtil.writeBytesToPath(targetPath, pngData); + } + } +} From 0036a334bc37b3e4bd8034c53f7de2dedfd0dcda Mon Sep 17 00:00:00 2001 From: Cameron Taylor Date: Fri, 16 Feb 2024 04:48:54 -0500 Subject: [PATCH 2/6] display fancy preview as a sprite on top of FlxG.stage, to properly render over substates --- .../funkin/util/plugins/ScreenshotPlugin.hx | 41 +++++++++---------- 1 file changed, 20 insertions(+), 21 deletions(-) diff --git a/source/funkin/util/plugins/ScreenshotPlugin.hx b/source/funkin/util/plugins/ScreenshotPlugin.hx index a8b494fee..40454854c 100644 --- a/source/funkin/util/plugins/ScreenshotPlugin.hx +++ b/source/funkin/util/plugins/ScreenshotPlugin.hx @@ -92,9 +92,9 @@ class ScreenshotPlugin extends FlxBasic flashColor: Preferences.flashingLights ? FlxColor.WHITE : null, // Was originally a black flash. // TODO: Add a way to configure screenshots from the options menu. - hotkeys: [FlxKey.PRINTSCREEN], + hotkeys: [FlxKey.F3], shouldHideMouse: false, - fancyPreview: true, // TODO: Fancy preview is broken on substates. + fancyPreview: true, })); } @@ -170,43 +170,42 @@ class ScreenshotPlugin extends FlxBasic static final PREVIEW_INITIAL_DELAY = 0.25; // How long before the preview starts fading in. static final PREVIEW_FADE_IN_DURATION = 0.3; // How long the preview takes to fade in. - static final PREVIEW_FADE_OUT_DELAY = 0.25; // How long the preview stays on screen. + static final PREVIEW_FADE_OUT_DELAY = 1.25; // How long the preview stays on screen. static final PREVIEW_FADE_OUT_DURATION = 0.3; // How long the preview takes to fade out. function showFancyPreview(bitmap:Bitmap):Void { - // TODO: This function looks really nice but breaks substates. - var targetCamera = new FlxCamera(); - targetCamera.bgColor.alpha = 0; // Show the scene behind the camera. - FlxG.cameras.add(targetCamera); + var scale:Float = 0.25; + var w:Int = Std.int(bitmap.bitmapData.width * scale); + var h:Int = Std.int(bitmap.bitmapData.height * scale); - var flxGraphic = FlxGraphic.fromBitmapData(bitmap.bitmapData, false, "screenshot", false); + var preview:BitmapData = new BitmapData(w, h, true); + var matrix:openfl.geom.Matrix = new openfl.geom.Matrix(); + matrix.scale(scale, scale); + preview.draw(bitmap.bitmapData, matrix); - var preview = new FunkinSprite(0, 0); - preview.frames = flxGraphic.imageFrame; - preview.setGraphicSize(bitmap.width / 4, bitmap.height / 4); - preview.x = FlxG.width - preview.width - 10; - preview.y = FlxG.height - preview.height - 10; + var previewBitmap = new Bitmap(preview); - preview.alpha = 0.0; - preview.cameras = [targetCamera]; - getCurrentState().add(preview); + FlxG.stage.addChild(previewBitmap); + + previewBitmap.alpha = 0.0; + previewBitmap.y -= 10; // Wait to fade in. new FlxTimer().start(PREVIEW_INITIAL_DELAY, function(_) { // Fade in. - FlxTween.tween(preview, {alpha: 1.0}, PREVIEW_FADE_IN_DURATION, + FlxTween.tween(previewBitmap, {alpha: 1.0, y: 0}, PREVIEW_FADE_IN_DURATION, { - ease: FlxEase.elasticOut, + ease: FlxEase.quartOut, onComplete: function(_) { // Wait to fade out. new FlxTimer().start(PREVIEW_FADE_OUT_DELAY, function(_) { // Fade out. - FlxTween.tween(preview, {alpha: 0.0}, PREVIEW_FADE_OUT_DURATION, + FlxTween.tween(previewBitmap, {alpha: 0.0, y: 10}, PREVIEW_FADE_OUT_DURATION, { - ease: FlxEase.elasticIn, + ease: FlxEase.quartInOut, onComplete: function(_) { - preview.kill(); + FlxG.stage.removeChild(previewBitmap); } }); }); From 94938313dd1e449b15f08c4b7798fc4e24f6b929 Mon Sep 17 00:00:00 2001 From: Cameron Taylor Date: Fri, 16 Feb 2024 05:24:43 -0500 Subject: [PATCH 3/6] click preview to open screenshots folder (and moved `openFolder` to FileUtil --- source/funkin/ui/debug/DebugMenuSubState.hx | 12 +--- source/funkin/util/FileUtil.hx | 19 ++++++ .../funkin/util/plugins/ScreenshotPlugin.hx | 65 ++++++++++++++++--- 3 files changed, 78 insertions(+), 18 deletions(-) diff --git a/source/funkin/ui/debug/DebugMenuSubState.hx b/source/funkin/ui/debug/DebugMenuSubState.hx index 861e99f6b..375fb8f5c 100644 --- a/source/funkin/ui/debug/DebugMenuSubState.hx +++ b/source/funkin/ui/debug/DebugMenuSubState.hx @@ -9,6 +9,7 @@ import funkin.ui.debug.charting.ChartEditorState; import funkin.ui.MusicBeatSubState; import funkin.util.logging.CrashHandler; import flixel.addons.transition.FlxTransitionableState; +import funkin.util.FileUtil; class DebugMenuSubState extends MusicBeatSubState { @@ -110,16 +111,7 @@ class DebugMenuSubState extends MusicBeatSubState #if sys function openLogFolder() { - #if windows - Sys.command('explorer', [CrashHandler.LOG_FOLDER]); - #elseif mac - // mac could be fuckie with where the log folder is relative to the game file... - // if this comment is still here... it means it has NOT been verified on mac yet! - Sys.command('open', [CrashHandler.LOG_FOLDER]); - #end - - // TODO: implement linux - // some shit with xdg-open :thinking: emoji... + FileUtil.openFolder(CrashHandler.LOG_FOLDER); } #end diff --git a/source/funkin/util/FileUtil.hx b/source/funkin/util/FileUtil.hx index 5d189c0e9..268aed57e 100644 --- a/source/funkin/util/FileUtil.hx +++ b/source/funkin/util/FileUtil.hx @@ -645,6 +645,25 @@ class FileUtil }; } + #if sys + public static function openFolder(pathFolder:String) + { + #if windows + Sys.command('explorer', [pathFolder]); + #elseif mac + // mac could be fuckie with where the log folder is relative to the game file... + // if this comment is still here... it means it has NOT been verified on mac yet! + // + // FileUtil.hx note: this was originally used to open the logs specifically! + // thats why the above comment is there! + Sys.command('open', [pathFolder]); + #end + + // TODO: implement linux + // some shit with xdg-open :thinking: emoji... + } + #end + static function convertTypeFilter(typeFilter:Array):String { var filter:String = null; diff --git a/source/funkin/util/plugins/ScreenshotPlugin.hx b/source/funkin/util/plugins/ScreenshotPlugin.hx index 40454854c..8d6f62a28 100644 --- a/source/funkin/util/plugins/ScreenshotPlugin.hx +++ b/source/funkin/util/plugins/ScreenshotPlugin.hx @@ -14,11 +14,13 @@ import flixel.util.FlxTimer; import funkin.graphics.FunkinSprite; import funkin.input.Cursor; import openfl.display.Bitmap; +import openfl.display.Sprite; import openfl.display.BitmapData; import openfl.display.PNGEncoderOptions; import openfl.geom.Matrix; import openfl.geom.Rectangle; import openfl.utils.ByteArray; +import openfl.events.MouseEvent; typedef ScreenshotPluginParams = { @@ -175,6 +177,27 @@ class ScreenshotPlugin extends FlxBasic function showFancyPreview(bitmap:Bitmap):Void { + // ermmm stealing this?? + var wasMouseHidden = false; + if (!FlxG.mouse.visible) + { + wasMouseHidden = true; + Cursor.show(); + } + + // so that it doesnt change the alpha when tweening in/out + var changingAlpha:Bool = false; + + // fuck it, cursed locally scoped functions, purely because im lazy + // (and so we can check changingAlpha, which is locally scoped.... because I'm lazy...) + var onHover = function(e:MouseEvent) { + if (!changingAlpha) e.target.alpha = 0.6; + }; + + var onHoverOut = function(e:MouseEvent) { + if (!changingAlpha) e.target.alpha = 1; + } + var scale:Float = 0.25; var w:Int = Std.int(bitmap.bitmapData.width * scale); var h:Int = Std.int(bitmap.bitmapData.height * scale); @@ -184,28 +207,49 @@ class ScreenshotPlugin extends FlxBasic matrix.scale(scale, scale); preview.draw(bitmap.bitmapData, matrix); + // used for movement + button stuff + var previewSprite = new Sprite(); + + previewSprite.buttonMode = true; + previewSprite.addEventListener(MouseEvent.MOUSE_DOWN, openScreenshotsFolder); + previewSprite.addEventListener(MouseEvent.MOUSE_OVER, onHover); + previewSprite.addEventListener(MouseEvent.MOUSE_OUT, onHoverOut); + + FlxG.stage.addChild(previewSprite); + + previewSprite.alpha = 0.0; + previewSprite.y -= 10; + var previewBitmap = new Bitmap(preview); - - FlxG.stage.addChild(previewBitmap); - - previewBitmap.alpha = 0.0; - previewBitmap.y -= 10; + previewSprite.addChild(previewBitmap); // Wait to fade in. new FlxTimer().start(PREVIEW_INITIAL_DELAY, function(_) { // Fade in. - FlxTween.tween(previewBitmap, {alpha: 1.0, y: 0}, PREVIEW_FADE_IN_DURATION, + changingAlpha = true; + FlxTween.tween(previewSprite, {alpha: 1.0, y: 0}, PREVIEW_FADE_IN_DURATION, { ease: FlxEase.quartOut, onComplete: function(_) { + changingAlpha = false; // Wait to fade out. new FlxTimer().start(PREVIEW_FADE_OUT_DELAY, function(_) { + changingAlpha = true; // Fade out. - FlxTween.tween(previewBitmap, {alpha: 0.0, y: 10}, PREVIEW_FADE_OUT_DURATION, + FlxTween.tween(previewSprite, {alpha: 0.0, y: 10}, PREVIEW_FADE_OUT_DURATION, { ease: FlxEase.quartInOut, onComplete: function(_) { - FlxG.stage.removeChild(previewBitmap); + if (wasMouseHidden) + { + Cursor.hide(); + } + + previewSprite.removeEventListener(MouseEvent.MOUSE_DOWN, openScreenshotsFolder); + previewSprite.removeEventListener(MouseEvent.MOUSE_OVER, onHover); + previewSprite.removeEventListener(MouseEvent.MOUSE_OUT, onHoverOut); + + FlxG.stage.removeChild(previewSprite); } }); }); @@ -214,6 +258,11 @@ class ScreenshotPlugin extends FlxBasic }); } + function openScreenshotsFolder(e:MouseEvent):Void + { + FileUtil.openFolder(SCREENSHOT_FOLDER); + } + static function getCurrentState():FlxState { var state = FlxG.state; From e4cd694c15b681a3473c95ae30dc51e2b9878054 Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Fri, 16 Feb 2024 14:42:28 -0500 Subject: [PATCH 4/6] ScreenshotPlugin now uses Player.controls. VolumePlugin is now outside MusicBeatState --- source/funkin/InitState.hx | 3 +- source/funkin/input/Controls.hx | 54 +++++++++---------- source/funkin/ui/MusicBeatState.hx | 15 ------ source/funkin/ui/MusicBeatSubState.hx | 5 -- .../funkin/util/plugins/ScreenshotPlugin.hx | 7 ++- source/funkin/util/plugins/VolumePlugin.hx | 34 ++++++++++++ 6 files changed, 67 insertions(+), 51 deletions(-) create mode 100644 source/funkin/util/plugins/VolumePlugin.hx diff --git a/source/funkin/InitState.hx b/source/funkin/InitState.hx index ec6a4e6f0..ac1b3903b 100644 --- a/source/funkin/InitState.hx +++ b/source/funkin/InitState.hx @@ -203,9 +203,10 @@ class InitState extends FlxState // Plugins provide a useful interface for globally active Flixel objects, // that receive update events regardless of the current state. // TODO: Move Module behavior to a Flixel plugin. - funkin.util.plugins.ScreenshotPlugin.initialize(); funkin.util.plugins.EvacuateDebugPlugin.initialize(); funkin.util.plugins.ReloadAssetsDebugPlugin.initialize(); + funkin.util.plugins.ScreenshotPlugin.initialize(); + funkin.util.plugins.VolumePlugin.initialize(); funkin.util.plugins.WatchPlugin.initialize(); // diff --git a/source/funkin/input/Controls.hx b/source/funkin/input/Controls.hx index 201c222a3..c4760cf5f 100644 --- a/source/funkin/input/Controls.hx +++ b/source/funkin/input/Controls.hx @@ -63,12 +63,10 @@ class Controls extends FlxActionSet var _debug_menu = new FlxActionDigital(Action.DEBUG_MENU); var _debug_chart = new FlxActionDigital(Action.DEBUG_CHART); var _debug_stage = new FlxActionDigital(Action.DEBUG_STAGE); + var _screenshot = new FlxActionDigital(Action.SCREENSHOT); var _volume_up = new FlxActionDigital(Action.VOLUME_UP); var _volume_down = new FlxActionDigital(Action.VOLUME_DOWN); var _volume_mute = new FlxActionDigital(Action.VOLUME_MUTE); - #if CAN_CHEAT - var _cheat = new FlxActionDigital(Action.CHEAT); - #end var byName:Map = new Map(); @@ -235,6 +233,11 @@ class Controls extends FlxActionSet inline function get_DEBUG_STAGE() return _debug_stage.check(); + public var SCREENSHOT(get, never):Bool; + + inline function get_SCREENSHOT() + return _screenshot.check(); + public var VOLUME_UP(get, never):Bool; inline function get_VOLUME_UP() @@ -255,13 +258,6 @@ class Controls extends FlxActionSet inline function get_RESET() return _reset.check(); - #if CAN_CHEAT - public var CHEAT(get, never):Bool; - - inline function get_CHEAT() - return _cheat.check(); - #end - public function new(name, scheme:KeyboardScheme = null) { super(name); @@ -295,13 +291,14 @@ class Controls extends FlxActionSet add(_pause); add(_cutscene_advance); add(_cutscene_skip); + add(_debug_menu); + add(_debug_chart); + add(_debug_stage); + add(_screenshot); add(_volume_up); add(_volume_down); add(_volume_mute); add(_reset); - #if CAN_CHEAT - add(_cheat); - #end for (action in digitalActions) byName[action.name] = action; @@ -391,12 +388,10 @@ class Controls extends FlxActionSet case DEBUG_MENU: _debug_menu; case DEBUG_CHART: _debug_chart; case DEBUG_STAGE: _debug_stage; + case SCREENSHOT: _screenshot; case VOLUME_UP: _volume_up; case VOLUME_DOWN: _volume_down; case VOLUME_MUTE: _volume_mute; - #if CAN_CHEAT - case CHEAT: _cheat; - #end } } @@ -464,6 +459,8 @@ class Controls extends FlxActionSet func(_debug_chart, JUST_PRESSED); case DEBUG_STAGE: func(_debug_stage, JUST_PRESSED); + case SCREENSHOT: + func(_screenshot, JUST_PRESSED); case VOLUME_UP: func(_volume_up, JUST_PRESSED); case VOLUME_DOWN: @@ -472,10 +469,6 @@ class Controls extends FlxActionSet func(_volume_mute, JUST_PRESSED); case RESET: func(_reset, JUST_PRESSED); - #if CAN_CHEAT - case CHEAT: - func(_cheat, JUST_PRESSED); - #end } } @@ -666,6 +659,8 @@ class Controls extends FlxActionSet bindKeys(Control.DEBUG_MENU, getDefaultKeybinds(scheme, Control.DEBUG_MENU)); bindKeys(Control.DEBUG_CHART, getDefaultKeybinds(scheme, Control.DEBUG_CHART)); bindKeys(Control.DEBUG_STAGE, getDefaultKeybinds(scheme, Control.DEBUG_STAGE)); + bindKeys(Control.RESET, getDefaultKeybinds(scheme, Control.RESET)); + bindKeys(Control.SCREENSHOT, getDefaultKeybinds(scheme, Control.SCREENSHOT)); bindKeys(Control.VOLUME_UP, getDefaultKeybinds(scheme, Control.VOLUME_UP)); bindKeys(Control.VOLUME_DOWN, getDefaultKeybinds(scheme, Control.VOLUME_DOWN)); bindKeys(Control.VOLUME_MUTE, getDefaultKeybinds(scheme, Control.VOLUME_MUTE)); @@ -693,6 +688,7 @@ class Controls extends FlxActionSet case Control.DEBUG_MENU: return [GRAVEACCENT]; case Control.DEBUG_CHART: return []; case Control.DEBUG_STAGE: return []; + case Control.SCREENSHOT: return [F3]; // TODO: Change this back to PrintScreen case Control.VOLUME_UP: return [PLUS, NUMPADPLUS]; case Control.VOLUME_DOWN: return [MINUS, NUMPADMINUS]; case Control.VOLUME_MUTE: return [ZERO, NUMPADZERO]; @@ -716,6 +712,7 @@ class Controls extends FlxActionSet case Control.DEBUG_MENU: return [GRAVEACCENT]; case Control.DEBUG_CHART: return []; case Control.DEBUG_STAGE: return []; + case Control.SCREENSHOT: return [PRINTSCREEN]; case Control.VOLUME_UP: return [PLUS]; case Control.VOLUME_DOWN: return [MINUS]; case Control.VOLUME_MUTE: return [ZERO]; @@ -739,6 +736,7 @@ class Controls extends FlxActionSet case Control.DEBUG_MENU: return [GRAVEACCENT]; case Control.DEBUG_CHART: return []; case Control.DEBUG_STAGE: return []; + case Control.SCREENSHOT: return [PRINTSCREEN]; case Control.VOLUME_UP: return [NUMPADPLUS]; case Control.VOLUME_DOWN: return [NUMPADMINUS]; case Control.VOLUME_MUTE: return [NUMPADZERO]; @@ -845,6 +843,7 @@ class Controls extends FlxActionSet Control.NOTE_LEFT => getDefaultGamepadBinds(Control.NOTE_LEFT), Control.NOTE_RIGHT => getDefaultGamepadBinds(Control.NOTE_RIGHT), Control.PAUSE => getDefaultGamepadBinds(Control.PAUSE), + // Control.SCREENSHOT => [], // Control.VOLUME_UP => [RIGHT_SHOULDER], // Control.VOLUME_DOWN => [LEFT_SHOULDER], // Control.VOLUME_MUTE => [RIGHT_TRIGGER], @@ -852,8 +851,7 @@ class Controls extends FlxActionSet Control.CUTSCENE_SKIP => getDefaultGamepadBinds(Control.CUTSCENE_SKIP), // Control.DEBUG_MENU // Control.DEBUG_CHART - Control.RESET => getDefaultGamepadBinds(Control.RESET), - #if CAN_CHEAT, Control.CHEAT => getDefaultGamepadBinds(Control.CHEAT) #end + Control.RESET => getDefaultGamepadBinds(Control.RESET) ]); } @@ -870,6 +868,7 @@ class Controls extends FlxActionSet case Control.NOTE_LEFT: return [DPAD_LEFT, X, LEFT_STICK_DIGITAL_LEFT, RIGHT_STICK_DIGITAL_LEFT]; case Control.NOTE_RIGHT: return [DPAD_RIGHT, B, LEFT_STICK_DIGITAL_RIGHT, RIGHT_STICK_DIGITAL_RIGHT]; case Control.PAUSE: return [START]; + case Control.SCREENSHOT: return []; case Control.VOLUME_UP: return []; case Control.VOLUME_DOWN: return []; case Control.VOLUME_MUTE: return []; @@ -878,7 +877,6 @@ class Controls extends FlxActionSet case Control.DEBUG_MENU: return []; case Control.DEBUG_CHART: return []; case Control.RESET: return [RIGHT_SHOULDER]; - #if CAN_CHEAT, Control.CHEAT: return [X]; #end default: // Fallthrough. } @@ -1236,6 +1234,8 @@ enum Control // CUTSCENE CUTSCENE_ADVANCE; CUTSCENE_SKIP; + // SCREENSHOT + SCREENSHOT; // VOLUME VOLUME_UP; VOLUME_DOWN; @@ -1244,9 +1244,6 @@ enum Control DEBUG_MENU; DEBUG_CHART; DEBUG_STAGE; - #if CAN_CHEAT - CHEAT; - #end } enum @@ -1289,13 +1286,12 @@ abstract Action(String) to String from String var VOLUME_UP = "volume_up"; var VOLUME_DOWN = "volume_down"; var VOLUME_MUTE = "volume_mute"; + // SCREENSHOT + var SCREENSHOT = "screenshot"; // DEBUG var DEBUG_MENU = "debug_menu"; var DEBUG_CHART = "debug_chart"; var DEBUG_STAGE = "debug_stage"; - #if CAN_CHEAT - var CHEAT = "cheat"; - #end } enum Device diff --git a/source/funkin/ui/MusicBeatState.hx b/source/funkin/ui/MusicBeatState.hx index 884fc5061..98197a0e7 100644 --- a/source/funkin/ui/MusicBeatState.hx +++ b/source/funkin/ui/MusicBeatState.hx @@ -58,19 +58,6 @@ class MusicBeatState extends FlxTransitionableState implements IEventHandler Conductor.stepHit.remove(this.stepHit); } - function handleControls():Void - { - var isHaxeUIFocused:Bool = haxe.ui.focus.FocusManager.instance?.focus != null; - - if (!isHaxeUIFocused) - { - // Rebindable volume keys. - if (controls.VOLUME_MUTE) FlxG.sound.toggleMuted(); - else if (controls.VOLUME_UP) FlxG.sound.changeVolume(0.1); - else if (controls.VOLUME_DOWN) FlxG.sound.changeVolume(-0.1); - } - } - function handleFunctionControls():Void { // Emergency exit button. @@ -84,8 +71,6 @@ class MusicBeatState extends FlxTransitionableState implements IEventHandler { super.update(elapsed); - handleControls(); - dispatchEvent(new UpdateScriptEvent(elapsed)); } diff --git a/source/funkin/ui/MusicBeatSubState.hx b/source/funkin/ui/MusicBeatSubState.hx index 9a6f1a323..2c8970357 100644 --- a/source/funkin/ui/MusicBeatSubState.hx +++ b/source/funkin/ui/MusicBeatSubState.hx @@ -53,11 +53,6 @@ class MusicBeatSubState extends FlxSubState implements IEventHandler { super.update(elapsed); - // Rebindable volume keys. - if (controls.VOLUME_MUTE) FlxG.sound.toggleMuted(); - else if (controls.VOLUME_UP) FlxG.sound.changeVolume(0.1); - else if (controls.VOLUME_DOWN) FlxG.sound.changeVolume(-0.1); - // Emergency exit button. if (FlxG.keys.justPressed.F4) FlxG.switchState(() -> new MainMenuState()); diff --git a/source/funkin/util/plugins/ScreenshotPlugin.hx b/source/funkin/util/plugins/ScreenshotPlugin.hx index 8d6f62a28..afb9d3495 100644 --- a/source/funkin/util/plugins/ScreenshotPlugin.hx +++ b/source/funkin/util/plugins/ScreenshotPlugin.hx @@ -78,7 +78,7 @@ class ScreenshotPlugin extends FlxBasic { super.update(elapsed); - if (FlxG.keys.anyJustReleased(_hotkeys)) + if (hasPressedScreenshot()) { capture(); } @@ -100,6 +100,11 @@ class ScreenshotPlugin extends FlxBasic })); } + public function hasPressedScreenshot():Bool + { + return PlayerSettings.player1.controls.SCREENSHOT; + } + public function updatePreferences():Void { _flashColor = Preferences.flashingLights ? FlxColor.WHITE : null; diff --git a/source/funkin/util/plugins/VolumePlugin.hx b/source/funkin/util/plugins/VolumePlugin.hx new file mode 100644 index 000000000..5dbe60abf --- /dev/null +++ b/source/funkin/util/plugins/VolumePlugin.hx @@ -0,0 +1,34 @@ +package funkin.util.plugins; + +import flixel.FlxBasic; + +/** + * Handles volume control in a way that is compatible with alternate control schemes. + */ +class VolumePlugin extends FlxBasic +{ + public function new() + { + super(); + } + + public static function initialize() + { + FlxG.plugins.addPlugin(new VolumePlugin()); + } + + public override function update(elapsed:Float):Void + { + super.update(elapsed); + + var isHaxeUIFocused:Bool = haxe.ui.focus.FocusManager.instance?.focus != null; + + if (!isHaxeUIFocused) + { + // Rebindable volume keys. + if (PlayerSettings.player1.controls.VOLUME_MUTE) FlxG.sound.toggleMuted(); + else if (PlayerSettings.player1.controls.VOLUME_UP) FlxG.sound.changeVolume(0.1); + else if (PlayerSettings.player1.controls.VOLUME_DOWN) FlxG.sound.changeVolume(-0.1); + } + } +} From 29e1c480fdffd1a7db39d727a710efa44c5637bd Mon Sep 17 00:00:00 2001 From: Cameron Taylor Date: Fri, 16 Feb 2024 16:35:57 -0500 Subject: [PATCH 5/6] unwrap openFolder from #if sys --- source/funkin/util/FileUtil.hx | 2 -- 1 file changed, 2 deletions(-) diff --git a/source/funkin/util/FileUtil.hx b/source/funkin/util/FileUtil.hx index 268aed57e..7a7b1422c 100644 --- a/source/funkin/util/FileUtil.hx +++ b/source/funkin/util/FileUtil.hx @@ -645,7 +645,6 @@ class FileUtil }; } - #if sys public static function openFolder(pathFolder:String) { #if windows @@ -662,7 +661,6 @@ class FileUtil // TODO: implement linux // some shit with xdg-open :thinking: emoji... } - #end static function convertTypeFilter(typeFilter:Array):String { From 0b58a4f66431a0979e518ae18e3af15ac7b3d44c Mon Sep 17 00:00:00 2001 From: Cameron Taylor Date: Fri, 16 Feb 2024 18:58:27 -0500 Subject: [PATCH 6/6] camera flash fix --- source/funkin/util/plugins/ScreenshotPlugin.hx | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/source/funkin/util/plugins/ScreenshotPlugin.hx b/source/funkin/util/plugins/ScreenshotPlugin.hx index afb9d3495..16d0c7244 100644 --- a/source/funkin/util/plugins/ScreenshotPlugin.hx +++ b/source/funkin/util/plugins/ScreenshotPlugin.hx @@ -166,13 +166,11 @@ class ScreenshotPlugin extends FlxBasic */ function showCaptureFeedback():Void { - if (_flashColor != null) - { - for (camera in FlxG.cameras.list) - { - camera.flash(_flashColor, CAMERA_FLASH_DURATION); - } - } + var flashBitmap = new Bitmap(new BitmapData(Std.int(FlxG.stage.width), Std.int(FlxG.stage.height), false, 0xFFFFFFFF)); + var flashSpr = new Sprite(); + flashSpr.addChild(flashBitmap); + FlxG.stage.addChild(flashSpr); + FlxTween.tween(flashSpr, {alpha: 0}, 0.15, {ease: FlxEase.quadOut, onComplete: _ -> FlxG.stage.removeChild(flashSpr)}); } static final PREVIEW_INITIAL_DELAY = 0.25; // How long before the preview starts fading in.