diff --git a/CMakeLists.txt b/CMakeLists.txt index bf7a667426..7361d370de 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -549,6 +549,7 @@ if (APPLE) set(DUSK_RESOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/platforms/tvos) else () set(DUSK_RESOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/platforms/macos) + set(DUSK_ENTITLEMENTS ${DUSK_RESOURCE_DIR}/Dusk.entitlements) endif () set(DUSK_INFO_PLIST ${DUSK_RESOURCE_DIR}/Info.plist.in) file(GLOB_RECURSE DUSK_RESOURCE_FILES @@ -579,6 +580,8 @@ if (APPLE) OUTPUT_NAME Dusk XCODE_ATTRIBUTE_CODE_SIGNING_ALLOWED "YES" XCODE_ATTRIBUTE_CODE_SIGNING_REQUIRED "YES" + XCODE_ATTRIBUTE_CODE_SIGN_ENTITLEMENTS ${DUSK_ENTITLEMENTS} + XCODE_ATTRIBUTE_ENABLE_HARDENED_RUNTIME "YES" ) endif () diff --git a/docs/modding.md b/docs/modding.md index bdb8618456..d053f66ded 100644 --- a/docs/modding.md +++ b/docs/modding.md @@ -51,6 +51,10 @@ add_dusk_mod(my_mod After building, `my_mod.dusk` is placed in `mods/` next to the project root (`DUSK_MODS_OUTPUT_DIR` cache variable). Copy it to the game's `mods/` folder and launch. +- Windows: `%APPDATA%\TwilitRealm\Dusk\mods` +- Linux: `~/.local/share/TwilitRealm/Dusk/mods` +- macOS: `~/Library/Application Support/TwilitRealm/Dusk/mods` + The `.dusk` archive is a standard zip containing `mod.json`, the compiled library, and an optional `res/` tree. `add_dusk_mod()` creates it automatically. --- diff --git a/include/dusk/mod_loader.hpp b/include/dusk/mod_loader.hpp index 72cb268747..5500facd72 100644 --- a/include/dusk/mod_loader.hpp +++ b/include/dusk/mod_loader.hpp @@ -55,7 +55,7 @@ public: private: std::vector m_mods; - std::filesystem::path m_modsDir = "mods"; + std::filesystem::path m_modsDir; bool m_initialized = false; void tryLoadDusk(const std::filesystem::path& modPath); diff --git a/platforms/macos/Dusk.entitlements b/platforms/macos/Dusk.entitlements new file mode 100644 index 0000000000..123d12a53e --- /dev/null +++ b/platforms/macos/Dusk.entitlements @@ -0,0 +1,8 @@ + + + + + com.apple.security.cs.disable-library-validation + + + diff --git a/src/dusk/mod_loader.cpp b/src/dusk/mod_loader.cpp index 4df11baed2..8fcd6b6635 100644 --- a/src/dusk/mod_loader.cpp +++ b/src/dusk/mod_loader.cpp @@ -253,7 +253,7 @@ void ModLoader::tryLoadDusk(const std::filesystem::path& modPath) { return; } - const fs::path cacheDir = fs::path("mods") / ".cache" / modPath.stem(); + const fs::path cacheDir = m_modsDir / ".cache" / modPath.stem(); std::error_code ec; fs::create_directories(cacheDir, ec); @@ -315,7 +315,7 @@ void ModLoader::init() { m_initialized = true; namespace fs = std::filesystem; - if (!fs::exists(m_modsDir)) { + if (!fs::is_directory(m_modsDir)) { DuskLog.info("ModLoader: mods directory '{}' not found — mod loading skipped", m_modsDir.string()); return; diff --git a/src/m_Do/m_Do_main.cpp b/src/m_Do/m_Do_main.cpp index 413503cf29..50f5064225 100644 --- a/src/m_Do/m_Do_main.cpp +++ b/src/m_Do/m_Do_main.cpp @@ -493,7 +493,7 @@ int game_main(int argc, char* argv[]) { ("h,help", "Print usage") ("console", "Show the Windows console window for logs", cxxopts::value()->default_value("false")->implicit_value("true")) ("dvd", "Path to DVD image file", cxxopts::value()) - ("mods", "Path to mods directory", cxxopts::value()->default_value("mods")) + ("mods", "Path to mods directory", cxxopts::value()) ("backend", "Graphics API backend to use (auto, d3d12, metal, vulkan, null)", cxxopts::value()) ("cvar", "Override configuration variables without modifying config", cxxopts::value>()); @@ -619,7 +619,15 @@ int game_main(int argc, char* argv[]) { mDoMain::developmentMode = 1; // Force Dev Mode for Debugging mDoDvdThd::SyncWidthSound = false; - dusk::ModLoader::instance().setModsDir(parsed_arg_options["mods"].as()); + // Setup mods + if (parsed_arg_options.contains("mods") && + !parsed_arg_options["mods"].as().empty()) + { + dusk::ModLoader::instance().setModsDir(parsed_arg_options["mods"].as()); + } else { + dusk::ModLoader::instance().setModsDir(dusk::ConfigPath / "mods"); + } + OSReport("Starting main01 (Game Loop)...\n"); main01();