From 5c9ee08922989219cda92c5d31ae36ccca412446 Mon Sep 17 00:00:00 2001
From: HJfod <60038575+HJfod@users.noreply.github.com>
Date: Sun, 26 Feb 2023 20:37:13 +0200
Subject: [PATCH 1/4] fix file open dialog default path not having a way to
 specify filename

---
 loader/include/Geode/utils/file.hpp    | 23 ++++++++++++++++++++-
 loader/src/platform/windows/nfdwin.cpp | 28 ++++++++++++++++++++++++--
 2 files changed, 48 insertions(+), 3 deletions(-)

diff --git a/loader/include/Geode/utils/file.hpp b/loader/include/Geode/utils/file.hpp
index 52a3afdc..57936ab1 100644
--- a/loader/include/Geode/utils/file.hpp
+++ b/loader/include/Geode/utils/file.hpp
@@ -187,6 +187,10 @@ namespace geode::utils::file {
         );
     };
 
+    /**
+     * Open a folder / file in the system's file explorer
+     * @param path Folder / file to open
+     */
     GEODE_DLL bool openFolder(ghc::filesystem::path const& path);
 
     enum class PickMode {
@@ -203,10 +207,27 @@ namespace geode::utils::file {
             std::unordered_set<std::string> files;
         };
 
-        ghc::filesystem::path defaultPath;
+        /**
+         * On PickMode::SaveFile and PickMode::OpenFile, last item is assumed 
+         * to be a filename, unless it points to an extant directory.
+         * On PickMode::OpenFolder, path is treated as leading up to a directory
+         */
+        std::optional<ghc::filesystem::path> defaultPath;
+        /**
+         * File extension filters to show on the file picker
+         */
         std::vector<Filter> filters;
     };
 
+    /**
+     * Prompt the user to pick a file using the system's file system picker
+     * @param mode Type of file selection prompt to show
+     * @param options Picker options
+     */
     GEODE_DLL Result<ghc::filesystem::path> pickFile(PickMode mode, FilePickOptions const& options);
+    /**
+     * Prompt the user to pick a bunch of files for opening using the system's file system picker
+     * @param options Picker options
+     */
     GEODE_DLL Result<std::vector<ghc::filesystem::path>> pickFiles(FilePickOptions const& options);
 }
diff --git a/loader/src/platform/windows/nfdwin.cpp b/loader/src/platform/windows/nfdwin.cpp
index fdf0819c..ad660a4b 100644
--- a/loader/src/platform/windows/nfdwin.cpp
+++ b/loader/src/platform/windows/nfdwin.cpp
@@ -125,6 +125,14 @@ static bool setDefaultPath(
     return true;
 }
 
