Skip to content

Commit

Permalink
Merge pull request #239 from muttleyxd/better-behavior-when-workshopd…
Browse files Browse the repository at this point in the history
…ir-is-missing

launcher, library: fix Steam integration parameter, improve behavior when workshop dir is missing
  • Loading branch information
muttleyxd authored Dec 28, 2022
2 parents 185ece4 + ed254f7 commit 4c06ead
Show file tree
Hide file tree
Showing 7 changed files with 86 additions and 44 deletions.
9 changes: 9 additions & 0 deletions src/arma3-unix-launcher-library/arma3client.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,15 @@ namespace ARMA3

std::vector<Mod> Client::GetWorkshopMods()
{
auto const workshop_path = GetPathWorkshop();

/*
* workshop directory may not exist, in case where we don't have any mods subscribed
* if parent path does not exist, then something is seriously broken and it should fail visibly
*/
if (!FilesystemUtils::Exists(workshop_path) && FilesystemUtils::Exists(workshop_path.parent_path()))
return {};

return GetModsFromDirectory(GetPathWorkshop());
}

Expand Down
2 changes: 1 addition & 1 deletion src/arma3-unix-launcher-library/steam_utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ path SteamUtils::GetGamePathFromInstallPath(path const &install_path, std::strin
path SteamUtils::GetWorkshopPath(path const &install_path, std::string const &appid) const
{
path proposed_path = install_path / "steamapps/workshop/content" / appid;
if (fs::Exists(proposed_path))
if (fs::Exists(proposed_path.parent_path()))
return proposed_path;

throw SteamWorkshopDirectoryNotFoundException(appid);
Expand Down
11 changes: 9 additions & 2 deletions src/arma3-unix-launcher/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,14 @@ int main(int argc, char *argv[])
{
spdlog::info("Install path: '{}'", path);
arma_path = steam.GetGamePathFromInstallPath(path, ARMA3::Definitions::app_id);
workshop_path = steam.GetWorkshopPath(path, ARMA3::Definitions::app_id);
try
{
workshop_path = steam.GetWorkshopPath(path, ARMA3::Definitions::app_id);
}
catch (std::exception const &e) // todo: write macro for this? ex. TRY()
{
spdlog::warn("Arma path is correct '{}', failed getting workshop path: '{}'", arma_path, e.what());
}
client = std::make_unique<ARMA3::Client>(arma_path, workshop_path);
break;
}
Expand Down Expand Up @@ -207,7 +214,7 @@ int main(int argc, char *argv[])
return 0;
}

MainWindow w(std::move(client), config_file, parser.get<bool>("--disable-steam-integration"));
MainWindow w(std::move(client), config_file, !parser.get<bool>("--disable-steam-integration"));
w.show();

return a.exec();
Expand Down
9 changes: 9 additions & 0 deletions src/dayz-linux-launcher-library/dayzclient.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,15 @@ namespace DayZ

std::vector<Mod> Client::GetWorkshopMods()
{
auto const workshop_path = GetPathWorkshop();

/*
* workshop directory may not exist, in case where we don't have any mods subscribed
* if parent path does not exist, then something is seriously broken and it should fail visibly
*/
if (!FilesystemUtils::Exists(workshop_path) && FilesystemUtils::Exists(workshop_path.parent_path()))
return {};

return GetModsFromDirectory(GetPathWorkshop());
}

Expand Down
10 changes: 9 additions & 1 deletion src/dayz-linux-launcher/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,14 @@ int main(int argc, char *argv[])
{
spdlog::info("Install path: '{}'", path);
arma_path = steam.GetGamePathFromInstallPath(path, DayZ::Definitions::app_id);
try
{
workshop_path = steam.GetWorkshopPath(path, ARMA3::Definitions::app_id);
}
catch (std::exception const &e) // todo: write macro for this? ex. TRY()
{
spdlog::warn("DayZ path is correct '{}', failed getting workshop path: '{}'", arma_path, e.what());
}
workshop_path = steam.GetWorkshopPath(path, DayZ::Definitions::app_id);
client = std::make_unique<DayZ::Client>(arma_path, workshop_path);
break;
Expand Down Expand Up @@ -206,7 +214,7 @@ int main(int argc, char *argv[])
return 0;
}

MainWindow w(std::move(client), config_file, parser.get<bool>("--disable-steam-integration"));
MainWindow w(std::move(client), config_file, !parser.get<bool>("--disable-steam-integration"));
w.show();

return a.exec();
Expand Down
69 changes: 41 additions & 28 deletions tests/unit/arma3-unix-launcher-library/test_arma3client.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -204,44 +204,57 @@ TEST_CASE_FIXTURE(ARMA3ClientTests, "GetWorkshopMods")
{
REQUIRE_CALL(filesystemUtilsMock, Exists(get_executable_path())).RETURN(true);
ARMA3::Client a3c(arma_path, workshop_path);
WHEN("Workshop directory does not contain mods")
WHEN("Workshop directory does not exist")
{
REQUIRE_CALL(filesystemUtilsMock, Ls(workshop_path, _)).RETURN(std::vector<std::string> {});
REQUIRE_CALL(filesystemUtilsMock, Exists(workshop_path)).RETURN(false);
REQUIRE_CALL(filesystemUtilsMock, Exists(workshop_path.parent_path())).RETURN(true);
THEN("Returned vector is empty")
{
CHECK(a3c.GetWorkshopMods().empty());
}
}
WHEN("Workshop directory contains only two directories with useless files inside")
WHEN("Workshop directory exists")
{
std::array<std::string, 2> const mod_names{"123", "456"};
std::array<std::filesystem::path, 2> const mod_paths{workshop_path / mod_names[0], workshop_path / mod_names[1]};
REQUIRE_CALL(filesystemUtilsMock, Ls(workshop_path, _)).RETURN(std::vector<std::string> {mod_paths[0], mod_paths[1]});
REQUIRE_CALL(filesystemUtilsMock, IsDirectory(mod_paths[0])).RETURN(true);
REQUIRE_CALL(filesystemUtilsMock, Ls(mod_paths[0], _)).RETURN(std::vector<std::string> {"useless.bin"});
REQUIRE_CALL(filesystemUtilsMock, IsDirectory(mod_paths[1])).RETURN(true);
REQUIRE_CALL(filesystemUtilsMock, Ls(mod_paths[1], _)).RETURN(std::vector<std::string> {"useless.bin"});
THEN("Returned vector is empty")
REQUIRE_CALL(filesystemUtilsMock, Exists(workshop_path)).RETURN(true);
WHEN("Workshop directory does not contain mods")
{
CHECK(a3c.GetWorkshopMods().empty());
REQUIRE_CALL(filesystemUtilsMock, Ls(workshop_path, _)).RETURN(std::vector<std::string> {});
THEN("Returned vector is empty")
{
CHECK(a3c.GetWorkshopMods().empty());
}
}
}
WHEN("Workshop directory contains two directories with workshop mods inside")
{
std::array<std::string, 2> const mod_names{"123", "456"};
std::array<std::filesystem::path, 2> const mod_paths{workshop_path / mod_names[0], workshop_path / mod_names[1]};
REQUIRE_CALL(filesystemUtilsMock, Ls(workshop_path, _)).RETURN(std::vector<std::string> {mod_paths[0], mod_paths[1]});
REQUIRE_CALL(filesystemUtilsMock, IsDirectory(mod_paths[0])).RETURN(true);
REQUIRE_CALL(filesystemUtilsMock, Ls(mod_paths[0], _)).RETURN(std::vector<std::string> {"addons"});
REQUIRE_CALL(modMock, Constructor(mod_paths[0], _));
REQUIRE_CALL(filesystemUtilsMock, IsDirectory(mod_paths[1])).RETURN(true);
REQUIRE_CALL(filesystemUtilsMock, Ls(mod_paths[1], _)).RETURN(std::vector<std::string> {"addons"});
REQUIRE_CALL(modMock, Constructor(mod_paths[1], _));
THEN("Returned vector is empty")
WHEN("Workshop directory contains only two directories with useless files inside")
{
auto mods = a3c.GetWorkshopMods();
CHECK_EQ(mod_paths[0], mods[0].path_);
CHECK_EQ(mod_paths[1], mods[1].path_);
std::array<std::string, 2> const mod_names{"123", "456"};
std::array<std::filesystem::path, 2> const mod_paths{workshop_path / mod_names[0], workshop_path / mod_names[1]};
REQUIRE_CALL(filesystemUtilsMock, Ls(workshop_path, _)).RETURN(std::vector<std::string> {mod_paths[0], mod_paths[1]});
REQUIRE_CALL(filesystemUtilsMock, IsDirectory(mod_paths[0])).RETURN(true);
REQUIRE_CALL(filesystemUtilsMock, Ls(mod_paths[0], _)).RETURN(std::vector<std::string> {"useless.bin"});
REQUIRE_CALL(filesystemUtilsMock, IsDirectory(mod_paths[1])).RETURN(true);
REQUIRE_CALL(filesystemUtilsMock, Ls(mod_paths[1], _)).RETURN(std::vector<std::string> {"useless.bin"});
THEN("Returned vector is empty")
{
CHECK(a3c.GetWorkshopMods().empty());
}
}
WHEN("Workshop directory contains two directories with workshop mods inside")
{
std::array<std::string, 2> const mod_names{"123", "456"};
std::array<std::filesystem::path, 2> const mod_paths{workshop_path / mod_names[0], workshop_path / mod_names[1]};
REQUIRE_CALL(filesystemUtilsMock, Ls(workshop_path, _)).RETURN(std::vector<std::string> {mod_paths[0], mod_paths[1]});
REQUIRE_CALL(filesystemUtilsMock, IsDirectory(mod_paths[0])).RETURN(true);
REQUIRE_CALL(filesystemUtilsMock, Ls(mod_paths[0], _)).RETURN(std::vector<std::string> {"addons"});
REQUIRE_CALL(modMock, Constructor(mod_paths[0], _));
REQUIRE_CALL(filesystemUtilsMock, IsDirectory(mod_paths[1])).RETURN(true);
REQUIRE_CALL(filesystemUtilsMock, Ls(mod_paths[1], _)).RETURN(std::vector<std::string> {"addons"});
REQUIRE_CALL(modMock, Constructor(mod_paths[1], _));
THEN("Returned vector is empty")
{
auto mods = a3c.GetWorkshopMods();
CHECK_EQ(mod_paths[0], mods[0].path_);
CHECK_EQ(mod_paths[1], mods[1].path_);
}
}
}
}
Expand Down
20 changes: 8 additions & 12 deletions tests/unit/arma3-unix-launcher-library/test_steam_utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -171,43 +171,39 @@ TEST_CASE_FIXTURE(SteamUtilsTests, "GetWorkshopDir_Success")
{
GIVEN("Valid appid for installed game")
{
std::string const invalid_game = "107411";
std::filesystem::path const expected_workshop_path = default_steam_path / "steamapps/workshop/content" / arma3_workshop_id;
std::filesystem::path const not_existing_workshop_path = default_steam_path / "steamapps/workshop/content" / invalid_game;
std::filesystem::path const parent_workshop_path = default_steam_path / "steamapps/workshop/content";

REQUIRE_CALL(filesystemUtilsMock, Exists(default_config_path)).RETURN(true);
REQUIRE_CALL(filesystemUtilsMock, RealPath(default_steam_path)).RETURN(default_steam_path);
REQUIRE_CALL(filesystemUtilsMock, Exists(expected_workshop_path)).RETURN(true);
REQUIRE_CALL(filesystemUtilsMock, Exists(not_existing_workshop_path)).RETURN(false);

SteamUtils steam({default_steam_path});

WHEN("Getting workshop path for installed game")
WHEN("Parent workshop directory exists")
{
REQUIRE_CALL(filesystemUtilsMock, Exists(parent_workshop_path)).RETURN(true);
THEN("Workshop path for installed game is returned")
{
CHECK_EQ(expected_workshop_path, steam.GetWorkshopPath(default_steam_path, arma3_workshop_id));
CHECK_THROWS_AS(steam.GetWorkshopPath(default_steam_path, invalid_game), SteamWorkshopDirectoryNotFoundException);
CHECK_EQ(parent_workshop_path / arma3_workshop_id, steam.GetWorkshopPath(default_steam_path, arma3_workshop_id));
}
}
}
}

TEST_CASE_FIXTURE(SteamUtilsTests, "GetWorkshopDir_Failed_NotExistingApp")
TEST_CASE_FIXTURE(SteamUtilsTests, "GetWorkshopDir_Failed_ParentDirectoryDoesNotExist")
{
GIVEN("Valid appid for installed game")
{
std::string const invalid_game = "107411";
std::filesystem::path const not_existing_workshop_path = default_steam_path / "steamapps/workshop/content" / invalid_game;
std::filesystem::path const parent_workshop_path = default_steam_path / "steamapps/workshop/content";

REQUIRE_CALL(filesystemUtilsMock, Exists(default_config_path)).RETURN(true);
REQUIRE_CALL(filesystemUtilsMock, RealPath(default_steam_path)).RETURN(default_steam_path);
REQUIRE_CALL(filesystemUtilsMock, Exists(not_existing_workshop_path)).RETURN(false);

SteamUtils steam({default_steam_path});

WHEN("Getting workshop path for not installed game")
WHEN("Parent workshop does not exist")
{
REQUIRE_CALL(filesystemUtilsMock, Exists(parent_workshop_path)).RETURN(false);
THEN("Exception is thrown")
{
CHECK_THROWS_AS(steam.GetWorkshopPath(default_steam_path, invalid_game), SteamWorkshopDirectoryNotFoundException);
Expand Down

0 comments on commit 4c06ead

Please sign in to comment.