Change: Record and show multiple errors for each NewGRF. (#14658)

This commit is contained in:
Peter Nelson
2025-09-26 19:00:45 +01:00
committed by dP
parent 25ad0317fb
commit e1fe2e19e9
5 changed files with 44 additions and 46 deletions

View File

@@ -148,9 +148,12 @@ GRFError *DisableGrf(StringID message, GRFConfig *config)
if (message == STR_NULL) return nullptr;
config->error = {STR_NEWGRF_ERROR_MSG_FATAL, message};
if (config == _cur_gps.grfconfig) config->error->param_value[0] = _cur_gps.nfo_line;
return &config->error.value();
auto it = std::ranges::find(config->errors, _cur_gps.nfo_line, &GRFError::nfo_line);
if (it == std::end(config->errors)) {
it = config->errors.emplace(it, STR_NEWGRF_ERROR_MSG_FATAL, _cur_gps.nfo_line, message);
}
if (config == _cur_gps.grfconfig) it->param_value[0] = _cur_gps.nfo_line;
return &*it;
}
/**
@@ -392,7 +395,7 @@ static void ResetNewGRF()
static void ResetNewGRFErrors()
{
for (const auto &c : _grfconfig) {
c->error.reset();
c->errors.clear();
}
}
@@ -1841,7 +1844,7 @@ void LoadNewGRF(SpriteID load_index, uint num_baseset)
if (num_non_static == NETWORK_MAX_GRF_COUNT) {
Debug(grf, 0, "'{}' is not loaded as the maximum number of non-static GRFs has been reached", c->filename);
c->status = GCS_DISABLED;
c->error = {STR_NEWGRF_ERROR_MSG_FATAL, STR_NEWGRF_ERROR_TOO_MANY_NEWGRFS_LOADED};
c->errors.emplace_back(STR_NEWGRF_ERROR_MSG_FATAL, 0, STR_NEWGRF_ERROR_TOO_MANY_NEWGRFS_LOADED);
continue;
}
num_non_static++;

View File

@@ -73,9 +73,6 @@ static void GRFLoadError(ByteReader &buf)
/* This is a fatal error, so make sure the GRF is deactivated and no
* more of it gets loaded. */
DisableGrf();
/* Make sure we show fatal errors, instead of silly infos from before */
_cur_gps.grfconfig->error.reset();
}
if (message_id >= lengthof(msgstr) && message_id != 0xFF) {
@@ -88,39 +85,41 @@ static void GRFLoadError(ByteReader &buf)
return;
}
/* For now we can only show one message per newgrf file. */
if (_cur_gps.grfconfig->error.has_value()) return;
/* An error may be emitted multiple times in different loading stages. Re-use if so. */
auto it = std::ranges::find(_cur_gps.grfconfig->errors, _cur_gps.nfo_line, &GRFError::nfo_line);
if (it == std::end(_cur_gps.grfconfig->errors)) {
it = _cur_gps.grfconfig->errors.emplace(it, sevstr[severity], _cur_gps.nfo_line);
}
_cur_gps.grfconfig->error = {sevstr[severity]};
GRFError *error = &_cur_gps.grfconfig->error.value();
GRFError &error = *it;
if (message_id == 0xFF) {
/* This is a custom error message. */
if (buf.HasData()) {
std::string_view message = buf.ReadString();
error->custom_message = TranslateTTDPatchCodes(_cur_gps.grffile->grfid, lang, true, message, SCC_RAW_STRING_POINTER);
error.custom_message = TranslateTTDPatchCodes(_cur_gps.grffile->grfid, lang, true, message, SCC_RAW_STRING_POINTER);
} else {
GrfMsg(7, "GRFLoadError: No custom message supplied.");
error->custom_message.clear();
error.custom_message.clear();
}
} else {
error->message = msgstr[message_id];
error.message = msgstr[message_id];
}
if (buf.HasData()) {
std::string_view data = buf.ReadString();
error->data = TranslateTTDPatchCodes(_cur_gps.grffile->grfid, lang, true, data);
error.data = TranslateTTDPatchCodes(_cur_gps.grffile->grfid, lang, true, data);
} else {
GrfMsg(7, "GRFLoadError: No message data supplied.");
error->data.clear();
error.data.clear();
}
/* Only two parameter numbers can be used in the string. */
for (uint i = 0; i < error->param_value.size() && buf.HasData(); i++) {
for (uint i = 0; i < error.param_value.size() && buf.HasData(); i++) {
uint param_number = buf.ReadByte();
error->param_value[i] = _cur_gps.grffile->GetParam(param_number);
error.param_value[i] = _cur_gps.grffile->GetParam(param_number);
}
}

View File

