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; if (message == STR_NULL) return nullptr;
config->error = {STR_NEWGRF_ERROR_MSG_FATAL, message}; auto it = std::ranges::find(config->errors, _cur_gps.nfo_line, &GRFError::nfo_line);
if (config == _cur_gps.grfconfig) config->error->param_value[0] = _cur_gps.nfo_line; if (it == std::end(config->errors)) {
return &config->error.value(); 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() static void ResetNewGRFErrors()
{ {
for (const auto &c : _grfconfig) { 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) { 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); Debug(grf, 0, "'{}' is not loaded as the maximum number of non-static GRFs has been reached", c->filename);
c->status = GCS_DISABLED; 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; continue;
} }
num_non_static++; 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 /* This is a fatal error, so make sure the GRF is deactivated and no
* more of it gets loaded. */ * more of it gets loaded. */
DisableGrf(); 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) { if (message_id >= lengthof(msgstr) && message_id != 0xFF) {
@@ -88,39 +85,41 @@ static void GRFLoadError(ByteReader &buf)
return; return;
} }
/* For now we can only show one message per newgrf file. */ /* An error may be emitted multiple times in different loading stages. Re-use if so. */
if (_cur_gps.grfconfig->error.has_value()) return; 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 = *it;
GRFError *error = &_cur_gps.grfconfig->error.value();
if (message_id == 0xFF) { if (message_id == 0xFF) {
/* This is a custom error message. */ /* This is a custom error message. */
if (buf.HasData()) { if (buf.HasData()) {
std::string_view message = buf.ReadString(); 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 { } else {
GrfMsg(7, "GRFLoadError: No custom message supplied."); GrfMsg(7, "GRFLoadError: No custom message supplied.");
error->custom_message.clear(); error.custom_message.clear();
} }
} else { } else {
error->message = msgstr[message_id]; error.message = msgstr[message_id];
} }
if (buf.HasData()) { if (buf.HasData()) {
std::string_view data = buf.ReadString(); 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 { } else {
GrfMsg(7, "GRFLoadError: No message data supplied."); GrfMsg(7, "GRFLoadError: No message data supplied.");
error->data.clear(); error.data.clear();
} }
/* Only two parameter numbers can be used in the string. */ /* 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(); 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), name(config.name),
info(config.info), info(config.info),
url(config.url), url(config.url),
error(config.error), errors(config.errors),
version(config.version), version(config.version),
min_loadable_version(config.min_loadable_version), min_loadable_version(config.min_loadable_version),
flags(config.flags), flags(config.flags),
@@ -156,15 +156,6 @@ GRFConfigList _grfconfig_newgame;
GRFConfigList _grfconfig_static; GRFConfigList _grfconfig_static;
uint _missing_extra_graphics = 0; 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. * Get the value of the given user-changeable parameter.
* @param info The grf parameter info to get the value for. * @param info The grf parameter info to get the value for.
@@ -472,7 +463,7 @@ compatible_grf:
c->ident.md5sum = f->ident.md5sum; c->ident.md5sum = f->ident.md5sum;
c->name = f->name; c->name = f->name;
c->info = f->name; c->info = f->name;
c->error.reset(); c->errors.clear();
c->version = f->version; c->version = f->version;
c->min_loadable_version = f->min_loadable_version; c->min_loadable_version = f->min_loadable_version;
c->num_valid_params = f->num_valid_params; c->num_valid_params = f->num_valid_params;

View File

@@ -107,12 +107,14 @@ struct GRFIdentifier {
/** Information about why GRF had problems during initialisation */ /** Information about why GRF had problems during initialisation */
struct GRFError { 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 custom_message{}; ///< Custom message (if present)
std::string data{}; ///< Additional data for message and custom_message std::string data{}; ///< Additional data for message and custom_message
StringID message{}; ///< Default message StringID message{}; ///< Default message
StringID severity{}; ///< Info / Warning / Error / Fatal 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 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 name{}; ///< NOSAVE: GRF name (Action 0x08)
GRFTextWrapper info{}; ///< NOSAVE: GRF info (author, copyright, ...) (Action 0x08) GRFTextWrapper info{}; ///< NOSAVE: GRF info (author, copyright, ...) (Action 0x08)
GRFTextWrapper url{}; ///< NOSAVE: URL belonging to this GRF. 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 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 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) { for (const auto &c : _grfconfig) {
/* Only show Fatal and Error level messages */ /* 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; std::vector<StringParameter> params;
params.emplace_back(c->GetName()); params.emplace_back(c->GetName());
params.emplace_back(c->error->message != STR_NULL ? c->error->message : STR_JUST_RAW_STRING); params.emplace_back(error.message != STR_NULL ? error.message : STR_JUST_RAW_STRING);
params.emplace_back(c->error->custom_message); params.emplace_back(error.custom_message);
params.emplace_back(c->filename); params.emplace_back(c->filename);
params.emplace_back(c->error->data); params.emplace_back(error.data);
for (const uint32_t &value : c->error->param_value) params.emplace_back(value); 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); ShowErrorMessage(GetEncodedStringWithArgs(STR_NEWGRF_ERROR_FATAL_POPUP, params), {}, WL_CRITICAL);
} else { } else {
ShowErrorMessage(GetEncodedStringWithArgs(STR_NEWGRF_ERROR_POPUP, params), {}, WL_ERROR); 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) static void ShowNewGRFInfo(const GRFConfig &c, const Rect &r, bool show_params)
{ {
Rect tr = r.Shrink(WidgetDimensions::scaled.frametext); Rect tr = r.Shrink(WidgetDimensions::scaled.frametext);
if (c.error.has_value()) { for (const GRFError &error : c.errors) {
std::array<StringParameter, 3 + std::tuple_size_v<decltype(c.error->param_value)>> params{}; std::array<StringParameter, 3 + std::tuple_size_v<decltype(error.param_value)>> params{};
auto it = params.begin(); 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.filename;
*it++ = c.error->data; *it++ = error.data;
for (const uint32_t &value : c.error->param_value) *it++ = value; 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) */ /* 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); 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); if (!c->errors.empty()) DrawSprite(SPR_WARNING_SIGN, 0, warning_left, tr.top + warning_offset_y);
uint txtoffset = !c->error.has_value() ? 0 : warning.width; 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); 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; tr.top += step_height;
} }