Skip to content

Commit

Permalink
More dependency untangling
Browse files Browse the repository at this point in the history
1. Moves more assets-related stuff from `init` to `engine/assets`.
2. Removes `SDL_audiolib` dependency from `soundsample.h`.
3. Cleans up some unused/missing includes.
  • Loading branch information
glebm committed Jan 9, 2025
1 parent f601e13 commit 564b41c
Show file tree
Hide file tree
Showing 53 changed files with 358 additions and 323 deletions.
1 change: 1 addition & 0 deletions Source/DiabloUI/diabloui.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include "engine/render/clx_render.hpp"
#include "engine/ticks.hpp"
#include "hwcursor.hpp"
#include "init.h"
#include "utils/algorithm/container.hpp"
#include "utils/display.h"
#include "utils/is_of.hpp"
Expand Down
2 changes: 2 additions & 0 deletions Source/DiabloUI/dialogs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@
#include "engine/load_clx.hpp"
#include "engine/load_pcx.hpp"
#include "engine/palette.h"
#include "headless_mode.hpp"
#include "hwcursor.hpp"
#include "init.h"
#include "utils/display.h"
#include "utils/is_of.hpp"
#include "utils/language.h"
Expand Down
7 changes: 4 additions & 3 deletions Source/DiabloUI/hero/selhero.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include "DiabloUI/selyesno.h"
#include "control.h"
#include "controls/plrctrls.h"
#include "engine/assets.hpp"
#include "game_mode.hpp"
#include "menu.h"
#include "options.h"
Expand Down Expand Up @@ -161,10 +162,10 @@ void SelheroListSelect(size_t value)
vecSelHeroDlgItems.push_back(std::make_unique<UiListItem>(_("Sorcerer"), static_cast<int>(HeroClass::Sorcerer)));
if (gbIsHellfire) {
vecSelHeroDlgItems.push_back(std::make_unique<UiListItem>(_("Monk"), static_cast<int>(HeroClass::Monk)));
if (gbBard || *sgOptions.Gameplay.testBard) {
if (HaveBardAssets() || *sgOptions.Gameplay.testBard) {
vecSelHeroDlgItems.push_back(std::make_unique<UiListItem>(_("Bard"), static_cast<int>(HeroClass::Bard)));
}
if (gbBarbarian || *sgOptions.Gameplay.testBarbarian) {
if (HaveBarbarianAssets() || *sgOptions.Gameplay.testBarbarian) {
vecSelHeroDlgItems.push_back(std::make_unique<UiListItem>(_("Barbarian"), static_cast<int>(HeroClass::Barbarian)));
}
}
Expand Down Expand Up @@ -263,7 +264,7 @@ void AddSelHeroBackground()
void SelheroClassSelectorSelect(size_t value)
{
auto hClass = static_cast<HeroClass>(vecSelHeroDlgItems[value]->m_value);
if (gbIsSpawn && (hClass == HeroClass::Rogue || hClass == HeroClass::Sorcerer || (hClass == HeroClass::Bard && !gbBard))) {
if (gbIsSpawn && (hClass == HeroClass::Rogue || hClass == HeroClass::Sorcerer || (hClass == HeroClass::Bard && !HaveBardAssets()))) {
RemoveSelHeroBackground();
UiSelOkDialog(nullptr, _("The Rogue and Sorcerer are only available in the full retail version of Diablo. Visit https://www.gog.com/game/diablo to purchase.").data(), false);
AddSelHeroBackground();
Expand Down
1 change: 1 addition & 0 deletions Source/DiabloUI/mainmenu.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include "DiabloUI/diabloui.h"
#include "DiabloUI/selok.h"
#include "control.h"
#include "engine/assets.hpp"
#include "engine/load_clx.hpp"
#include "game_mode.hpp"
#include "utils/language.h"
Expand Down
2 changes: 2 additions & 0 deletions Source/DiabloUI/settingsmenu.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

#include <cstdint>
#include <optional>
#include <vector>

#include <function_ref.hpp>

Expand All @@ -11,6 +12,7 @@
#include "controls/controller_motion.h"
#include "controls/plrctrls.h"
#include "controls/remap_keyboard.h"
#include "engine/assets.hpp"
#include "engine/render/text_render.hpp"
#include "hwcursor.hpp"
#include "options.h"
Expand Down
6 changes: 3 additions & 3 deletions Source/appfat.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,15 +49,15 @@ void FreeDlg()
SNetDestroy();
}

[[noreturn]] void DisplayFatalErrorAndExit(std::string_view title, std::string_view body)
} // namespace

void DisplayFatalErrorAndExit(std::string_view title, std::string_view body)
{
FreeDlg();
UiErrorOkDialog(title, body);
diablo_quit(1);
}

} // namespace

void app_fatal(std::string_view str)
{
DisplayFatalErrorAndExit(_("Error"), str);
Expand Down
7 changes: 7 additions & 0 deletions Source/appfat.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,13 @@ namespace devilution {
#define assert(exp) (void)((exp) || (assert_fail(__LINE__, __FILE__, #exp), 0))
#endif

/**
* @brief Terminates the game and displays an error message box.
* @param str Message box title.
* @param str Error message.
*/
[[noreturn]] void DisplayFatalErrorAndExit(std::string_view title, std::string_view body);

/**
* @brief Terminates the game and displays an error message box.
* @param str Error message.
Expand Down
1 change: 0 additions & 1 deletion Source/control.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@
#include "engine/trn.hpp"
#include "gamemenu.h"
#include "headless_mode.hpp"
#include "init.h"
#include "inv.h"
#include "inv_iterators.hpp"
#include "levels/setmaps.h"
Expand Down
3 changes: 1 addition & 2 deletions Source/diablo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include <config.h>

#include "DiabloUI/selstart.h"
#include "appfat.h"
#include "automap.h"
#include "capture.h"
#include "control.h"
Expand Down Expand Up @@ -124,8 +125,6 @@ bool gbProcessPlayers;
bool gbLoadGame;
bool cineflag;
int PauseMode;
bool gbBard;
bool gbBarbarian;
clicktype sgbMouseDown;
uint16_t gnTickDelay = 50;
char gszProductName[64] = "DevilutionX vUnknown";
Expand Down
8 changes: 6 additions & 2 deletions Source/diablo.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@

#include <cstdint>

#include <SDL.h>

#ifdef USE_SDL1
#include "utils/sdl2_to_1_2_backports.h"
#endif

#ifdef _DEBUG
#include "monstdat.h"
#endif
Expand Down Expand Up @@ -69,8 +75,6 @@ extern bool cineflag;
/* These are defined in fonts.h */
extern void FontsCleanup();
extern DVL_API_FOR_TEST int PauseMode;
extern bool gbBard;
extern bool gbBarbarian;
extern clicktype sgbMouseDown;
extern uint16_t gnTickDelay;
extern char gszProductName[64];
Expand Down
1 change: 1 addition & 0 deletions Source/dvlnet/packet.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include "appfat.h"
#include "dvlnet/abstract_net.h"
#include "utils/attributes.h"
#include "utils/endian_read.hpp"
#include "utils/endian_write.hpp"
#include "utils/str_cat.hpp"
#include "utils/stubs.h"
Expand Down
2 changes: 1 addition & 1 deletion Source/effects.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
#include "engine/sound.h"
#include "engine/sound_defs.hpp"
#include "engine/sound_position.hpp"
#include "init.h"
#include "game_mode.hpp"
#include "player.h"
#include "utils/is_of.hpp"

Expand Down
209 changes: 209 additions & 0 deletions Source/engine/assets.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,17 @@
#include <cstring>
#include <string_view>

#include "appfat.h"
#include "game_mode.hpp"
#include "utils/file_util.h"
#include "utils/log.hpp"
#include "utils/paths.h"
#include "utils/str_cat.hpp"
#include "utils/str_split.hpp"

#if defined(_WIN32) && !defined(__UWP__) && !defined(DEVILUTIONX_WINDOWS_NO_WCHAR)
#include <find_steam_game.h>
#endif

#ifndef UNPACKED_MPQS
#include "mpq/mpq_sdl_rwops.hpp"
Expand Down Expand Up @@ -258,4 +264,207 @@ std::string FailedToOpenFileErrorMessage(std::string_view path, std::string_view
return fmt::format(fmt::runtime(_("Failed to open file:\n{:s}\n\n{:s}\n\nThe MPQ file(s) might be damaged. Please check the file integrity.")), path, error);
}

namespace {
#ifdef UNPACKED_MPQS
std::optional<std::string> FindUnpackedMpqData(const std::vector<std::string> &paths, std::string_view mpqName)
{
std::string targetPath;
for (const std::string &path : paths) {
targetPath.clear();
targetPath.reserve(path.size() + mpqName.size() + 1);
targetPath.append(path).append(mpqName) += DirectorySeparator;
if (FileExists(targetPath)) {
LogVerbose(" Found unpacked MPQ directory: {}", targetPath);
return targetPath;
}
}
return std::nullopt;
}
#else
std::optional<MpqArchive> LoadMPQ(const std::vector<std::string> &paths, std::string_view mpqName)
{
std::optional<MpqArchive> archive;
std::string mpqAbsPath;
std::int32_t error = 0;
for (const auto &path : paths) {
mpqAbsPath = path + mpqName.data();
if ((archive = MpqArchive::Open(mpqAbsPath.c_str(), error))) {
LogVerbose(" Found: {} in {}", mpqName, path);
return archive;
}
if (error != 0) {
LogError("Error {}: {}", MpqArchive::ErrorMessage(error), mpqAbsPath);
}
}
if (error == 0) {
LogVerbose("Missing: {}", mpqName);
}

return std::nullopt;
}
#endif

std::vector<std::string> GetMPQSearchPaths()
{
std::vector<std::string> paths;
paths.push_back(paths::BasePath());
paths.push_back(paths::PrefPath());
if (paths[0] == paths[1])
paths.pop_back();
paths.push_back(paths::ConfigPath());
if (paths[0] == paths[1] || (paths.size() == 3 && (paths[0] == paths[2] || paths[1] == paths[2])))
paths.pop_back();

#if (defined(__unix__) || defined(__APPLE__)) && !defined(__ANDROID__)
// `XDG_DATA_HOME` is usually the root path of `paths::PrefPath()`, so we only
// add `XDG_DATA_DIRS`.
const char *xdgDataDirs = std::getenv("XDG_DATA_DIRS");
if (xdgDataDirs != nullptr) {
for (const std::string_view path : SplitByChar(xdgDataDirs, ':')) {
std::string fullPath(path);
if (!path.empty() && path.back() != '/')
fullPath += '/';
fullPath.append("diasurgical/devilutionx/");
paths.push_back(std::move(fullPath));
}
} else {
paths.emplace_back("/usr/local/share/diasurgical/devilutionx/");
paths.emplace_back("/usr/share/diasurgical/devilutionx/");
}
#elif defined(NXDK)
paths.emplace_back("D:\\");
#elif defined(_WIN32) && !defined(__UWP__) && !defined(DEVILUTIONX_WINDOWS_NO_WCHAR)
char gogpath[_FSG_PATH_MAX];
fsg_get_gog_game_path(gogpath, "1412601690");
if (strlen(gogpath) > 0) {
paths.emplace_back(std::string(gogpath) + "/");
paths.emplace_back(std::string(gogpath) + "/hellfire/");
}
#endif

if (paths.empty() || !paths.back().empty()) {
paths.emplace_back(); // PWD
}

if (SDL_LOG_PRIORITY_VERBOSE >= SDL_LogGetPriority(SDL_LOG_CATEGORY_APPLICATION)) {
LogVerbose("Paths:\n base: {}\n pref: {}\n config: {}\n assets: {}",
paths::BasePath(), paths::PrefPath(), paths::ConfigPath(), paths::AssetsPath());

std::string message;
for (std::size_t i = 0; i < paths.size(); ++i) {
message.append(fmt::format("\n{:6d}. '{}'", i + 1, paths[i]));
}
LogVerbose("MPQ search paths:{}", message);
}

return paths;
}

} // namespace

void LoadCoreArchives()
{
auto paths = GetMPQSearchPaths();

#ifdef UNPACKED_MPQS
font_data_path = FindUnpackedMpqData(paths, "fonts");
#else // !UNPACKED_MPQS
#if !defined(__ANDROID__) && !defined(__APPLE__) && !defined(__3DS__) && !defined(__SWITCH__)
// Load devilutionx.mpq first to get the font file for error messages
devilutionx_mpq = LoadMPQ(paths, "devilutionx.mpq");
#endif
font_mpq = LoadMPQ(paths, "fonts.mpq"); // Extra fonts
#endif
}

void LoadLanguageArchive()
{
#ifdef UNPACKED_MPQS
lang_data_path = std::nullopt;
#else
lang_mpq = std::nullopt;
#endif

std::string_view code = GetLanguageCode();
if (code != "en") {
std::string langMpqName { code };
#ifdef UNPACKED_MPQS
lang_data_path = FindUnpackedMpqData(GetMPQSearchPaths(), langMpqName);
#else
langMpqName.append(".mpq");
lang_mpq = LoadMPQ(GetMPQSearchPaths(), langMpqName);
#endif
}
}

void LoadGameArchives()
{
auto paths = GetMPQSearchPaths();
#ifdef UNPACKED_MPQS
diabdat_data_path = FindUnpackedMpqData(paths, "diabdat");
if (!diabdat_data_path) {
spawn_data_path = FindUnpackedMpqData(paths, "spawn");
if (spawn_data_path)
gbIsSpawn = true;
}
if (!HeadlessMode) {
AssetRef ref = FindAsset("ui_art\\title.clx");
if (!ref.ok()) {
LogError("{}", SDL_GetError());
InsertCDDlg(_("diabdat.mpq or spawn.mpq"));
}
}
hellfire_data_path = FindUnpackedMpqData(paths, "hellfire");
if (hellfire_data_path)
gbIsHellfire = true;
if (forceHellfire && !hellfire_data_path)
InsertCDDlg("hellfire");

const bool hasMonk = FileExists(*hellfire_data_path + "plrgfx/monk/mha/mhaas.clx");
const bool hasMusic = FileExists(*hellfire_data_path + "music/dlvlf.wav")
|| FileExists(*hellfire_data_path + "music/dlvlf.mp3");
const bool hasVoice = FileExists(*hellfire_data_path + "sfx/hellfire/cowsut1.wav")
|| FileExists(*hellfire_data_path + "sfx/hellfire/cowsut1.mp3");

if (gbIsHellfire && (!hasMonk || !hasMusic || !hasVoice)) {
DisplayFatalErrorAndExit(_("Some Hellfire MPQs are missing"), _("Not all Hellfire MPQs were found.\nPlease copy all the hf*.mpq files."));
}
#else // !UNPACKED_MPQS
diabdat_mpq = LoadMPQ(paths, "DIABDAT.MPQ");
if (!diabdat_mpq) {
// DIABDAT.MPQ is uppercase on the original CD and the GOG version.
diabdat_mpq = LoadMPQ(paths, "diabdat.mpq");
}

if (!diabdat_mpq) {
spawn_mpq = LoadMPQ(paths, "spawn.mpq");
if (spawn_mpq)
gbIsSpawn = true;
}
if (!HeadlessMode) {
AssetRef ref = FindAsset("ui_art\\title.pcx");
if (!ref.ok()) {
LogError("{}", SDL_GetError());
InsertCDDlg(_("diabdat.mpq or spawn.mpq"));
}
}

hellfire_mpq = LoadMPQ(paths, "hellfire.mpq");
if (hellfire_mpq)
gbIsHellfire = true;
if (forceHellfire && !hellfire_mpq)
InsertCDDlg("hellfire.mpq");

hfmonk_mpq = LoadMPQ(paths, "hfmonk.mpq");
hfbard_mpq = LoadMPQ(paths, "hfbard.mpq");
hfbarb_mpq = LoadMPQ(paths, "hfbarb.mpq");
hfmusic_mpq = LoadMPQ(paths, "hfmusic.mpq");
hfvoice_mpq = LoadMPQ(paths, "hfvoice.mpq");

if (gbIsHellfire && (!hfmonk_mpq || !hfmusic_mpq || !hfvoice_mpq)) {
DisplayFatalErrorAndExit(_("Some Hellfire MPQs are missing"), _("Not all Hellfire MPQs were found.\nPlease copy all the hf*.mpq files."));
}
#endif
}

} // namespace devilution
Loading

0 comments on commit 564b41c

Please sign in to comment.