diff --git a/src/anm2/anm2.cpp b/src/anm2/anm2.cpp index f994e62..56eee81 100644 --- a/src/anm2/anm2.cpp +++ b/src/anm2/anm2.cpp @@ -1546,7 +1546,7 @@ namespace anm2ed else element_child_id_erase(*container, type, element.id); if (type == ElementType::SOUND_ELEMENT || type == ElementType::SPRITESHEET) - element.path = path::lower_case_backslash_handle(element.path); + element.path = path::backslash_handle(element.path); container->children.push_back(element); } diff --git a/src/document.cpp b/src/document.cpp index 6941696..cd684b0 100644 --- a/src/document.cpp +++ b/src/document.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -408,7 +409,7 @@ namespace anm2ed if (!spritesheet) return false; util::WorkingDirectory workingDirectory(directory_get()); - textures[id] = resource::Texture(spritesheet->path); + textures[id] = resource::Texture(path::case_insensitive_find(spritesheet->path)); texturePaths[id] = spritesheet->path; return true; } @@ -419,7 +420,7 @@ namespace anm2ed if (!sound) return false; util::WorkingDirectory workingDirectory(directory_get()); - sounds[id] = resource::Audio(sound->path); + sounds[id] = resource::Audio(path::case_insensitive_find(sound->path)); soundPaths[id] = sound->path; return true; } @@ -439,7 +440,7 @@ namespace anm2ed texturePaths.at(spritesheet.id) != spritesheet.path; if (isReload) { - textures[spritesheet.id] = resource::Texture(spritesheet.path); + textures[spritesheet.id] = resource::Texture(path::case_insensitive_find(spritesheet.path)); texturePaths[spritesheet.id] = spritesheet.path; } } @@ -469,7 +470,7 @@ namespace anm2ed !sounds.contains(sound.id) || !soundPaths.contains(sound.id) || soundPaths.at(sound.id) != sound.path; if (isReload) { - sounds[sound.id] = resource::Audio(sound.path); + sounds[sound.id] = resource::Audio(path::case_insensitive_find(sound.path)); soundPaths[sound.id] = sound.path; } } @@ -1575,7 +1576,10 @@ namespace anm2ed for (auto& path : paths) { auto pathCopy = path; - auto loadPath = path::lower_case_backslash_handle(pathCopy); + auto storagePath = path::backslash_handle(pathCopy); + std::optional workingDirectory{}; + if (!storagePath.is_absolute()) workingDirectory.emplace(directory); + auto loadPath = path::case_insensitive_find(storagePath); auto texture = resource::Texture(loadPath); if (!texture.is_valid()) { @@ -1586,7 +1590,7 @@ namespace anm2ed continue; } - loaded.push_back({.relativePath = path::backslash_replace(path::make_relative(loadPath, directory)), + loaded.push_back({.relativePath = path::backslash_replace(path::make_relative(storagePath, directory)), .texture = std::move(texture)}); } if (loaded.empty()) return; @@ -1639,12 +1643,12 @@ namespace anm2ed auto id = element_child_next_id_get(*items, ElementType::SOUND_ELEMENT); auto soundElement = element_make(ElementType::SOUND_ELEMENT); soundElement.id = id; - auto loadPath = path::lower_case_backslash_handle(path); + auto loadPath = path::backslash_handle(path); auto relativePath = path::backslash_replace(path::make_relative(loadPath, directory)); { WorkingDirectory workingDirectory(directory_get()); soundElement.path = relativePath; - sounds[id] = resource::Audio(soundElement.path); + sounds[id] = resource::Audio(path::case_insensitive_find(soundElement.path)); soundPaths[id] = soundElement.path; } auto soundPath = path::to_utf8(soundElement.path); diff --git a/src/imgui/window/window.cpp b/src/imgui/window/window.cpp index 10a77bf..21c661e 100644 --- a/src/imgui/window/window.cpp +++ b/src/imgui/window/window.cpp @@ -297,7 +297,7 @@ namespace anm2ed::imgui std::filesystem::path window_asset_path_get(Document& document, const std::filesystem::path& path) { - auto loadPath = path::lower_case_backslash_handle(path); + auto loadPath = path::backslash_handle(path); return path::backslash_replace(path::make_relative(loadPath, document.directory_get())); } @@ -2326,8 +2326,28 @@ namespace anm2ed::imgui auto behavior = [&]() { auto spritesheet = document.anm2.element_get(ElementType::SPRITESHEET, id); - if (!spritesheet) return; - spritesheet->path = window_asset_path_get(document, dialogPath); + auto texture = document.texture_get(id); + if (!spritesheet || !texture) return; + auto newPath = window_asset_path_get(document, dialogPath); + auto pathString = path::to_utf8(newPath); + WorkingDirectory workingDirectory(document.directory_get()); + path::ensure_directory(newPath.parent_path()); + if (!texture->write_png(newPath)) + { + toasts.push(std::vformat(localize.get(TOAST_SAVE_SPRITESHEET_FAILED), + std::make_format_args(id, pathString))); + logger.error( + std::vformat(localize.get(TOAST_SAVE_SPRITESHEET_FAILED, anm2ed::ENGLISH), + std::make_format_args(id, pathString))); + return; + } + spritesheet->path = newPath; + document.texturePaths[id] = spritesheet->path; + document.spritesheet_hash_set_saved(id); + toasts.push(std::vformat(localize.get(TOAST_SAVE_SPRITESHEET), + std::make_format_args(id, pathString))); + logger.info(std::vformat(localize.get(TOAST_SAVE_SPRITESHEET, anm2ed::ENGLISH), + std::make_format_args(id, pathString))); }; window_edit(document, Document::SPRITESHEETS, diff --git a/src/util/path.cpp b/src/util/path.cpp index ccfa1e8..346666d 100644 --- a/src/util/path.cpp +++ b/src/util/path.cpp @@ -118,15 +118,55 @@ namespace anm2ed::util::path return path; } - std::filesystem::path lower_case_backslash_handle(const std::filesystem::path& path) + std::filesystem::path backslash_handle(const std::filesystem::path& path) { auto newPath = path; if (is_exist(newPath)) return newPath; newPath = backslash_replace(newPath); - if (is_exist(newPath)) return newPath; - - newPath = to_lower(newPath); return newPath; } + + std::filesystem::path case_insensitive_find(const std::filesystem::path& path) + { + auto handledPath = backslash_handle(path); + if (is_exist(handledPath)) return handledPath; + + auto resolvedPath = handledPath.root_path(); + for (const auto& part : handledPath.relative_path()) + { + auto candidate = resolvedPath / part; + if (is_exist(candidate)) + { + resolvedPath = candidate; + continue; + } + + auto parent = resolvedPath.empty() ? std::filesystem::path(".") : resolvedPath; + std::error_code ec{}; + bool isFound{}; + if (std::filesystem::is_directory(parent, ec)) + { + auto partLower = to_lower(part); + std::filesystem::directory_iterator it(parent, ec); + std::filesystem::directory_iterator end{}; + for (; !ec && it != end; it.increment(ec)) + if (to_lower(it->path().filename()) == partLower) + { + resolvedPath /= it->path().filename(); + isFound = true; + break; + } + } + + if (!isFound) resolvedPath = candidate; + } + + if (is_exist(resolvedPath)) return resolvedPath; + + auto lowerPath = to_lower(handledPath); + if (is_exist(lowerPath)) return lowerPath; + + return handledPath; + } } diff --git a/src/util/path.hpp b/src/util/path.hpp index 8a979b6..bcaba0a 100644 --- a/src/util/path.hpp +++ b/src/util/path.hpp @@ -18,5 +18,6 @@ namespace anm2ed::util::path bool ensure_directory(const std::filesystem::path&); - std::filesystem::path lower_case_backslash_handle(const std::filesystem::path&); + std::filesystem::path backslash_handle(const std::filesystem::path&); + std::filesystem::path case_insensitive_find(const std::filesystem::path&); } diff --git a/workshop/metadata.xml b/workshop/metadata.xml index 662df09..4247886 100644 --- a/workshop/metadata.xml +++ b/workshop/metadata.xml @@ -53,6 +53,6 @@ Alternatively, if you have subscribed to the mod, you can find the latest releas [h3]Happy animating![/h3] [img]https://files.catbox.moe/4auc1c.gif[/img] - 2.20 + 2.21 Public