Skip to content

Commit a8bb486

Browse files
committed
feat: Support +/- syntax in ini file instead of two add/remove sections
1 parent b6b8412 commit a8bb486

File tree

4 files changed

+60
-23
lines changed

4 files changed

+60
-23
lines changed

UE4SS/src/SettingsManager.cpp

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -56,17 +56,16 @@ namespace RC
5656
mods_directories.insert(mods_directories.begin(), std::filesystem::path{Overrides.ModsFolderPath});
5757
}
5858

59-
auto mods_paths_add_list = parser.get_ordered_list(STR("Overrides.ModsFolderPaths.Add"));
60-
mods_paths_add_list.for_each([](uint32_t i, const StringType& item) {
61-
// Add if not already in the list.
62-
// Moves to the bottom of the list if it already exists.
63-
UE4SSProgram::get_program().add_mods_directory(item);
64-
});
65-
66-
auto mods_paths_remove_list = parser.get_ordered_list(STR("Overrides.ModsFolderPaths.Remove"));
67-
mods_paths_remove_list.for_each([](uint32_t i, const StringType& item) {
68-
// Removes if it exists in the list.
69-
UE4SSProgram::get_program().remove_mods_directory(item);
59+
auto mods_paths_list = parser.get_list(section_overrides);
60+
mods_paths_list.for_each(STR("ModsFolderPaths"), [](const StringType& key, const Ini::Value& value) {
61+
if (key.starts_with(STR('+')))
62+
{
63+
UE4SSProgram::get_program().add_mods_directory(value.get_string_value());
64+
}
65+
else if (key.starts_with(STR('-')))
66+
{
67+
UE4SSProgram::get_program().remove_mods_directory(value.get_string_value());
68+
}
7069
});
7170

7271
constexpr static File::CharType section_general[] = STR("General");

assets/UE4SS-settings.ini

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,14 @@
33
; Default: <dll_directory>/Mods
44
ModsFolderPath =
55

6-
[Overrides.ModsFolderPaths.Add]
76
; Additional mods directories to load mods from.
8-
; Spaces are allowed, but do not use quotes!
9-
; Paths can be relative to the working directory (where UE4SS.dll is located), or absolute.
10-
; Mods will be loaded starting from the top of this list, with mods from further down overriding mods from further up.
11-
; The value of 'ModsFolderPath' is automatically inserted as the first value.
7+
; Use + prefix to add a directory, - prefix to remove.
8+
; Can be relative to working directory or absolute paths.
9+
; Note: If multiple directories contain mods with the same name, the last one found will be loaded.
1210
; Example:
13-
; ../SharedMods
14-
; C:/MyMods
15-
; Default: None
16-
17-
[Overrides.ModsFolderPaths.Remove]
18-
; Remove mods directories to load mods from.
11+
; +ModsFolderPaths = ../SharedMods
12+
; +ModsFolderPaths = C:/MyMods
13+
; -ModsFolderPaths = ../SharedMods
1914
; Default: None
2015

2116
[General]

deps/first/IniParser/include/IniParser/Section.hpp

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ namespace RC::Ini
1111
{
1212
std::unordered_map<File::StringType, Value> key_value_pairs{};
1313
std::vector<File::StringType> ordered_list{};
14+
std::vector<std::pair<File::StringType, Value>> key_value_array{};
1415
bool is_ordered_list{};
1516
};
1617

@@ -59,6 +60,40 @@ namespace RC::Ini
5960
}
6061
}
6162
}
63+
64+
template <typename Callable>
65+
auto for_each(const StringType match_key, Callable callable)
66+
{
67+
if (!m_section)
68+
{
69+
return;
70+
}
71+
if constexpr (CallableWithKeyValuePair<Callable>)
72+
{
73+
for (const auto& [key, value] : m_section->key_value_array)
74+
{
75+
// Skip '+' or '-' when comparing.
76+
StringViewType key_view{key.begin() + 1, key.end()};
77+
if (key_view == match_key)
78+
{
79+
callable(key, value);
80+
}
81+
}
82+
}
83+
else
84+
{
85+
for (size_t i = 0; i < m_section->key_value_array.size(); ++i)
86+
{
87+
auto [key, value] = m_section->key_value_array[i];
88+
// Skip '+' or '-' when comparing.
89+
StringViewType key_view{key.begin() + 1, key.end()};
90+
if (key_view == match_key)
91+
{
92+
callable(i, value.get_string_value());
93+
}
94+
}
95+
}
96+
}
6297
};
6398

6499
// Backwards compatibility just in case some external code made direct references to 'OrderedList'.

deps/first/IniParser/src/TokenParser.cpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -371,7 +371,15 @@ namespace RC::Ini
371371
}
372372

373373
// Create the value with the correct key and an empty value and store a pointer to it so that the value can be set later
374-
m_current_value = &m_current_section->key_value_pairs.emplace(m_current_character_data, Value{}).first->second;
374+
if (!m_current_character_data.empty() && (m_current_character_data.starts_with(STR('+')) || m_current_character_data.starts_with(STR('-'))))
375+
{
376+
// Retaining '+' and '-' for the user to process later.
377+
m_current_value = &m_current_section->key_value_array.emplace_back(m_current_character_data, Value{}).second;
378+
}
379+
else
380+
{
381+
m_current_value = &m_current_section->key_value_pairs.emplace(m_current_character_data, Value{}).first->second;
382+
}
375383
m_current_value->add_string_value(STR(""));
376384
m_current_value->set_ref(m_current_value);
377385
m_current_character_data.clear();

0 commit comments

Comments
 (0)