Skip to content

Commit

Permalink
Case-insensitive path lookup
Browse files Browse the repository at this point in the history
  • Loading branch information
Yangff committed Feb 24, 2024
1 parent 11c1180 commit 2064346
Show file tree
Hide file tree
Showing 4 changed files with 94 additions and 36 deletions.
41 changes: 20 additions & 21 deletions UE4SS/src/Mod/LuaMod.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -644,26 +644,17 @@ namespace RC
// Verify that there's a 'Scripts' directory
// Give the full path to the 'Scripts' directory to the mod container
std::filesystem::path mod_path_fs = m_mod_path;
auto path = (mod_path_fs / SYSSTR("scripts"));
if (std::filesystem::exists(path))
auto scripts_directory = File::get_path_if_exists(mod_path_fs, "Scripts");
if (scripts_directory)
{
// "scripts" get priority over "Scripts"
m_scripts_path = to_system(path);
m_scripts_path = to_system(*scripts_directory);
}
else
{
// failed, we try the other case
path = (mod_path_fs / SYSSTR("Scripts"));
if (std::filesystem::exists(path))
{
m_scripts_path = to_system(path);
}
else
{
// If the 'Scripts' directory doesn't exist then mark the mod as non-installable and move on to the next mod
set_installable(false);
return;
}
// If the 'Scripts' directory doesn't exist then mark the mod as non-installable and move on to the next mod
set_installable(false);
return;
}
}

Expand Down Expand Up @@ -841,8 +832,12 @@ namespace RC

lua_getfield(lua_state, -1, "path");
std::string current_paths = lua_tostring(lua_state, -1);
current_paths.append(std::format(";{}" LUA_DIRSEP "{}" LUA_DIRSEP "scripts" LUA_DIRSEP "?.lua", to_string(m_program.get_mods_directory()).c_str(), to_string(get_name())));
current_paths.append(std::format(";{}" LUA_DIRSEP "{}" LUA_DIRSEP "Scripts" LUA_DIRSEP "?.lua", to_string(m_program.get_mods_directory()).c_str(), to_string(get_name())));
auto scripts_directory = File::get_path_if_exists(m_mod_path, "Scripts");
if (scripts_directory)
{
auto scripts_path = ((*scripts_directory) / "?.lua").string();
current_paths.append(std::format(";{}", scripts_path));
}
current_paths.append(std::format(";{}" LUA_DIRSEP "shared" LUA_DIRSEP "?.lua", to_string(m_program.get_mods_directory()).c_str()));
current_paths.append(std::format(";{}" LUA_DIRSEP "shared" LUA_DIRSEP "?" LUA_DIRSEP "?.lua", to_string(m_program.get_mods_directory()).c_str()));
lua_pop(lua_state, 1);
Expand All @@ -851,9 +846,13 @@ namespace RC

lua_getfield(lua_state, -1, "cpath");
std::string current_cpaths = lua_tostring(lua_state, -1);
current_cpaths.append(std::format(";{}" LUA_DIRSEP "{}" LUA_DIRSEP "scripts" LUA_DIRSEP "?.dll", to_string(m_program.get_mods_directory()).c_str(), to_string(get_name())));
current_cpaths.append(std::format(";{}" LUA_DIRSEP "{}" LUA_DIRSEP "Scripts" LUA_DIRSEP "?.dll", to_string(m_program.get_mods_directory()).c_str(), to_string(get_name())));
current_cpaths.append(std::format(";{}" LUA_DIRSEP "{}" LUA_DIRSEP "?.dll", to_string(m_program.get_mods_directory()).c_str(), to_string(get_name())));
if (scripts_directory)
{
#define STRINGIFY(x) #x
auto dlls_path = ((*scripts_directory) / ("?" STRINGIFY(DLLEXT))).string();
current_cpaths.append(std::format(";{}", dlls_path));
}
current_cpaths.append(std::format(";{}" LUA_DIRSEP "{}" LUA_DIRSEP "?" STRINGIFY(DLLEXT), to_string(m_program.get_mods_directory()).c_str(), to_string(get_name())));
lua_pop(lua_state, 1);
lua_pushstring(lua_state, current_cpaths.c_str());
lua_setfield(lua_state, -2, "cpath");
Expand Down Expand Up @@ -2271,7 +2270,7 @@ No overload found for function 'CreateLogicModsDirectory'.
lua.throw_error("CreateLogicModsDirectory: Could not locate the \"Content\" directory because the directory structure is unknown (not "
"<RootGamePath>/Game/Content)\n");
}
auto logic_mods_dir = game_content_dir / "Paks/LogicMods";
auto logic_mods_dir = game_content_dir / "Paks" / "LogicMods";
if (std::filesystem::exists(logic_mods_dir))
{
Output::send<LogLevel::Warning>(
Expand Down
30 changes: 15 additions & 15 deletions UE4SS/src/UE4SSProgram.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -441,7 +441,12 @@ namespace RC
}

m_log_directory = m_working_directory;
m_settings_path_and_file.append(m_settings_file_name);
auto resolaved_settings_file = File::get_path_if_exists(m_settings_path_and_file, m_settings_file_name);
if (resolaved_settings_file) {
m_settings_path_and_file = *resolaved_settings_file;
} else {
throw std::runtime_error{"UE4SS-Settings.ini file not found"};
}
}