@@ -40,7 +40,7 @@ GRFConfig::GRFConfig(const GRFConfig &config) :
name(config.name),
info(config.info),
url(config.url),
error(config.error),
errors(config.errors),
version(config.version),
min_loadable_version(config.min_loadable_version),
flags(config.flags),
@@ -156,15 +156,6 @@ GRFConfigList _grfconfig_newgame;
GRFConfigList _grfconfig_static;
uint _missing_extra_graphics = 0;
/**
* Construct a new GRFError.
* @param severity The severity of this error.
* @param message The actual error-string.
*/
GRFError::GRFError(StringID severity, StringID message) : message(message), severity(severity)
{
}
/**
* Get the value of the given user-changeable parameter.
* @param info The grf parameter info to get the value for.
@@ -472,7 +463,7 @@ compatible_grf:
c->ident.md5sum = f->ident.md5sum;
c->name = f->name;
c->info = f->name;
c->error.reset();
c->errors.clear();
c->version = f->version;
c->min_loadable_version = f->min_loadable_version;
c->num_valid_params = f->num_valid_params;

View File

@@ -107,12 +107,14 @@ struct GRFIdentifier {
/** Information about why GRF had problems during initialisation */
struct GRFError {
GRFError(StringID severity, StringID message = {});
GRFError(StringID severity, uint32_t nfo_line, StringID message = {})
: message(message), severity(severity), nfo_line(nfo_line) {}
std::string custom_message{}; ///< Custom message (if present)
std::string data{}; ///< Additional data for message and custom_message
StringID message{}; ///< Default message
StringID severity{}; ///< Info / Warning / Error / Fatal
uint32_t nfo_line; ///< Line within NewGRF of error.
std::array<uint32_t, 2> param_value{}; ///< Values of GRF parameters to show for message and custom_message
};
@@ -169,7 +171,7 @@ struct GRFConfig {
GRFTextWrapper name{}; ///< NOSAVE: GRF name (Action 0x08)
GRFTextWrapper info{}; ///< NOSAVE: GRF info (author, copyright, ...) (Action 0x08)
GRFTextWrapper url{}; ///< NOSAVE: URL belonging to this GRF.
std::optional<GRFError> error = std::nullopt; ///< NOSAVE: Error/Warning during GRF loading (Action 0x0B)
std::vector<GRFError> errors; ///< NOSAVE: Error/Warning during GRF loading (Action 0x0B)
uint32_t version = 0; ///< NOSAVE: Version a NewGRF can set so only the newest NewGRF is shown
uint32_t min_loadable_version = 0; ///< NOSAVE: Minimum compatible version a NewGRF can define

View File

@@ -51,17 +51,20 @@ void ShowNewGRFError()
for (const auto &c : _grfconfig) {
/* Only show Fatal and Error level messages */
if (!c->error.has_value() || (c->error->severity != STR_NEWGRF_ERROR_MSG_FATAL && c->error->severity != STR_NEWGRF_ERROR_MSG_ERROR)) continue;
if (c->errors.empty()) continue;
const GRFError &error = c->errors.back();
if (error.severity != STR_NEWGRF_ERROR_MSG_FATAL && error.severity != STR_NEWGRF_ERROR_MSG_ERROR) continue;
std::vector<StringParameter> params;
params.emplace_back(c->GetName());
params.emplace_back(c->error->message != STR_NULL ? c->error->message : STR_JUST_RAW_STRING);
params.emplace_back(c->error->custom_message);
params.emplace_back(error.message != STR_NULL ? error.message : STR_JUST_RAW_STRING);
params.emplace_back(error.custom_message);
params.emplace_back(c->filename);
params.emplace_back(c->error->data);
for (const uint32_t &value : c->error->param_value) params.emplace_back(value);
params.emplace_back(error.data);
for (const uint32_t &value : error.param_value) params.emplace_back(value);
if (c->error->severity == STR_NEWGRF_ERROR_MSG_FATAL) {
if (error.severity == STR_NEWGRF_ERROR_MSG_FATAL) {
ShowErrorMessage(GetEncodedStringWithArgs(STR_NEWGRF_ERROR_FATAL_POPUP, params), {}, WL_CRITICAL);
} else {
ShowErrorMessage(GetEncodedStringWithArgs(STR_NEWGRF_ERROR_POPUP, params), {}, WL_ERROR);
@@ -81,15 +84,15 @@ static StringID GetGRFPaletteString(uint8_t palette)
static void ShowNewGRFInfo(const GRFConfig &c, const Rect &r, bool show_params)
{
Rect tr = r.Shrink(WidgetDimensions::scaled.frametext);
if (c.error.has_value()) {
std::array<StringParameter, 3 + std::tuple_size_v<decltype(c.error->param_value)>> params{};
for (const GRFError &error : c.errors) {
std::array<StringParameter, 3 + std::tuple_size_v<decltype(error.param_value)>> params{};
auto it = params.begin();
*it++ = c.error->custom_message; // is skipped by built-in messages
*it++ = error.custom_message; // is skipped by built-in messages
*it++ = c.filename;
*it++ = c.error->data;
for (const uint32_t &value : c.error->param_value) *it++ = value;
*it++ = error.data;
for (const uint32_t &value : error.param_value) *it++ = value;
tr.top = DrawStringMultiLine(tr, GetString(c.error->severity, GetStringWithArgs(c.error->message != STR_NULL ? c.error->message : STR_JUST_RAW_STRING, {params.begin(), it})));
tr.top = DrawStringMultiLine(tr, GetString(error.severity, GetStringWithArgs(error.message != STR_NULL ? error.message : STR_JUST_RAW_STRING, {params.begin(), it})));
}
/* Draw filename or not if it is not known (GRF sent over internet) */
@@ -868,8 +871,8 @@ struct NewGRFWindow : public Window, NewGRFScanCallback {
}
}
DrawSprite(SPR_SQUARE, pal, square_left, tr.top + square_offset_y);
if (c->error.has_value()) DrawSprite(SPR_WARNING_SIGN, 0, warning_left, tr.top + warning_offset_y);
uint txtoffset = !c->error.has_value() ? 0 : warning.width;
if (!c->errors.empty()) DrawSprite(SPR_WARNING_SIGN, 0, warning_left, tr.top + warning_offset_y);
uint txtoffset = c->errors.empty() ? 0 : warning.width;
DrawString(text_left + (rtl ? 0 : txtoffset), text_right - (rtl ? txtoffset : 0), tr.top + offset_y, std::move(text), h ? TC_WHITE : TC_ORANGE);
tr.top += step_height;
}