+static bool setDefaultFile(
+    IFileDialog* dialog,
+    ghc::filesystem::path const& fileName
+) {
+    dialog->SetFileName(fileName.wstring().c_str());
+    return true;
+}
+
 template<class T>
 struct Holder {
     T m_deallocator;
@@ -173,8 +181,24 @@ Result<> nfdPick(
     if (!addFiltersToDialog(dialog, options.filters)) {
         return Err("Unable to add filters to dialog");
     }
-    if (!setDefaultPath(dialog, options.defaultPath)) {
-        return Err("Unable to set default path to dialog");
+    if (options.defaultPath && options.defaultPath.value().wstring().size()) {
+        ghc::filesystem::path path = options.defaultPath.value();
+        if (mode == NFDMode::OpenFile || mode == NFDMode::SaveFile) {
+            if (!ghc::filesystem::exists(path) || !ghc::filesystem::is_directory(path)) {
+                if (path.has_filename()) {
+                    setDefaultFile(dialog, path.filename());
+                }
+                if (path.has_parent_path()) {
+                    path = path.parent_path();
+                }
+                else {
+                    path = "";
+                }
+            }
+        }
+        if (path.wstring().size() && !setDefaultPath(dialog, path)) {
+            return Err("Unable to set default path to dialog");
+        }
     }
 
     if (mode == NFDMode::OpenFiles) {

From 33a91d67bccf5fc57b5f41c2fb96ff71efee684a Mon Sep 17 00:00:00 2001
From: HJfod <60038575+HJfod@users.noreply.github.com>
Date: Sun, 26 Feb 2023 21:08:21 +0200
Subject: [PATCH 2/4] fix EditorPauseLayer size

---
 bindings/GeometryDash.bro | 1 -
 1 file changed, 1 deletion(-)

diff --git a/bindings/GeometryDash.bro b/bindings/GeometryDash.bro
index 934303a6..956eb895 100644
--- a/bindings/GeometryDash.bro
+++ b/bindings/GeometryDash.bro
@@ -1159,7 +1159,6 @@ class EditorPauseLayer : CCBlockLayer, FLAlertLayerProtocol {
     void onSong(cocos2d::CCObject*) = win 0x74e70, mac 0x13e470;
 
     bool m_saved;
-    PAD = mac 0x4, win 0x4;
     CCMenuItemSpriteExtra* m_guidelinesOffButton;
     CCMenuItemSpriteExtra* m_guidelinesOnButton;
     LevelEditorLayer* m_editorLayer;

From 4a15afc7a7e38692ffa7032c48209fa8f77e846f Mon Sep 17 00:00:00 2001
From: hjfod <dreadrollmusic@gmail.com>
Date: Mon, 27 Feb 2023 18:36:36 +0200
Subject: [PATCH 3/4] add EditorUI::sliderChanged + Result::ok + bump version

---
 VERSION                               |  2 +-
 bindings/GeometryDash.bro             |  1 +
 loader/include/Geode/utils/Result.hpp | 44 +++++++++++++++++++++++++++
 3 files changed, 46 insertions(+), 1 deletion(-)

diff --git a/VERSION b/VERSION
index ebfa287c..73ff4a6f 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-1.0.0-beta.8
\ No newline at end of file
+1.0.0-beta.9
\ No newline at end of file
diff --git a/bindings/GeometryDash.bro b/bindings/GeometryDash.bro
index 956eb895..6fb6f127 100644
--- a/bindings/GeometryDash.bro
+++ b/bindings/GeometryDash.bro
@@ -1275,6 +1275,7 @@ class EditorUI : cocos2d::CCLayer, FLAlertLayerProtocol, ColorSelectDelegate, GJ
     void alignObjects(cocos2d::CCArray* objs, bool alignY) = mac 0x2cea0, win 0x8f320;
     virtual void scrollWheel(float vertical, float horizontal) = win 0x921d0, mac 0x31370, ios 0x2c4884;
     void createMoveMenu() = mac 0x275e0, win 0x8c0d0;
+    void sliderChanged(cocos2d::CCObject* slider) = win 0x78cc0;
 
     bool m_isPlayingMusic;
     EditButtonBar* m_buttonBar;
diff --git a/loader/include/Geode/utils/Result.hpp b/loader/include/Geode/utils/Result.hpp
index 227bfaf8..7f95750a 100644
--- a/loader/include/Geode/utils/Result.hpp
+++ b/loader/include/Geode/utils/Result.hpp
@@ -204,6 +204,50 @@ namespace geode {
         [[nodiscard]] constexpr decltype(auto) errorOr(U&& val) const& {
             return this->Base::error_or(std::forward<U>(val));
         }
+
+        /**
+         * Convert the result into an optional containing the value if Ok, and 
+         * nullopt if Err
+         */
+        [[nodiscard]] constexpr decltype(auto) ok() const& {
+            if (this->isOk()) {
+                return std::optional(this->unwrap());
+            }
+            return std::nullopt;
+        }
+
+        /**
+         * Convert the result into an optional containing the value if Ok, and 
+         * nullopt if Err
+         */
+        [[nodiscard]] constexpr decltype(auto) ok() && {
+            if (this->isOk()) {
+                return std::optional(this->unwrap());
+            }
+            return std::nullopt;
+        }
+
+        /**
+         * Convert the result into an optional containing the error if Err, and 
+         * nullopt if Ok
+         */
+        [[nodiscard]] constexpr decltype(auto) err() const& {
+            if (this->isErr()) {
+                return std::optional(this->unwrapErr());
+            }
+            return std::nullopt;
+        }
+
+        /**
+         * Convert the result into an optional containing the error if Err, and 
+         * nullopt if Ok
+         */
+        [[nodiscard]] constexpr decltype(auto) err() && {
+            if (this->isErr()) {
+                return std::optional(this->unwrapErr());
+            }
+            return std::nullopt;
+        }
     };
 
     template <class T = impl::DefaultValue>

From 5ecee87e1ccf724f8aae02e3a9f1c36583339783 Mon Sep 17 00:00:00 2001
From: ninXout <58670749+ninXout@users.noreply.github.com>
Date: Wed, 1 Mar 2023 11:26:51 -0500
Subject: [PATCH 4/4] Some MacOS bindings (#140)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* [CreatorLayer] onGauntlets()

* [LevelTools] base64EncodeString(), verifyLevelIntegrity(), xPosForTime(), timeForXPos(), getAudioFilename(), getAudioTitle(), getArtistForAudio(), getURLForAudio().

* [LevelTools] getLevel()

* [LocalLevelManager] init()

* [LeaderboardsLayer] init(), [LevelLeaderboard] init()

---------

Co-authored-by: Nosu♡ <93537876+Nosu-u@users.noreply.github.com>
---
 bindings/GeometryDash.bro | 21 +++++++++++++--------
 1 file changed, 13 insertions(+), 8 deletions(-)

diff --git a/bindings/GeometryDash.bro b/bindings/GeometryDash.bro
index 6fb6f127..f43b79ee 100644
--- a/bindings/GeometryDash.bro
+++ b/bindings/GeometryDash.bro
@@ -866,7 +866,7 @@ class CreatorLayer : cocos2d::CCLayer {
     void onFameLevels(cocos2d::CCObject*) = win 0x4ee70;
     void onMapPacks(cocos2d::CCObject*) = win 0x4efb0;
     void onOnlineLevels(cocos2d::CCObject*) = win 0x4ef60;
-    void onGauntlets(cocos2d::CCObject*) = win 0x4f0a0;
+    void onGauntlets(cocos2d::CCObject*) = mac 0x142b20, win 0x4f0a0;
     void onSecretVault(cocos2d::CCObject*) = win 0x4f1d0;
     void onTreasureRoom(cocos2d::CCObject*) = win 0x4f540;
     virtual void sceneWillResume() = win 0x4fb50;
@@ -3476,7 +3476,7 @@ class LeaderboardManagerDelegate {}
 
 class LeaderboardsLayer : cocos2d::CCLayer {
     static LeaderboardsLayer* create(LeaderboardState state) = win 0x158710;
-    bool init(LeaderboardState state) = win 0x1587b0;
+    bool init(LeaderboardState state) = mac 0x29f6d0, win 0x1587b0;
 }
 
 class LevelBrowserLayer : cocos2d::CCLayer {
@@ -3763,7 +3763,7 @@ class LevelInfoLayer : cocos2d::CCLayer, LevelDownloadDelegate, LevelUpdateDeleg
 class LevelLeaderboard : FLAlertLayer {
     void onChangeType(cocos2d::CCObject* sender) = win 0x17d090;
     void onGarage(cocos2d::CCObject* sender) = win 0x17d1b0;
-    bool init(GJGameLevel* level, int type) = win 0x17c4f0;
+    bool init(GJGameLevel* level, int type) = mac 0x20d710, win 0x17c4f0;
     static LevelLeaderboard* create(GJGameLevel* level, LevelLeaderboardType leaderboardType) = win 0x17c440;
 }
 
@@ -3929,6 +3929,7 @@ class LocalLevelManager : cocos2d::CCNode {
     inline static LocalLevelManager* get() {
         return LocalLevelManager::sharedState();
     }
+    bool init() = mac 0x2384e0;
 
     PAD = mac 0x10, win 0x1C;
     cocos2d::CCDictionary* m_loadData;
@@ -5406,11 +5407,15 @@ class VideoOptionsLayer : FLAlertLayer {
 }
 
 class LevelTools {
-    static gd::string base64EncodeString(gd::string) = win 0x18b310;
+    static gd::string base64EncodeString(gd::string) = mac 0x294470, win 0x18b310;
     static gd::string base64DecodeString(gd::string) = mac 0x294510, win 0x18b3b0;
-    static GJGameLevel *getLevel(int, bool) = win 0x189370;
-    static bool verifyLevelIntegrity(gd::string, int) = win 0x18b180;
-    static float xPosForTime(float, cocos2d::CCArray*, int) = win 0x18acd0;
-    static float timeForXPos(float, cocos2d::CCArray*, int) = win 0x18ae70;
+    static GJGameLevel* getLevel(int, bool) = mac 0x2908c0, win 0x189370;
+    static bool verifyLevelIntegrity(gd::string, int) = mac 0x294360, win 0x18b180;
+    static float xPosForTime(float, cocos2d::CCArray*, int) = mac 0x293d90, win 0x18acd0;
+    static float timeForXPos(float, cocos2d::CCArray*, int) = mac 0x293eb0, win 0x18ae70;
+    static gd::string getAudioFilename(int) = mac 0x292840;
+    static gd::string getAudioTitle(int) = mac 0x2922f0;
+    static gd::string getArtistForAudio(int) = mac 0x292d90;
+    static gd::string getURLForAudio(int) = mac 0x292f10;
 }
 // clang-format on