diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e1594b4241..548a43a088 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -463,6 +463,8 @@ add_files( subsidy_func.h subsidy_gui.cpp subsidy_type.h + survey.cpp + survey.h tar_type.h tbtr_template_gui_main.cpp tbtr_template_gui_create.cpp diff --git a/src/network/network_survey.cpp b/src/network/network_survey.cpp index d2ef43c88f..21c3c396ae 100644 --- a/src/network/network_survey.cpp +++ b/src/network/network_survey.cpp @@ -11,34 +11,14 @@ #include "network_survey.h" #include "network.h" #include "network_func.h" -#include "network_internal.h" -#include "../company_base.h" +#include "../settings_type.h" #include "../debug.h" #include "../debug_fmt.h" -#include "../rev.h" -#include "../settings_type.h" -#include "../settings_internal.h" -#include "../timer/timer_game_tick.h" -#include "../sl/saveload.h" -#include "../date_func.h" -#include "../string_func.h" - -#include "../currency.h" -#include "../fontcache.h" -#include "../language.h" - -#include "../ai/ai_info.hpp" -#include "../game/game.hpp" -#include "../game/game_info.hpp" - -#include "../music/music_driver.hpp" -#include "../sound/sound_driver.hpp" -#include "../video/video_driver.hpp" - -#include "../base_media_base.h" -#include "../blitter/factory.hpp" +#include "../survey.h" #include "../3rdparty/nlohmann/json.hpp" +#include "../core/format.hpp" +#include "../3rdparty/fmt/chrono.h" #include "../safeguards.h" @@ -53,259 +33,6 @@ NLOHMANN_JSON_SERIALIZE_ENUM(NetworkSurveyHandler::Reason, { {NetworkSurveyHandler::Reason::CRASH, "crash"}, }) -NLOHMANN_JSON_SERIALIZE_ENUM(GRFStatus, { - {GRFStatus::GCS_UNKNOWN, "unknown"}, - {GRFStatus::GCS_DISABLED, "disabled"}, - {GRFStatus::GCS_NOT_FOUND, "not found"}, - {GRFStatus::GCS_INITIALISED, "initialised"}, - {GRFStatus::GCS_ACTIVATED, "activated"}, -}) - -static const std::string _vehicle_type_to_string[] = { - "train", - "roadveh", - "ship", - "aircraft", -}; - -/* Defined in one of the os/ survey files. */ -extern void SurveyOS(nlohmann::json &json); - -/** - * Convert a settings table to JSON. - * - * @param survey The JSON object. - * @param table The settings table to convert. - * @param object The object to get the settings from. - */ -static void SurveySettingsTable(nlohmann::json &survey, const SettingTable &table, void *object) -{ - char buf[512]; - for (auto &sd : table) { - /* Skip any old settings we no longer save/load. */ - if (!SlIsObjectCurrentlyValid(sd->save.version_from, sd->save.version_to, sd->save.ext_feature_test)) continue; - - auto name = sd->name; - sd->FormatValue(buf, lastof(buf), object); - - survey[name] = buf; - } -} - -/** - * Convert settings to JSON. - * - * @param survey The JSON object. - */ -static void SurveySettings(nlohmann::json &survey) -{ - IterateSettingsTables([&](const SettingTable &table, void *object) { - SurveySettingsTable(survey, table, object); - }); -} - -/** - * Convert generic OpenTTD information to JSON. - * - * @param survey The JSON object. - */ -static void SurveyOpenTTD(nlohmann::json &survey) -{ - survey["version"]["revision"] = std::string(_openttd_revision); - survey["version"]["modified"] = _openttd_revision_modified; - survey["version"]["tagged"] = _openttd_revision_tagged; - survey["version"]["hash"] = std::string(_openttd_revision_hash); - survey["version"]["newgrf"] = fmt::format("{:X}", _openttd_newgrf_version); - survey["version"]["content"] = std::string(_openttd_content_version); - survey["build_date"] = std::string(_openttd_build_date); - survey["bits"] = -#ifdef POINTER_IS_64BIT - 64 -#else - 32 -#endif - ; - survey["endian"] = -#if (TTD_ENDIAN == TTD_LITTLE_ENDIAN) - "little" -#else - "big" -#endif - ; - survey["dedicated_build"] = -#ifdef DEDICATED - "yes" -#else - "no" -#endif - ; -} - -/** - * Convert generic game information to JSON. - * - * @param survey The JSON object. - */ -static void SurveyConfiguration(nlohmann::json &survey) -{ - survey["network"] = _networking ? (_network_server ? "server" : "client") : "no"; - if (_current_language != nullptr) { - survey["language"]["filename"] = StrLastPathSegment(_current_language->file); - survey["language"]["name"] = _current_language->name; - survey["language"]["isocode"] = _current_language->isocode; - } - if (BlitterFactory::GetCurrentBlitter() != nullptr) { - survey["blitter"] = BlitterFactory::GetCurrentBlitter()->GetName(); - } - if (MusicDriver::GetInstance() != nullptr) { - survey["music_driver"] = MusicDriver::GetInstance()->GetName(); - } - if (SoundDriver::GetInstance() != nullptr) { - survey["sound_driver"] = SoundDriver::GetInstance()->GetName(); - } - if (VideoDriver::GetInstance() != nullptr) { - survey["video_driver"] = VideoDriver::GetInstance()->GetName(); - survey["video_info"] = VideoDriver::GetInstance()->GetInfoString(); - } - if (BaseGraphics::GetUsedSet() != nullptr) { - survey["graphics_set"] = fmt::format("{}.{}", BaseGraphics::GetUsedSet()->name, BaseGraphics::GetUsedSet()->version); - } - if (BaseMusic::GetUsedSet() != nullptr) { - survey["music_set"] = fmt::format("{}.{}", BaseMusic::GetUsedSet()->name, BaseMusic::GetUsedSet()->version); - } - if (BaseSounds::GetUsedSet() != nullptr) { - survey["sound_set"] = fmt::format("{}.{}", BaseSounds::GetUsedSet()->name, BaseSounds::GetUsedSet()->version); - } -} - -/** - * Convert font information to JSON. - * - * @param survey The JSON object. - */ -static void SurveyFont(nlohmann::json &survey) -{ - survey["small"] = FontCache::Get(FS_SMALL)->GetFontName(); - survey["medium"] = FontCache::Get(FS_NORMAL)->GetFontName(); - survey["large"] = FontCache::Get(FS_LARGE)->GetFontName(); - survey["mono"] = FontCache::Get(FS_MONO)->GetFontName(); -} - -/** - * Convert company information to JSON. - * - * @param survey The JSON object. - */ -static void SurveyCompanies(nlohmann::json &survey) -{ - for (const Company *c : Company::Iterate()) { - auto &company = survey[std::to_string(c->index)]; - if (c->ai_info == nullptr) { - company["type"] = "human"; - } else { - company["type"] = "ai"; - company["script"] = fmt::format("{}.{}", c->ai_info->GetName(), c->ai_info->GetVersion()); - } - - for (VehicleType type = VEH_BEGIN; type < VEH_COMPANY_END; type++) { - uint amount = c->group_all[type].num_vehicle; - company["vehicles"][_vehicle_type_to_string[type]] = amount; - } - - company["infrastructure"]["road"] = c->infrastructure.GetRoadTotal(); - company["infrastructure"]["tram"] = c->infrastructure.GetTramTotal(); - company["infrastructure"]["rail"] = c->infrastructure.GetRailTotal(); - company["infrastructure"]["signal"] = c->infrastructure.signal; - company["infrastructure"]["water"] = c->infrastructure.water; - company["infrastructure"]["station"] = c->infrastructure.station; - company["infrastructure"]["airport"] = c->infrastructure.airport; - } -} - -/** - * Convert timer information to JSON. - * - * @param survey The JSON object. - */ -static void SurveyTimers(nlohmann::json &survey) -{ - survey["ticks"] = _scaled_tick_counter; - survey["seconds"] = std::chrono::duration_cast(std::chrono::steady_clock::now() - _switch_mode_time).count(); - - survey["calendar"] = fmt::format("{:04}-{:02}-{:02} ({})", _cur_date_ymd.year, _cur_date_ymd.month + 1, _cur_date_ymd.day, _date_fract); -} - -/** - * Convert GRF information to JSON. - * - * @param survey The JSON object. - */ -static void SurveyGrfs(nlohmann::json &survey) -{ - for (GRFConfig *c = _grfconfig; c != nullptr; c = c->next) { - auto grfid = fmt::format("{:08x}", BSWAP32(c->ident.grfid)); - auto &grf = survey[grfid]; - - grf["md5sum"] = FormatArrayAsHex(c->ident.md5sum); - grf["status"] = c->status; - - if ((c->palette & GRFP_GRF_MASK) == GRFP_GRF_UNSET) grf["palette"] = "unset"; - if ((c->palette & GRFP_GRF_MASK) == GRFP_GRF_DOS) grf["palette"] = "dos"; - if ((c->palette & GRFP_GRF_MASK) == GRFP_GRF_WINDOWS) grf["palette"] = "windows"; - if ((c->palette & GRFP_GRF_MASK) == GRFP_GRF_ANY) grf["palette"] = "any"; - - if ((c->palette & GRFP_BLT_MASK) == GRFP_BLT_UNSET) grf["blitter"] = "unset"; - if ((c->palette & GRFP_BLT_MASK) == GRFP_BLT_32BPP) grf["blitter"] = "32bpp"; - - grf["is_static"] = HasBit(c->flags, GCF_STATIC); - - std::vector parameters; - for (int i = 0; i < c->num_params; i++) { - parameters.push_back(c->param[i]); - } - grf["parameters"] = parameters; - } -} - -/** - * Convert game-script information to JSON. - * - * @param survey The JSON object. - */ -static void SurveyGameScript(nlohmann::json &survey) -{ - if (Game::GetInfo() == nullptr) return; - - survey = fmt::format("{}.{}", Game::GetInfo()->GetName(), Game::GetInfo()->GetVersion()); -} - -/** - * Change the bytes of memory into a textual version rounded up to the biggest unit. - * - * For example, 16751108096 would become 16 GiB. - * - * @param memory The bytes of memory. - * @return std::string A textual representation. - */ -std::string SurveyMemoryToText(uint64_t memory) -{ - memory = memory / 1024; // KiB - memory = CeilDiv(memory, 1024); // MiB - - /* Anything above 512 MiB we represent in GiB. */ - if (memory > 512) { - return fmt::format("{} GiB", CeilDiv(memory, 1024)); - } - - /* Anything above 64 MiB we represent in a multiplier of 128 MiB. */ - if (memory > 64) { - return fmt::format("{} MiB", Ceil(memory, 128)); - } - - /* Anything else in a multiplier of 4 MiB. */ - return fmt::format("{} MiB", Ceil(memory, 4)); -} - /** * Create the payload for the survey. * @@ -320,6 +47,7 @@ std::string NetworkSurveyHandler::CreatePayload(Reason reason, bool for_preview) survey["schema"] = NETWORK_SURVEY_VERSION; survey["reason"] = reason; survey["id"] = _savegame_id; + survey["date"] = fmt::format("{:%Y-%m-%d %H:%M:%S} (UTC)", fmt::gmtime(time(nullptr))); #ifdef SURVEY_KEY /* We censor the key to avoid people trying to be "clever" and use it to send their own surveys. */ @@ -334,13 +62,15 @@ std::string NetworkSurveyHandler::CreatePayload(Reason reason, bool for_preview) SurveyOpenTTD(info["openttd"]); SurveyConfiguration(info["configuration"]); SurveyFont(info["font"]); + SurveyCompiler(info["compiler"]); + SurveyLibraries(info["libraries"]); } { auto &game = survey["game"]; SurveyTimers(game["timers"]); SurveyCompanies(game["companies"]); - SurveySettings(game["settings"]); + SurveySettings(game["settings"], false); SurveyGrfs(game["grfs"]); SurveyGameScript(game["game_script"]); } diff --git a/src/survey.cpp b/src/survey.cpp new file mode 100644 index 0000000000..a3fa39c0e8 --- /dev/null +++ b/src/survey.cpp @@ -0,0 +1,425 @@ +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + */ + +/** @file survey.cpp Functions to survey the current game / system, for crashlog and network-survey. */ + +#include "stdafx.h" + +#include "survey.h" + +#include "network/network.h" +#include "rev.h" +#include "settings_type.h" +#include "settings_internal.h" +#include "timer/timer_game_tick.h" +#include "sl/saveload.h" +#include "date_func.h" + +#include "currency.h" +#include "fontcache.h" +#include "language.h" + +#include "ai/ai_info.hpp" +#include "game/game.hpp" +#include "game/game_info.hpp" + +#include "music/music_driver.hpp" +#include "sound/sound_driver.hpp" +#include "video/video_driver.hpp" + +#include "base_media_base.h" +#include "blitter/factory.hpp" + +#include "core/format.hpp" + +#ifdef WITH_ALLEGRO +# include +#endif /* WITH_ALLEGRO */ +#ifdef WITH_FONTCONFIG +# include +#endif /* WITH_FONTCONFIG */ +#ifdef WITH_PNG + /* pngconf.h, included by png.h doesn't like something in the + * freetype headers. As such it's not alphabetically sorted. */ +# include +#endif /* WITH_PNG */ +#ifdef WITH_FREETYPE +# include +# include FT_FREETYPE_H +#endif /* WITH_FREETYPE */ +#ifdef WITH_HARFBUZZ +# include +#endif /* WITH_HARFBUZZ */ +#ifdef WITH_ICU_I18N +# include +#endif /* WITH_ICU_I18N */ +#ifdef WITH_LIBLZMA +# include +#endif +#ifdef WITH_LZO +#include +#endif +#if defined(WITH_SDL) || defined(WITH_SDL2) +# include +#endif /* WITH_SDL || WITH_SDL2 */ +#ifdef WITH_ZLIB +# include +#endif +#ifdef WITH_CURL +# include +#endif + +#include "safeguards.h" + +NLOHMANN_JSON_SERIALIZE_ENUM(GRFStatus, { + {GRFStatus::GCS_UNKNOWN, "unknown"}, + {GRFStatus::GCS_DISABLED, "disabled"}, + {GRFStatus::GCS_NOT_FOUND, "not found"}, + {GRFStatus::GCS_INITIALISED, "initialised"}, + {GRFStatus::GCS_ACTIVATED, "activated"}, +}) + +/** Lookup table to convert a VehicleType to a string. */ +static const std::string _vehicle_type_to_string[] = { + "train", + "roadveh", + "ship", + "aircraft", +}; + +/** + * Convert a settings table to JSON. + * + * @param survey The JSON object. + * @param table The settings table to convert. + * @param object The object to get the settings from. + * @param skip_if_default If true, skip any settings that are on their default value. + */ +static void SurveySettingsTable(nlohmann::json &survey, const SettingTable &table, void *object, bool skip_if_default) +{ + char buf[512]; + for (auto &sd : table) { + /* Skip any old settings we no longer save/load. */ + if (!SlIsObjectCurrentlyValid(sd->save.version_from, sd->save.version_to, sd->save.ext_feature_test)) continue; + + if (skip_if_default && sd->IsDefaultValue(object)) continue; + sd->FormatValue(buf, lastof(buf), object); + survey[sd->name] = buf; + } +} + +/** + * Convert settings to JSON. + * + * @param survey The JSON object. + */ +void SurveySettings(nlohmann::json &survey, bool skip_if_default) +{ + IterateSettingsTables([&](const SettingTable &table, void *object) { + SurveySettingsTable(survey, table, object, skip_if_default); + }); +} + +/** + * Convert compiler information to JSON. + * + * @param survey The JSON object. + */ +void SurveyCompiler(nlohmann::json &survey) +{ +#if defined(_MSC_VER) + survey["name"] = "MSVC"; + survey["version"] = _MSC_VER; +#elif defined(__ICC) && defined(__GNUC__) + survey["name"] = "ICC"; + survey["version"] = __ICC; +# if defined(__GNUC__) + survey["extra"] = fmt::format("GCC {}.{}.{} mode", __GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__); +# endif +#elif defined(__GNUC__) + survey["name"] = "GCC"; + survey["version"] = fmt::format("{}.{}.{}", __GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__); +#else + survey["name"] = "unknown"; +#endif + +#if defined(__VERSION__) + survey["extra"] = __VERSION__; +#endif +} + +/** + * Convert generic OpenTTD information to JSON. + * + * @param survey The JSON object. + */ +void SurveyOpenTTD(nlohmann::json &survey) +{ + survey["version"]["revision"] = std::string(_openttd_revision); + survey["version"]["modified"] = _openttd_revision_modified; + survey["version"]["tagged"] = _openttd_revision_tagged; + survey["version"]["hash"] = std::string(_openttd_revision_hash); + survey["version"]["newgrf"] = fmt::format("{:X}", _openttd_newgrf_version); + survey["version"]["content"] = std::string(_openttd_content_version); + survey["build_date"] = std::string(_openttd_build_date); + survey["bits"] = +#ifdef POINTER_IS_64BIT + 64 +#else + 32 +#endif + ; + survey["endian"] = +#if (TTD_ENDIAN == TTD_LITTLE_ENDIAN) + "little" +#else + "big" +#endif + ; + survey["dedicated_build"] = +#ifdef DEDICATED + "yes" +#else + "no" +#endif + ; +} + +/** + * Convert generic game information to JSON. + * + * @param survey The JSON object. + */ +void SurveyConfiguration(nlohmann::json &survey) +{ + survey["network"] = _networking ? (_network_server ? "server" : "client") : "no"; + if (_current_language != nullptr) { + survey["language"]["filename"] = StrLastPathSegment(_current_language->file); + survey["language"]["name"] = _current_language->name; + survey["language"]["isocode"] = _current_language->isocode; + } + if (BlitterFactory::GetCurrentBlitter() != nullptr) { + survey["blitter"] = BlitterFactory::GetCurrentBlitter()->GetName(); + } + if (MusicDriver::GetInstance() != nullptr) { + survey["music_driver"] = MusicDriver::GetInstance()->GetName(); + } + if (SoundDriver::GetInstance() != nullptr) { + survey["sound_driver"] = SoundDriver::GetInstance()->GetName(); + } + if (VideoDriver::GetInstance() != nullptr) { + survey["video_driver"] = VideoDriver::GetInstance()->GetName(); + survey["video_info"] = VideoDriver::GetInstance()->GetInfoString(); + } + if (BaseGraphics::GetUsedSet() != nullptr) { + survey["graphics_set"] = fmt::format("{}.{}", BaseGraphics::GetUsedSet()->name, BaseGraphics::GetUsedSet()->version); + } + if (BaseMusic::GetUsedSet() != nullptr) { + survey["music_set"] = fmt::format("{}.{}", BaseMusic::GetUsedSet()->name, BaseMusic::GetUsedSet()->version); + } + if (BaseSounds::GetUsedSet() != nullptr) { + survey["sound_set"] = fmt::format("{}.{}", BaseSounds::GetUsedSet()->name, BaseSounds::GetUsedSet()->version); + } +} + +/** + * Convert font information to JSON. + * + * @param survey The JSON object. + */ +void SurveyFont(nlohmann::json &survey) +{ + survey["small"] = FontCache::Get(FS_SMALL)->GetFontName(); + survey["medium"] = FontCache::Get(FS_NORMAL)->GetFontName(); + survey["large"] = FontCache::Get(FS_LARGE)->GetFontName(); + survey["mono"] = FontCache::Get(FS_MONO)->GetFontName(); +} + +/** + * Convert company information to JSON. + * + * @param survey The JSON object. + */ +void SurveyCompanies(nlohmann::json &survey) +{ + for (const Company *c : Company::Iterate()) { + auto &company = survey[std::to_string(c->index)]; + if (c->ai_info == nullptr) { + company["type"] = "human"; + } else { + company["type"] = "ai"; + company["script"] = fmt::format("{}.{}", c->ai_info->GetName(), c->ai_info->GetVersion()); + } + + for (VehicleType type = VEH_BEGIN; type < VEH_COMPANY_END; type++) { + uint amount = c->group_all[type].num_vehicle; + company["vehicles"][_vehicle_type_to_string[type]] = amount; + } + + company["infrastructure"]["road"] = c->infrastructure.GetRoadTotal(); + company["infrastructure"]["tram"] = c->infrastructure.GetTramTotal(); + company["infrastructure"]["rail"] = c->infrastructure.GetRailTotal(); + company["infrastructure"]["signal"] = c->infrastructure.signal; + company["infrastructure"]["water"] = c->infrastructure.water; + company["infrastructure"]["station"] = c->infrastructure.station; + company["infrastructure"]["airport"] = c->infrastructure.airport; + } +} + +/** + * Convert timer information to JSON. + * + * @param survey The JSON object. + */ +void SurveyTimers(nlohmann::json &survey) +{ + survey["ticks"] = _scaled_tick_counter; + survey["seconds"] = std::chrono::duration_cast(std::chrono::steady_clock::now() - _switch_mode_time).count(); + + survey["calendar"] = fmt::format("{:04}-{:02}-{:02} ({})", _cur_date_ymd.year, _cur_date_ymd.month + 1, _cur_date_ymd.day, _date_fract); +} + +/** + * Convert GRF information to JSON. + * + * @param survey The JSON object. + */ +void SurveyGrfs(nlohmann::json &survey) +{ + for (GRFConfig *c = _grfconfig; c != nullptr; c = c->next) { + auto grfid = fmt::format("{:08x}", BSWAP32(c->ident.grfid)); + auto &grf = survey[grfid]; + + grf["md5sum"] = FormatArrayAsHex(c->ident.md5sum); + grf["status"] = c->status; + + if ((c->palette & GRFP_GRF_MASK) == GRFP_GRF_UNSET) grf["palette"] = "unset"; + if ((c->palette & GRFP_GRF_MASK) == GRFP_GRF_DOS) grf["palette"] = "dos"; + if ((c->palette & GRFP_GRF_MASK) == GRFP_GRF_WINDOWS) grf["palette"] = "windows"; + if ((c->palette & GRFP_GRF_MASK) == GRFP_GRF_ANY) grf["palette"] = "any"; + + if ((c->palette & GRFP_BLT_MASK) == GRFP_BLT_UNSET) grf["blitter"] = "unset"; + if ((c->palette & GRFP_BLT_MASK) == GRFP_BLT_32BPP) grf["blitter"] = "32bpp"; + + grf["is_static"] = HasBit(c->flags, GCF_STATIC); + + std::vector parameters; + for (int i = 0; i < c->num_params; i++) { + parameters.push_back(c->param[i]); + } + grf["parameters"] = parameters; + } +} + +/** + * Convert game-script information to JSON. + * + * @param survey The JSON object. + */ +void SurveyGameScript(nlohmann::json &survey) +{ + if (Game::GetInfo() == nullptr) return; + + survey = fmt::format("{}.{}", Game::GetInfo()->GetName(), Game::GetInfo()->GetVersion()); +} + +/** + * Convert compiled libraries information to JSON. + * + * @param survey The JSON object. + */ +void SurveyLibraries(nlohmann::json &survey) +{ +#ifdef WITH_ALLEGRO + survey["allegro"] = std::string(allegro_id); +#endif /* WITH_ALLEGRO */ + +#ifdef WITH_FONTCONFIG + int version = FcGetVersion(); + survey["fontconfig"] = fmt::format("{}.{}.{}", version / 10000, (version / 100) % 100, version % 100); +#endif /* WITH_FONTCONFIG */ + +#ifdef WITH_FREETYPE + FT_Library library; + int major, minor, patch; + FT_Init_FreeType(&library); + FT_Library_Version(library, &major, &minor, &patch); + FT_Done_FreeType(library); + survey["freetype"] = fmt::format("{}.{}.{}", major, minor, patch); +#endif /* WITH_FREETYPE */ + +#if defined(WITH_HARFBUZZ) + survey["harfbuzz"] = hb_version_string(); +#endif /* WITH_HARFBUZZ */ + +#if defined(WITH_ICU_I18N) + /* 4 times 0-255, separated by dots (.) and a trailing '\0' */ + char buf[4 * 3 + 3 + 1]; + UVersionInfo ver; + u_getVersion(ver); + u_versionToString(ver, buf); + survey["icu_i18n"] = buf; +#endif /* WITH_ICU_I18N */ + +#ifdef WITH_LIBLZMA + survey["lzma"] = lzma_version_string(); +#endif + +#ifdef WITH_LZO + survey["lzo"] = lzo_version_string(); +#endif + +#ifdef WITH_PNG + survey["png"] = png_get_libpng_ver(nullptr); +#endif /* WITH_PNG */ + +#ifdef WITH_SDL + const SDL_version *sdl_v = SDL_Linked_Version(); + survey["sdl"] = fmt::format("{}.{}.{}", sdl_v->major, sdl_v->minor, sdl_v->patch); +#elif defined(WITH_SDL2) + SDL_version sdl2_v; + SDL_GetVersion(&sdl2_v); + survey["sdl2"] = fmt::format("{}.{}.{}", sdl2_v.major, sdl2_v.minor, sdl2_v.patch); +#endif + +#ifdef WITH_ZLIB + survey["zlib"] = zlibVersion(); +#endif + +#ifdef WITH_CURL + auto *curl_v = curl_version_info(CURLVERSION_NOW); + survey["curl"] = curl_v->version; + survey["curl_ssl"] = curl_v->ssl_version == nullptr ? "none" : curl_v->ssl_version; +#endif +} + +/** + * Change the bytes of memory into a textual version rounded up to the biggest unit. + * + * For example, 16751108096 would become 16 GiB. + * + * @param memory The bytes of memory. + * @return std::string A textual representation. + */ +std::string SurveyMemoryToText(uint64_t memory) +{ + memory = memory / 1024; // KiB + memory = CeilDiv(memory, 1024); // MiB + + /* Anything above 512 MiB we represent in GiB. */ + if (memory > 512) { + return fmt::format("{} GiB", CeilDiv(memory, 1024)); + } + + /* Anything above 64 MiB we represent in a multiplier of 128 MiB. */ + if (memory > 64) { + return fmt::format("{} MiB", Ceil(memory, 128)); + } + + /* Anything else in a multiplier of 4 MiB. */ + return fmt::format("{} MiB", Ceil(memory, 4)); +} diff --git a/src/survey.h b/src/survey.h new file mode 100644 index 0000000000..aae16d4bf4 --- /dev/null +++ b/src/survey.h @@ -0,0 +1,31 @@ +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + */ + +/** @file survey.h Functions to survey the current game / system, for crashlog and network-survey. */ + +#ifndef SURVEY_H +#define SURVEY_H + +#include "3rdparty/nlohmann/json.hpp" + +std::string SurveyMemoryToText(uint64_t memory); + +void SurveyCompanies(nlohmann::json &survey); +void SurveyCompiler(nlohmann::json &survey); +void SurveyConfiguration(nlohmann::json &survey); +void SurveyFont(nlohmann::json &survey); +void SurveyGameScript(nlohmann::json &survey); +void SurveyGrfs(nlohmann::json &survey); +void SurveyLibraries(nlohmann::json &survey); +void SurveyOpenTTD(nlohmann::json &survey); +void SurveySettings(nlohmann::json &survey, bool skip_if_default); +void SurveyTimers(nlohmann::json &survey); + +/* Defined in os//survey_.cpp. */ +void SurveyOS(nlohmann::json &json); + +#endif /* SURVEY_H */