OpenTTD Source 20250711-master-gaaf5d39b15
newgrf_badge_config.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 <http://www.gnu.org/licenses/>.
6 */
7
10#include "stdafx.h"
12#include "ini_type.h"
13#include "newgrf.h"
14#include "newgrf_badge.h"
15#include "newgrf_badge_config.h"
16#include "newgrf_badge_type.h"
17
18#include "table/strings.h"
19
20#include "safeguards.h"
21
24public:
25 static inline const BadgeClassConfigItem EMPTY_CONFIG_ITEM{};
26
27 std::array<std::vector<BadgeClassConfigItem>, GrfSpecFeature::GSF_END> features = {};
28
29 static constexpr GrfSpecFeatures CONFIGURABLE_FEATURES = {
30 GSF_TRAINS, GSF_ROADVEHICLES, GSF_SHIPS, GSF_AIRCRAFT, GSF_STATIONS, GSF_HOUSES, GSF_OBJECTS, GSF_ROADSTOPS,
31 };
32
33 static inline const std::array<std::string_view, GrfSpecFeature::GSF_END> sections = {
34 "badges_trains", // GSF_TRAINS
35 "badges_roadvehicles", // GSF_ROADVEHICLES
36 "badges_ships", // GSF_SHIPS
37 "badges_aircraft", // GSF_AIRCRAFT
38 "badges_stations", // GSF_STATIONS
39 {}, // GSF_CANALS
40 {}, // GSF_BRIDGES
41 "badges_houses", // GSF_HOUSES
42 {}, // GSF_GLOBALVAR
43 {}, // GSF_INDUSTRYTILES
44 {}, // GSF_INDUSTRIES
45 {}, // GSF_CARGOES
46 {}, // GSF_SOUNDFX
47 {}, // GSF_AIRPORTS
48 {}, // GSF_SIGNALS
49 "badges_objects", // GSF_OBJECTS
50 {}, // GSF_RAILTYPES
51 {}, // GSF_AIRPORTTILES
52 {}, // GSF_ROADTYPES
53 {}, // GSF_TRAMTYPES
54 "badges_roadstops", // GSF_ROADSTOPS
55 {}, // GSF_BADGES
56 };
57};
58
61
66std::span<BadgeClassConfigItem> GetBadgeClassConfiguration(GrfSpecFeature feature)
67{
68 assert(BadgeClassConfig::CONFIGURABLE_FEATURES.Test(feature));
69 assert(feature < std::size(_badge_config.features));
70 return _badge_config.features[to_underlying(feature)];
71}
72
77{
78 for (const GrfSpecFeature &feature : BadgeClassConfig::CONFIGURABLE_FEATURES) {
79 auto &config = _badge_config.features[feature];
80
81 for (const BadgeID &index : GetClassBadges()) {
82 const Badge &badge = *GetBadge(index);
83 if (badge.name == STR_NULL) continue;
84 if (!badge.features.Test(feature)) continue;
85
86 auto found = std::ranges::find(config, badge.label, &BadgeClassConfigItem::label);
87 if (found != std::end(config)) continue;
88
89 /* Not found, insert it. */
90 config.emplace_back(badge.label, 0, true, false);
91 }
92 }
93}
94
100{
101 assert(feature < GrfSpecFeature::GSF_END);
102
103 auto &config = _badge_config.features[feature];
104 config.clear();
105
106 for (const BadgeID &index : GetClassBadges()) {
107 const Badge &badge = *GetBadge(index);
108 if (badge.name == STR_NULL) continue;
109 config.emplace_back(badge.label, 0, true, false);
110 }
111}
112
119std::pair<const BadgeClassConfigItem &, int> GetBadgeClassConfigItem(GrfSpecFeature feature, std::string_view label)
120{
121 if (BadgeClassConfig::CONFIGURABLE_FEATURES.Test(feature)) {
122 auto config = GetBadgeClassConfiguration(feature);
123 auto found = std::ranges::find(config, label, &BadgeClassConfigItem::label);
124 if (found != std::end(config)) {
125 /* Sort order is simply the position in the configuration list. */
126 return {*found, static_cast<int>(std::distance(std::begin(config), found))};
127 }
128 }
129
130 return {BadgeClassConfig::EMPTY_CONFIG_ITEM, 0};
131}
132
138static void BadgeClassLoadConfigFeature(const IniFile &ini, GrfSpecFeature feature)
139{
140 assert(BadgeClassConfig::CONFIGURABLE_FEATURES.Test(feature));
141 assert(!BadgeClassConfig::sections[feature].empty());
142
143 auto &config = _badge_config.features[feature];
144 config.clear();
145
146 const IniGroup *group = ini.GetGroup(BadgeClassConfig::sections[feature]);
147 if (group == nullptr) return;
148
149 for (const IniItem &item : group->items) {
150 int column = 0;
151 bool show_icon = true;
152 bool show_filter = false;
153
154 if (item.value.has_value() && !item.value.value().empty()) {
155 StringConsumer consumer(item.value.value());
156 if (consumer.ReadCharIf('?')) show_filter = true;
157 if (consumer.ReadCharIf('!')) show_icon = false;
158 if (auto value = consumer.TryReadIntegerBase<int>(10); value.has_value()) column = *value;
159 }
160
161 config.emplace_back(item.name, column, show_icon, show_filter);
162 }
163}
164
170{
171 for (const GrfSpecFeature &feature : BadgeClassConfig::CONFIGURABLE_FEATURES) {
172 BadgeClassLoadConfigFeature(ini, feature);
173 }
174}
175
182{
183 assert(BadgeClassConfig::CONFIGURABLE_FEATURES.Test(feature));
184 assert(!BadgeClassConfig::sections[feature].empty());
185
186 IniGroup &group = ini.GetOrCreateGroup(BadgeClassConfig::sections[feature]);
187 group.Clear();
188
189 for (const auto &item : _badge_config.features[to_underlying(feature)]) {
190 group.CreateItem(item.label).SetValue(fmt::format("{}{}{}", item.show_filter ? "?" : "", item.show_icon ? "" : "!", item.column));
191 }
192}
193
199{
200 for (const GrfSpecFeature &feature : BadgeClassConfig::CONFIGURABLE_FEATURES) {
201 BadgeClassSaveConfigFeature(ini, feature);
202 }
203}
std::string label
Class label.
Global state for badge class configuration.
std::string label
Label of badge.
GrfSpecFeatures features
Bitmask of which features use this badge.
StringID name
Short name.
constexpr bool Test(Tvalue_type value) const
Test if the value-th bit is set.
Parse data from a string / buffer.
bool ReadCharIf(char c)
Check whether the next 8-bit char matches 'c', and skip it.
std::optional< T > TryReadIntegerBase(int base, bool clamp=false)
Try to read and parse an integer in number 'base', and then advance the reader.
constexpr std::underlying_type_t< enum_type > to_underlying(enum_type e)
Implementation of std::to_underlying (from C++23)
Definition enum_type.hpp:17
Types related to reading/writing '*.ini' files.
Base for the NewGRF implementation.
GrfSpecFeature
Definition newgrf.h:69
Badge * GetBadge(BadgeID index)
Get a badge if it exists.
std::span< const BadgeID > GetClassBadges()
Get a read-only view of class badge index.
Functions related to NewGRF badges.
void AddBadgeClassesToConfiguration()
Add current badge classes to user configuration.
void ResetBadgeClassConfiguration(GrfSpecFeature feature)
Reset badge class configuration for a feature.
static void BadgeClassSaveConfigFeature(IniFile &ini, GrfSpecFeature feature)
Save badge column preferences.
static void BadgeClassLoadConfigFeature(const IniFile &ini, GrfSpecFeature feature)
Load badge column preferences.
std::pair< const BadgeClassConfigItem &, int > GetBadgeClassConfigItem(GrfSpecFeature feature, std::string_view label)
Get configuration for a badge class.
void BadgeClassSaveConfig(IniFile &ini)
Save badge column preferences.
static BadgeClassConfig _badge_config
Static instance of badge class configuration state.
std::span< BadgeClassConfigItem > GetBadgeClassConfiguration(GrfSpecFeature feature)
Get the badge user configuration for a feature.
void BadgeClassLoadConfig(const IniFile &ini)
Load badge column preferences.
Functions related to NewGRF badge configuration.
Types related to NewGRF badges.
A number of safeguards to prevent using unsafe methods.
Definition of base types and functions in a cross-platform compatible way.
Parse strings.
Ini file that supports both loading and saving.
Definition ini_type.h:86
A group within an ini file.
Definition ini_type.h:34
void Clear()
Clear all items in the group.
Definition ini_load.cpp:97
IniItem & CreateItem(std::string_view name)
Create an item with the given name.
Definition ini_load.cpp:80
std::list< IniItem > items
all items in the group
Definition ini_type.h:35
A single "line" in an ini file.
Definition ini_type.h:23
void SetValue(std::string_view value)
Replace the current value with another value.
Definition ini_load.cpp:31
const IniGroup * GetGroup(std::string_view name) const
Get the group with the given name.
Definition ini_load.cpp:118
IniGroup & GetOrCreateGroup(std::string_view name)
Get the group with the given name, and if it doesn't exist create a new group.
Definition ini_load.cpp:146