auto UE4SSProgram::create_emergency_console_for_early_error(SystemStringViewType error_message) -> void
Expand Down Expand Up @@ -1036,17 +1041,14 @@ namespace RC
else
{
// Create the mod but don't install it yet
if (std::filesystem::exists(sub_directory.path() / "scripts"))
m_mods.emplace_back(std::make_unique<LuaMod>(*this, to_system_string(sub_directory.path().stem()), to_system_string(sub_directory.path())));
#ifdef LINUX
else if (std::filesystem::exists(sub_directory.path() / "Scripts"))
// avoid we have both "scripts" and "Scripts" in the same mod
auto scripts_directory = File::get_path_if_exists(sub_directory.path(), "Scripts");
auto dlls_directory = File::get_path_if_exists(sub_directory.path(), "dlls");
if (scripts_directory) {
m_mods.emplace_back(std::make_unique<LuaMod>(*this, to_system_string(sub_directory.path().stem()), to_system_string(sub_directory.path())));
#endif
#ifdef HAS_CPPMOD
if (std::filesystem::exists(sub_directory.path() / "dlls"))
}
if (dlls_directory) {
m_mods.emplace_back(std::make_unique<CppMod>(*this, to_system_string(sub_directory.path().stem()), to_system_string(sub_directory.path())));
#endif
}
}
}
}
Expand Down Expand Up @@ -1219,14 +1221,12 @@ namespace RC
return std::format("is_directory ran into error {}", ec.value());
}

if (!std::filesystem::exists(mod_directory.path() / "enabled.txt", ec))
auto enabled = File::get_path_if_exists(mod_directory.path(), "enabled.txt");

if (!enabled.has_value())
{
continue;
}
if (ec.value() != 0)
{
return std::format("exists ran into error {}", ec.value());
}

auto mod = UE4SSProgram::find_mod_by_name<ModType>(to_system_string(mod_directory.path().stem()), UE4SSProgram::IsInstalled::Yes);
if (!dynamic_cast<ModType*>(mod))
Expand Down
5 changes: 5 additions & 0 deletions deps/first/File/include/File/File.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,9 @@ namespace RC::File
CreateIfNonExistent = CreateIfNonExistent::No) -> Handle;

RC_FILE_API auto delete_file(const std::filesystem::path& file_path_and_name) -> void;


// Search a path that can access `base / tail`, where the tail part is allowed to be case insensitive.
// Returns the path found or std::nullopt if no path was found.
RC_FILE_API auto get_path_if_exists(const std::filesystem::path& base, const std::filesystem::path& tail) -> std::optional<const std::filesystem::path>;
} // namespace RC::File
54 changes: 54 additions & 0 deletions deps/first/File/src/File.cpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,19 @@
#include <File/File.hpp>
#include <algorithm>

namespace RC::File
{
// we can't access helper/string here? or can we add helper to file's dep?
static bool case_insensitive_equals(char a, char b)
{
return std::tolower(static_cast<unsigned char>(a)) == std::tolower(static_cast<unsigned char>(b));
}

static bool case_insensitive_compare(const std::string& a, const std::string& b)
{
return std::equal(a.begin(), a.end(), b.begin(), b.end(), case_insensitive_equals);
}

auto construct_handle(const std::filesystem::path& file_name, const OpenProperties& open_properties) -> Handle
{
auto internal_handle = Handle::FileType::open_file(file_name, open_properties);
Expand All @@ -26,4 +38,46 @@ namespace RC::File
{
Handle::FileType::delete_file(file_path_and_name);
}

auto get_path_if_exists(const std::filesystem::path& base, const std::filesystem::path& tail) -> std::optional<const std::filesystem::path>
{
if (!std::filesystem::exists(base))
{
throw std::runtime_error("Base path does not exist: " + base.string());
}
if (tail.is_absolute())
{
throw std::runtime_error("Tail path must be relative: " + tail.string());
}
auto normalized_tail = tail.lexically_normal();
auto full_path = base.lexically_normal();
for (const auto& part : normalized_tail)
{
if (std::filesystem::exists(full_path / part))
{
full_path /= part;
}
else
{
bool found = false;
for (const auto& entry : std::filesystem::directory_iterator(full_path))
{
// case-insensitive comparison
auto entry_filename = entry.path().filename().string();
auto part_filename = part.string();
if (case_insensitive_compare(entry_filename, part_filename))
{
full_path /= entry.path().filename();
found = true;
break;
}
}
if (!found)
{
return std::nullopt;
}
}
}
return full_path;
}
} // namespace RC::File

0 comments on commit 2064346

Please sign in to comment.