@@ -1304,119 +1304,132 @@ namespace RC
13041304 auto start_mods () -> std::string
13051305 {
13061306 ProfilerScope ();
1307- // Part #1: Start all mods that are enabled in mods.txt.
1308- Output::send (STR (" Starting mods (from mods.txt load order)...\n " ));
13091307
1310- std::filesystem::path mods_directory = UE4SSProgram::get_program ().get_mods_directory ();
1311- std::wstring enabled_mods_file{mods_directory / " mods.txt" };
1312- if (!std::filesystem::exists (enabled_mods_file))
1308+ const auto & main_mods_directory = UE4SSProgram::get_program ().get_mods_directory ();
1309+ for (const auto & mods_directory : std::ranges::reverse_view (UE4SSProgram::get_program ().get_mods_directories ()))
13131310 {
1314- Output::send (STR (" No mods.txt file found...\n " ));
1315- }
1316- else
1317- {
1318- // 'mods.txt' exists, lets parse it
1311+ if (!std::filesystem::exists (mods_directory))
1312+ {
1313+ continue ;
1314+ }
1315+
1316+ // Only parse mods.txt from allowed directories.
1317+ if (UE4SSProgram::settings_manager.Overrides .ParseModsFromAdditionalPaths || mods_directory == main_mods_directory)
1318+ {
1319+ // Part #1: Start all mods that are enabled in mods.txt.
1320+ std::wstring enabled_mods_file{mods_directory / " mods.txt" };
1321+ if (!std::filesystem::exists (enabled_mods_file))
1322+ {
1323+ Output::send (STR (" No mods.txt file found...\n " ));
1324+ }
1325+ else
1326+ {
1327+ // 'mods.txt' exists, lets parse it
1328+ Output::send (STR (" Starting mods (from mods.txt ({}) load order)...\n " ), ensure_str (enabled_mods_file));
1329+
1330+ // First, check for BOM using a byte stream
1331+ std::ifstream bom_check (enabled_mods_file, std::ios::binary);
1332+ char bom[3 ] = {0 };
1333+ bom_check.read (bom, 3 );
1334+ bool has_bom = (bom[0 ] == ' \xEF ' && bom[1 ] == ' \xBB ' && bom[2 ] == ' \xBF ' );
1335+ bom_check.close ();
1336+
1337+ // Now open the actual stream
1338+ StreamIType mods_stream{enabled_mods_file};
1339+
1340+ // If BOM was detected, skip the first "character" (which will be the BOM interpreted as a wide char)
1341+ if (has_bom)
1342+ {
1343+ wchar_t discard;
1344+ mods_stream.get (discard);
1345+ }
1346+
1347+ StringType current_line;
1348+ while (std::getline (mods_stream, current_line))
1349+ {
1350+ // Don't parse any lines with ';'
1351+ if (current_line.find (STR (" ;" )) != current_line.npos )
1352+ {
1353+ continue ;
1354+ }
1355+
1356+ // Don't parse if the line is impossibly short (empty lines for example)
1357+ if (current_line.size () <= 4 )
1358+ {
1359+ continue ;
1360+ }
13191361
1320- // First, check for BOM using a byte stream
1321- std::ifstream bom_check (enabled_mods_file, std::ios::binary);
1322- char bom[3 ] = {0 };
1323- bom_check.read (bom, 3 );
1324- bool has_bom = (bom[0 ] == ' \xEF ' && bom[1 ] == ' \xBB ' && bom[2 ] == ' \xBF ' );
1325- bom_check.close ();
1362+ // Remove all spaces
1363+ auto end = std::remove (current_line.begin (), current_line.end (), STR (' ' ));
1364+ current_line.erase (end, current_line.end ());
13261365
1327- // Now open the actual stream
1328- StreamIType mods_stream{enabled_mods_file};
1366+ // Parse the line into something that can be converted into proper data
1367+ StringType mod_name = explode_by_occurrence (current_line, STR (' :' ), 1 );
1368+ StringType mod_enabled = explode_by_occurrence (current_line, STR (' :' ), ExplodeType::FromEnd);
13291369
1330- // If BOM was detected, skip the first "character" (which will be the BOM interpreted as a wide char)
1331- if (has_bom) {
1332- wchar_t discard;
1333- mods_stream.get (discard);
1370+ auto mod = UE4SSProgram::find_mod_by_name<ModType>(mod_name, UE4SSProgram::IsInstalled::Yes);
1371+ if (!mod || !dynamic_cast <ModType*>(mod) || mod->is_started ())
1372+ {
1373+ continue ;
1374+ }
1375+
1376+ if (!mod_enabled.empty () && mod_enabled[0 ] == STR (' 1' ))
1377+ {
1378+ Output::send (STR (" Starting {} mod '{}'\n " ), std::is_same_v<ModType, LuaMod> ? STR (" Lua" ) : STR (" C++" ), mod->get_name ().data ());
1379+ mod->start_mod ();
1380+ }
1381+ else
1382+ {
1383+ Output::send (STR (" Mod '{}' disabled in mods.txt.\n " ), mod_name);
1384+ }
1385+ }
1386+ }
13341387 }
13351388
1336- StringType current_line;
1337- while (std::getline (mods_stream, current_line))
1389+ // Part #2: Start all mods that have enabled.txt present in the mod directory.
1390+ Output::send (STR (" Starting mods (from enabled.txt ({}), no defined load order)...\n " ), ensure_str (mods_directory));
1391+
1392+ for (const auto & mod_directory : std::filesystem::directory_iterator (mods_directory))
13381393 {
1339- // Don't parse any lines with ';'
1340- if (current_line.find (STR (" ;" )) != current_line.npos )
1394+ std::error_code ec{};
1395+
1396+ if (!mod_directory.is_directory (ec))
13411397 {
13421398 continue ;
13431399 }
1344-
1345- // Don't parse if the line is impossibly short (empty lines for example)
1346- if (current_line.size () <= 4 )
1400+ if (ec.value () != 0 )
13471401 {
1348- continue ;
1402+ return fmt::format ( " is_directory ran into error {} " , ec. value ()) ;
13491403 }
13501404
1351- // Remove all spaces
1352- auto end = std::remove (current_line.begin (), current_line.end (), STR (' ' ));
1353- current_line.erase (end, current_line.end ());
1354-
1355- // Parse the line into something that can be converted into proper data
1356- StringType mod_name = explode_by_occurrence (current_line, STR (' :' ), 1 );
1357- StringType mod_enabled = explode_by_occurrence (current_line, STR (' :' ), ExplodeType::FromEnd);
1358-
1359- auto mod = UE4SSProgram::find_mod_by_name<ModType>(mod_name, UE4SSProgram::IsInstalled::Yes);
1360- if (!mod || !dynamic_cast <ModType*>(mod))
1405+ if (!std::filesystem::exists (mod_directory.path () / " enabled.txt" , ec))
13611406 {
13621407 continue ;
13631408 }
1409+ if (ec.value () != 0 )
1410+ {
1411+ return fmt::format (" exists ran into error {}" , ec.value ());
1412+ }
13641413
1365- if (!mod_enabled.empty () && mod_enabled[0 ] == STR (' 1' ))
1414+ auto mod = UE4SSProgram::find_mod_by_name<ModType>(ensure_str (mod_directory.path ().stem ()), UE4SSProgram::IsInstalled::Yes);
1415+ if (!dynamic_cast <ModType*>(mod))
13661416 {
1367- Output::send (STR (" Starting {} mod '{}'\n " ), std::is_same_v<ModType, LuaMod> ? STR (" Lua" ) : STR (" C++" ), mod->get_name ().data ());
1368- mod->start_mod ();
1417+ continue ;
13691418 }
1370- else
1419+ if (!mod)
13711420 {
1372- Output::send (STR (" Mod '{}' disabled in mods.txt.\n " ), mod_name);
1421+ Output::send<LogLevel::Warning>(STR (" Found a mod with enabled.txt but mod has not been installed properly.\n " ));
1422+ continue ;
13731423 }
1374- }
1375- }
1376-
1377- // Part #2: Start all mods that have enabled.txt present in the mod directory.
1378- Output::send (STR (" Starting mods (from enabled.txt, no defined load order)...\n " ));
1379-
1380- for (const auto & mod_directory : std::filesystem::directory_iterator (mods_directory))
1381- {
1382- std::error_code ec{};
1383-
1384- if (!mod_directory.is_directory (ec))
1385- {
1386- continue ;
1387- }
1388- if (ec.value () != 0 )
1389- {
1390- return fmt::format (" is_directory ran into error {}" , ec.value ());
1391- }
1392-
1393- if (!std::filesystem::exists (mod_directory.path () / " enabled.txt" , ec))
1394- {
1395- continue ;
1396- }
1397- if (ec.value () != 0 )
1398- {
1399- return fmt::format (" exists ran into error {}" , ec.value ());
1400- }
14011424
1402- auto mod = UE4SSProgram::find_mod_by_name<ModType>(ensure_str (mod_directory.path ().stem ()), UE4SSProgram::IsInstalled::Yes);
1403- if (!dynamic_cast <ModType*>(mod))
1404- {
1405- continue ;
1406- }
1407- if (!mod)
1408- {
1409- Output::send<LogLevel::Warning>(STR (" Found a mod with enabled.txt but mod has not been installed properly.\n " ));
1410- continue ;
1411- }
1425+ if (mod->is_started ())
1426+ {
1427+ continue ;
1428+ }
14121429
1413- if (mod->is_started ())
1414- {
1415- continue ;
1430+ Output::send (STR (" Mod '{}' has enabled.txt, starting mod.\n " ), mod->get_name ().data ());
1431+ mod->start_mod ();
14161432 }
1417-
1418- Output::send (STR (" Mod '{}' has enabled.txt, starting mod.\n " ), mod->get_name ().data ());
1419- mod->start_mod ();
14201433 }
14211434
14221435 return {};
0 commit comments