mirror of https://github.com/OpenTTD/OpenTTD
Compare commits
2 Commits
a0353af223
...
ba51a34b4c
Author | SHA1 | Date |
---|---|---|
|
ba51a34b4c | |
|
37e2f99c09 |
|
@ -432,6 +432,8 @@ add_files(
|
|||
subsidy_func.h
|
||||
subsidy_gui.cpp
|
||||
subsidy_type.h
|
||||
survey.cpp
|
||||
survey.h
|
||||
tar_type.h
|
||||
terraform_cmd.cpp
|
||||
terraform_cmd.h
|
||||
|
|
392
src/crashlog.cpp
392
src/crashlog.cpp
|
@ -9,297 +9,60 @@
|
|||
|
||||
#include "stdafx.h"
|
||||
#include "crashlog.h"
|
||||
#include "survey.h"
|
||||
#include "gamelog.h"
|
||||
#include "timer/timer_game_calendar.h"
|
||||
#include "map_func.h"
|
||||
#include "rev.h"
|
||||
#include "strings_func.h"
|
||||
#include "blitter/factory.hpp"
|
||||
#include "base_media_base.h"
|
||||
#include "music/music_driver.hpp"
|
||||
#include "sound/sound_driver.hpp"
|
||||
#include "video/video_driver.hpp"
|
||||
#include "saveload/saveload.h"
|
||||
#include "screenshot.h"
|
||||
#include "gfx_func.h"
|
||||
#include "network/network.h"
|
||||
#include "network/network_survey.h"
|
||||
#include "language.h"
|
||||
#include "fontcache.h"
|
||||
#include "news_gui.h"
|
||||
#include "fileio_func.h"
|
||||
#include "fileio_type.h"
|
||||
|
||||
#include "ai/ai_info.hpp"
|
||||
#include "game/game.hpp"
|
||||
#include "game/game_info.hpp"
|
||||
#include "company_base.h"
|
||||
#include "company_func.h"
|
||||
#include "3rdparty/fmt/chrono.h"
|
||||
#include "3rdparty/fmt/std.h"
|
||||
|
||||
#ifdef WITH_ALLEGRO
|
||||
# include <allegro.h>
|
||||
#endif /* WITH_ALLEGRO */
|
||||
#ifdef WITH_FONTCONFIG
|
||||
# include <fontconfig/fontconfig.h>
|
||||
#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 <png.h>
|
||||
#endif /* WITH_PNG */
|
||||
#ifdef WITH_FREETYPE
|
||||
# include <ft2build.h>
|
||||
# include FT_FREETYPE_H
|
||||
#endif /* WITH_FREETYPE */
|
||||
#ifdef WITH_HARFBUZZ
|
||||
# include <hb.h>
|
||||
#endif /* WITH_HARFBUZZ */
|
||||
#ifdef WITH_ICU_I18N
|
||||
# include <unicode/uversion.h>
|
||||
#endif /* WITH_ICU_I18N */
|
||||
#ifdef WITH_LIBLZMA
|
||||
# include <lzma.h>
|
||||
#endif
|
||||
#ifdef WITH_LZO
|
||||
#include <lzo/lzo1x.h>
|
||||
#endif
|
||||
#if defined(WITH_SDL) || defined(WITH_SDL2)
|
||||
# include <SDL.h>
|
||||
#endif /* WITH_SDL || WITH_SDL2 */
|
||||
#ifdef WITH_ZLIB
|
||||
# include <zlib.h>
|
||||
#endif
|
||||
#ifdef WITH_CURL
|
||||
# include <curl/curl.h>
|
||||
#endif
|
||||
#include "core/format.hpp"
|
||||
|
||||
#include "safeguards.h"
|
||||
|
||||
/* static */ std::string CrashLog::message{ "<none>" };
|
||||
/* static */ std::string CrashLog::message{};
|
||||
|
||||
void CrashLog::LogCompiler(std::back_insert_iterator<std::string> &output_iterator) const
|
||||
{
|
||||
fmt::format_to(output_iterator, " Compiler: "
|
||||
#if defined(_MSC_VER)
|
||||
"MSVC {}", _MSC_VER
|
||||
#elif defined(__ICC) && defined(__GNUC__)
|
||||
"ICC {} (GCC {}.{}.{} mode)", __ICC, __GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__
|
||||
#elif defined(__ICC)
|
||||
"ICC {}", __ICC
|
||||
#elif defined(__GNUC__)
|
||||
"GCC {}.{}.{}", __GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__
|
||||
#else
|
||||
"<unknown>"
|
||||
#endif
|
||||
);
|
||||
#if defined(__VERSION__)
|
||||
fmt::format_to(output_iterator, " \"" __VERSION__ "\"\n\n");
|
||||
#else
|
||||
fmt::format_to(output_iterator, "\n\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes OpenTTD's version to the buffer.
|
||||
* @param output_iterator Iterator to write the output to.
|
||||
*/
|
||||
void CrashLog::LogOpenTTDVersion(std::back_insert_iterator<std::string> &output_iterator) const
|
||||
{
|
||||
fmt::format_to(output_iterator,
|
||||
"OpenTTD version:\n"
|
||||
" Version: {} ({})\n"
|
||||
" NewGRF ver: {:08x}\n"
|
||||
" Bits: {}\n"
|
||||
" Endian: {}\n"
|
||||
" Dedicated: {}\n"
|
||||
" Build date: {}\n\n",
|
||||
_openttd_revision,
|
||||
_openttd_revision_modified,
|
||||
_openttd_newgrf_version,
|
||||
#ifdef POINTER_IS_64BIT
|
||||
64,
|
||||
#else
|
||||
32,
|
||||
#endif
|
||||
#if (TTD_ENDIAN == TTD_LITTLE_ENDIAN)
|
||||
"little",
|
||||
#else
|
||||
"big",
|
||||
#endif
|
||||
#ifdef DEDICATED
|
||||
"yes",
|
||||
#else
|
||||
"no",
|
||||
#endif
|
||||
_openttd_build_date
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the (important) configuration settings to the buffer.
|
||||
* E.g. graphics set, sound set, blitter and AIs.
|
||||
* @param output_iterator Iterator to write the output to.
|
||||
*/
|
||||
void CrashLog::LogConfiguration(std::back_insert_iterator<std::string> &output_iterator) const
|
||||
{
|
||||
fmt::format_to(output_iterator,
|
||||
"Configuration:\n"
|
||||
" Blitter: {}\n"
|
||||
" Graphics set: {} ({})\n"
|
||||
" Language: {}\n"
|
||||
" Music driver: {}\n"
|
||||
" Music set: {} ({})\n"
|
||||
" Network: {}\n"
|
||||
" Sound driver: {}\n"
|
||||
" Sound set: {} ({})\n"
|
||||
" Video driver: {}\n\n",
|
||||
BlitterFactory::GetCurrentBlitter() == nullptr ? "none" : BlitterFactory::GetCurrentBlitter()->GetName(),
|
||||
BaseGraphics::GetUsedSet() == nullptr ? "none" : BaseGraphics::GetUsedSet()->name,
|
||||
BaseGraphics::GetUsedSet() == nullptr ? UINT32_MAX : BaseGraphics::GetUsedSet()->version,
|
||||
_current_language == nullptr ? "none" : _current_language->file.filename(),
|
||||
MusicDriver::GetInstance() == nullptr ? "none" : MusicDriver::GetInstance()->GetName(),
|
||||
BaseMusic::GetUsedSet() == nullptr ? "none" : BaseMusic::GetUsedSet()->name,
|
||||
BaseMusic::GetUsedSet() == nullptr ? UINT32_MAX : BaseMusic::GetUsedSet()->version,
|
||||
_networking ? (_network_server ? "server" : "client") : "no",
|
||||
SoundDriver::GetInstance() == nullptr ? "none" : SoundDriver::GetInstance()->GetName(),
|
||||
BaseSounds::GetUsedSet() == nullptr ? "none" : BaseSounds::GetUsedSet()->name,
|
||||
BaseSounds::GetUsedSet() == nullptr ? UINT32_MAX : BaseSounds::GetUsedSet()->version,
|
||||
VideoDriver::GetInstance() == nullptr ? "none" : VideoDriver::GetInstance()->GetInfoString()
|
||||
);
|
||||
|
||||
fmt::format_to(output_iterator,
|
||||
"Fonts:\n"
|
||||
" Small: {}\n"
|
||||
" Medium: {}\n"
|
||||
" Large: {}\n"
|
||||
" Mono: {}\n\n",
|
||||
FontCache::GetName(FS_SMALL),
|
||||
FontCache::GetName(FS_NORMAL),
|
||||
FontCache::GetName(FS_LARGE),
|
||||
FontCache::GetName(FS_MONO)
|
||||
);
|
||||
|
||||
fmt::format_to(output_iterator, "AI Configuration (local: {}) (current: {}):\n", _local_company, _current_company);
|
||||
for (const Company *c : Company::Iterate()) {
|
||||
if (c->ai_info == nullptr) {
|
||||
fmt::format_to(output_iterator, " {:2}: Human\n", c->index);
|
||||
} else {
|
||||
fmt::format_to(output_iterator, " {:2}: {} (v{})\n", (int)c->index, c->ai_info->GetName(), c->ai_info->GetVersion());
|
||||
}
|
||||
}
|
||||
|
||||
if (Game::GetInfo() != nullptr) {
|
||||
fmt::format_to(output_iterator, " GS: {} (v{})\n", Game::GetInfo()->GetName(), Game::GetInfo()->GetVersion());
|
||||
}
|
||||
fmt::format_to(output_iterator, "\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes information (versions) of the used libraries.
|
||||
* @param output_iterator Iterator to write the output to.
|
||||
*/
|
||||
void CrashLog::LogLibraries(std::back_insert_iterator<std::string> &output_iterator) const
|
||||
{
|
||||
fmt::format_to(output_iterator, "Libraries:\n");
|
||||
|
||||
#ifdef WITH_ALLEGRO
|
||||
fmt::format_to(output_iterator, " Allegro: {}\n", allegro_id);
|
||||
#endif /* WITH_ALLEGRO */
|
||||
|
||||
#ifdef WITH_FONTCONFIG
|
||||
int version = FcGetVersion();
|
||||
fmt::format_to(output_iterator, " FontConfig: {}.{}.{}\n", 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);
|
||||
fmt::format_to(output_iterator, " FreeType: {}.{}.{}\n", major, minor, patch);
|
||||
#endif /* WITH_FREETYPE */
|
||||
|
||||
#if defined(WITH_HARFBUZZ)
|
||||
fmt::format_to(output_iterator, " HarfBuzz: {}\n", 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);
|
||||
fmt::format_to(output_iterator, " ICU i18n: {}\n", buf);
|
||||
#endif /* WITH_ICU_I18N */
|
||||
|
||||
#ifdef WITH_LIBLZMA
|
||||
fmt::format_to(output_iterator, " LZMA: {}\n", lzma_version_string());
|
||||
#endif
|
||||
|
||||
#ifdef WITH_LZO
|
||||
fmt::format_to(output_iterator, " LZO: {}\n", lzo_version_string());
|
||||
#endif
|
||||
|
||||
#ifdef WITH_PNG
|
||||
fmt::format_to(output_iterator, " PNG: {}\n", png_get_libpng_ver(nullptr));
|
||||
#endif /* WITH_PNG */
|
||||
|
||||
#ifdef WITH_SDL
|
||||
const SDL_version *sdl_v = SDL_Linked_Version();
|
||||
fmt::format_to(output_iterator, " SDL1: {}.{}.{}\n", sdl_v->major, sdl_v->minor, sdl_v->patch);
|
||||
#elif defined(WITH_SDL2)
|
||||
SDL_version sdl2_v;
|
||||
SDL_GetVersion(&sdl2_v);
|
||||
fmt::format_to(output_iterator, " SDL2: {}.{}.{}\n", sdl2_v.major, sdl2_v.minor, sdl2_v.patch);
|
||||
#endif
|
||||
|
||||
#ifdef WITH_ZLIB
|
||||
fmt::format_to(output_iterator, " Zlib: {}\n", zlibVersion());
|
||||
#endif
|
||||
|
||||
#ifdef WITH_CURL
|
||||
auto *curl_v = curl_version_info(CURLVERSION_NOW);
|
||||
fmt::format_to(output_iterator, " Curl: {}\n", curl_v->version);
|
||||
if (curl_v->ssl_version != nullptr) {
|
||||
fmt::format_to(output_iterator, " Curl SSL: {}\n", curl_v->ssl_version);
|
||||
} else {
|
||||
fmt::format_to(output_iterator, " Curl SSL: none\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
fmt::format_to(output_iterator, "\n");
|
||||
}
|
||||
/** The version of the schema of the JSON information. */
|
||||
constexpr uint8_t CRASHLOG_SURVEY_VERSION = 1;
|
||||
|
||||
/**
|
||||
* Writes the gamelog data to the buffer.
|
||||
* @param output_iterator Iterator to write the output to.
|
||||
*/
|
||||
void CrashLog::LogGamelog(std::back_insert_iterator<std::string> &output_iterator) const
|
||||
static void SurveyGamelog(nlohmann::json &json)
|
||||
{
|
||||
_gamelog.Print([&output_iterator](const std::string &s) {
|
||||
fmt::format_to(output_iterator, "{}\n", s);
|
||||
json = nlohmann::json::array();
|
||||
|
||||
_gamelog.Print([&json](const std::string &s) {
|
||||
json.push_back(s);
|
||||
});
|
||||
fmt::format_to(output_iterator, "\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes up to 32 recent news messages to the buffer, with the most recent first.
|
||||
* @param output_iterator Iterator to write the output to.
|
||||
*/
|
||||
void CrashLog::LogRecentNews(std::back_insert_iterator<std::string> &output_iterator) const
|
||||
static void SurveyRecentNews(nlohmann::json &json)
|
||||
{
|
||||
fmt::format_to(output_iterator, "Recent news messages:\n");
|
||||
json = nlohmann::json::array();
|
||||
|
||||
int i = 0;
|
||||
for (NewsItem *news = _latest_news; i < 32 && news != nullptr; news = news->prev, i++) {
|
||||
TimerGameCalendar::YearMonthDay ymd;
|
||||
TimerGameCalendar::ConvertDateToYMD(news->date, &ymd);
|
||||
fmt::format_to(output_iterator, "({}-{:02}-{:02}) StringID: {}, Type: {}, Ref1: {}, {}, Ref2: {}, {}\n",
|
||||
ymd.year, ymd.month + 1, ymd.day, news->string_id, news->type,
|
||||
news->reftype1, news->ref1, news->reftype2, news->ref2);
|
||||
json.push_back(fmt::format("({}-{:02}-{:02}) StringID: {}, Type: {}, Ref1: {}, {}, Ref2: {}, {}",
|
||||
ymd.year, ymd.month + 1, ymd.day, news->string_id, news->type,
|
||||
news->reftype1, news->ref1, news->reftype2, news->ref2));
|
||||
}
|
||||
fmt::format_to(output_iterator, "\n");
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -320,28 +83,95 @@ std::string CrashLog::CreateFileName(const char *ext, bool with_dir) const
|
|||
|
||||
/**
|
||||
* Fill the crash log buffer with all data of a crash log.
|
||||
* @param output_iterator Iterator to write the output to.
|
||||
*/
|
||||
void CrashLog::FillCrashLog(std::back_insert_iterator<std::string> &output_iterator) const
|
||||
void CrashLog::FillCrashLog()
|
||||
{
|
||||
fmt::format_to(output_iterator, "*** OpenTTD Crash Report ***\n\n");
|
||||
fmt::format_to(output_iterator, "Crash at: {:%Y-%m-%d %H:%M:%S} (UTC)\n", fmt::gmtime(time(nullptr)));
|
||||
/* Reminder: this JSON is read in an automated fashion.
|
||||
* If any structural changes are applied, please bump the version. */
|
||||
this->survey["schema"] = CRASHLOG_SURVEY_VERSION;
|
||||
this->survey["date"] = fmt::format("{:%Y-%m-%d %H:%M:%S} (UTC)", fmt::gmtime(time(nullptr)));
|
||||
|
||||
TimerGameCalendar::YearMonthDay ymd;
|
||||
TimerGameCalendar::ConvertDateToYMD(TimerGameCalendar::date, &ymd);
|
||||
fmt::format_to(output_iterator, "In game date: {}-{:02}-{:02} ({})\n\n", ymd.year, ymd.month + 1, ymd.day, TimerGameCalendar::date_fract);
|
||||
/* If no internal reason was logged, it must be a crash. */
|
||||
if (CrashLog::message.empty()) {
|
||||
this->SurveyCrash(this->survey["crash"]);
|
||||
} else {
|
||||
this->survey["crash"]["reason"] = CrashLog::message;
|
||||
CrashLog::message.clear();
|
||||
}
|
||||
|
||||
this->LogError(output_iterator, CrashLog::message);
|
||||
this->LogOpenTTDVersion(output_iterator);
|
||||
this->LogStacktrace(output_iterator);
|
||||
this->LogOSVersion(output_iterator);
|
||||
this->LogCompiler(output_iterator);
|
||||
this->LogConfiguration(output_iterator);
|
||||
this->LogLibraries(output_iterator);
|
||||
this->LogGamelog(output_iterator);
|
||||
this->LogRecentNews(output_iterator);
|
||||
if (!this->TryExecute("stacktrace", [this]() { this->SurveyStacktrace(this->survey["stacktrace"]); return true; })) {
|
||||
this->survey["stacktrace"] = "crashed while gathering information";
|
||||
}
|
||||
|
||||
fmt::format_to(output_iterator, "*** End of OpenTTD Crash Report ***\n");
|
||||
{
|
||||
auto &info = this->survey["info"];
|
||||
if (!this->TryExecute("os", [&info]() { SurveyOS(info["os"]); return true; })) {
|
||||
info["os"] = "crashed while gathering information";
|
||||
}
|
||||
if (!this->TryExecute("openttd", [&info]() { SurveyOpenTTD(info["openttd"]); return true; })) {
|
||||
info["openttd"] = "crashed while gathering information";
|
||||
}
|
||||
if (!this->TryExecute("configuration", [&info]() { SurveyConfiguration(info["configuration"]); return true; })) {
|
||||
info["configuration"] = "crashed while gathering information";
|
||||
}
|
||||
if (!this->TryExecute("font", [&info]() { SurveyFont(info["font"]); return true; })) {
|
||||
info["font"] = "crashed while gathering information";
|
||||
}
|
||||
if (!this->TryExecute("compiler", [&info]() { SurveyCompiler(info["compiler"]); return true; })) {
|
||||
info["compiler"] = "crashed while gathering information";
|
||||
}
|
||||
if (!this->TryExecute("libraries", [&info]() { SurveyLibraries(info["libraries"]); return true; })) {
|
||||
info["libraries"] = "crashed while gathering information";
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
auto &game = this->survey["game"];
|
||||
game["local_company"] = _local_company;
|
||||
game["current_company"] = _current_company;
|
||||
|
||||
if (!this->TryExecute("timers", [&game]() { SurveyTimers(game["timers"]); return true; })) {
|
||||
game["libraries"] = "crashed while gathering information";
|
||||
}
|
||||
if (!this->TryExecute("companies", [&game]() { SurveyCompanies(game["companies"]); return true; })) {
|
||||
game["companies"] = "crashed while gathering information";
|
||||
}
|
||||
if (!this->TryExecute("settings", [&game]() { SurveySettings(game["settings_changed"], true); return true; })) {
|
||||
game["settings"] = "crashed while gathering information";
|
||||
}
|
||||
if (!this->TryExecute("grfs", [&game]() { SurveyGrfs(game["grfs"]); return true; })) {
|
||||
game["grfs"] = "crashed while gathering information";
|
||||
}
|
||||
if (!this->TryExecute("game_script", [&game]() { SurveyGameScript(game["game_script"]); return true; })) {
|
||||
game["game_script"] = "crashed while gathering information";
|
||||
}
|
||||
if (!this->TryExecute("gamelog", [&game]() { SurveyGamelog(game["gamelog"]); return true; })) {
|
||||
game["gamelog"] = "crashed while gathering information";
|
||||
}
|
||||
if (!this->TryExecute("news", [&game]() { SurveyRecentNews(game["news"]); return true; })) {
|
||||
game["news"] = "crashed while gathering information";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CrashLog::PrintCrashLog() const
|
||||
{
|
||||
fmt::print(" OpenTTD version:\n");
|
||||
fmt::print(" Version: {}\n", this->survey["info"]["openttd"]["version"]["revision"].get<std::string>());
|
||||
fmt::print(" Hash: {}\n", this->survey["info"]["openttd"]["version"]["hash"].get<std::string>());
|
||||
fmt::print(" NewGRF ver: {}\n", this->survey["info"]["openttd"]["version"]["newgrf"].get<std::string>());
|
||||
fmt::print(" Content ver: {}\n", this->survey["info"]["openttd"]["version"]["content"].get<std::string>());
|
||||
fmt::print("\n");
|
||||
|
||||
fmt::print(" Crash:\n");
|
||||
fmt::print(" Reason: {}\n", this->survey["crash"]["reason"].get<std::string>());
|
||||
fmt::print("\n");
|
||||
|
||||
fmt::print(" Stacktrace:\n");
|
||||
for (const auto &line : this->survey["stacktrace"]) {
|
||||
fmt::print(" {}\n", line.get<std::string>());
|
||||
}
|
||||
fmt::print("\n");
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -351,13 +181,15 @@ void CrashLog::FillCrashLog(std::back_insert_iterator<std::string> &output_itera
|
|||
*/
|
||||
bool CrashLog::WriteCrashLog()
|
||||
{
|
||||
this->crashlog_filename = this->CreateFileName(".log");
|
||||
this->crashlog_filename = this->CreateFileName(".json.log");
|
||||
|
||||
FILE *file = FioFOpenFile(this->crashlog_filename, "w", NO_DIRECTORY);
|
||||
if (file == nullptr) return false;
|
||||
|
||||
size_t len = this->crashlog.size();
|
||||
size_t written = fwrite(this->crashlog.data(), 1, len, file);
|
||||
std::string survey_json = this->survey.dump(4);
|
||||
|
||||
size_t len = survey_json.size();
|
||||
size_t written = fwrite(survey_json.data(), 1, len, file);
|
||||
|
||||
FioFCloseFile(file);
|
||||
return len == written;
|
||||
|
@ -414,6 +246,9 @@ bool CrashLog::WriteScreenshot()
|
|||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send the survey result, noting it was a crash.
|
||||
*/
|
||||
void CrashLog::SendSurvey() const
|
||||
{
|
||||
if (_game_mode == GM_NORMAL) {
|
||||
|
@ -433,14 +268,13 @@ void CrashLog::MakeCrashLog()
|
|||
if (crashlogged) return;
|
||||
crashlogged = true;
|
||||
|
||||
crashlog.reserve(65536);
|
||||
auto output_iterator = std::back_inserter(crashlog);
|
||||
|
||||
fmt::print("Crash encountered, generating crash log...\n");
|
||||
this->FillCrashLog(output_iterator);
|
||||
fmt::print("{}\n", crashlog);
|
||||
this->FillCrashLog();
|
||||
fmt::print("Crash log generated.\n\n");
|
||||
|
||||
fmt::print("Crash in summary:\n");
|
||||
this->TryExecute("crashlog", [this]() { this->PrintCrashLog(); return true; });
|
||||
|
||||
fmt::print("Writing crash log to disk...\n");
|
||||
bool ret = this->TryExecute("crashlog", [this]() { return this->WriteCrashLog(); });
|
||||
if (ret) {
|
||||
|
|
|
@ -10,6 +10,8 @@
|
|||
#ifndef CRASHLOG_H
|
||||
#define CRASHLOG_H
|
||||
|
||||
#include "3rdparty/nlohmann/json.hpp"
|
||||
|
||||
/**
|
||||
* Helper class for creating crash logs.
|
||||
*/
|
||||
|
@ -17,40 +19,20 @@ class CrashLog {
|
|||
private:
|
||||
/** Error message coming from #FatalError(format, ...). */
|
||||
static std::string message;
|
||||
protected:
|
||||
/**
|
||||
* Writes OS' version to the buffer.
|
||||
* @param output_iterator Iterator to write the output to.
|
||||
*/
|
||||
virtual void LogOSVersion(std::back_insert_iterator<std::string> &output_iterator) const = 0;
|
||||
|
||||
/**
|
||||
* Writes compiler (and its version, if available) to the buffer.
|
||||
* @param output_iterator Iterator to write the output to.
|
||||
* Convert system crash reason to JSON.
|
||||
*
|
||||
* @param survey The JSON object.
|
||||
*/
|
||||
virtual void LogCompiler(std::back_insert_iterator<std::string> &output_iterator) const;
|
||||
virtual void SurveyCrash(nlohmann::json &survey) const = 0;
|
||||
|
||||
/**
|
||||
* Writes actually encountered error to the buffer.
|
||||
* @param output_iterator Iterator to write the output to.
|
||||
* @param message Message passed to use for errors.
|
||||
* Convert stacktrace to JSON.
|
||||
*
|
||||
* @param survey The JSON object.
|
||||
*/
|
||||
virtual void LogError(std::back_insert_iterator<std::string> &output_iterator, const std::string_view message) const = 0;
|
||||
|
||||
/**
|
||||
* Writes the stack trace to the buffer, if there is information about it
|
||||
* available.
|
||||
* @param output_iterator Iterator to write the output to.
|
||||
*/
|
||||
virtual void LogStacktrace(std::back_insert_iterator<std::string> &output_iterator) const = 0;
|
||||
|
||||
void LogOpenTTDVersion(std::back_insert_iterator<std::string> &output_iterator) const;
|
||||
void LogConfiguration(std::back_insert_iterator<std::string> &output_iterator) const;
|
||||
void LogLibraries(std::back_insert_iterator<std::string> &output_iterator) const;
|
||||
void LogGamelog(std::back_insert_iterator<std::string> &output_iterator) const;
|
||||
void LogRecentNews(std::back_insert_iterator<std::string> &output_iterator) const;
|
||||
|
||||
std::string CreateFileName(const char *ext, bool with_dir = true) const;
|
||||
virtual void SurveyStacktrace(nlohmann::json &survey) const = 0;
|
||||
|
||||
/**
|
||||
* Execute the func() and return its value. If any exception / signal / crash happens,
|
||||
|
@ -63,19 +45,23 @@ protected:
|
|||
*/
|
||||
virtual bool TryExecute(std::string_view section_name, std::function<bool()> &&func) = 0;
|
||||
|
||||
protected:
|
||||
std::string CreateFileName(const char *ext, bool with_dir = true) const;
|
||||
|
||||
public:
|
||||
/** Stub destructor to silence some compilers. */
|
||||
virtual ~CrashLog() = default;
|
||||
|
||||
std::string crashlog;
|
||||
nlohmann::json survey;
|
||||
std::string crashlog_filename;
|
||||
std::string crashdump_filename;
|
||||
std::string savegame_filename;
|
||||
std::string screenshot_filename;
|
||||
|
||||
void FillCrashLog(std::back_insert_iterator<std::string> &output_iterator) const;
|
||||
bool WriteCrashLog();
|
||||
void FillCrashLog();
|
||||
void PrintCrashLog() const;
|
||||
|
||||
bool WriteCrashLog();
|
||||
virtual bool WriteCrashDump();
|
||||
bool WriteSavegame();
|
||||
bool WriteScreenshot();
|
||||
|
|
|
@ -524,6 +524,7 @@ STR_NEWS_MENU_DELETE_ALL_MESSAGES :Apagar todas as
|
|||
# About menu
|
||||
###length 11
|
||||
STR_ABOUT_MENU_LAND_BLOCK_INFO :Informação da área do terreno
|
||||
STR_ABOUT_MENU_HELP :Ajuda & manuais
|
||||
STR_ABOUT_MENU_SEPARATOR :
|
||||
STR_ABOUT_MENU_TOGGLE_CONSOLE :Alternar console
|
||||
STR_ABOUT_MENU_AI_DEBUG :Depurar IA/Script do jogo
|
||||
|
@ -2125,6 +2126,7 @@ STR_INTRO_MULTIPLAYER :{BLACK}Multi-jo
|
|||
|
||||
STR_INTRO_GAME_OPTIONS :{BLACK}Opções do Jogo
|
||||
STR_INTRO_HIGHSCORE :{BLACK}Pontuações
|
||||
STR_INTRO_HELP :{BLACK}Ajuda & Manuais
|
||||
STR_INTRO_CONFIG_SETTINGS_TREE :{BLACK}Configurações
|
||||
STR_INTRO_NEWGRF_SETTINGS :{BLACK}Configurar NewGRF
|
||||
STR_INTRO_ONLINE_CONTENT :{BLACK}Checar conteúdo on-line
|
||||
|
@ -2146,6 +2148,7 @@ STR_INTRO_TOOLTIP_TOYLAND_LANDSCAPE :{BLACK}Selecion
|
|||
|
||||
STR_INTRO_TOOLTIP_GAME_OPTIONS :{BLACK}Exibir opções de jogo
|
||||
STR_INTRO_TOOLTIP_HIGHSCORE :{BLACK}Exibe as pontuações
|
||||
STR_INTRO_TOOLTIP_HELP :{BLACK}Obter acesso à documentação e recursos online
|
||||
STR_INTRO_TOOLTIP_CONFIG_SETTINGS_TREE :{BLACK}Config. de exibição
|
||||
STR_INTRO_TOOLTIP_NEWGRF_SETTINGS :{BLACK}Exibir configs. dos NewGRF
|
||||
STR_INTRO_TOOLTIP_ONLINE_CONTENT :{BLACK}Checar por conteúdo novo e atualizado para baixar
|
||||
|
@ -2168,6 +2171,17 @@ STR_ABANDON_GAME_QUERY :{YELLOW}Você t
|
|||
STR_ABANDON_SCENARIO_QUERY :{YELLOW}Você tem certeza que quer abandonar este cenário?
|
||||
|
||||
# Help window
|
||||
STR_HELP_WINDOW_CAPTION :{WHITE}Ajuda & Manuais
|
||||
STR_HELP_WINDOW_WEBSITES :{BLACK}Sites na Web
|
||||
STR_HELP_WINDOW_DOCUMENTS :{BLACK}Documentos
|
||||
STR_HELP_WINDOW_README :{BLACK}Leia-me
|
||||
STR_HELP_WINDOW_CHANGELOG :{BLACK}Log de mudanças
|
||||
STR_HELP_WINDOW_KNOWN_BUGS :{BLACK}Erros conhecidos
|
||||
STR_HELP_WINDOW_LICENSE :{BLACK}Licença
|
||||
STR_HELP_WINDOW_MAIN_WEBSITE :{BLACK}OpenTTD
|
||||
STR_HELP_WINDOW_MANUAL_WIKI :{BLACK}Manual / Wiki
|
||||
STR_HELP_WINDOW_BUGTRACKER :{BLACK}Relatar um erro
|
||||
STR_HELP_WINDOW_COMMUNITY :{BLACK}Comunidade
|
||||
|
||||
# Cheat window
|
||||
STR_CHEATS :{WHITE}Trapaças
|
||||
|
@ -4702,6 +4716,11 @@ STR_AI_SETTINGS_SETTING :{STRING}: {ORAN
|
|||
|
||||
|
||||
# Textfile window
|
||||
STR_TEXTFILE_JUMPLIST :{WHITE}Tabela de Conteúdo
|
||||
STR_TEXTFILE_JUMPLIST_TOOLTIP :{BLACK}Acesso rápido a uma seção do arquivo mostrado nesta lista
|
||||
STR_TEXTFILE_JUMPLIST_ITEM :{WHITE}{STRING}
|
||||
STR_TEXTFILE_NAVBACK_TOOLTIP :{BLACK}Retornar no histórico de navegação
|
||||
STR_TEXTFILE_NAVFORWARD_TOOLTIP :{BLACK}Retornar adiante no histórico de navegação
|
||||
STR_TEXTFILE_WRAP_TEXT :{WHITE}Quebra de linha
|
||||
STR_TEXTFILE_WRAP_TEXT_TOOLTIP :[BLACK}Quebra linhas automaticamente para que o texto caiba na janela
|
||||
STR_TEXTFILE_VIEW_README :{BLACK}Ver o leia-me
|
||||
|
@ -4712,6 +4731,7 @@ STR_TEXTFILE_README_CAPTION :{WHITE}{STRING}
|
|||
STR_TEXTFILE_CHANGELOG_CAPTION :{WHITE}{STRING} log de mudanças de {STRING}
|
||||
STR_TEXTFILE_LICENCE_CAPTION :{WHITE}{STRING} licença de {STRING}
|
||||
STR_TEXTFILE_SURVEY_RESULT_CAPTION :{WHITE}Visualização do resultado da pesquisa
|
||||
STR_TEXTFILE_GAME_MANUAL_CAPTION :{WHITE}OpenTTD documento '{STRING}'
|
||||
|
||||
|
||||
# Vehicle loading indicators
|
||||
|
|
|
@ -523,6 +523,7 @@ STR_NEWS_MENU_DELETE_ALL_MESSAGES :Delete all mess
|
|||
# About menu
|
||||
###length 11
|
||||
STR_ABOUT_MENU_LAND_BLOCK_INFO :Land area information
|
||||
STR_ABOUT_MENU_HELP :Help & manuals
|
||||
STR_ABOUT_MENU_SEPARATOR :
|
||||
STR_ABOUT_MENU_TOGGLE_CONSOLE :Toggle console
|
||||
STR_ABOUT_MENU_AI_DEBUG :AI/Game script debug
|
||||
|
@ -2124,6 +2125,7 @@ STR_INTRO_MULTIPLAYER :{BLACK}Multipla
|
|||
|
||||
STR_INTRO_GAME_OPTIONS :{BLACK}Game Options
|
||||
STR_INTRO_HIGHSCORE :{BLACK}Highscore Table
|
||||
STR_INTRO_HELP :{BLACK}Help & Manuals
|
||||
STR_INTRO_CONFIG_SETTINGS_TREE :{BLACK}Settings
|
||||
STR_INTRO_NEWGRF_SETTINGS :{BLACK}NewGRF Settings
|
||||
STR_INTRO_ONLINE_CONTENT :{BLACK}Check Online Content
|
||||
|
@ -2145,6 +2147,7 @@ STR_INTRO_TOOLTIP_TOYLAND_LANDSCAPE :{BLACK}Select '
|
|||
|
||||
STR_INTRO_TOOLTIP_GAME_OPTIONS :{BLACK}Display game options
|
||||
STR_INTRO_TOOLTIP_HIGHSCORE :{BLACK}Display highscore table
|
||||
STR_INTRO_TOOLTIP_HELP :{BLACK}Get access to documentation and online resources
|
||||
STR_INTRO_TOOLTIP_CONFIG_SETTINGS_TREE :{BLACK}Display settings
|
||||
STR_INTRO_TOOLTIP_NEWGRF_SETTINGS :{BLACK}Display NewGRF settings
|
||||
STR_INTRO_TOOLTIP_ONLINE_CONTENT :{BLACK}Check for new and updated content to download
|
||||
|
@ -2167,6 +2170,17 @@ STR_ABANDON_GAME_QUERY :{YELLOW}Are you
|
|||
STR_ABANDON_SCENARIO_QUERY :{YELLOW}Are you sure you want to abandon this scenario?
|
||||
|
||||
# Help window
|
||||
STR_HELP_WINDOW_CAPTION :{WHITE}Help & Manuals
|
||||
STR_HELP_WINDOW_WEBSITES :{BLACK}Websites
|
||||
STR_HELP_WINDOW_DOCUMENTS :{BLACK}Documents
|
||||
STR_HELP_WINDOW_README :{BLACK}Readme
|
||||
STR_HELP_WINDOW_CHANGELOG :{BLACK}Changelog
|
||||
STR_HELP_WINDOW_KNOWN_BUGS :{BLACK}Known Bugs
|
||||
STR_HELP_WINDOW_LICENSE :{BLACK}License
|
||||
STR_HELP_WINDOW_MAIN_WEBSITE :{BLACK}OpenTTD
|
||||
STR_HELP_WINDOW_MANUAL_WIKI :{BLACK}Manual / Wiki
|
||||
STR_HELP_WINDOW_BUGTRACKER :{BLACK}Report a Bug
|
||||
STR_HELP_WINDOW_COMMUNITY :{BLACK}Community
|
||||
|
||||
# Cheat window
|
||||
STR_CHEATS :{WHITE}Cheats
|
||||
|
@ -4701,6 +4715,11 @@ STR_AI_SETTINGS_SETTING :{STRING}: {ORAN
|
|||
|
||||
|
||||
# Textfile window
|
||||
STR_TEXTFILE_JUMPLIST :{WHITE}Table of Contents
|
||||
STR_TEXTFILE_JUMPLIST_TOOLTIP :{BLACK}Quickly jump to a section in the displayed file via this list
|
||||
STR_TEXTFILE_JUMPLIST_ITEM :{WHITE}{STRING}
|
||||
STR_TEXTFILE_NAVBACK_TOOLTIP :{BLACK}Go back in navigation history
|
||||
STR_TEXTFILE_NAVFORWARD_TOOLTIP :{BLACK}Return forward in navigation history
|
||||
STR_TEXTFILE_WRAP_TEXT :{WHITE}Wrap text
|
||||
STR_TEXTFILE_WRAP_TEXT_TOOLTIP :{BLACK}Wrap the text of the window so it all fits without having to scroll
|
||||
STR_TEXTFILE_VIEW_README :{BLACK}View readme
|
||||
|
@ -4711,6 +4730,7 @@ STR_TEXTFILE_README_CAPTION :{WHITE}{STRING}
|
|||
STR_TEXTFILE_CHANGELOG_CAPTION :{WHITE}{STRING} changelog of {STRING}
|
||||
STR_TEXTFILE_LICENCE_CAPTION :{WHITE}{STRING} license of {STRING}
|
||||
STR_TEXTFILE_SURVEY_RESULT_CAPTION :{WHITE}Preview of survey result
|
||||
STR_TEXTFILE_GAME_MANUAL_CAPTION :{WHITE}OpenTTD document '{STRING}'
|
||||
|
||||
|
||||
# Vehicle loading indicators
|
||||
|
|
|
@ -523,6 +523,7 @@ STR_NEWS_MENU_DELETE_ALL_MESSAGES :Poista kaikki v
|
|||
# About menu
|
||||
###length 11
|
||||
STR_ABOUT_MENU_LAND_BLOCK_INFO :Maa-alueen tiedot
|
||||
STR_ABOUT_MENU_HELP :Ohjeet ja oppaat
|
||||
STR_ABOUT_MENU_SEPARATOR :
|
||||
STR_ABOUT_MENU_TOGGLE_CONSOLE :Konsoli
|
||||
STR_ABOUT_MENU_AI_DEBUG :Tekoälyn/peliskriptin virheenjäljitys
|
||||
|
@ -2124,6 +2125,7 @@ STR_INTRO_MULTIPLAYER :{BLACK}Moninpel
|
|||
|
||||
STR_INTRO_GAME_OPTIONS :{BLACK}Pelin valinnat
|
||||
STR_INTRO_HIGHSCORE :{BLACK}Pistetaulukko
|
||||
STR_INTRO_HELP :{BLACK}Ohjeet ja oppaat
|
||||
STR_INTRO_CONFIG_SETTINGS_TREE :{BLACK}Asetukset
|
||||
STR_INTRO_NEWGRF_SETTINGS :{BLACK}NewGRF-asetukset
|
||||
STR_INTRO_ONLINE_CONTENT :{BLACK}Tarkista online-sisältö
|
||||
|
@ -2145,6 +2147,7 @@ STR_INTRO_TOOLTIP_TOYLAND_LANDSCAPE :{BLACK}Valitse
|
|||
|
||||
STR_INTRO_TOOLTIP_GAME_OPTIONS :{BLACK}Näytä pelin valinnat
|
||||
STR_INTRO_TOOLTIP_HIGHSCORE :{BLACK}Näytä pistetaulukko
|
||||
STR_INTRO_TOOLTIP_HELP :{BLACK}Tutustu dokumentaatioon ja online-resursseihin
|
||||
STR_INTRO_TOOLTIP_CONFIG_SETTINGS_TREE :{BLACK}Näytä asetukset
|
||||
STR_INTRO_TOOLTIP_NEWGRF_SETTINGS :{BLACK}Näytä NewGRF-asetukset
|
||||
STR_INTRO_TOOLTIP_ONLINE_CONTENT :{BLACK}Tarkista uutta ja päivitettyä sisältöä ladattavaksi
|
||||
|
@ -2167,6 +2170,17 @@ STR_ABANDON_GAME_QUERY :{YELLOW}Lopetet
|
|||
STR_ABANDON_SCENARIO_QUERY :{YELLOW}Haluatko varmasti hylätä tämän skenaarion?
|
||||
|
||||
# Help window
|
||||
STR_HELP_WINDOW_CAPTION :{WHITE}Ohjeet ja oppaat
|
||||
STR_HELP_WINDOW_WEBSITES :{BLACK}Verkkosivustot
|
||||
STR_HELP_WINDOW_DOCUMENTS :{BLACK}Asiakirjat
|
||||
STR_HELP_WINDOW_README :{BLACK}Lueminut-tiedosto
|
||||
STR_HELP_WINDOW_CHANGELOG :{BLACK}Muutosloki
|
||||
STR_HELP_WINDOW_KNOWN_BUGS :{BLACK}Tiedossa olevat virheet
|
||||
STR_HELP_WINDOW_LICENSE :{BLACK}Lisenssi
|
||||
STR_HELP_WINDOW_MAIN_WEBSITE :{BLACK}OpenTTD
|
||||
STR_HELP_WINDOW_MANUAL_WIKI :{BLACK}Käyttöopas/wiki
|
||||
STR_HELP_WINDOW_BUGTRACKER :{BLACK}Ilmoita virheestä
|
||||
STR_HELP_WINDOW_COMMUNITY :{BLACK}Yhteisö
|
||||
|
||||
# Cheat window
|
||||
STR_CHEATS :{WHITE}Huijaukset
|
||||
|
@ -4701,6 +4715,11 @@ STR_AI_SETTINGS_SETTING :{STRING}: {ORAN
|
|||
|
||||
|
||||
# Textfile window
|
||||
STR_TEXTFILE_JUMPLIST :{WHITE}Sisällysluettelo
|
||||
STR_TEXTFILE_JUMPLIST_TOOLTIP :{BLACK}Tämän luettelon avulla voit nopeasti siirtyä näytettävän tiedoston johonkin osioon
|
||||
STR_TEXTFILE_JUMPLIST_ITEM :{WHITE}{STRING}
|
||||
STR_TEXTFILE_NAVBACK_TOOLTIP :{BLACK}Siirry taaksepäin selaushistoriassa
|
||||
STR_TEXTFILE_NAVFORWARD_TOOLTIP :{BLACK}Siirry eteenpäin selaushistoriassa
|
||||
STR_TEXTFILE_WRAP_TEXT :{WHITE}Tekstin rivitys
|
||||
STR_TEXTFILE_WRAP_TEXT_TOOLTIP :{BLACK}Rivitä teksti ikkunaan niin, että se näkyy kokonaan rullaamatta
|
||||
STR_TEXTFILE_VIEW_README :{BLACK}Näytä readme-tiedosto
|
||||
|
@ -4711,6 +4730,7 @@ STR_TEXTFILE_README_CAPTION :{WHITE}{STRING}
|
|||
STR_TEXTFILE_CHANGELOG_CAPTION :{WHITE}{STRING}:n {STRING} muutosloki
|
||||
STR_TEXTFILE_LICENCE_CAPTION :{WHITE}{STRING}:n {STRING} lisenssi
|
||||
STR_TEXTFILE_SURVEY_RESULT_CAPTION :{WHITE}Tutkimustuloksen esikatselu
|
||||
STR_TEXTFILE_GAME_MANUAL_CAPTION :{WHITE}OpenTTD-asiakirja ”{STRING}”
|
||||
|
||||
|
||||
# Vehicle loading indicators
|
||||
|
|
|
@ -524,6 +524,7 @@ STR_NEWS_MENU_DELETE_ALL_MESSAGES :Effacer tous le
|
|||
# About menu
|
||||
###length 11
|
||||
STR_ABOUT_MENU_LAND_BLOCK_INFO :Outil d'inspection du paysage
|
||||
STR_ABOUT_MENU_HELP :Aide et manuels
|
||||
STR_ABOUT_MENU_SEPARATOR :
|
||||
STR_ABOUT_MENU_TOGGLE_CONSOLE :Afficher/Cacher la console
|
||||
STR_ABOUT_MENU_AI_DEBUG :Débogage de scripts
|
||||
|
@ -2125,6 +2126,7 @@ STR_INTRO_MULTIPLAYER :{BLACK}Jouer en
|
|||
|
||||
STR_INTRO_GAME_OPTIONS :{BLACK}Options globales
|
||||
STR_INTRO_HIGHSCORE :{BLACK}Meilleurs scores
|
||||
STR_INTRO_HELP :{BLACK}Aide et manuels
|
||||
STR_INTRO_CONFIG_SETTINGS_TREE :{BLACK}Paramètres de jeu
|
||||
STR_INTRO_NEWGRF_SETTINGS :{BLACK}Paramètres NewGRF
|
||||
STR_INTRO_ONLINE_CONTENT :{BLACK}Contenu additionnel en ligne
|
||||
|
@ -2146,6 +2148,7 @@ STR_INTRO_TOOLTIP_TOYLAND_LANDSCAPE :{BLACK}Sélecti
|
|||
|
||||
STR_INTRO_TOOLTIP_GAME_OPTIONS :{BLACK}Afficher les options du jeu
|
||||
STR_INTRO_TOOLTIP_HIGHSCORE :{BLACK}Afficher le tableau des meilleurs scores
|
||||
STR_INTRO_TOOLTIP_HELP :{BLACK}Accéder à la documentation et aux ressources en ligne
|
||||
STR_INTRO_TOOLTIP_CONFIG_SETTINGS_TREE :{BLACK}Afficher les paramètres
|
||||
STR_INTRO_TOOLTIP_NEWGRF_SETTINGS :{BLACK}Afficher la configuration des NewGRF
|
||||
STR_INTRO_TOOLTIP_ONLINE_CONTENT :{BLACK}Vérifier les contenus nouveaux ou mis à jour téléchargeables
|
||||
|
@ -2168,6 +2171,17 @@ STR_ABANDON_GAME_QUERY :{YELLOW}Êtes-v
|
|||
STR_ABANDON_SCENARIO_QUERY :{YELLOW}Êtes-vous sûr de vouloir abandonner ce scénario{NBSP}?
|
||||
|
||||
# Help window
|
||||
STR_HELP_WINDOW_CAPTION :{WHITE}Aide et manuels
|
||||
STR_HELP_WINDOW_WEBSITES :{BLACK}Sites web
|
||||
STR_HELP_WINDOW_DOCUMENTS :{BLACK}Documents
|
||||
STR_HELP_WINDOW_README :{BLACK}Lisez-moi
|
||||
STR_HELP_WINDOW_CHANGELOG :{BLACK}Journal des modifications
|
||||
STR_HELP_WINDOW_KNOWN_BUGS :{BLACK}Bugs connus
|
||||
STR_HELP_WINDOW_LICENSE :{BLACK}Licence
|
||||
STR_HELP_WINDOW_MAIN_WEBSITE :{BLACK}OpenTTD
|
||||
STR_HELP_WINDOW_MANUAL_WIKI :{BLACK}Manuel / Wiki
|
||||
STR_HELP_WINDOW_BUGTRACKER :{BLACK}Rapporter un bug
|
||||
STR_HELP_WINDOW_COMMUNITY :{BLACK}Communauté
|
||||
|
||||
# Cheat window
|
||||
STR_CHEATS :{WHITE}Triches
|
||||
|
@ -4702,6 +4716,11 @@ STR_AI_SETTINGS_SETTING :{STRING}{NBSP}:
|
|||
|
||||
|
||||
# Textfile window
|
||||
STR_TEXTFILE_JUMPLIST :{WHITE}Table des matières
|
||||
STR_TEXTFILE_JUMPLIST_TOOLTIP :{BLACK}Sauter rapidement à une section dans le fichier affiché via cette liste
|
||||
STR_TEXTFILE_JUMPLIST_ITEM :{WHITE}{STRING}
|
||||
STR_TEXTFILE_NAVBACK_TOOLTIP :{BLACK}Reculer dans l'historique de navigation
|
||||
STR_TEXTFILE_NAVFORWARD_TOOLTIP :{BLACK}Avancer dans l'historique de navigation
|
||||
STR_TEXTFILE_WRAP_TEXT :{WHITE}Retour à la ligne automatique
|
||||
STR_TEXTFILE_WRAP_TEXT_TOOLTIP :{BLACK}Insérer des retours à la ligne dans le texte de la fenêtre afin qu'il s'affiche entièrement sans faire défiler
|
||||
STR_TEXTFILE_VIEW_README :{BLACK}Voir le Lisez-moi
|
||||
|
@ -4712,6 +4731,7 @@ STR_TEXTFILE_README_CAPTION :{WHITE}Lisez-mo
|
|||
STR_TEXTFILE_CHANGELOG_CAPTION :{WHITE}Journal des modifications pour le module {STRING} {STRING}
|
||||
STR_TEXTFILE_LICENCE_CAPTION :{WHITE}Licence du module {STRING} {STRING}
|
||||
STR_TEXTFILE_SURVEY_RESULT_CAPTION :{WHITE}Prévisualisation des données d'analyse
|
||||
STR_TEXTFILE_GAME_MANUAL_CAPTION :{WHITE}Document OpenTTD '{STRING}'
|
||||
|
||||
|
||||
# Vehicle loading indicators
|
||||
|
|
|
@ -524,6 +524,7 @@ STR_NEWS_MENU_DELETE_ALL_MESSAGES :모든 뉴스
|
|||
# About menu
|
||||
###length 11
|
||||
STR_ABOUT_MENU_LAND_BLOCK_INFO :지형 정보
|
||||
STR_ABOUT_MENU_HELP :도움말 & 매뉴얼
|
||||
STR_ABOUT_MENU_SEPARATOR :
|
||||
STR_ABOUT_MENU_TOGGLE_CONSOLE :콘솔 켜기/끄기
|
||||
STR_ABOUT_MENU_AI_DEBUG :인공지능/게임 스크립트 디버그
|
||||
|
@ -1427,11 +1428,13 @@ STR_CONFIG_SETTING_PLANE_CRASHES_NONE :없음*
|
|||
STR_CONFIG_SETTING_PLANE_CRASHES_REDUCED :적음
|
||||
STR_CONFIG_SETTING_PLANE_CRASHES_NORMAL :보통
|
||||
|
||||
STR_CONFIG_SETTING_CROSSING_WITH_COMPETITOR :경쟁사 소유의 도로나 선로에 건널목 건설 허용: {STRING}
|
||||
STR_CONFIG_SETTING_CROSSING_WITH_COMPETITOR_HELPTEXT :다른 회사 소유의 도로나 선로에 건널목을 건설하는 것을 허용합니다
|
||||
|
||||
STR_CONFIG_SETTING_STOP_ON_TOWN_ROAD :도시 소유의 도로 위에 버스 정류장 건설 허용: {STRING}
|
||||
STR_CONFIG_SETTING_STOP_ON_TOWN_ROAD_HELPTEXT :도시 소유의 도로 위에 버스 정류장 건설을 허용합니다.
|
||||
STR_CONFIG_SETTING_STOP_ON_TOWN_ROAD_HELPTEXT :도시 소유의 도로 위에 버스 정류장 건설을 허용합니다
|
||||
STR_CONFIG_SETTING_STOP_ON_COMPETITOR_ROAD :경쟁자 소유의 도로 위에 버스 정류장 건설 허용: {STRING}
|
||||
STR_CONFIG_SETTING_STOP_ON_COMPETITOR_ROAD_HELPTEXT :다른 회사 소유의 도로 위에 버스 정류장을 건설하는 것을 허용합니다.
|
||||
STR_CONFIG_SETTING_STOP_ON_COMPETITOR_ROAD_HELPTEXT :다른 회사 소유의 도로 위에 버스 정류장을 건설하는 것을 허용합니다
|
||||
STR_CONFIG_SETTING_DYNAMIC_ENGINES_EXISTING_VEHICLES :{WHITE}이미 차량이 존재하면 이 설정을 변경하실 수 없습니다.
|
||||
|
||||
STR_CONFIG_SETTING_INFRASTRUCTURE_MAINTENANCE :기반시설 유지비: {STRING}
|
||||
|
@ -2123,6 +2126,7 @@ STR_INTRO_MULTIPLAYER :{BLACK}멀티
|
|||
|
||||
STR_INTRO_GAME_OPTIONS :{BLACK}게임 설정
|
||||
STR_INTRO_HIGHSCORE :{BLACK}고득점 순위표
|
||||
STR_INTRO_HELP :{BLACK}도움말 & 매뉴얼
|
||||
STR_INTRO_CONFIG_SETTINGS_TREE :{BLACK}설정
|
||||
STR_INTRO_NEWGRF_SETTINGS :{BLACK}NewGRF 설정
|
||||
STR_INTRO_ONLINE_CONTENT :{BLACK}온라인 콘텐츠 다운로드
|
||||
|
@ -2144,6 +2148,7 @@ STR_INTRO_TOOLTIP_TOYLAND_LANDSCAPE :{BLACK}장난
|
|||
|
||||
STR_INTRO_TOOLTIP_GAME_OPTIONS :{BLACK}게임 기본 설정 창을 보여줍니다
|
||||
STR_INTRO_TOOLTIP_HIGHSCORE :{BLACK}고득점 순위표를 보여줍니다
|
||||
STR_INTRO_TOOLTIP_HELP :{BLACK}각종 문서와 온라인 링크를 확인합니다
|
||||
STR_INTRO_TOOLTIP_CONFIG_SETTINGS_TREE :{BLACK}설정 창을 엽니다
|
||||
STR_INTRO_TOOLTIP_NEWGRF_SETTINGS :{BLACK}NewGRF 설정 창을 엽니다
|
||||
STR_INTRO_TOOLTIP_ONLINE_CONTENT :{BLACK}새로 나왔거나 업데이트된 콘텐츠를 체크하여 다운로드합니다
|
||||
|
@ -2166,6 +2171,17 @@ STR_ABANDON_GAME_QUERY :{YELLOW}정말
|
|||
STR_ABANDON_SCENARIO_QUERY :{YELLOW}정말 이 시나리오를 종료하시겠습니까?
|
||||
|
||||
# Help window
|
||||
STR_HELP_WINDOW_CAPTION :{WHITE}도움말 & 매뉴얼
|
||||
STR_HELP_WINDOW_WEBSITES :{BLACK}웹사이트
|
||||
STR_HELP_WINDOW_DOCUMENTS :{BLACK}문서
|
||||
STR_HELP_WINDOW_README :{BLACK}Readme
|
||||
STR_HELP_WINDOW_CHANGELOG :{BLACK}변경기록
|
||||
STR_HELP_WINDOW_KNOWN_BUGS :{BLACK}알려진 버그
|
||||
STR_HELP_WINDOW_LICENSE :{BLACK}라이선스
|
||||
STR_HELP_WINDOW_MAIN_WEBSITE :{BLACK}OpenTTD
|
||||
STR_HELP_WINDOW_MANUAL_WIKI :{BLACK}매뉴얼 / 위키
|
||||
STR_HELP_WINDOW_BUGTRACKER :{BLACK}버그 신고
|
||||
STR_HELP_WINDOW_COMMUNITY :{BLACK}커뮤니티
|
||||
|
||||
# Cheat window
|
||||
STR_CHEATS :{WHITE}치트
|
||||
|
@ -2654,6 +2670,7 @@ STR_TRANSPARENT_BUILDINGS_TOOLTIP :{BLACK}정거
|
|||
STR_TRANSPARENT_BRIDGES_TOOLTIP :{BLACK}다리를 보여줄 지 선택합니다. 고정하려면 CTRL+클릭하세요
|
||||
STR_TRANSPARENT_STRUCTURES_TOOLTIP :{BLACK}등대나 안테나 같은 구조물을 보여줄 지 선택합니다. 고정하려면 CTRL+클릭하세요
|
||||
STR_TRANSPARENT_CATENARY_TOOLTIP :{BLACK}전차선을 보여줄 지 선택합니다. 고정하려면 CTRL+클릭하세요
|
||||
STR_TRANSPARENT_TEXT_TOOLTIP :{BLACK}적재/하차 및 수입/지출 텍스트를 보여줄 지 선택합니다. 고정하려면 CTRL+클릭하세요
|
||||
STR_TRANSPARENT_INVISIBLE_TOOLTIP :{BLACK}반투명 대신 아예 안 보이게 할 항목을 선택하세요
|
||||
|
||||
# Linkgraph legend window
|
||||
|
@ -4699,6 +4716,11 @@ STR_AI_SETTINGS_SETTING :{STRING}: {ORAN
|
|||
|
||||
|
||||
# Textfile window
|
||||
STR_TEXTFILE_JUMPLIST :{WHITE}목차
|
||||
STR_TEXTFILE_JUMPLIST_TOOLTIP :{BLACK}이 목록을 이용하여 표시된 파일의 특정 단락으로 빠르게 이동합니다
|
||||
STR_TEXTFILE_JUMPLIST_ITEM :{WHITE}{STRING}
|
||||
STR_TEXTFILE_NAVBACK_TOOLTIP :{BLACK}탐색 기록 뒤로 가기
|
||||
STR_TEXTFILE_NAVFORWARD_TOOLTIP :{BLACK}탐색 기록 앞으로 가기
|
||||
STR_TEXTFILE_WRAP_TEXT :{WHITE}자동 줄 바꿈
|
||||
STR_TEXTFILE_WRAP_TEXT_TOOLTIP :{BLACK}본문 내용에 자동 줄 바꿈을 설정하여 스크롤하지 않고도 본문의 모든 내용을 볼 수 있게 합니다.
|
||||
STR_TEXTFILE_VIEW_README :{BLACK}Readme 보기
|
||||
|
@ -4709,6 +4731,7 @@ STR_TEXTFILE_README_CAPTION :{WHITE}{STRING}
|
|||
STR_TEXTFILE_CHANGELOG_CAPTION :{WHITE}{STRING} {STRING}의 변경기록
|
||||
STR_TEXTFILE_LICENCE_CAPTION :{WHITE}{STRING} {STRING}의 저작권
|
||||
STR_TEXTFILE_SURVEY_RESULT_CAPTION :{WHITE}설문조사 결과 미리보기
|
||||
STR_TEXTFILE_GAME_MANUAL_CAPTION :{WHITE}OpenTTD '{STRING}' 문서
|
||||
|
||||
|
||||
# Vehicle loading indicators
|
||||
|
|
|
@ -649,6 +649,7 @@ STR_NEWS_MENU_DELETE_ALL_MESSAGES :Удалить
|
|||
# About menu
|
||||
###length 11
|
||||
STR_ABOUT_MENU_LAND_BLOCK_INFO :Информация об участке земли
|
||||
STR_ABOUT_MENU_HELP :Помощь и документация
|
||||
STR_ABOUT_MENU_SEPARATOR :
|
||||
STR_ABOUT_MENU_TOGGLE_CONSOLE :Консоль
|
||||
STR_ABOUT_MENU_AI_DEBUG :Отладка ИИ / скриптов
|
||||
|
@ -2275,6 +2276,7 @@ STR_INTRO_MULTIPLAYER :{BLACK}Сете
|
|||
|
||||
STR_INTRO_GAME_OPTIONS :{BLACK}Основные настройки
|
||||
STR_INTRO_HIGHSCORE :{BLACK}Таблица рекордов
|
||||
STR_INTRO_HELP :{BLACK}Помощь и документация
|
||||
STR_INTRO_CONFIG_SETTINGS_TREE :{BLACK}Расширенные настройки
|
||||
STR_INTRO_NEWGRF_SETTINGS :{BLACK}Настройки NewGRF
|
||||
STR_INTRO_ONLINE_CONTENT :{BLACK}Проверить онлайн-контент
|
||||
|
@ -2296,6 +2298,7 @@ STR_INTRO_TOOLTIP_TOYLAND_LANDSCAPE :{BLACK}Выбр
|
|||
|
||||
STR_INTRO_TOOLTIP_GAME_OPTIONS :{BLACK}Изменить основные настройки игры
|
||||
STR_INTRO_TOOLTIP_HIGHSCORE :{BLACK}Показать таблицу рекордов
|
||||
STR_INTRO_TOOLTIP_HELP :{BLACK}Ссылки на документацию и интернет-ресурсы
|
||||
STR_INTRO_TOOLTIP_CONFIG_SETTINGS_TREE :{BLACK}Изменить расширенные настройки игры
|
||||
STR_INTRO_TOOLTIP_NEWGRF_SETTINGS :{BLACK}Показать настройки NewGRF
|
||||
STR_INTRO_TOOLTIP_ONLINE_CONTENT :{BLACK}Найти новый и обновлённый контент для загрузки
|
||||
|
@ -2318,6 +2321,17 @@ STR_ABANDON_GAME_QUERY :{YELLOW}Вы д
|
|||
STR_ABANDON_SCENARIO_QUERY :{YELLOW}Вы уверены, что хотите выйти из этого сценария?
|
||||
|
||||
# Help window
|
||||
STR_HELP_WINDOW_CAPTION :{WHITE}Помощь и документация
|
||||
STR_HELP_WINDOW_WEBSITES :{BLACK}Веб-сайты
|
||||
STR_HELP_WINDOW_DOCUMENTS :{BLACK}Документы
|
||||
STR_HELP_WINDOW_README :{BLACK}Readme
|
||||
STR_HELP_WINDOW_CHANGELOG :{BLACK}История изменений
|
||||
STR_HELP_WINDOW_KNOWN_BUGS :{BLACK}Известные ошибки
|
||||
STR_HELP_WINDOW_LICENSE :{BLACK}Лицензия
|
||||
STR_HELP_WINDOW_MAIN_WEBSITE :{BLACK}OpenTTD
|
||||
STR_HELP_WINDOW_MANUAL_WIKI :{BLACK}Инструкция / Wiki
|
||||
STR_HELP_WINDOW_BUGTRACKER :{BLACK}Сообщить об ошибке
|
||||
STR_HELP_WINDOW_COMMUNITY :{BLACK}Сообщество
|
||||
|
||||
# Cheat window
|
||||
STR_CHEATS :{WHITE}Читы
|
||||
|
@ -4888,6 +4902,11 @@ STR_AI_SETTINGS_SETTING :{STRING}: {ORAN
|
|||
|
||||
|
||||
# Textfile window
|
||||
STR_TEXTFILE_JUMPLIST :{WHITE}Содержание
|
||||
STR_TEXTFILE_JUMPLIST_TOOLTIP :{BLACK}Список для быстрого перехода к определённой секции отображаемого файла
|
||||
STR_TEXTFILE_JUMPLIST_ITEM :{WHITE}{STRING}
|
||||
STR_TEXTFILE_NAVBACK_TOOLTIP :{BLACK}Назад
|
||||
STR_TEXTFILE_NAVFORWARD_TOOLTIP :{BLACK}Вперёд
|
||||
STR_TEXTFILE_WRAP_TEXT :{WHITE}Переносить текст
|
||||
STR_TEXTFILE_WRAP_TEXT_TOOLTIP :{BLACK}Переносить текст так, чтобы он помещался в окне без необходимости прокрутки
|
||||
STR_TEXTFILE_VIEW_README :{BLACK}Посмотреть инструкцию
|
||||
|
@ -4898,6 +4917,7 @@ STR_TEXTFILE_README_CAPTION :{WHITE}Инст
|
|||
STR_TEXTFILE_CHANGELOG_CAPTION :{WHITE}Список изменений к {STRING} {STRING}
|
||||
STR_TEXTFILE_LICENCE_CAPTION :{WHITE}Лицензия к {STRING} {STRING}
|
||||
STR_TEXTFILE_SURVEY_RESULT_CAPTION :{WHITE}Собранные данные
|
||||
STR_TEXTFILE_GAME_MANUAL_CAPTION :{WHITE}Документ OpenTTD «{STRING}»
|
||||
|
||||
|
||||
# Vehicle loading indicators
|
||||
|
|
|
@ -12,26 +12,9 @@
|
|||
#include "settings_table.h"
|
||||
#include "network.h"
|
||||
#include "../debug.h"
|
||||
#include "../rev.h"
|
||||
#include "../settings_type.h"
|
||||
#include "../timer/timer_game_tick.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 "../3rdparty/nlohmann/json.hpp"
|
||||
#include "../survey.h"
|
||||
#include "../3rdparty/fmt/chrono.h"
|
||||
#include "../3rdparty/fmt/std.h"
|
||||
|
||||
#include "../safeguards.h"
|
||||
|
||||
|
@ -46,294 +29,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);
|
||||
|
||||
/**
|
||||
* List of all the generic setting tables.
|
||||
*
|
||||
* There are a few tables that are special and not processed like the rest:
|
||||
* - _currency_settings
|
||||
* - _misc_settings
|
||||
* - _company_settings
|
||||
* - _win32_settings
|
||||
* As such, they are not part of this list.
|
||||
*/
|
||||
static auto &GenericSettingTables()
|
||||
{
|
||||
static const SettingTable _generic_setting_tables[] = {
|
||||
_difficulty_settings,
|
||||
_economy_settings,
|
||||
_game_settings,
|
||||
_gui_settings,
|
||||
_linkgraph_settings,
|
||||
_locale_settings,
|
||||
_multimedia_settings,
|
||||
_network_settings,
|
||||
_news_display_settings,
|
||||
_pathfinding_settings,
|
||||
_script_settings,
|
||||
_world_settings,
|
||||
};
|
||||
return _generic_setting_tables;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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)
|
||||
{
|
||||
for (auto &desc : table) {
|
||||
const SettingDesc *sd = GetSettingDesc(desc);
|
||||
/* Skip any old settings we no longer save/load. */
|
||||
if (!SlIsObjectCurrentlyValid(sd->save.version_from, sd->save.version_to)) continue;
|
||||
|
||||
auto name = sd->GetName();
|
||||
survey[name] = sd->FormatValue(object);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert settings to JSON.
|
||||
*
|
||||
* @param survey The JSON object.
|
||||
*/
|
||||
static void SurveySettings(nlohmann::json &survey)
|
||||
{
|
||||
SurveySettingsTable(survey, _misc_settings, nullptr);
|
||||
#if defined(_WIN32) && !defined(DEDICATED)
|
||||
SurveySettingsTable(survey, _win32_settings, nullptr);
|
||||
#endif
|
||||
for (auto &table : GenericSettingTables()) {
|
||||
SurveySettingsTable(survey, table, &_settings_game);
|
||||
}
|
||||
SurveySettingsTable(survey, _currency_settings, &_custom_currency);
|
||||
SurveySettingsTable(survey, _company_settings, &_settings_client.company);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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"] = _current_language->file.filename().string();
|
||||
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"] = TimerGameTick::counter;
|
||||
survey["seconds"] = std::chrono::duration_cast<std::chrono::seconds>(std::chrono::steady_clock::now() - _switch_mode_time).count();
|
||||
|
||||
TimerGameCalendar::YearMonthDay ymd;
|
||||
TimerGameCalendar::ConvertDateToYMD(TimerGameCalendar::date, &ymd);
|
||||
survey["calendar"] = fmt::format("{:04}-{:02}-{:02} ({})", ymd.year, ymd.month + 1, ymd.day, TimerGameCalendar::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<uint32_t> 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.
|
||||
*
|
||||
|
@ -348,6 +43,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. */
|
||||
|
@ -362,13 +58,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"]);
|
||||
}
|
||||
|
|
|
@ -49,53 +49,24 @@ class CrashLogOSX : public CrashLog {
|
|||
/** Signal that has been thrown. */
|
||||
int signum;
|
||||
|
||||
void LogOSVersion(std::back_insert_iterator<std::string> &output_iterator) const override
|
||||
void SurveyCrash(nlohmann::json &survey) const override
|
||||
{
|
||||
int ver_maj, ver_min, ver_bug;
|
||||
GetMacOSVersion(&ver_maj, &ver_min, &ver_bug);
|
||||
|
||||
const NXArchInfo *arch = NXGetLocalArchInfo();
|
||||
|
||||
fmt::format_to(output_iterator,
|
||||
"Operating system:\n"
|
||||
" Name: Mac OS X\n"
|
||||
" Release: {}.{}.{}\n"
|
||||
" Machine: {}\n"
|
||||
" Min Ver: {}\n"
|
||||
" Max Ver: {}\n",
|
||||
ver_maj, ver_min, ver_bug,
|
||||
arch != nullptr ? arch->description : "unknown",
|
||||
MAC_OS_X_VERSION_MIN_REQUIRED,
|
||||
MAC_OS_X_VERSION_MAX_ALLOWED
|
||||
);
|
||||
survey["id"] = signum;
|
||||
survey["reason"] = strsignal(signum);
|
||||
}
|
||||
|
||||
void LogError(std::back_insert_iterator<std::string> &output_iterator, const std::string_view message) const override
|
||||
void SurveyStacktrace(nlohmann::json &survey) const override
|
||||
{
|
||||
fmt::format_to(output_iterator,
|
||||
"Crash reason:\n"
|
||||
" Signal: {} ({})\n"
|
||||
" Message: {}\n\n",
|
||||
strsignal(this->signum),
|
||||
this->signum,
|
||||
message
|
||||
);
|
||||
}
|
||||
|
||||
void LogStacktrace(std::back_insert_iterator<std::string> &output_iterator) const override
|
||||
{
|
||||
fmt::format_to(output_iterator, "\nStacktrace:\n");
|
||||
|
||||
void *trace[64];
|
||||
int trace_size = backtrace(trace, lengthof(trace));
|
||||
|
||||
survey = nlohmann::json::array();
|
||||
|
||||
char **messages = backtrace_symbols(trace, trace_size);
|
||||
for (int i = 0; i < trace_size; i++) {
|
||||
fmt::format_to(output_iterator, "{}\n", messages[i]);
|
||||
survey.push_back(messages[i]);
|
||||
}
|
||||
free(messages);
|
||||
|
||||
fmt::format_to(output_iterator, "\n");
|
||||
}
|
||||
|
||||
#ifdef WITH_UNOFFICIAL_BREAKPAD
|
||||
|
@ -153,7 +124,7 @@ public:
|
|||
"A serious fault condition occurred in the game. The game will shut down.";
|
||||
|
||||
std::string message = fmt::format(
|
||||
"Please send crash.log, crash.dmp, and crash.sav to the developers. "
|
||||
"Please send crash.json.log, crash.dmp, and crash.sav to the developers. "
|
||||
"This will greatly help debugging.\n\n"
|
||||
"https://github.com/OpenTTD/OpenTTD/issues.\n\n"
|
||||
"{}\n{}\n{}\n{}",
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
#include "../../stdafx.h"
|
||||
|
||||
#include "../../3rdparty/fmt/format.h"
|
||||
#include "../../3rdparty/nlohmann/json.hpp"
|
||||
#include "../../survey.h"
|
||||
#include "macos.h"
|
||||
|
||||
#include <mach-o/arch.h>
|
||||
|
@ -18,8 +18,6 @@
|
|||
|
||||
#include "../../safeguards.h"
|
||||
|
||||
extern std::string SurveyMemoryToText(uint64_t memory);
|
||||
|
||||
void SurveyOS(nlohmann::json &json)
|
||||
{
|
||||
int ver_maj, ver_min, ver_bug;
|
||||
|
|
|
@ -49,55 +49,26 @@ class CrashLogUnix : public CrashLog {
|
|||
/** Signal that has been thrown. */
|
||||
int signum;
|
||||
|
||||
void LogOSVersion(std::back_insert_iterator<std::string> &output_iterator) const override
|
||||
void SurveyCrash(nlohmann::json &survey) const override
|
||||
{
|
||||
struct utsname name;
|
||||
if (uname(&name) < 0) {
|
||||
fmt::format_to(output_iterator, "Could not get OS version: {}\n", strerror(errno));
|
||||
return;
|
||||
}
|
||||
|
||||
fmt::format_to(output_iterator,
|
||||
"Operating system:\n"
|
||||
" Name: {}\n"
|
||||
" Release: {}\n"
|
||||
" Version: {}\n"
|
||||
" Machine: {}\n",
|
||||
name.sysname,
|
||||
name.release,
|
||||
name.version,
|
||||
name.machine
|
||||
);
|
||||
survey["id"] = signum;
|
||||
survey["reason"] = strsignal(signum);
|
||||
}
|
||||
|
||||
void LogError(std::back_insert_iterator<std::string> &output_iterator, const std::string_view message) const override
|
||||
void SurveyStacktrace(nlohmann::json &survey) const override
|
||||
{
|
||||
fmt::format_to(output_iterator,
|
||||
"Crash reason:\n"
|
||||
" Signal: {} ({})\n"
|
||||
" Message: {}\n\n",
|
||||
strsignal(this->signum),
|
||||
this->signum,
|
||||
message
|
||||
);
|
||||
}
|
||||
|
||||
void LogStacktrace(std::back_insert_iterator<std::string> &output_iterator) const override
|
||||
{
|
||||
fmt::format_to(output_iterator, "Stacktrace:\n");
|
||||
#if defined(__GLIBC__)
|
||||
void *trace[64];
|
||||
int trace_size = backtrace(trace, lengthof(trace));
|
||||
|
||||
survey = nlohmann::json::array();
|
||||
|
||||
char **messages = backtrace_symbols(trace, trace_size);
|
||||
for (int i = 0; i < trace_size; i++) {
|
||||
fmt::format_to(output_iterator, " [{:02}] {}\n", i, messages[i]);
|
||||
survey.push_back(messages[i]);
|
||||
}
|
||||
free(messages);
|
||||
#else
|
||||
fmt::format_to(output_iterator, " Not supported.\n");
|
||||
#endif
|
||||
fmt::format_to(output_iterator, "\n");
|
||||
}
|
||||
|
||||
#ifdef WITH_UNOFFICIAL_BREAKPAD
|
||||
|
|
|
@ -8,8 +8,7 @@
|
|||
/** @file survey_unix.cpp Unix implementation of OS-specific survey information. */
|
||||
|
||||
#include "../../stdafx.h"
|
||||
|
||||
#include "../../3rdparty/nlohmann/json.hpp"
|
||||
#include "../../survey.h"
|
||||
|
||||
#include <sys/utsname.h>
|
||||
#include <thread>
|
||||
|
@ -17,8 +16,6 @@
|
|||
|
||||
#include "../../safeguards.h"
|
||||
|
||||
extern std::string SurveyMemoryToText(uint64_t memory);
|
||||
|
||||
void SurveyOS(nlohmann::json &json)
|
||||
{
|
||||
struct utsname name;
|
||||
|
|
|
@ -38,6 +38,33 @@
|
|||
/** Exception code used for custom abort. */
|
||||
static constexpr DWORD CUSTOM_ABORT_EXCEPTION = 0xE1212012;
|
||||
|
||||
/** A map between exception code and its name. */
|
||||
static const std::map<DWORD, std::string> exception_code_to_name{
|
||||
{EXCEPTION_ACCESS_VIOLATION, "EXCEPTION_ACCESS_VIOLATION"},
|
||||
{EXCEPTION_ARRAY_BOUNDS_EXCEEDED, "EXCEPTION_ARRAY_BOUNDS_EXCEEDED"},
|
||||
{EXCEPTION_BREAKPOINT, "EXCEPTION_BREAKPOINT"},
|
||||
{EXCEPTION_DATATYPE_MISALIGNMENT, "EXCEPTION_DATATYPE_MISALIGNMENT"},
|
||||
{EXCEPTION_FLT_DENORMAL_OPERAND, "EXCEPTION_FLT_DENORMAL_OPERAND"},
|
||||
{EXCEPTION_FLT_DIVIDE_BY_ZERO, "EXCEPTION_FLT_DIVIDE_BY_ZERO"},
|
||||
{EXCEPTION_FLT_INEXACT_RESULT, "EXCEPTION_FLT_INEXACT_RESULT"},
|
||||
{EXCEPTION_FLT_INVALID_OPERATION, "EXCEPTION_FLT_INVALID_OPERATION"},
|
||||
{EXCEPTION_FLT_OVERFLOW, "EXCEPTION_FLT_OVERFLOW"},
|
||||
{EXCEPTION_FLT_STACK_CHECK, "EXCEPTION_FLT_STACK_CHECK"},
|
||||
{EXCEPTION_FLT_UNDERFLOW, "EXCEPTION_FLT_UNDERFLOW"},
|
||||
{EXCEPTION_GUARD_PAGE, "EXCEPTION_GUARD_PAGE"},
|
||||
{EXCEPTION_ILLEGAL_INSTRUCTION, "EXCEPTION_ILLEGAL_INSTRUCTION"},
|
||||
{EXCEPTION_IN_PAGE_ERROR, "EXCEPTION_IN_PAGE_ERROR"},
|
||||
{EXCEPTION_INT_DIVIDE_BY_ZERO, "EXCEPTION_INT_DIVIDE_BY_ZERO"},
|
||||
{EXCEPTION_INT_OVERFLOW, "EXCEPTION_INT_OVERFLOW"},
|
||||
{EXCEPTION_INVALID_DISPOSITION, "EXCEPTION_INVALID_DISPOSITION"},
|
||||
{EXCEPTION_INVALID_HANDLE, "EXCEPTION_INVALID_HANDLE"},
|
||||
{EXCEPTION_NONCONTINUABLE_EXCEPTION, "EXCEPTION_NONCONTINUABLE_EXCEPTION"},
|
||||
{EXCEPTION_PRIV_INSTRUCTION, "EXCEPTION_PRIV_INSTRUCTION"},
|
||||
{EXCEPTION_SINGLE_STEP, "EXCEPTION_SINGLE_STEP"},
|
||||
{EXCEPTION_STACK_OVERFLOW, "EXCEPTION_STACK_OVERFLOW"},
|
||||
{STATUS_UNWIND_CONSOLIDATE, "STATUS_UNWIND_CONSOLIDATE"},
|
||||
};
|
||||
|
||||
/**
|
||||
* Forcefully try to terminate the application.
|
||||
*
|
||||
|
@ -57,9 +84,17 @@ class CrashLogWindows : public CrashLog {
|
|||
/** Information about the encountered exception */
|
||||
EXCEPTION_POINTERS *ep;
|
||||
|
||||
void LogOSVersion(std::back_insert_iterator<std::string> &output_iterator) const override;
|
||||
void LogError(std::back_insert_iterator<std::string> &output_iterator, const std::string_view message) const override;
|
||||
void LogStacktrace(std::back_insert_iterator<std::string> &output_iterator) const override;
|
||||
void SurveyCrash(nlohmann::json &survey) const override
|
||||
{
|
||||
survey["id"] = ep->ExceptionRecord->ExceptionCode;
|
||||
if (exception_code_to_name.count(ep->ExceptionRecord->ExceptionCode) > 0) {
|
||||
survey["reason"] = exception_code_to_name.at(ep->ExceptionRecord->ExceptionCode);
|
||||
} else {
|
||||
survey["reason"] = "Unknown exception code";
|
||||
}
|
||||
}
|
||||
|
||||
void SurveyStacktrace(nlohmann::json &survey) const override;
|
||||
public:
|
||||
|
||||
#ifdef WITH_UNOFFICIAL_BREAKPAD
|
||||
|
@ -136,41 +171,11 @@ public:
|
|||
|
||||
/* static */ CrashLogWindows *CrashLogWindows::current = nullptr;
|
||||
|
||||
/* virtual */ void CrashLogWindows::LogOSVersion(std::back_insert_iterator<std::string> &output_iterator) const
|
||||
{
|
||||
_OSVERSIONINFOA os;
|
||||
os.dwOSVersionInfoSize = sizeof(os);
|
||||
GetVersionExA(&os);
|
||||
|
||||
fmt::format_to(output_iterator,
|
||||
"Operating system:\n"
|
||||
" Name: Windows\n"
|
||||
" Release: {}.{}.{} ({})\n",
|
||||
os.dwMajorVersion,
|
||||
os.dwMinorVersion,
|
||||
os.dwBuildNumber,
|
||||
os.szCSDVersion
|
||||
);
|
||||
}
|
||||
|
||||
/* virtual */ void CrashLogWindows::LogError(std::back_insert_iterator<std::string> &output_iterator, const std::string_view message) const
|
||||
{
|
||||
fmt::format_to(output_iterator,
|
||||
"Crash reason:\n"
|
||||
" Exception: {:08X}\n"
|
||||
" Location: {:X}\n"
|
||||
" Message: {}\n\n",
|
||||
ep->ExceptionRecord->ExceptionCode,
|
||||
(size_t)ep->ExceptionRecord->ExceptionAddress,
|
||||
message
|
||||
);
|
||||
}
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
static const uint MAX_SYMBOL_LEN = 512;
|
||||
static const uint MAX_FRAMES = 64;
|
||||
|
||||
/* virtual */ void CrashLogWindows::LogStacktrace(std::back_insert_iterator<std::string> &output_iterator) const
|
||||
/* virtual */ void CrashLogWindows::SurveyStacktrace(nlohmann::json &survey) const
|
||||
{
|
||||
DllLoader dbghelp(L"dbghelp.dll");
|
||||
struct ProcPtrs {
|
||||
|
@ -195,7 +200,7 @@ static const uint MAX_FRAMES = 64;
|
|||
dbghelp.GetProcAddress("SymGetLineFromAddr64"),
|
||||
};
|
||||
|
||||
fmt::format_to(output_iterator, "Stack trace:\n");
|
||||
survey = nlohmann::json::array();
|
||||
|
||||
/* Try to load the functions from the DLL, if that fails because of a too old dbghelp.dll, just skip it. */
|
||||
if (dbghelp.Success()) {
|
||||
|
@ -246,7 +251,7 @@ static const uint MAX_FRAMES = 64;
|
|||
hCur, GetCurrentThread(), &frame, &ctx, nullptr, proc.pSymFunctionTableAccess64, proc.pSymGetModuleBase64, nullptr)) break;
|
||||
|
||||
if (frame.AddrPC.Offset == frame.AddrReturn.Offset) {
|
||||
fmt::format_to(output_iterator, " <infinite loop>\n");
|
||||
survey.push_back("<infinite loop>");
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -260,33 +265,31 @@ static const uint MAX_FRAMES = 64;
|
|||
}
|
||||
|
||||
/* Print module and instruction pointer. */
|
||||
fmt::format_to(output_iterator, "[{:02}] {:20s} {:X}", num, mod_name, frame.AddrPC.Offset);
|
||||
std::string message = fmt::format("{:20s} {:X}", mod_name, frame.AddrPC.Offset);
|
||||
|
||||
/* Get symbol name and line info if possible. */
|
||||
DWORD64 offset;
|
||||
if (proc.pSymGetSymFromAddr64(hCur, frame.AddrPC.Offset, &offset, sym_info)) {
|
||||
fmt::format_to(output_iterator, " {} + {}", sym_info->Name, offset);
|
||||
message += fmt::format(" {} + {}", sym_info->Name, offset);
|
||||
|
||||
DWORD line_offs;
|
||||
IMAGEHLP_LINE64 line;
|
||||
line.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
|
||||
if (proc.pSymGetLineFromAddr64(hCur, frame.AddrPC.Offset, &line_offs, &line)) {
|
||||
fmt::format_to(output_iterator, " ({}:{})", line.FileName, line.LineNumber);
|
||||
message += fmt::format(" ({}:{})", line.FileName, line.LineNumber);
|
||||
}
|
||||
}
|
||||
fmt::format_to(output_iterator, "\n");
|
||||
|
||||
survey.push_back(message);
|
||||
}
|
||||
|
||||
proc.pSymCleanup(hCur);
|
||||
}
|
||||
|
||||
fmt::format_to(output_iterator, "\n");
|
||||
}
|
||||
#else
|
||||
/* virtual */ void CrashLogWindows::LogStacktrace(std::back_insert_iterator<std::string> &output_iterator) const
|
||||
/* virtual */ void CrashLogWindows::SurveyStacktrace(nlohmann::json &survey) const
|
||||
{
|
||||
fmt::format_to(output_iterator, "Stack trace:\n");
|
||||
fmt::format_to(output_iterator, " Not supported.\n");
|
||||
/* Not supported. */
|
||||
}
|
||||
#endif /* _MSC_VER */
|
||||
|
||||
|
@ -430,7 +433,7 @@ static bool _expanded;
|
|||
|
||||
static const wchar_t _crash_desc[] =
|
||||
L"A serious fault condition occurred in the game. The game will shut down.\n"
|
||||
L"Please send crash.log, crash.dmp, and crash.sav to the developers.\n"
|
||||
L"Please send crash.json.log, crash.dmp, and crash.sav to the developers.\n"
|
||||
L"This will greatly help debugging.\n\n"
|
||||
L"https://github.com/OpenTTD/OpenTTD/issues\n\n"
|
||||
L"%s\n%s\n%s\n%s\n";
|
||||
|
@ -462,9 +465,10 @@ static INT_PTR CALLBACK CrashDialogFunc(HWND wnd, UINT msg, WPARAM wParam, LPARA
|
|||
{
|
||||
switch (msg) {
|
||||
case WM_INITDIALOG: {
|
||||
size_t crashlog_length = CrashLogWindows::current->crashlog.size() + 1;
|
||||
std::string crashlog = CrashLogWindows::current->survey.dump(4);
|
||||
size_t crashlog_length = crashlog.size() + 1;
|
||||
/* Reserve extra space for LF to CRLF conversion. */
|
||||
crashlog_length += std::count(CrashLogWindows::current->crashlog.begin(), CrashLogWindows::current->crashlog.end(), '\n');
|
||||
crashlog_length += std::count(crashlog.begin(), crashlog.end(), '\n');
|
||||
|
||||
const size_t filename_count = 4;
|
||||
const size_t filename_buf_length = MAX_PATH + 1;
|
||||
|
@ -486,7 +490,7 @@ static INT_PTR CALLBACK CrashDialogFunc(HWND wnd, UINT msg, WPARAM wParam, LPARA
|
|||
char *crashlog_dos_nl = reinterpret_cast<char *>(filename_buf + filename_buf_length * filename_count);
|
||||
|
||||
/* Convert unix -> dos newlines because the edit box only supports that properly. */
|
||||
const char *crashlog_unix_nl = CrashLogWindows::current->crashlog.data();
|
||||
const char *crashlog_unix_nl = crashlog.data();
|
||||
char *p = crashlog_dos_nl;
|
||||
char32_t c;
|
||||
while ((c = Utf8Consume(&crashlog_unix_nl))) {
|
||||
|
|
|
@ -10,15 +10,13 @@
|
|||
#include "../../stdafx.h"
|
||||
|
||||
#include "../../3rdparty/fmt/format.h"
|
||||
#include "../../3rdparty/nlohmann/json.hpp"
|
||||
#include "../../survey.h"
|
||||
|
||||
#include <thread>
|
||||
#include <windows.h>
|
||||
|
||||
#include "../../safeguards.h"
|
||||
|
||||
extern std::string SurveyMemoryToText(uint64_t memory);
|
||||
|
||||
void SurveyOS(nlohmann::json &json)
|
||||
{
|
||||
_OSVERSIONINFOA os;
|
||||
|
|
|
@ -716,6 +716,12 @@ bool IntSettingDesc::IsSameValue(const IniItem *item, void *object) const
|
|||
return item_value == object_value;
|
||||
}
|
||||
|
||||
bool IntSettingDesc::IsDefaultValue(void *object) const
|
||||
{
|
||||
int32_t object_value = this->Read(object);
|
||||
return this->def == object_value;
|
||||
}
|
||||
|
||||
std::string StringSettingDesc::FormatValue(const void *object) const
|
||||
{
|
||||
const std::string &str = this->Read(object);
|
||||
|
@ -742,12 +748,24 @@ bool StringSettingDesc::IsSameValue(const IniItem *item, void *object) const
|
|||
return item->value->compare(str) == 0;
|
||||
}
|
||||
|
||||
bool StringSettingDesc::IsDefaultValue(void *object) const
|
||||
{
|
||||
const std::string &str = this->Read(object);
|
||||
return this->def == str;
|
||||
}
|
||||
|
||||
bool ListSettingDesc::IsSameValue(const IniItem *item, void *object) const
|
||||
{
|
||||
/* Checking for equality is way more expensive than just writing the value. */
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ListSettingDesc::IsDefaultValue(void *object) const
|
||||
{
|
||||
/* Defaults of lists are often complicated, and hard to compare. */
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads all items from a 'grpname' section into a list
|
||||
* The list parameter can be a nullptr pointer, in this case nothing will be
|
||||
|
|
|
@ -130,6 +130,14 @@ struct SettingDesc {
|
|||
* @return True if the value is definitely the same (might be false when the same).
|
||||
*/
|
||||
virtual bool IsSameValue(const IniItem *item, void *object) const = 0;
|
||||
|
||||
/**
|
||||
* Check whether the value is the same as the default value.
|
||||
*
|
||||
* @param object The object the setting is in.
|
||||
* @return true iff the value is the default value.
|
||||
*/
|
||||
virtual bool IsDefaultValue(void *object) const = 0;
|
||||
};
|
||||
|
||||
/** Base integer type, including boolean, settings. Only these are shown in the settings UI. */
|
||||
|
@ -215,6 +223,7 @@ struct IntSettingDesc : SettingDesc {
|
|||
std::string FormatValue(const void *object) const override;
|
||||
void ParseValue(const IniItem *item, void *object) const override;
|
||||
bool IsSameValue(const IniItem *item, void *object) const override;
|
||||
bool IsDefaultValue(void *object) const override;
|
||||
int32_t Read(const void *object) const;
|
||||
|
||||
private:
|
||||
|
@ -307,6 +316,7 @@ struct StringSettingDesc : SettingDesc {
|
|||
std::string FormatValue(const void *object) const override;
|
||||
void ParseValue(const IniItem *item, void *object) const override;
|
||||
bool IsSameValue(const IniItem *item, void *object) const override;
|
||||
bool IsDefaultValue(void *object) const override;
|
||||
const std::string &Read(const void *object) const;
|
||||
|
||||
private:
|
||||
|
@ -324,6 +334,7 @@ struct ListSettingDesc : SettingDesc {
|
|||
std::string FormatValue(const void *object) const override;
|
||||
void ParseValue(const IniItem *item, void *object) const override;
|
||||
bool IsSameValue(const IniItem *item, void *object) const override;
|
||||
bool IsDefaultValue(void *object) const override;
|
||||
};
|
||||
|
||||
/** Placeholder for settings that have been removed, but might still linger in the savegame. */
|
||||
|
@ -334,6 +345,7 @@ struct NullSettingDesc : SettingDesc {
|
|||
std::string FormatValue(const void *object) const override { NOT_REACHED(); }
|
||||
void ParseValue(const IniItem *item, void *object) const override { NOT_REACHED(); }
|
||||
bool IsSameValue(const IniItem *item, void *object) const override { NOT_REACHED(); }
|
||||
bool IsDefaultValue(void *object) const override { NOT_REACHED(); }
|
||||
};
|
||||
|
||||
typedef std::variant<IntSettingDesc, BoolSettingDesc, OneOfManySettingDesc, ManyOfManySettingDesc, StringSettingDesc, ListSettingDesc, NullSettingDesc> SettingVariant;
|
||||
|
|
|
@ -0,0 +1,458 @@
|
|||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/** @file survey.cpp Functions to survey the current game / system, for crashlog and network-survey. */
|
||||
|
||||
#include "stdafx.h"
|
||||
|
||||
#include "survey.h"
|
||||
|
||||
#include "settings_table.h"
|
||||
#include "network/network.h"
|
||||
#include "rev.h"
|
||||
#include "settings_type.h"
|
||||
#include "timer/timer_game_tick.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"
|
||||
|
||||
#ifdef WITH_ALLEGRO
|
||||
# include <allegro.h>
|
||||
#endif /* WITH_ALLEGRO */
|
||||
#ifdef WITH_FONTCONFIG
|
||||
# include <fontconfig/fontconfig.h>
|
||||
#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 <png.h>
|
||||
#endif /* WITH_PNG */
|
||||
#ifdef WITH_FREETYPE
|
||||
# include <ft2build.h>
|
||||
# include FT_FREETYPE_H
|
||||
#endif /* WITH_FREETYPE */
|
||||
#ifdef WITH_HARFBUZZ
|
||||
# include <hb.h>
|
||||
#endif /* WITH_HARFBUZZ */
|
||||
#ifdef WITH_ICU_I18N
|
||||
# include <unicode/uversion.h>
|
||||
#endif /* WITH_ICU_I18N */
|
||||
#ifdef WITH_LIBLZMA
|
||||
# include <lzma.h>
|
||||
#endif
|
||||
#ifdef WITH_LZO
|
||||
#include <lzo/lzo1x.h>
|
||||
#endif
|
||||
#if defined(WITH_SDL) || defined(WITH_SDL2)
|
||||
# include <SDL.h>
|
||||
#endif /* WITH_SDL || WITH_SDL2 */
|
||||
#ifdef WITH_ZLIB
|
||||
# include <zlib.h>
|
||||
#endif
|
||||
#ifdef WITH_CURL
|
||||
# include <curl/curl.h>
|
||||
#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",
|
||||
};
|
||||
|
||||
/**
|
||||
* List of all the generic setting tables.
|
||||
*
|
||||
* There are a few tables that are special and not processed like the rest:
|
||||
* - _currency_settings
|
||||
* - _misc_settings
|
||||
* - _company_settings
|
||||
* - _win32_settings
|
||||
* As such, they are not part of this list.
|
||||
*/
|
||||
static auto &GenericSettingTables()
|
||||
{
|
||||
static const SettingTable _generic_setting_tables[] = {
|
||||
_difficulty_settings,
|
||||
_economy_settings,
|
||||
_game_settings,
|
||||
_gui_settings,
|
||||
_linkgraph_settings,
|
||||
_locale_settings,
|
||||
_multimedia_settings,
|
||||
_network_settings,
|
||||
_news_display_settings,
|
||||
_pathfinding_settings,
|
||||
_script_settings,
|
||||
_world_settings,
|
||||
};
|
||||
return _generic_setting_tables;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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)
|
||||
{
|
||||
for (auto &desc : table) {
|
||||
const SettingDesc *sd = GetSettingDesc(desc);
|
||||
/* Skip any old settings we no longer save/load. */
|
||||
if (!SlIsObjectCurrentlyValid(sd->save.version_from, sd->save.version_to)) continue;
|
||||
|
||||
auto name = sd->GetName();
|
||||
if (skip_if_default && sd->IsDefaultValue(object)) continue;
|
||||
survey[name] = sd->FormatValue(object);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert settings to JSON.
|
||||
*
|
||||
* @param survey The JSON object.
|
||||
*/
|
||||
void SurveySettings(nlohmann::json &survey, bool skip_if_default)
|
||||
{
|
||||
SurveySettingsTable(survey, _misc_settings, nullptr, skip_if_default);
|
||||
#if defined(_WIN32) && !defined(DEDICATED)
|
||||
SurveySettingsTable(survey, _win32_settings, nullptr, skip_if_default);
|
||||
#endif
|
||||
for (auto &table : GenericSettingTables()) {
|
||||
SurveySettingsTable(survey, table, &_settings_game, skip_if_default);
|
||||
}
|
||||
SurveySettingsTable(survey, _currency_settings, &_custom_currency, skip_if_default);
|
||||
SurveySettingsTable(survey, _company_settings, &_settings_client.company, 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"] = _current_language->file.filename().string();
|
||||
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"] = TimerGameTick::counter;
|
||||
survey["seconds"] = std::chrono::duration_cast<std::chrono::seconds>(std::chrono::steady_clock::now() - _switch_mode_time).count();
|
||||
|
||||
TimerGameCalendar::YearMonthDay ymd;
|
||||
TimerGameCalendar::ConvertDateToYMD(TimerGameCalendar::date, &ymd);
|
||||
survey["calendar"] = fmt::format("{:04}-{:02}-{:02} ({})", ymd.year, ymd.month + 1, ymd.day, TimerGameCalendar::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<uint32_t> 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));
|
||||
}
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/** @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/<os>/survey_<os>.cpp. */
|
||||
void SurveyOS(nlohmann::json &json);
|
||||
|
||||
#endif /* SURVEY_H */
|
Loading…
Reference in New Issue