OpenTTD Source 20260621-master-g720d10536d
newgrf_actb.cpp
Go to the documentation of this file.
1/*
2 * This file is part of OpenTTD.
3 * 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.
4 * 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.
5 * 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 <https://www.gnu.org/licenses/old-licenses/gpl-2.0>.
6 */
7
9
10#include "../stdafx.h"
11#include "../debug.h"
12#include "newgrf_bytereader.h"
13#include "newgrf_internal.h"
14#include "../language.h"
15
16#include "table/strings.h"
17
18#include "../safeguards.h"
19
20/* Action 0x0B */
21static void GRFLoadError(ByteReader &buf)
22{
23 /* <0B> <severity> <language-id> <message-id> [<message...> 00] [<data...>] 00 [<parnum>]
24 *
25 * B severity 00: notice, continue loading grf file
26 * 01: warning, continue loading grf file
27 * 02: error, but continue loading grf file, and attempt
28 * loading grf again when loading or starting next game
29 * 03: error, abort loading and prevent loading again in
30 * the future (only when restarting the patch)
31 * B language-id see action 4, use 1F for built-in error messages
32 * B message-id message to show, see below
33 * S message for custom messages (message-id FF), text of the message
34 * not present for built-in messages.
35 * V data additional data for built-in (or custom) messages
36 * B parnum parameter numbers to be shown in the message (maximum of 2) */
37
38 static const StringID msgstr[] = {
39 STR_NEWGRF_ERROR_VERSION_NUMBER,
40 STR_NEWGRF_ERROR_DOS_OR_WINDOWS,
41 STR_NEWGRF_ERROR_UNSET_SWITCH,
42 STR_NEWGRF_ERROR_INVALID_PARAMETER,
43 STR_NEWGRF_ERROR_LOAD_BEFORE,
44 STR_NEWGRF_ERROR_LOAD_AFTER,
45 STR_NEWGRF_ERROR_OTTD_VERSION_NUMBER,
46 };
47
48 static const StringID sevstr[] = {
49 STR_NEWGRF_ERROR_MSG_INFO,
50 STR_NEWGRF_ERROR_MSG_WARNING,
51 STR_NEWGRF_ERROR_MSG_ERROR,
52 STR_NEWGRF_ERROR_MSG_FATAL
53 };
54
55 uint8_t severity = buf.ReadByte();
56 uint8_t lang = buf.ReadByte();
57 uint8_t message_id = buf.ReadByte();
58
59 /* Skip the error if it isn't valid for the current language. */
60 if (!CheckGrfLangID(lang, _cur_gps.grffile->grf_version)) return;
61
62 /* Skip the error until the activation stage unless bit 7 of the severity
63 * is set. */
64 if (!HasBit(severity, 7) && _cur_gps.stage == GrfLoadingStage::Init) {
65 GrfMsg(7, "GRFLoadError: Skipping non-fatal GRFLoadError in stage {}", _cur_gps.stage);
66 return;
67 }
68 ClrBit(severity, 7);
69
70 if (severity >= lengthof(sevstr)) {
71 GrfMsg(7, "GRFLoadError: Invalid severity id {}. Setting to 2 (non-fatal error).", severity);
72 severity = 2;
73 } else if (severity == 3) {
74 /* This is a fatal error, so make sure the GRF is deactivated and no
75 * more of it gets loaded. */
76 DisableGrf();
77 }
78
79 if (message_id >= lengthof(msgstr) && message_id != 0xFF) {
80 GrfMsg(7, "GRFLoadError: Invalid message id.");
81 return;
82 }
83
84 if (buf.Remaining() <= 1) {
85 GrfMsg(7, "GRFLoadError: No message data supplied.");
86 return;
87 }
88
89 /* An error may be emitted multiple times in different loading stages. Re-use if so. */
90 auto it = std::ranges::find(_cur_gps.grfconfig->errors, _cur_gps.nfo_line, &GRFError::nfo_line);
91 if (it == std::end(_cur_gps.grfconfig->errors)) {
92 it = _cur_gps.grfconfig->errors.emplace(it, sevstr[severity], _cur_gps.nfo_line);
93 }
94
95 GRFError &error = *it;
96
97 if (message_id == 0xFF) {
98 /* This is a custom error message. */
99 if (buf.HasData()) {
100 std::string_view message = buf.ReadString();
101
102 error.custom_message = TranslateTTDPatchCodes(_cur_gps.grffile->grfid, _current_language->newgrflangid, true, message, SCC_RAW_STRING_POINTER);
103 } else {
104 GrfMsg(7, "GRFLoadError: No custom message supplied.");
105 error.custom_message.clear();
106 }
107 } else {
108 error.message = msgstr[message_id];
109 }
110
111 if (buf.HasData()) {
112 std::string_view data = buf.ReadString();
113
114 error.data = TranslateTTDPatchCodes(_cur_gps.grffile->grfid, _current_language->newgrflangid, true, data);
115 } else {
116 GrfMsg(7, "GRFLoadError: No message data supplied.");
117 error.data.clear();
118 }
119
120 /* Only two parameter numbers can be used in the string. */
121 for (uint i = 0; i < error.param_value.size() && buf.HasData(); i++) {
122 uint param_number = buf.ReadByte();
123 error.param_value[i] = _cur_gps.grffile->GetParam(param_number);
124 }
125}
126
134template <> void GrfActionHandler<0x0B>::Init(ByteReader &buf) { GRFLoadError(buf); }
136template <> void GrfActionHandler<0x0B>::Reserve(ByteReader &buf) { GRFLoadError(buf); }
138template <> void GrfActionHandler<0x0B>::Activation(ByteReader &buf) { GRFLoadError(buf); }
constexpr bool HasBit(const T x, const uint8_t y)
Checks if a bit in a value is set.
constexpr T ClrBit(T &x, const uint8_t y)
Clears a bit in a variable.
Class to read from a NewGRF file.
std::string_view ReadString()
Read a NUL-terminated string.
uint8_t ReadByte()
Read a single byte (8 bits).
Functions related to debugging.
Information about languages and their files.
const LanguageMetadata * _current_language
The currently loaded language.
Definition strings.cpp:54
GRFError * DisableGrf(StringID message, GRFConfig *config)
Disable a GRF.
Definition newgrf.cpp:139
@ Init
Second step of NewGRF loading; load all actions into memory.
Definition newgrf.h:60
NewGRF buffer reader definition.
NewGRF internal processing state.
std::string TranslateTTDPatchCodes(uint32_t grfid, uint8_t language_id, bool allow_newlines, std::string_view str, StringControlCode byte80)
Translate TTDPatch string codes into something OpenTTD can handle (better).
A number of safeguards to prevent using unsafe methods.
Definition of base types and functions in a cross-platform compatible way.
#define lengthof(array)
Return the length of an fixed size array.
Definition stdafx.h:271
uint32_t StringID
Numeric value that represents a string, independent of the selected language.
Information about why GRF had problems during initialisation.
std::array< uint32_t, 2 > param_value
Values of GRF parameters to show for message and custom_message.
uint32_t nfo_line
Line within NewGRF of error.
StringID message
Default message.
std::string custom_message
Custom message (if present).
std::string data
Additional data for message and custom_message.
static void FileScan(ByteReader &buf)
Implementation of the GrfLoadingStage::FileScan stage of this action.
static void SafetyScan(ByteReader &buf)
Implementation of the GrfLoadingStage::SafetyScan stage of this action.
static void Reserve(ByteReader &buf)
Implementation of the GrfLoadingStage::Reserve stage of this action.
static void Activation(ByteReader &buf)
Implementation of the GrfLoadingStage::Activation stage of this action.
static void Init(ByteReader &buf)
Implementation of the GrfLoadingStage::Init stage of this action.
static void LabelScan(ByteReader &buf)
Implementation of the GrfLoadingStage::LabelScan stage of this action.