From 9f29192ae8fa7902ad198c84d549b38b4d568bc1 Mon Sep 17 00:00:00 2001 From: Lenheart <947330670@qq.com> Date: Sat, 21 Feb 2026 03:34:48 +0800 Subject: [PATCH] =?UTF-8?q?feat(=E5=B9=B3=E5=8F=B0):=20=E6=B7=BB=E5=8A=A0S?= =?UTF-8?q?witch=E5=B9=B3=E5=8F=B0=E6=94=AF=E6=8C=81=E5=B9=B6=E5=AE=9E?= =?UTF-8?q?=E7=8E=B0=E8=B5=84=E6=BA=90=E7=AE=A1=E7=90=86=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增Switch平台初始化与清理功能 - 实现Asset资源管理器类,提供文件读写、路径处理等功能 - 完善Window类的销毁逻辑,释放SDL资源 - 更新Switch平台编译配置,移除冗余标志 - 在主程序中集成资源管理器功能 --- Fostbite2D/include/fostbite2D/core/window.h | 2 +- .../include/fostbite2D/platform/switch.h | 18 + Fostbite2D/include/fostbite2D/utils/asset.h | 397 ++++++++++++++++ .../src/fostbite2D/core/application.cpp | 20 +- Fostbite2D/src/fostbite2D/core/window.cpp | 10 +- Fostbite2D/src/fostbite2D/platform/switch.cpp | 17 + Fostbite2D/src/fostbite2D/utils/asset.cpp | 435 ++++++++++++++++++ Fostbite2D/src/main.cpp | 12 + platform/switch.lua | 2 +- 9 files changed, 905 insertions(+), 8 deletions(-) create mode 100644 Fostbite2D/include/fostbite2D/platform/switch.h create mode 100644 Fostbite2D/include/fostbite2D/utils/asset.h create mode 100644 Fostbite2D/src/fostbite2D/platform/switch.cpp create mode 100644 Fostbite2D/src/fostbite2D/utils/asset.cpp diff --git a/Fostbite2D/include/fostbite2D/core/window.h b/Fostbite2D/include/fostbite2D/core/window.h index 0abd98b..3c63be2 100644 --- a/Fostbite2D/include/fostbite2D/core/window.h +++ b/Fostbite2D/include/fostbite2D/core/window.h @@ -79,7 +79,7 @@ struct WindowConfig { class Window { public: Window() = default; - virtual ~Window() = default; + ~Window() = default; /** * @brief 创建窗口 diff --git a/Fostbite2D/include/fostbite2D/platform/switch.h b/Fostbite2D/include/fostbite2D/platform/switch.h new file mode 100644 index 0000000..2428027 --- /dev/null +++ b/Fostbite2D/include/fostbite2D/platform/switch.h @@ -0,0 +1,18 @@ +#pragma once + +#ifdef __SWITCH__ + +#include +#include + +namespace frostbite2D { +/** + * @brief Switch平台相关函数 + */ + +void switchInit(); +void switchShutdown(); + +} // namespace frostbite2D + +#endif diff --git a/Fostbite2D/include/fostbite2D/utils/asset.h b/Fostbite2D/include/fostbite2D/utils/asset.h new file mode 100644 index 0000000..644d884 --- /dev/null +++ b/Fostbite2D/include/fostbite2D/utils/asset.h @@ -0,0 +1,397 @@ +#pragma once + +#include +#include +#include +#include +#include + +namespace frostbite2D { + +namespace fs = std::filesystem; + +/** + * @brief 文件信息结构体 + */ +struct FileInfo { + std::string name; ///< 文件名(包含扩展名) + std::string extension; ///< 文件扩展名(包含点,如 ".txt") + std::string fullPath; ///< 完整路径 + uint64 size = 0; ///< 文件大小(字节) + bool isDirectory = false; ///< 是否为目录 + bool isRegularFile = false; ///< 是否为普通文件 + bool exists = false; ///< 是否存在 +}; + +/** + * @brief 资源管理类(单例) + * + * 提供文件读写、目录操作、路径处理等功能。 + * 支持设置工作目录,所有相对路径将基于工作目录解析。 + * 支持 UTF-8 编码的中文路径。 + * + * @example + * auto& asset = Asset::get(); + * asset.setWorkingDirectory("D:/游戏/资源"); + * std::string content; + * asset.readTextFile("配置/设置.json", content); + */ +class Asset { +public: + /** + * @brief 获取单例实例 + * @return 资源管理器实例引用 + */ + static Asset &get(); + + Asset(const Asset &) = delete; + Asset &operator=(const Asset &) = delete; + + // --------------------------------------------------------------------------- + // 文件读写 + // --------------------------------------------------------------------------- + + /** + * @brief 读取文本文件 + * @param path 文件路径(相对或绝对路径) + * @param outContent 输出文件内容 + * @return 读取成功返回 true + */ + bool readTextFile(const std::string &path, std::string &outContent); + + /** + * @brief 写入文本文件 + * @param path 文件路径 + * @param content 要写入的内容 + * @param append 是否追加模式,默认覆盖 + * @return 写入成功返回 true + */ + bool writeTextFile(const std::string &path, const std::string &content, + bool append = false); + + /** + * @brief 读取二进制文件 + * @param path 文件路径 + * @param outData 输出字节数组 + * @return 读取成功返回 true + */ + bool readBinaryFile(const std::string &path, std::vector &outData); + + /** + * @brief 写入二进制文件 + * @param path 文件路径 + * @param data 要写入的字节数组 + * @param append 是否追加模式,默认覆盖 + * @return 写入成功返回 true + */ + bool writeBinaryFile(const std::string &path, const std::vector &data, + bool append = false); + + /** + * @brief 读取文本文件到字符串(便捷方法) + * @param path 文件路径 + * @return 文件内容,失败返回 std::nullopt + */ + std::optional readFileToString(const std::string &path); + + /** + * @brief 读取二进制文件到字节数组(便捷方法) + * @param path 文件路径 + * @return 字节数组,失败返回 std::nullopt + */ + std::optional> readFileToBytes(const std::string &path); + + // --------------------------------------------------------------------------- + // 文件/目录检查 + // --------------------------------------------------------------------------- + + /** + * @brief 检查路径是否存在 + * @param path 路径 + * @return 存在返回 true + */ + bool exists(const std::string &path) const; + + /** + * @brief 检查路径是否为目录 + * @param path 路径 + * @return 是目录返回 true + */ + bool isDirectory(const std::string &path) const; + + /** + * @brief 检查路径是否为普通文件 + * @param path 路径 + * @return 是普通文件返回 true + */ + bool isRegularFile(const std::string &path) const; + + /** + * @brief 检查文件或目录是否为空 + * @param path 路径 + * @return 为空返回 true + */ + bool isEmpty(const std::string &path) const; + + // --------------------------------------------------------------------------- + // 目录操作 + // --------------------------------------------------------------------------- + + /** + * @brief 创建单层目录 + * @param path 目录路径 + * @return 创建成功返回 true + */ + bool createDirectory(const std::string &path); + + /** + * @brief 递归创建多层目录 + * @param path 目录路径 + * @return 创建成功返回 true + */ + bool createDirectories(const std::string &path); + + /** + * @brief 删除文件 + * @param path 文件路径 + * @return 删除成功返回 true + */ + bool removeFile(const std::string &path); + + /** + * @brief 删除目录及其所有内容 + * @param path 目录路径 + * @return 删除成功返回 true + */ + bool removeDirectory(const std::string &path); + + // --------------------------------------------------------------------------- + // 文件操作 + // --------------------------------------------------------------------------- + + /** + * @brief 复制文件 + * @param from 源文件路径 + * @param to 目标文件路径 + * @param overwrite 是否覆盖已存在的文件 + * @return 复制成功返回 true + */ + bool copyFile(const std::string &from, const std::string &to, + bool overwrite = false); + + /** + * @brief 移动文件 + * @param from 源文件路径 + * @param to 目标文件路径 + * @return 移动成功返回 true + */ + bool moveFile(const std::string &from, const std::string &to); + + /** + * @brief 重命名文件或目录 + * @param oldPath 原路径 + * @param newPath 新路径 + * @return 重命名成功返回 true + */ + bool rename(const std::string &oldPath, const std::string &newPath); + + // --------------------------------------------------------------------------- + // 目录遍历 + // --------------------------------------------------------------------------- + + /** + * @brief 列出目录中的所有文件 + * @param directoryPath 目录路径 + * @param recursive 是否递归遍历子目录 + * @return 文件路径列表 + */ + std::vector listFiles(const std::string &directoryPath, + bool recursive = false); + + /** + * @brief 列出目录中的所有子目录 + * @param directoryPath 目录路径 + * @param recursive 是否递归遍历子目录 + * @return 子目录路径列表 + */ + std::vector listDirectories(const std::string &directoryPath, + bool recursive = false); + + /** + * @brief 列出目录中的所有文件和子目录 + * @param directoryPath 目录路径 + * @param recursive 是否递归遍历子目录 + * @return 所有项目路径列表 + */ + std::vector listAll(const std::string &directoryPath, + bool recursive = false); + + /** + * @brief 按扩展名列出文件 + * @param directoryPath 目录路径 + * @param extension 文件扩展名(如 ".png") + * @param recursive 是否递归遍历子目录 + * @return 匹配的文件路径列表 + */ + std::vector + listFilesWithExtension(const std::string &directoryPath, + const std::string &extension, bool recursive = false); + + // --------------------------------------------------------------------------- + // 文件信息 + // --------------------------------------------------------------------------- + + /** + * @brief 获取文件详细信息 + * @param path 文件路径 + * @return 文件信息结构体 + */ + FileInfo getFileInfo(const std::string &path); + + /** + * @brief 获取文件大小 + * @param path 文件路径 + * @return 文件大小(字节) + */ + uint64 getFileSize(const std::string &path) const; + + // --------------------------------------------------------------------------- + // 路径处理 + // --------------------------------------------------------------------------- + + /** + * @brief 获取文件名(包含扩展名) + * @param path 文件路径 + * @return 文件名 + */ + std::string getFileName(const std::string &path) const; + + /** + * @brief 获取文件名(不含扩展名) + * @param path 文件路径 + * @return 文件名 + */ + std::string getFileNameWithoutExtension(const std::string &path) const; + + /** + * @brief 获取文件扩展名 + * @param path 文件路径 + * @return 扩展名(包含点,如 ".txt") + */ + std::string getExtension(const std::string &path) const; + + /** + * @brief 获取父目录路径 + * @param path 文件路径 + * @return 父目录路径 + */ + std::string getParentPath(const std::string &path) const; + + /** + * @brief 获取绝对路径 + * @param path 相对或绝对路径 + * @return 绝对路径 + */ + std::string getAbsolutePath(const std::string &path) const; + + /** + * @brief 获取规范路径(解析符号链接和相对路径) + * @param path 路径 + * @return 规范化路径 + */ + std::string getCanonicalPath(const std::string &path) const; + + /** + * @brief 合并两个路径 + * @param left 左侧路径 + * @param right 右侧路径 + * @return 合并后的路径 + */ + std::string combinePath(const std::string &left, + const std::string &right) const; + + /** + * @brief 规范化路径(转换为系统首选格式) + * @param path 路径 + * @return 规范化路径 + */ + std::string normalizePath(const std::string &path) const; + + // --------------------------------------------------------------------------- + // 工作目录 + // --------------------------------------------------------------------------- + + /** + * @brief 获取当前工作目录 + * @return 当前工作目录路径 + */ + std::string getCurrentPath() const; + + /** + * @brief 设置当前工作目录 + * @param path 目录路径 + * @return 设置成功返回 true + */ + bool setCurrentPath(const std::string &path); + + /** + * @brief 设置资源工作目录 + * + * 设置后,所有相对路径操作都将基于此目录。 + * + * @param path 工作目录路径 + */ + void setWorkingDirectory(const std::string &path); + + /** + * @brief 获取资源工作目录 + * @return 工作目录路径 + */ + const std::string &getWorkingDirectory() const; + + /** + * @brief 解析相对路径为完整路径 + * @param relativePath 相对路径 + * @return 完整路径 + */ + std::string resolvePath(const std::string &relativePath) const; + + // --------------------------------------------------------------------------- + // 资源根目录 + // --------------------------------------------------------------------------- + + /** + * @brief 设置资源根目录 + * @param root 资源根目录路径 + */ + void setAssetRoot(const std::string &root); + + /** + * @brief 获取资源根目录 + * @return 资源根目录路径 + */ + const std::string &getAssetRoot() const; + + /** + * @brief 解析资源相对路径 + * + * 将相对路径解析为:工作目录/资源根目录/相对路径 + * + * @param relativePath 相对路径 + * @return 完整路径 + */ + std::string resolveAssetPath(const std::string &relativePath) const; + +private: + Asset() = default; + ~Asset() = default; + + fs::path toPath(const std::string &path) const; + std::string fromPath(const fs::path &path) const; + std::string resolveFullPath(const std::string &path) const; + + std::string workingDirectory_; + std::string assetRoot_; +}; + +} // namespace frostbite2D diff --git a/Fostbite2D/src/fostbite2D/core/application.cpp b/Fostbite2D/src/fostbite2D/core/application.cpp index 6407ce9..f6752b7 100644 --- a/Fostbite2D/src/fostbite2D/core/application.cpp +++ b/Fostbite2D/src/fostbite2D/core/application.cpp @@ -1,5 +1,6 @@ #include #include +#include namespace frostbite2D { Application &Application::get() { @@ -34,6 +35,11 @@ bool Application::init(const AppConfig &config) { return true; } + // 平台相关初始化 +#ifdef __SWITCH__ + switchInit(); +#endif + this->window_ = new Window(); if (!window_->create(config.windowConfig)) { @@ -47,12 +53,16 @@ bool Application::init(const AppConfig &config) { void Application::shutdown() { if (!initialized_) return; + + if (window_) { + window_->destroy(); + window_ = nullptr; + } - // VRAMMgr::get().printStats(); - - // ServiceLocator::instance().clear(); - - // window_ = nullptr; + // 平台相关清理 +#ifdef __SWITCH__ + switchShutdown(); +#endif initialized_ = false; running_ = false; diff --git a/Fostbite2D/src/fostbite2D/core/window.cpp b/Fostbite2D/src/fostbite2D/core/window.cpp index 5b9d816..dbd1f23 100644 --- a/Fostbite2D/src/fostbite2D/core/window.cpp +++ b/Fostbite2D/src/fostbite2D/core/window.cpp @@ -87,7 +87,15 @@ bool Window::create(const WindowConfig &cfg) { return true; } -void Window::destroy() {} +void Window::destroy() { + if (sdlWindow_) { + SDL_GL_DeleteContext(glContext_); + glContext_ = nullptr; + SDL_DestroyWindow(sdlWindow_); + sdlWindow_ = nullptr; + } + SDL_Quit(); +} void Window::poll() {} diff --git a/Fostbite2D/src/fostbite2D/platform/switch.cpp b/Fostbite2D/src/fostbite2D/platform/switch.cpp new file mode 100644 index 0000000..7d98c4c --- /dev/null +++ b/Fostbite2D/src/fostbite2D/platform/switch.cpp @@ -0,0 +1,17 @@ +#include + +#ifdef __SWITCH__ +namespace frostbite2D { +void switchInit() { + // 初始化Switch平台相关的资源 + socketInitializeDefault(); + nxlinkStdio(); +} + +void switchShutdown() { + // 清理Switch平台相关的资源 + socketExit(); +} +} // namespace frostbite2D + +#endif \ No newline at end of file diff --git a/Fostbite2D/src/fostbite2D/utils/asset.cpp b/Fostbite2D/src/fostbite2D/utils/asset.cpp new file mode 100644 index 0000000..ac6754d --- /dev/null +++ b/Fostbite2D/src/fostbite2D/utils/asset.cpp @@ -0,0 +1,435 @@ +#include +#include +#include +#include + +namespace frostbite2D { + +Asset &Asset::get() { + static Asset instance; + return instance; +} + +fs::path Asset::toPath(const std::string &path) const { +#ifdef _WIN32 + return fs::u8path(path); +#else + return fs::path(path); +#endif +} + +std::string Asset::fromPath(const fs::path &path) const { +#ifdef _WIN32 + return path.u8string(); +#else + return path.string(); +#endif +} + +std::string Asset::resolveFullPath(const std::string &path) const { + if (path.empty()) { + return path; + } + + fs::path p = toPath(path); + if (p.is_absolute()) { + return path; + } + + if (!workingDirectory_.empty()) { + return fromPath(toPath(workingDirectory_) / p); + } + + return path; +} + +bool Asset::readTextFile(const std::string &path, std::string &outContent) { + std::string fullPath = resolveFullPath(path); + + if (!exists(fullPath)) { + return false; + } + + std::ifstream file(toPath(fullPath), std::ios::in | std::ios::binary); + if (!file.is_open()) { + return false; + } + + std::ostringstream ss; + ss << file.rdbuf(); + outContent = ss.str(); + file.close(); + return true; +} + +bool Asset::writeTextFile(const std::string &path, const std::string &content, + bool append) { + std::string fullPath = resolveFullPath(path); + + auto mode = std::ios::out; + if (append) { + mode |= std::ios::app; + } + + std::ofstream file(toPath(fullPath), mode); + if (!file.is_open()) { + return false; + } + + file << content; + file.close(); + return true; +} + +bool Asset::readBinaryFile(const std::string &path, + std::vector &outData) { + std::string fullPath = resolveFullPath(path); + + if (!exists(fullPath)) { + return false; + } + + std::ifstream file(toPath(fullPath), std::ios::in | std::ios::binary); + if (!file.is_open()) { + return false; + } + + file.seekg(0, std::ios::end); + auto size = file.tellg(); + file.seekg(0, std::ios::beg); + + outData.resize(static_cast(size)); + file.read(reinterpret_cast(outData.data()), size); + file.close(); + return true; +} + +bool Asset::writeBinaryFile(const std::string &path, + const std::vector &data, bool append) { + std::string fullPath = resolveFullPath(path); + + auto mode = std::ios::out | std::ios::binary; + if (append) { + mode |= std::ios::app; + } + + std::ofstream file(toPath(fullPath), mode); + if (!file.is_open()) { + return false; + } + + file.write(reinterpret_cast(data.data()), data.size()); + file.close(); + return true; +} + +bool Asset::exists(const std::string &path) const { + std::error_code ec; + return fs::exists(toPath(resolveFullPath(path)), ec); +} + +bool Asset::isDirectory(const std::string &path) const { + std::error_code ec; + return fs::is_directory(toPath(resolveFullPath(path)), ec); +} + +bool Asset::isRegularFile(const std::string &path) const { + std::error_code ec; + return fs::is_regular_file(toPath(resolveFullPath(path)), ec); +} + +bool Asset::createDirectory(const std::string &path) { + std::error_code ec; + return fs::create_directory(toPath(resolveFullPath(path)), ec); +} + +bool Asset::createDirectories(const std::string &path) { + std::error_code ec; + return fs::create_directories(toPath(resolveFullPath(path)), ec); +} + +bool Asset::removeFile(const std::string &path) { + std::error_code ec; + return fs::remove(toPath(resolveFullPath(path)), ec); +} + +bool Asset::removeDirectory(const std::string &path) { + std::error_code ec; + return fs::remove_all(toPath(resolveFullPath(path)), ec) > 0; +} + +bool Asset::copyFile(const std::string &from, const std::string &to, + bool overwrite) { + std::error_code ec; + auto options = + overwrite ? fs::copy_options::overwrite_existing : fs::copy_options::none; + return fs::copy_file(toPath(resolveFullPath(from)), + toPath(resolveFullPath(to)), options, ec); +} + +bool Asset::moveFile(const std::string &from, const std::string &to) { + std::error_code ec; + fs::rename(toPath(resolveFullPath(from)), toPath(resolveFullPath(to)), ec); + return !ec; +} + +bool Asset::rename(const std::string &oldPath, const std::string &newPath) { + std::error_code ec; + fs::rename(toPath(resolveFullPath(oldPath)), toPath(resolveFullPath(newPath)), + ec); + return !ec; +} + +std::vector Asset::listFiles(const std::string &directoryPath, + bool recursive) { + std::vector files; + fs::path fullPath = toPath(resolveFullPath(directoryPath)); + + std::error_code ec; + if (!fs::exists(fullPath, ec) || !fs::is_directory(fullPath, ec)) { + return files; + } + + try { + if (recursive) { + for (const auto &entry : fs::recursive_directory_iterator(fullPath, ec)) { + if (entry.is_regular_file()) { + files.push_back(fromPath(entry.path())); + } + } + } else { + for (const auto &entry : fs::directory_iterator(fullPath, ec)) { + if (entry.is_regular_file()) { + files.push_back(fromPath(entry.path())); + } + } + } + } catch (...) { + } + + return files; +} + +std::vector +Asset::listDirectories(const std::string &directoryPath, bool recursive) { + std::vector directories; + fs::path fullPath = toPath(resolveFullPath(directoryPath)); + + std::error_code ec; + if (!fs::exists(fullPath, ec) || !fs::is_directory(fullPath, ec)) { + return directories; + } + + try { + if (recursive) { + for (const auto &entry : fs::recursive_directory_iterator(fullPath, ec)) { + if (entry.is_directory()) { + directories.push_back(fromPath(entry.path())); + } + } + } else { + for (const auto &entry : fs::directory_iterator(fullPath, ec)) { + if (entry.is_directory()) { + directories.push_back(fromPath(entry.path())); + } + } + } + } catch (...) { + } + + return directories; +} + +std::vector Asset::listAll(const std::string &directoryPath, + bool recursive) { + std::vector items; + fs::path fullPath = toPath(resolveFullPath(directoryPath)); + + std::error_code ec; + if (!fs::exists(fullPath, ec) || !fs::is_directory(fullPath, ec)) { + return items; + } + + try { + if (recursive) { + for (const auto &entry : fs::recursive_directory_iterator(fullPath, ec)) { + items.push_back(fromPath(entry.path())); + } + } else { + for (const auto &entry : fs::directory_iterator(fullPath, ec)) { + items.push_back(fromPath(entry.path())); + } + } + } catch (...) { + } + + return items; +} + +std::vector +Asset::listFilesWithExtension(const std::string &directoryPath, + const std::string &extension, bool recursive) { + std::vector files; + fs::path fullPath = toPath(resolveFullPath(directoryPath)); + fs::path ext = toPath(extension); + + std::error_code ec; + if (!fs::exists(fullPath, ec) || !fs::is_directory(fullPath, ec)) { + return files; + } + + try { + if (recursive) { + for (const auto &entry : fs::recursive_directory_iterator(fullPath, ec)) { + if (entry.is_regular_file() && entry.path().extension() == ext) { + files.push_back(fromPath(entry.path())); + } + } + } else { + for (const auto &entry : fs::directory_iterator(fullPath, ec)) { + if (entry.is_regular_file() && entry.path().extension() == ext) { + files.push_back(fromPath(entry.path())); + } + } + } + } catch (...) { + } + + return files; +} + +FileInfo Asset::getFileInfo(const std::string &path) { + FileInfo info; + std::string fullPath = resolveFullPath(path); + info.fullPath = fullPath; + + if (!exists(fullPath)) { + info.exists = false; + return info; + } + + info.exists = true; + info.isDirectory = isDirectory(fullPath); + info.isRegularFile = isRegularFile(fullPath); + + fs::path p = toPath(fullPath); + info.name = fromPath(p.filename()); + info.extension = fromPath(p.extension()); + + if (info.isRegularFile) { + std::error_code ec; + info.size = fs::file_size(p, ec); + if (ec) { + info.size = 0; + } + } + + return info; +} + +std::string Asset::getFileName(const std::string &path) const { + return fromPath(toPath(path).filename()); +} + +std::string Asset::getFileNameWithoutExtension(const std::string &path) const { + return fromPath(toPath(path).stem()); +} + +std::string Asset::getExtension(const std::string &path) const { + return fromPath(toPath(path).extension()); +} + +std::string Asset::getParentPath(const std::string &path) const { + return fromPath(toPath(path).parent_path()); +} + +std::string Asset::getAbsolutePath(const std::string &path) const { + std::error_code ec; + return fromPath(fs::absolute(toPath(resolveFullPath(path)), ec)); +} + +std::string Asset::getCanonicalPath(const std::string &path) const { + std::error_code ec; + return fromPath(fs::canonical(toPath(resolveFullPath(path)), ec)); +} + +std::string Asset::getCurrentPath() const { + std::error_code ec; + return fromPath(fs::current_path(ec)); +} + +bool Asset::setCurrentPath(const std::string &path) { + std::error_code ec; + fs::current_path(toPath(path), ec); + return !ec; +} + +std::string Asset::combinePath(const std::string &left, + const std::string &right) const { + return fromPath(toPath(left) / toPath(right)); +} + +std::string Asset::normalizePath(const std::string &path) const { + std::error_code ec; + auto p = fs::absolute(toPath(resolveFullPath(path)), ec); + if (ec) { + return path; + } + return fromPath(p.make_preferred()); +} + +uint64 Asset::getFileSize(const std::string &path) const { + std::error_code ec; + auto size = fs::file_size(toPath(resolveFullPath(path)), ec); + if (ec) { + return 0; + } + return size; +} + +bool Asset::isEmpty(const std::string &path) const { + std::error_code ec; + return fs::is_empty(toPath(resolveFullPath(path)), ec); +} + +std::optional Asset::readFileToString(const std::string &path) { + std::string content; + if (readTextFile(path, content)) { + return content; + } + return std::nullopt; +} + +std::optional> +Asset::readFileToBytes(const std::string &path) { + std::vector data; + if (readBinaryFile(path, data)) { + return data; + } + return std::nullopt; +} + +void Asset::setWorkingDirectory(const std::string &path) { + workingDirectory_ = path; +} + +const std::string &Asset::getWorkingDirectory() const { + return workingDirectory_; +} + +std::string Asset::resolvePath(const std::string &relativePath) const { + return resolveFullPath(relativePath); +} + +void Asset::setAssetRoot(const std::string &root) { assetRoot_ = root; } + +const std::string &Asset::getAssetRoot() const { return assetRoot_; } + +std::string Asset::resolveAssetPath(const std::string &relativePath) const { + if (assetRoot_.empty()) { + return resolveFullPath(relativePath); + } + return resolveFullPath(combinePath(assetRoot_, relativePath)); +} + +} // namespace frostbite2D diff --git a/Fostbite2D/src/main.cpp b/Fostbite2D/src/main.cpp index 1b5e7bf..529d7de 100644 --- a/Fostbite2D/src/main.cpp +++ b/Fostbite2D/src/main.cpp @@ -2,6 +2,8 @@ #include #include #include +#include + #include using namespace frostbite2D; @@ -22,6 +24,16 @@ int main(int argc, char **argv) { return -1; } + Asset &asset = Asset::get(); + // asset.setWorkingDirectory("I:/DOF/骑士团"); + asset.setWorkingDirectory("/switch/testgame"); + std::string content; + if (asset.readTextFile("test.txt", content)) { + SDL_Log("test.txt content: %s", content.c_str()); + } else { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to read test.txt!"); + } + app.shutdown(); SDL_Log("程序正常退出"); diff --git a/platform/switch.lua b/platform/switch.lua index c1e7d3a..dd9b166 100644 --- a/platform/switch.lua +++ b/platform/switch.lua @@ -17,7 +17,7 @@ target("Frostbite2D") set_toolset("strip", path.join(devkitA64, "bin/aarch64-none-elf-strip.exe")) -- 架构标志 - local arch_flags = "-march=armv8-a+crc+crypto -mtune=cortex-a57 -mtp=soft -fPIE" + local arch_flags = "-march=armv8-a+crc+crypto -mtune=cortex-a57 -fPIE" add_cxflags(arch_flags) -- 使用 devkitPro 提供的 switch.specs 文件 add_ldflags("-specs=" .. path.join(devkitPro, "libnx/switch.specs"), "-g", arch_flags)