From fd16c379ff4880bdf7677b742a9375ca7014c07e Mon Sep 17 00:00:00 2001
From: squidbus <175574877+squidbus@users.noreply.github.com>
Date: Tue, 25 Mar 2025 09:22:48 -0700
Subject: [PATCH] Use Application Support directory on macOS. (#553)

---
 README.md                 | 1 +
 include/zelda_support.h   | 2 ++
 src/game/config.cpp       | 7 +++++++
 src/main/support_apple.mm | 9 +++++++++
 4 files changed, 19 insertions(+)

diff --git a/README.md b/README.md
index 95f9aa3..77868c8 100644
--- a/README.md
+++ b/README.md
@@ -122,6 +122,7 @@ You'll probably also want to change the default behavior so that you don't need
 #### Where is the savefile stored?
 - Windows: `%LOCALAPPDATA%\Zelda64Recompiled\saves`
 - Linux: `~/.config/Zelda64Recompiled/saves`
+- macOS: `~/Library/Application Support/Zelda64Recompiled/saves`
 
 #### How do I choose a different ROM?
 **You don't.** This project is **only** a port of Majora's Mask (and Ocarina of Time in the future), and it will only accept one specific ROM: the US version of the N64 release of Majora's Mask. ROMs in formats other than .z64 will be automatically converted, as long as it is the correct ROM. **It is not an emulator and it cannot run any arbitrary ROM.** 
diff --git a/include/zelda_support.h b/include/zelda_support.h
index 9751e9a..70dfe6f 100644
--- a/include/zelda_support.h
+++ b/include/zelda_support.h
@@ -3,6 +3,7 @@
 
 #include <functional>
 #include <filesystem>
+#include <optional>
 
 namespace zelda64 {
     std::filesystem::path get_asset_path(const char* asset);
@@ -12,6 +13,7 @@ namespace zelda64 {
 // Apple specific methods that usually require Objective-C. Implemented in support_apple.mm.
 #ifdef __APPLE__
     void dispatch_on_ui_thread(std::function<void()> func);
+    std::optional<std::filesystem::path> get_application_support_directory();
     std::filesystem::path get_bundle_resource_directory();
     std::filesystem::path get_bundle_directory();
 #endif
diff --git a/src/game/config.cpp b/src/game/config.cpp
index 7f6c614..17ff9e4 100644
--- a/src/game/config.cpp
+++ b/src/game/config.cpp
@@ -162,6 +162,13 @@ std::filesystem::path zelda64::get_app_folder_path() {
        return std::filesystem::path{getenv("APP_FOLDER_PATH")};
    }
 
+#if defined(__APPLE__)
+   const auto supportdir = zelda64::get_application_support_directory();
+   if (supportdir) {
+       return *supportdir / zelda64::program_id;
+   }
+#endif
+
    const char *homedir;
 
    if ((homedir = getenv("HOME")) == nullptr) {
diff --git a/src/main/support_apple.mm b/src/main/support_apple.mm
index 604a998..60a851e 100644
--- a/src/main/support_apple.mm
+++ b/src/main/support_apple.mm
@@ -12,6 +12,15 @@ namespace zelda64 {
         });
     }
 
+    std::optional<std::filesystem::path> get_application_support_directory() {
+        NSArray *dirs = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES);
+        if ([dirs count] > 0) {
+            NSString *dir = [dirs firstObject];
+            return std::filesystem::path([dir UTF8String]);
+        }
+        return std::nullopt;
+    }
+
     std::filesystem::path get_bundle_resource_directory() {
         NSString *bundlePath = [[NSBundle mainBundle] resourcePath];
         return std::filesystem::path([bundlePath UTF8String]);