diff --git a/assets b/assets index 4abd6cc06e..e96a11394d 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit 4abd6cc06e56c6d56440fa858262932db118250c +Subproject commit e96a11394d5d6d6b366c073c3b1579257608be0e diff --git a/source/funkin/export bs/ui/debug/DebugMenuSubState.hx b/source/funkin/export bs/ui/debug/DebugMenuSubState.hx deleted file mode 100644 index 6fc6be9378..0000000000 --- a/source/funkin/export bs/ui/debug/DebugMenuSubState.hx +++ /dev/null @@ -1,150 +0,0 @@ -package funkin.ui.debug; - -import flixel.math.FlxPoint; -import flixel.FlxObject; -import flixel.FlxSprite; -import funkin.ui.MusicBeatSubState; -import funkin.audio.FunkinSound; -import funkin.ui.TextMenuList; -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 -{ - var items:TextMenuList; - - /** - * Camera focus point - */ - var camFocusPoint:FlxObject; - - override function create():Void - { - FlxTransitionableState.skipNextTransIn = true; - super.create(); - - bgColor = 0x00000000; - - // Create an object for the camera to track. - camFocusPoint = new FlxObject(0, 0); - add(camFocusPoint); - - // Follow the camera focus as we scroll. - FlxG.camera.follow(camFocusPoint, null, 0.06); - - // Create the green background. - var menuBG = new FlxSprite().loadGraphic(Paths.image('menuDesat')); - menuBG.color = 0xFF4CAF50; - menuBG.setGraphicSize(Std.int(menuBG.width * 1.1)); - menuBG.updateHitbox(); - menuBG.screenCenter(); - menuBG.scrollFactor.set(0, 0); - add(menuBG); - - // Create the list for menu items. - items = new TextMenuList(); - // Move the camera when the menu is scrolled. - items.onChange.add(onMenuChange); - add(items); - - FlxTransitionableState.skipNextTransIn = true; - - // Create each menu item. - // Call onMenuChange when the first item is created to move the camera . - #if FEATURE_CHART_EDITOR - onMenuChange(createItem("CHART EDITOR", openChartEditor)); - #end - // createItem("Input Offset Testing", openInputOffsetTesting); - createItem("CHARACTER SELECT", openCharSelect, true); - createItem("ANIMATION EDITOR", openAnimationEditor); - createItem("STAGE EDITOR", openStageEditor); - createItem("CHARACTER CREATOR", openCharCreator); - // createItem("TEST STICKERS", testStickers); - #if sys - createItem("OPEN CRASH LOG FOLDER", openLogFolder); - #end - FlxG.camera.focusOn(new FlxPoint(camFocusPoint.x, camFocusPoint.y + 500)); - } - - function onMenuChange(selected:TextMenuItem) - { - camFocusPoint.setPosition(selected.x + selected.width / 2, selected.y + selected.height / 2); - } - - override function update(elapsed:Float) - { - super.update(elapsed); - - if (controls.BACK) - { - FunkinSound.playOnce(Paths.sound('cancelMenu')); - exitDebugMenu(); - } - } - - function createItem(name:String, callback:Void->Void, fireInstantly = false) - { - var item = items.createItem(0, 100 + items.length * 100, name, BOLD, callback); - item.fireInstantly = fireInstantly; - item.screenCenter(X); - return item; - } - - function openChartEditor() - { - FlxTransitionableState.skipNextTransIn = true; - - FlxG.switchState(() -> new ChartEditorState()); - } - - function openInputOffsetTesting() - { - openSubState(new funkin.ui.debug.latency.LatencyState()); - trace('Input Offset Testing'); - } - - function openCharSelect() - { - FlxG.switchState(new funkin.ui.charSelect.CharSelectSubState()); - } - - function openAnimationEditor() - { - FlxG.switchState(() -> new funkin.ui.debug.anim.DebugBoundingState()); - trace('Animation Editor'); - } - - function testStickers() - { - openSubState(new funkin.ui.transition.StickerSubState()); - trace('opened stickers'); - } - - function openStageEditor() - { - trace('Stage Editor'); - FlxG.switchState(() -> new funkin.ui.debug.stageeditor.StageEditorState()); - } - - function openCharCreator() - { - trace('Character Creator'); - FlxG.switchState(() -> new funkin.ui.debug.char.CharCreatorState()); - } - - #if sys - function openLogFolder() - { - FileUtil.openFolder(CrashHandler.LOG_FOLDER); - } - #end - - function exitDebugMenu() - { - // TODO: Add a transition? - this.close(); - } -} diff --git a/source/funkin/export bs/util/FileUtil.hx b/source/funkin/export bs/util/FileUtil.hx deleted file mode 100644 index fdf7d123d0..0000000000 --- a/source/funkin/export bs/util/FileUtil.hx +++ /dev/null @@ -1,722 +0,0 @@ -package funkin.util; - -import haxe.zip.Entry; -import lime.utils.Bytes; -import lime.ui.FileDialog; -import openfl.net.FileFilter; -import haxe.io.Path; -import openfl.net.FileReference; -import openfl.events.Event; -import openfl.events.IOErrorEvent; -import haxe.ui.containers.dialogs.Dialog.DialogButton; -import haxe.ui.containers.dialogs.Dialogs; -import haxe.ui.containers.dialogs.Dialogs.SelectedFileInfo; -import haxe.ui.containers.dialogs.Dialogs.FileDialogExtensionInfo; - -/** - * Utilities for reading and writing files on various platforms. - */ -class FileUtil -{ - public static final FILE_FILTER_FNFC:FileFilter = new FileFilter("Friday Night Funkin' Chart (.fnfc)", "*.fnfc"); - public static final FILE_FILTER_JSON:FileFilter = new FileFilter("JSON Data File (.json)", "*.json"); - public static final FILE_FILTER_XML:FileFilter = new FileFilter("XML Data File (.xml)", "*.xml"); - public static final FILE_FILTER_TXT:FileFilter = new FileFilter("Text File (.txt)", "*.txt"); - 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_FILTER_FNFS:FileFilter = new FileFilter("Friday Night Funkin' Stage (.fnfs)", "*.fnfs"); - - public static final FILE_EXTENSION_INFO_FNFC:FileDialogExtensionInfo = - { - extension: 'fnfc', - label: 'Friday Night Funkin\' Chart', - }; - public static final FILE_EXTENSION_INFO_ZIP:FileDialogExtensionInfo = - { - extension: 'zip', - label: 'ZIP Archive', - }; - public static final FILE_EXTENSION_INFO_JSON:FileDialogExtensionInfo = - { - extension: 'json', - label: 'JSON Data File', - }; - public static final FILE_EXTENSION_INFO_XML:FileDialogExtensionInfo = - { - extension: 'xml', - label: 'XML Data File', - }; - public static final FILE_EXTENSION_INFO_TXT:FileDialogExtensionInfo = - { - extension: 'txt', - label: 'Text File', - }; - public static final FILE_EXTENSION_INFO_PNG:FileDialogExtensionInfo = - { - extension: 'png', - label: 'PNG Image', - }; - - public static final FILE_EXTENSION_INFO_FNFS:FileDialogExtensionInfo = - { - extension: 'fnfs', - label: 'Friday Night Funkin\' Stage', - }; - - /** - * Browses for a single file, then calls `onSelect(fileInfo)` when a file is selected. - * Powered by HaxeUI, so it works on all platforms. - * File contents will be binary, not String. - * - * @param typeFilter - * @param onSelect A callback that provides a `SelectedFileInfo` object when a file is selected. - * @param onCancel A callback that is called when the user closes the dialog without selecting a file. - */ - public static function browseForBinaryFile(dialogTitle:String, ?typeFilter:Array, ?onSelect:SelectedFileInfo->Void, - ?onCancel:Void->Void) - { - var onComplete = function(button, selectedFiles) { - if (button == DialogButton.OK && selectedFiles.length > 0) - { - onSelect(selectedFiles[0]); - } - else - { - onCancel(); - } - }; - - Dialogs.openFile(onComplete, - { - readContents: true, - readAsBinary: true, // Binary - multiple: false, - extensions: typeFilter ?? [], - title: dialogTitle, - }); - } - - /** - * Browses for a single file, then calls `onSelect(fileInfo)` when a file is selected. - * Powered by HaxeUI, so it works on all platforms. - * File contents will be a String, not binary. - * - * @param typeFilter - * @param onSelect A callback that provides a `SelectedFileInfo` object when a file is selected. - * @param onCancel A callback that is called when the user closes the dialog without selecting a file. - */ - public static function browseForTextFile(dialogTitle:String, ?typeFilter:Array, ?onSelect:SelectedFileInfo->Void, - ?onCancel:Void->Void) - { - var onComplete = function(button, selectedFiles) { - if (button == DialogButton.OK && selectedFiles.length > 0) - { - onSelect(selectedFiles[0]); - } - else - { - onCancel(); - } - }; - - Dialogs.openFile(onComplete, - { - readContents: true, - readAsBinary: false, // Text - multiple: false, - extensions: typeFilter ?? [], - title: dialogTitle, - }); - } - - /** - * Browses for a directory, then calls `onSelect(path)` when a path chosen. - * Note that on HTML5 this will immediately fail. - * - * @param typeFilter TODO What does this do? - * @return Whether the file dialog was opened successfully. - */ - public static function browseForDirectory(?typeFilter:Array, ?onSelect:String->Void, ?onCancel:Void->Void, ?defaultPath:String, - ?dialogTitle:String):Bool - { - #if desktop - var filter:String = convertTypeFilter(typeFilter); - var fileDialog:FileDialog = new FileDialog(); - if (onSelect != null) fileDialog.onSelect.add(onSelect); - if (onCancel != null) fileDialog.onCancel.add(onCancel); - fileDialog.browse(OPEN_DIRECTORY, filter, defaultPath, dialogTitle); - return true; - #elseif html5 - onCancel(); - return false; - #else - onCancel(); - return false; - #end - } - - /** - * Browses for multiple file, then calls `onSelect(paths)` when a path chosen. - * Note that on HTML5 this will immediately fail. - * - * @return Whether the file dialog was opened successfully. - */ - public static function browseForMultipleFiles(?typeFilter:Array, ?onSelect:Array->Void, ?onCancel:Void->Void, ?defaultPath:String, - ?dialogTitle:String):Bool - { - #if desktop - var filter:String = convertTypeFilter(typeFilter); - var fileDialog:FileDialog = new FileDialog(); - if (onSelect != null) fileDialog.onSelectMultiple.add(onSelect); - if (onCancel != null) fileDialog.onCancel.add(onCancel); - fileDialog.browse(OPEN_MULTIPLE, filter, defaultPath, dialogTitle); - return true; - #elseif html5 - onCancel(); - return false; - #else - onCancel(); - return false; - #end - } - - /** - * Browses for a file location to save to, then calls `onSave(path)` when a path chosen. - * Note that on HTML5 you can't do much with this, you should call `saveFile(resource:haxe.io.Bytes)` instead. - * - * @param typeFilter TODO What does this do? - * @return Whether the file dialog was opened successfully. - */ - public static function browseForSaveFile(?typeFilter:Array, ?onSelect:String->Void, ?onCancel:Void->Void, ?defaultPath:String, - ?dialogTitle:String):Bool - { - #if desktop - var filter:String = convertTypeFilter(typeFilter); - var fileDialog:FileDialog = new FileDialog(); - if (onSelect != null) fileDialog.onSelect.add(onSelect); - if (onCancel != null) fileDialog.onCancel.add(onCancel); - fileDialog.browse(SAVE, filter, defaultPath, dialogTitle); - return true; - #elseif html5 - onCancel(); - return false; - #else - onCancel(); - return false; - #end - } - - /** - * Browses for a single file location, then writes the provided `haxe.io.Bytes` data and calls `onSave(path)` when done. - * Works great on desktop and HTML5. - * - * @return Whether the file dialog was opened successfully. - */ - public static function saveFile(data:Bytes, ?typeFilter:Array, ?onSave:String->Void, ?onCancel:Void->Void, ?defaultFileName:String, - ?dialogTitle:String):Bool - { - #if desktop - var filter:String = convertTypeFilter(typeFilter); - var fileDialog:FileDialog = new FileDialog(); - if (onSave != null) fileDialog.onSave.add(onSave); - if (onCancel != null) fileDialog.onCancel.add(onCancel); - fileDialog.save(data, filter, defaultFileName, dialogTitle); - return true; - #elseif html5 - var filter:String = defaultFileName != null ? Path.extension(defaultFileName) : null; - var fileDialog:FileDialog = new FileDialog(); - if (onSave != null) fileDialog.onSave.add(onSave); - if (onCancel != null) fileDialog.onCancel.add(onCancel); - fileDialog.save(data, filter, defaultFileName, dialogTitle); - return true; - #else - onCancel(); - return false; - #end - } - - /** - * Prompts the user to save multiple files. - * On desktop, this will prompt the user for a directory, then write all of the files to there. - * On HTML5, this will zip the files up and prompt the user to save that. - * - * @param typeFilter TODO What does this do? - * @return Whether the file dialog was opened successfully. - */ - public static function saveMultipleFiles(resources:Array, ?onSaveAll:Array->Void, ?onCancel:Void->Void, ?defaultPath:String, - force:Bool = false):Bool - { - #if desktop - // Prompt the user for a directory, then write all of the files to there. - var onSelectDir:String->Void = function(targetPath:String):Void { - var paths:Array = []; - for (resource in resources) - { - var filePath = haxe.io.Path.join([targetPath, resource.fileName]); - try - { - if (resource.data == null) - { - trace('WARNING: File $filePath has no data or content. Skipping.'); - continue; - } - else - { - writeBytesToPath(filePath, resource.data, force ? Force : Skip); - } - } - catch (_) - { - throw 'Failed to write file (probably already exists): $filePath'; - } - paths.push(filePath); - } - onSaveAll(paths); - } - trace('Browsing for directory to save individual files to...'); - #if mac - defaultPath = null; - #end - browseForDirectory(null, onSelectDir, onCancel, defaultPath, 'Choose directory to save all files to...'); - return true; - #elseif html5 - saveFilesAsZIP(resources, onSaveAll, onCancel, defaultPath, force); - return true; - #else - onCancel(); - return false; - #end - } - - /** - * Takes an array of file entries and prompts the user to save them as a ZIP file. - */ - public static function saveFilesAsZIP(resources:Array, ?onSave:Array->Void, ?onCancel:Void->Void, ?defaultPath:String, force:Bool = false):Bool - { - // Create a ZIP file. - var zipBytes:Bytes = createZIPFromEntries(resources); - var onSave:String->Void = function(path:String) { - trace('Saved ${resources.length} files to ZIP at "$path".'); - if (onSave != null) onSave([path]); - }; - // Prompt the user to save the ZIP file. - saveFile(zipBytes, [FILE_FILTER_ZIP], onSave, onCancel, defaultPath, 'Save files as ZIP...'); - return true; - } - - /** - * Takes an array of file entries and prompts the user to save them as a FNFC file. - */ - public static function saveChartAsFNFC(resources:Array, ?onSave:Array->Void, ?onCancel:Void->Void, ?defaultPath:String, - force:Bool = false):Bool - { - // Create a ZIP file. - var zipBytes:Bytes = createZIPFromEntries(resources); - var onSave:String->Void = function(path:String) { - trace('Saved FNF file to "$path"'); - if (onSave != null) onSave([path]); - }; - // Prompt the user to save the ZIP file. - saveFile(zipBytes, [FILE_FILTER_FNFC], onSave, onCancel, defaultPath, 'Save chart as FNFC...'); - return true; - } - - /** - * Takes an array of file entries and forcibly writes a ZIP to the given path. - * Only works on desktop, because HTML5 doesn't allow you to write files to arbitrary paths. - * Use `saveFilesAsZIP` instead. - * @param force Whether to force overwrite an existing file. - */ - public static function saveFilesAsZIPToPath(resources:Array, path:String, mode:FileWriteMode = Skip):Bool - { - #if desktop - // Create a ZIP file. - var zipBytes:Bytes = createZIPFromEntries(resources); - // Write the ZIP. - writeBytesToPath(path, zipBytes, mode); - return true; - #else - return false; - #end - } - - /** - * Read string file contents directly from a given path. - * Only works on desktop. - * - * @param path The path to the file. - * @return The file contents. - */ - public static function readStringFromPath(path:String):String - { - #if sys - return sys.io.File.getContent(path); - #else - trace('ERROR: readStringFromPath not implemented for this platform'); - return null; - #end - } - - /** - * Read bytes file contents directly from a given path. - * Only works on desktop. - * - * @param path The path to the file. - * @return The file contents. - */ - public static function readBytesFromPath(path:String):Bytes - { - #if sys - if (!doesFileExist(path)) return null; - return sys.io.File.getBytes(path); - #else - return null; - #end - } - - public static function doesFileExist(path:String):Bool - { - #if sys - return sys.FileSystem.exists(path); - #else - return false; - #end - } - - /** - * Browse for a file to read and execute a callback once we have a file reference. - * Works great on HTML5 or desktop. - * - * @param callback The function to call when the file is loaded. - */ - public static function browseFileReference(callback:FileReference->Void) - { - var file = new FileReference(); - file.addEventListener(Event.SELECT, function(e) { - var selectedFileRef:FileReference = e.target; - trace('Selected file: ' + selectedFileRef.name); - selectedFileRef.addEventListener(Event.COMPLETE, function(e) { - var loadedFileRef:FileReference = e.target; - trace('Loaded file: ' + loadedFileRef.name); - callback(loadedFileRef); - }); - selectedFileRef.load(); - }); - file.browse(); - } - - /** - * Prompts the user to save a file to their computer. - */ - public static function writeFileReference(path:String, data:String) - { - var file = new FileReference(); - file.addEventListener(Event.COMPLETE, function(e:Event) { - trace('Successfully wrote file.'); - }); - file.addEventListener(Event.CANCEL, function(e:Event) { - trace('Cancelled writing file.'); - }); - file.addEventListener(IOErrorEvent.IO_ERROR, function(e:IOErrorEvent) { - trace('IO error writing file.'); - }); - file.save(data, path); - } - - /** - * Read JSON file contents directly from a given path. - * Only works on desktop. - * - * @param path The path to the file. - * @return The JSON data. - */ - public static function readJSONFromPath(path:String):Dynamic - { - #if sys - try - { - return SerializerUtil.fromJSON(sys.io.File.getContent(path)); - } - catch (ex) - { - return null; - } - #else - return null; - #end - } - - /** - * Write string file contents directly to a given path. - * Only works on desktop. - * - * @param path The path to the file. - * @param data The string to write. - * @param mode Whether to Force, Skip, or Ask to overwrite an existing file. - */ - public static function writeStringToPath(path:String, data:String, mode:FileWriteMode = Skip):Void - { - #if sys - createDirIfNotExists(Path.directory(path)); - switch (mode) - { - case Force: - sys.io.File.saveContent(path, data); - case Skip: - if (!doesFileExist(path)) - { - sys.io.File.saveContent(path, data); - } - else - { - // Do nothing. - // throw 'File already exists: $path'; - } - case Ask: - if (doesFileExist(path)) - { - // TODO: We don't have the technology to use native popups yet. - throw 'File already exists: $path'; - } - else - { - sys.io.File.saveContent(path, data); - } - } - #else - throw 'Direct file writing by path not supported on this platform.'; - #end - } - - /** - * Write byte file contents directly to a given path. - * Only works on desktop. - * - * @param path The path to the file. - * @param data The bytes to write. - * @param mode Whether to Force, Skip, or Ask to overwrite an existing file. - */ - public static function writeBytesToPath(path:String, data:Bytes, mode:FileWriteMode = Skip):Void - { - #if sys - createDirIfNotExists(Path.directory(path)); - switch (mode) - { - case Force: - sys.io.File.saveBytes(path, data); - case Skip: - if (!doesFileExist(path)) - { - sys.io.File.saveBytes(path, data); - } - else - { - // Do nothing. - // throw 'File already exists: $path'; - } - case Ask: - if (doesFileExist(path)) - { - // TODO: We don't have the technology to use native popups yet. - throw 'File already exists: $path'; - } - else - { - sys.io.File.saveBytes(path, data); - } - } - #else - throw 'Direct file writing by path not supported on this platform.'; - #end - } - - /** - * Write string file contents directly to the end of a file at the given path. - * Only works on desktop. - * - * @param path The path to the file. - * @param data The string to append. - */ - public static function appendStringToPath(path:String, data:String):Void - { - #if sys - sys.io.File.append(path, false).writeString(data); - #else - throw 'Direct file writing by path not supported on this platform.'; - #end - } - - /** - * Create a directory if it doesn't already exist. - * Only works on desktop. - * - * @param dir The path to the directory. - */ - public static function createDirIfNotExists(dir:String):Void - { - #if sys - if (!doesFileExist(dir)) - { - sys.FileSystem.createDirectory(dir); - } - #end - } - - static var tempDir:String = null; - static final TEMP_ENV_VARS:Array = ['TEMP', 'TMPDIR', 'TEMPDIR', 'TMP']; - - /** - * Get the path to a temporary directory we can use for writing files. - * Only works on desktop. - * - * @return The path to the temporary directory. - */ - public static function getTempDir():String - { - if (tempDir != null) return tempDir; - #if sys - #if windows - var path:String = null; - for (envName in TEMP_ENV_VARS) - { - path = Sys.getEnv(envName); - if (path == '') path = null; - if (path != null) break; - } - tempDir = Path.join([path, 'funkin/']); - return tempDir; - #else - tempDir = '/tmp/funkin/'; - return tempDir; - #end - #else - return null; - #end - } - - /** - * Create a Bytes object containing a ZIP file, containing the provided entries. - * - * @param entries The entries to add to the ZIP file. - * @return The ZIP file as a Bytes object. - */ - public static function createZIPFromEntries(entries:Array):Bytes - { - var o:haxe.io.BytesOutput = new haxe.io.BytesOutput(); - var zipWriter:haxe.zip.Writer = new haxe.zip.Writer(o); - zipWriter.write(entries.list()); - return o.getBytes(); - } - - public static function readZIPFromBytes(input:Bytes):Array - { - trace('TEST: ' + input.length); - trace(input.sub(0, 30).toHex()); - var bytesInput = new haxe.io.BytesInput(input); - var zippedEntries = haxe.zip.Reader.readZip(bytesInput); - var results:Array = []; - for (entry in zippedEntries) - { - if (entry.compressed) - { - entry.data = haxe.zip.Reader.unzip(entry); - } - results.push(entry); - } - return results; - } - - public static function mapZIPEntriesByName(input:Array):Map - { - var results:Map = []; - for (entry in input) - { - results.set(entry.fileName, entry); - } - return results; - } - - /** - * Create a ZIP file entry from a file name and its string contents. - * - * @param name The name of the file. You can use slashes to create subdirectories. - * @param content The string contents of the file. - * @return The resulting entry. - */ - public static function makeZIPEntry(name:String, content:String):Entry - { - var data:Bytes = haxe.io.Bytes.ofString(content, UTF8); - return makeZIPEntryFromBytes(name, data); - } - - /** - * Create a ZIP file entry from a file name and its string contents. - * - * @param name The name of the file. You can use slashes to create subdirectories. - * @param data The byte data of the file. - * @return The resulting entry. - */ - public static function makeZIPEntryFromBytes(name:String, data:haxe.io.Bytes):Entry - { - return { - fileName: name, - fileSize: data.length, - data: data, - dataSize: data.length, - compressed: false, - fileTime: Date.now(), - crc32: null, - extraFields: null, - }; - } - - 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... - } - - static function convertTypeFilter(typeFilter:Array):String - { - var filter:String = null; - if (typeFilter != null) - { - var filters:Array = []; - for (type in typeFilter) - { - filters.push(StringTools.replace(StringTools.replace(type.extension, '*.', ''), ';', ',')); - } - filter = filters.join(';'); - } - return filter; - } -} - -enum FileWriteMode -{ - /** - * Forcibly overwrite the file if it already exists. - */ - Force; - - /** - * Ask the user if they want to overwrite the file if it already exists. - */ - Ask; - - /** - * Skip the file if it already exists. - */ - Skip; -} diff --git a/source/funkin/export bs/util/MouseUtil.hx b/source/funkin/export bs/util/MouseUtil.hx deleted file mode 100644 index fa498a9a5a..0000000000 --- a/source/funkin/export bs/util/MouseUtil.hx +++ /dev/null @@ -1,48 +0,0 @@ -package funkin.util; - -import flixel.math.FlxPoint; - -/** - * Utility functions related to the mouse. - */ -class MouseUtil -{ - static var oldCamPos:FlxPoint = new FlxPoint(); - static var oldMousePos:FlxPoint = new FlxPoint(); - - /** - * Used to be for general camera middle click dragging, now generalized for any click and drag type shit! - * Listen I don't make the rules here - * @param target what you want to be dragged, defaults to CAMERA SCROLL - * @param jusPres the "justPressed", should be a button of some sort - * @param pressed the "pressed", which should be the same button as `jusPres` - */ - public static function mouseCamDrag(?target:FlxPoint, ?jusPres:Bool, ?pressed:Bool):Void - { - if (target == null) target = FlxG.camera.scroll; - - if (jusPres == null) jusPres = FlxG.mouse.justPressedMiddle; - - if (pressed == null) pressed = FlxG.mouse.pressedMiddle; - - if (jusPres) - { - oldCamPos.set(target.x, target.y); - oldMousePos.set(FlxG.mouse.viewX, FlxG.mouse.viewY); - } - - if (pressed) - { - target.x = oldCamPos.x - (FlxG.mouse.viewX - oldMousePos.x); - target.y = oldCamPos.y - (FlxG.mouse.viewY - oldMousePos.y); - } - } - - /** - * Increment the zoom level of the current camera by the mouse wheel scroll value. - */ - public static function mouseWheelZoom():Void - { - if (FlxG.mouse.wheel != 0) FlxG.camera.zoom += FlxG.mouse.wheel * (0.1 * FlxG.camera.zoom); - } -} diff --git a/source/funkin/ui/debug/DebugMenuSubState.hx b/source/funkin/ui/debug/DebugMenuSubState.hx index cc6a2426e7..6fc6be9378 100644 --- a/source/funkin/ui/debug/DebugMenuSubState.hx +++ b/source/funkin/ui/debug/DebugMenuSubState.hx @@ -61,6 +61,7 @@ class DebugMenuSubState extends MusicBeatSubState createItem("CHARACTER SELECT", openCharSelect, true); createItem("ANIMATION EDITOR", openAnimationEditor); createItem("STAGE EDITOR", openStageEditor); + createItem("CHARACTER CREATOR", openCharCreator); // createItem("TEST STICKERS", testStickers); #if sys createItem("OPEN CRASH LOG FOLDER", openLogFolder); @@ -128,6 +129,12 @@ class DebugMenuSubState extends MusicBeatSubState FlxG.switchState(() -> new funkin.ui.debug.stageeditor.StageEditorState()); } + function openCharCreator() + { + trace('Character Creator'); + FlxG.switchState(() -> new funkin.ui.debug.char.CharCreatorState()); + } + #if sys function openLogFolder() { diff --git a/source/funkin/export bs/ui/debug/char/CharCreatorCharacter.hx b/source/funkin/ui/debug/char/CharCreatorCharacter.hx similarity index 100% rename from source/funkin/export bs/ui/debug/char/CharCreatorCharacter.hx rename to source/funkin/ui/debug/char/CharCreatorCharacter.hx diff --git a/source/funkin/export bs/ui/debug/char/CharCreatorState.hx b/source/funkin/ui/debug/char/CharCreatorState.hx similarity index 100% rename from source/funkin/export bs/ui/debug/char/CharCreatorState.hx rename to source/funkin/ui/debug/char/CharCreatorState.hx diff --git a/source/funkin/export bs/ui/debug/char/animate/CharSelectAnimateFrames.hx b/source/funkin/ui/debug/char/animate/CharSelectAnimateFrames.hx similarity index 100% rename from source/funkin/export bs/ui/debug/char/animate/CharSelectAnimateFrames.hx rename to source/funkin/ui/debug/char/animate/CharSelectAnimateFrames.hx diff --git a/source/funkin/export bs/ui/debug/char/animate/CharSelectAtlasSprite.hx b/source/funkin/ui/debug/char/animate/CharSelectAtlasSprite.hx similarity index 100% rename from source/funkin/export bs/ui/debug/char/animate/CharSelectAtlasSprite.hx rename to source/funkin/ui/debug/char/animate/CharSelectAtlasSprite.hx diff --git a/source/funkin/export bs/ui/debug/char/components/dialogs/AddAnimDialog.hx b/source/funkin/ui/debug/char/components/dialogs/AddAnimDialog.hx similarity index 100% rename from source/funkin/export bs/ui/debug/char/components/dialogs/AddAnimDialog.hx rename to source/funkin/ui/debug/char/components/dialogs/AddAnimDialog.hx diff --git a/source/funkin/export bs/ui/debug/char/components/dialogs/DefaultPageDialog.hx b/source/funkin/ui/debug/char/components/dialogs/DefaultPageDialog.hx similarity index 100% rename from source/funkin/export bs/ui/debug/char/components/dialogs/DefaultPageDialog.hx rename to source/funkin/ui/debug/char/components/dialogs/DefaultPageDialog.hx diff --git a/source/funkin/export bs/ui/debug/char/components/dialogs/import.hx b/source/funkin/ui/debug/char/components/dialogs/import.hx similarity index 100% rename from source/funkin/export bs/ui/debug/char/components/dialogs/import.hx rename to source/funkin/ui/debug/char/components/dialogs/import.hx diff --git a/source/funkin/export bs/ui/debug/char/components/wizard/AddCharFilesDialog.hx b/source/funkin/ui/debug/char/components/wizard/AddCharFilesDialog.hx similarity index 100% rename from source/funkin/export bs/ui/debug/char/components/wizard/AddCharFilesDialog.hx rename to source/funkin/ui/debug/char/components/wizard/AddCharFilesDialog.hx diff --git a/source/funkin/export bs/ui/debug/char/components/wizard/ConfirmDialog.hx b/source/funkin/ui/debug/char/components/wizard/ConfirmDialog.hx similarity index 100% rename from source/funkin/export bs/ui/debug/char/components/wizard/ConfirmDialog.hx rename to source/funkin/ui/debug/char/components/wizard/ConfirmDialog.hx diff --git a/source/funkin/export bs/ui/debug/char/components/wizard/DefaultWizardDialog.hx b/source/funkin/ui/debug/char/components/wizard/DefaultWizardDialog.hx similarity index 100% rename from source/funkin/export bs/ui/debug/char/components/wizard/DefaultWizardDialog.hx rename to source/funkin/ui/debug/char/components/wizard/DefaultWizardDialog.hx diff --git a/source/funkin/export bs/ui/debug/char/components/wizard/RenderWizardDialog.hx b/source/funkin/ui/debug/char/components/wizard/RenderWizardDialog.hx similarity index 100% rename from source/funkin/export bs/ui/debug/char/components/wizard/RenderWizardDialog.hx rename to source/funkin/ui/debug/char/components/wizard/RenderWizardDialog.hx diff --git a/source/funkin/export bs/ui/debug/char/components/wizard/StartWizardDialog.hx b/source/funkin/ui/debug/char/components/wizard/StartWizardDialog.hx similarity index 100% rename from source/funkin/export bs/ui/debug/char/components/wizard/StartWizardDialog.hx rename to source/funkin/ui/debug/char/components/wizard/StartWizardDialog.hx diff --git a/source/funkin/export bs/ui/debug/char/handlers/CharCreatorStartupWizard.hx b/source/funkin/ui/debug/char/handlers/CharCreatorStartupWizard.hx similarity index 100% rename from source/funkin/export bs/ui/debug/char/handlers/CharCreatorStartupWizard.hx rename to source/funkin/ui/debug/char/handlers/CharCreatorStartupWizard.hx diff --git a/source/funkin/export bs/ui/debug/char/import.hx b/source/funkin/ui/debug/char/import.hx similarity index 100% rename from source/funkin/export bs/ui/debug/char/import.hx rename to source/funkin/ui/debug/char/import.hx diff --git a/source/funkin/export bs/ui/debug/char/pages/CharCreatorDefaultPage.hx b/source/funkin/ui/debug/char/pages/CharCreatorDefaultPage.hx similarity index 100% rename from source/funkin/export bs/ui/debug/char/pages/CharCreatorDefaultPage.hx rename to source/funkin/ui/debug/char/pages/CharCreatorDefaultPage.hx diff --git a/source/funkin/export bs/ui/debug/char/pages/CharCreatorFreeplayPage.hx b/source/funkin/ui/debug/char/pages/CharCreatorFreeplayPage.hx similarity index 100% rename from source/funkin/export bs/ui/debug/char/pages/CharCreatorFreeplayPage.hx rename to source/funkin/ui/debug/char/pages/CharCreatorFreeplayPage.hx diff --git a/source/funkin/export bs/ui/debug/char/pages/CharCreatorGameplayPage.hx b/source/funkin/ui/debug/char/pages/CharCreatorGameplayPage.hx similarity index 100% rename from source/funkin/export bs/ui/debug/char/pages/CharCreatorGameplayPage.hx rename to source/funkin/ui/debug/char/pages/CharCreatorGameplayPage.hx diff --git a/source/funkin/export bs/ui/debug/char/pages/CharCreatorSelectPage.hx b/source/funkin/ui/debug/char/pages/CharCreatorSelectPage.hx similarity index 100% rename from source/funkin/export bs/ui/debug/char/pages/CharCreatorSelectPage.hx rename to source/funkin/ui/debug/char/pages/CharCreatorSelectPage.hx diff --git a/source/funkin/export bs/ui/debug/char/util/CharCreatorUtil.hx b/source/funkin/ui/debug/char/util/CharCreatorUtil.hx similarity index 100% rename from source/funkin/export bs/ui/debug/char/util/CharCreatorUtil.hx rename to source/funkin/ui/debug/char/util/CharCreatorUtil.hx diff --git a/source/funkin/util/FileUtil.hx b/source/funkin/util/FileUtil.hx index 5b053bb08c..fdf7d123d0 100644 --- a/source/funkin/util/FileUtil.hx +++ b/source/funkin/util/FileUtil.hx @@ -20,6 +20,8 @@ class FileUtil { public static final FILE_FILTER_FNFC:FileFilter = new FileFilter("Friday Night Funkin' Chart (.fnfc)", "*.fnfc"); public static final FILE_FILTER_JSON:FileFilter = new FileFilter("JSON Data File (.json)", "*.json"); + public static final FILE_FILTER_XML:FileFilter = new FileFilter("XML Data File (.xml)", "*.xml"); + public static final FILE_FILTER_TXT:FileFilter = new FileFilter("Text File (.txt)", "*.txt"); 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_FILTER_FNFS:FileFilter = new FileFilter("Friday Night Funkin' Stage (.fnfs)", "*.fnfs"); @@ -34,6 +36,21 @@ class FileUtil extension: 'zip', label: 'ZIP Archive', }; + public static final FILE_EXTENSION_INFO_JSON:FileDialogExtensionInfo = + { + extension: 'json', + label: 'JSON Data File', + }; + public static final FILE_EXTENSION_INFO_XML:FileDialogExtensionInfo = + { + extension: 'xml', + label: 'XML Data File', + }; + public static final FILE_EXTENSION_INFO_TXT:FileDialogExtensionInfo = + { + extension: 'txt', + label: 'Text File', + }; public static final FILE_EXTENSION_INFO_PNG:FileDialogExtensionInfo = { extension: 'png', diff --git a/source/funkin/util/MouseUtil.hx b/source/funkin/util/MouseUtil.hx index 5248437a8f..fa498a9a5a 100644 --- a/source/funkin/util/MouseUtil.hx +++ b/source/funkin/util/MouseUtil.hx @@ -28,13 +28,13 @@ class MouseUtil if (jusPres) { oldCamPos.set(target.x, target.y); - oldMousePos.set(FlxG.mouse.screenX, FlxG.mouse.screenY); + oldMousePos.set(FlxG.mouse.viewX, FlxG.mouse.viewY); } if (pressed) { - target.x = oldCamPos.x - (FlxG.mouse.screenX - oldMousePos.x); - target.y = oldCamPos.y - (FlxG.mouse.screenY - oldMousePos.y); + target.x = oldCamPos.x - (FlxG.mouse.viewX - oldMousePos.x); + target.y = oldCamPos.y - (FlxG.mouse.viewY - oldMousePos.y); } }