-
Notifications
You must be signed in to change notification settings - Fork 217
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Converts mods.txt to use mods.json #540
base: main
Are you sure you want to change the base?
Changes from all commits
a0359bf
4a5de8a
81a56ce
60a8402
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -384,7 +384,7 @@ namespace RC | |
std::filesystem::path game_exe_path = exe_path_buffer; | ||
std::filesystem::path game_directory_path = game_exe_path.parent_path(); | ||
m_legacy_root_directory = game_directory_path; | ||
|
||
m_working_directory = m_root_directory; | ||
m_mods_directory = m_working_directory / "Mods"; | ||
m_game_executable_directory = game_directory_path; | ||
|
@@ -1117,67 +1117,127 @@ namespace RC | |
} | ||
} | ||
|
||
template <typename ModType> | ||
auto start_mods() -> std::string | ||
auto UE4SSProgram::read_mods_json(std::string mod_list_file, std::vector<ModData>& mod_data_vector) -> void | ||
{ | ||
ProfilerScope(); | ||
// Part #1: Start all mods that are enabled in mods.txt. | ||
Output::send(STR("Starting mods (from mods.txt load order)...\n")); | ||
|
||
std::filesystem::path mods_directory = UE4SSProgram::get_program().get_mods_directory(); | ||
std::wstring enabled_mods_file{mods_directory / "mods.txt"}; | ||
if (!std::filesystem::exists(enabled_mods_file)) | ||
std::string buffer{}; | ||
glz::parse_error pe = glz::read_file_json(mod_data_vector, mod_list_file, buffer); | ||
if (pe) | ||
{ | ||
Output::send(STR("No mods.txt file found...\n")); | ||
std::string descriptive_error = glz::format_error(pe, buffer); | ||
|
||
size_t count = descriptive_error.size() + 1; | ||
wchar_t* converted_method_name = new wchar_t[count]; | ||
|
||
size_t num_of_char_converted = 0; | ||
mbstowcs_s(&num_of_char_converted, converted_method_name, count, descriptive_error.data(), count); | ||
|
||
auto converted = File::StringViewType(converted_method_name); | ||
|
||
delete[] converted_method_name; | ||
|
||
Output::send<LogLevel::Error>(STR("{}\n\nError parsing mods.json file, please fix the file...\n"), converted); | ||
Comment on lines
+1126
to
+1138
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What is this ? |
||
} | ||
else | ||
{ | ||
// 'mods.txt' exists, lets parse it | ||
std::wifstream mods_stream{enabled_mods_file}; | ||
} | ||
|
||
std::wstring current_line; | ||
while (std::getline(mods_stream, current_line)) | ||
auto UE4SSProgram::write_mods_json(std::string mod_list_file, std::vector<ModData>& mod_data_vector) -> void | ||
{ | ||
std::string mod_data_buffer; | ||
glz::write<glz::opts{.prettify = true}>(mod_data_vector, mod_data_buffer); | ||
glz::error_code ec = glz::buffer_to_file(mod_data_buffer, mod_list_file); | ||
} | ||
|
||
auto UE4SSProgram::convert_legacy_mods_file(StringType legacy_mod_list_file, std::vector<ModData>& mod_data_vector) -> void | ||
{ | ||
Output::send(STR("Converting legacy mods.txt to mods.json...\n")); | ||
std::wifstream mods_stream = File::open_file_skip_BOM(legacy_mod_list_file); | ||
try { | ||
mods_stream = File::open_file_skip_BOM(legacy_mod_list_file); | ||
} catch (const std::exception& e) { | ||
std::cerr << e.what() << std::endl; | ||
} | ||
Comment on lines
+1153
to
+1157
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is bad, don't throw here, just let the exception fall through to main like we do with all fatal exceptions. |
||
std::wstring current_line; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Use |
||
while (std::getline(mods_stream, current_line)) | ||
{ | ||
|
||
// Don't parse any lines with ';' | ||
if (current_line.find(L";") != current_line.npos) | ||
{ | ||
// Don't parse any lines with ';' | ||
if (current_line.find(L";") != current_line.npos) | ||
{ | ||
continue; | ||
} | ||
continue; | ||
} | ||
|
||
// Don't parse if the line is impossibly short (empty lines for example) | ||
if (current_line.size() <= 4) | ||
{ | ||
continue; | ||
} | ||
// Don't parse if the line is impossibly short (empty lines for example) | ||
if (current_line.size() <= 4) | ||
{ | ||
continue; | ||
} | ||
|
||
// Remove all spaces | ||
auto end = std::remove(current_line.begin(), current_line.end(), L' '); | ||
current_line.erase(end, current_line.end()); | ||
// Remove all spaces | ||
auto end = std::remove(current_line.begin(), current_line.end(), L' '); | ||
current_line.erase(end, current_line.end()); | ||
|
||
// Parse the line into something that can be converted into proper data | ||
std::wstring mod_name = explode_by_occurrence(current_line, L':', 1); | ||
std::wstring mod_enabled = explode_by_occurrence(current_line, L':', ExplodeType::FromEnd); | ||
// Parse the line into something that can be converted into proper data | ||
std::wstring mod_name = explode_by_occurrence(current_line, L':', 1); | ||
std::wstring mod_enabled = explode_by_occurrence(current_line, L':', ExplodeType::FromEnd); | ||
Comment on lines
+1179
to
+1180
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Use |
||
bool mod_enabled_out = !mod_enabled.empty() && mod_enabled[0] == L'1'; | ||
|
||
auto mod = UE4SSProgram::find_mod_by_name<ModType>(mod_name, UE4SSProgram::IsInstalled::Yes); | ||
if (!mod || !dynamic_cast<ModType*>(mod)) | ||
{ | ||
continue; | ||
} | ||
auto it = std::find_if(mod_data_vector.begin(), mod_data_vector.end(), | ||
[&mod_name](const ModData& element) { | ||
return element.mod_name == to_string(mod_name); | ||
}); | ||
|
||
if (!mod_enabled.empty() && mod_enabled[0] == L'1') | ||
{ | ||
Output::send(STR("Starting {} mod '{}'\n"), std::is_same_v<ModType, LuaMod> ? STR("Lua") : STR("C++"), mod->get_name().data()); | ||
mod->start_mod(); | ||
} | ||
else | ||
{ | ||
Output::send(STR("Mod '{}' disabled in mods.txt.\n"), mod_name); | ||
} | ||
if (it == mod_data_vector.end()) { | ||
mod_data_vector.push_back({to_string(mod_name), mod_enabled_out}); | ||
} | ||
} | ||
|
||
Output::send(STR("mods.txt entries converted to mods.json. Please delete mods.txt if no mod managers rely on it to avoid conflicting with changes to the json...\n")); | ||
} | ||
|
||
|
||
// Part #2: Start all mods that have enabled.txt present in the mod directory. | ||
Output::send(STR("Starting mods (from enabled.txt, no defined load order)...\n")); | ||
template <typename ModType> | ||
auto start_mods() -> std::string | ||
{ | ||
ProfilerScope(); | ||
// Part #1: Start all mods that are enabled in mods.json. | ||
std::filesystem::path mods_directory = UE4SSProgram::get_program().get_mods_directory(); | ||
std::filesystem::path legacy_mod_list_file{mods_directory / "mods.txt"}; | ||
std::filesystem::path mod_list_file{mods_directory / "mods.json"}; | ||
std::vector<UE4SSProgram::ModData> mod_data_vector{}; | ||
UE4SSProgram& program = UE4SSProgram::get_program(); | ||
|
||
if (std::filesystem::exists(mod_list_file)) | ||
{ | ||
UE4SSProgram::read_mods_json(mod_list_file.string(), mod_data_vector); | ||
} | ||
|
||
if (std::filesystem::exists(legacy_mod_list_file)) | ||
{ | ||
UE4SSProgram::convert_legacy_mods_file(legacy_mod_list_file, mod_data_vector); | ||
} | ||
|
||
UE4SSProgram::write_mods_json(mod_list_file.string(), mod_data_vector); | ||
|
||
|
||
Output::send(STR("Starting mods (from mods.json load order)...\n")); | ||
for (auto it = mod_data_vector.begin(); it != mod_data_vector.end(); ++it) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Any reason why we're using the more complicated iterator method of looping here instead of the simpler |
||
{ | ||
auto mod = UE4SSProgram::find_mod_by_name<ModType>(it->mod_name, UE4SSProgram::IsInstalled::Yes); | ||
if (!mod || !dynamic_cast<ModType*>(mod)) | ||
{ | ||
continue; | ||
} | ||
|
||
if (it->mod_enabled) | ||
{ | ||
Output::send(STR("Starting {} mod '{}'\n"), std::is_same_v<ModType, LuaMod> ? STR("Lua") : STR("C++"), mod->get_name().data()); | ||
mod->start_mod(); | ||
} | ||
else | ||
{ | ||
Output::send(STR("Mod '{}' disabled in mods.json.\n"), to_wstring(it->mod_name)); | ||
} | ||
} | ||
|
||
|
||
for (const auto& mod_directory : std::filesystem::directory_iterator(mods_directory)) | ||
{ | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,42 +1,42 @@ | ||
[ | ||
{ | ||
"mod_name": "CheatManagerEnablerMod", | ||
"mod_enabled": true | ||
}, | ||
{ | ||
"mod_name": "ActorDumperMod", | ||
"mod_enabled": false | ||
}, | ||
{ | ||
"mod_name": "ConsoleCommandsMod", | ||
"mod_enabled": true | ||
}, | ||
{ | ||
"mod_name": "ConsoleEnablerMod", | ||
"mod_enabled": true | ||
}, | ||
{ | ||
"mod_name": "SplitScreenMod", | ||
"mod_enabled": false | ||
}, | ||
{ | ||
"mod_name": "LineTraceMod", | ||
"mod_enabled": true | ||
}, | ||
{ | ||
"mod_name": "BPML_GenericFunctions", | ||
"mod_enabled": true | ||
}, | ||
{ | ||
"mod_name": "BPModLoaderMod", | ||
"mod_enabled": true | ||
}, | ||
{ | ||
"mod_name": "jsbLuaProfilerMod", | ||
"mod_enabled": false | ||
}, | ||
{ | ||
"mod_name": "Keybinds", | ||
"mod_enabled": true | ||
} | ||
{ | ||
"mod_name": "CheatManagerEnablerMod", | ||
"mod_enabled": true | ||
}, | ||
{ | ||
"mod_name": "ActorDumperMod", | ||
"mod_enabled": false | ||
}, | ||
{ | ||
"mod_name": "ConsoleCommandsMod", | ||
"mod_enabled": true | ||
}, | ||
{ | ||
"mod_name": "ConsoleEnablerMod", | ||
"mod_enabled": true | ||
}, | ||
{ | ||
"mod_name": "SplitScreenMod", | ||
"mod_enabled": false | ||
}, | ||
{ | ||
"mod_name": "LineTraceMod", | ||
"mod_enabled": true | ||
}, | ||
{ | ||
"mod_name": "BPML_GenericFunctions", | ||
"mod_enabled": true | ||
}, | ||
{ | ||
"mod_name": "BPModLoaderMod", | ||
"mod_enabled": true | ||
}, | ||
{ | ||
"mod_name": "jsbLuaProfilerMod", | ||
"mod_enabled": false | ||
}, | ||
{ | ||
"mod_name": "Keybinds", | ||
"mod_enabled": true | ||
} | ||
] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unused variable ?
I can't find any usages in this PR.