1
0
Fork 0

Codechange: Use std::vector for GRFConfig lists. (#10835)

This replaces the C-style custom managed linked-list and allows use of iterators etc.
pull/13419/head
Peter Nelson 2025-01-31 17:09:09 +00:00 committed by GitHub
parent 40aeedeade
commit 5664b1e2f6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
23 changed files with 248 additions and 384 deletions

View File

@ -47,8 +47,7 @@ struct LoadCheckData {
Gamelog gamelog; ///< Gamelog actions Gamelog gamelog; ///< Gamelog actions
LoadCheckData() : grfconfig(nullptr), LoadCheckData() : grf_compatibility(GLC_NOT_FOUND)
grf_compatibility(GLC_NOT_FOUND)
{ {
} }
@ -67,7 +66,7 @@ struct LoadCheckData {
*/ */
bool HasNewGrfs() bool HasNewGrfs()
{ {
return this->checkable && this->error == INVALID_STRING_ID && this->grfconfig != nullptr; return this->checkable && this->error == INVALID_STRING_ID && !this->grfconfig.empty();
} }
void Clear(); void Clear();

View File

@ -590,7 +590,7 @@ public:
if (tr.top > tr.bottom) return; if (tr.top > tr.bottom) return;
/* NewGrf compatibility */ /* NewGrf compatibility */
SetDParam(0, _load_check_data.grfconfig == nullptr ? STR_NEWGRF_LIST_NONE : SetDParam(0, _load_check_data.grfconfig.empty() ? STR_NEWGRF_LIST_NONE :
STR_NEWGRF_LIST_ALL_FOUND + _load_check_data.grf_compatibility); STR_NEWGRF_LIST_ALL_FOUND + _load_check_data.grf_compatibility);
DrawString(tr, STR_SAVELOAD_DETAIL_GRFSTATUS); DrawString(tr, STR_SAVELOAD_DETAIL_GRFSTATUS);
tr.top += GetCharacterHeight(FS_NORMAL); tr.top += GetCharacterHeight(FS_NORMAL);

View File

@ -579,8 +579,8 @@ void Gamelog::GRFAddList(const GRFConfigList &newg)
{ {
assert(this->action_type == GLAT_START || this->action_type == GLAT_LOAD); assert(this->action_type == GLAT_START || this->action_type == GLAT_LOAD);
for (GRFConfig *gc = newg; gc != nullptr; gc = gc->next) { for (const auto &c : newg) {
this->GRFAdd(*gc); this->GRFAdd(*c);
} }
} }
@ -591,8 +591,8 @@ void Gamelog::GRFAddList(const GRFConfigList &newg)
static std::vector<const GRFConfig *> GenerateGRFList(const GRFConfigList &grfc) static std::vector<const GRFConfig *> GenerateGRFList(const GRFConfigList &grfc)
{ {
std::vector<const GRFConfig *> list; std::vector<const GRFConfig *> list;
for (const GRFConfig *g = grfc; g != nullptr; g = g->next) { for (const auto &g : grfc) {
if (IsLoggableGrfConfig(*g)) list.push_back(g); if (IsLoggableGrfConfig(*g)) list.push_back(g.get());
} }
return list; return list;

View File

@ -144,6 +144,31 @@ void CheckExternalFiles()
if (!error_msg.empty()) ShowInfoI(error_msg); if (!error_msg.empty()) ShowInfoI(error_msg);
} }
/**
* Get GRFConfig for the default extra graphics.
* @return Managed pointer to default extra GRFConfig.
*/
static std::unique_ptr<GRFConfig> GetDefaultExtraGRFConfig()
{
auto gc = std::make_unique<GRFConfig>("OPENTTD.GRF");
gc->palette |= GRFP_GRF_DOS;
FillGRFDetails(*gc, false, BASESET_DIR);
ClrBit(gc->flags, GCF_INIT_ONLY);
return gc;
}
/**
* Get GRFConfig for the baseset extra graphics.
* @return Managed pointer to baseset extra GRFConfig.
*/
static std::unique_ptr<GRFConfig> GetBasesetExtraGRFConfig()
{
auto gc = std::make_unique<GRFConfig>(BaseGraphics::GetUsedSet()->GetOrCreateExtraConfig());
if (gc->param.empty()) gc->SetParameterDefaults();
ClrBit(gc->flags, GCF_INIT_ONLY);
return gc;
}
/** Actually load the sprite tables. */ /** Actually load the sprite tables. */
static void LoadSpriteTables() static void LoadSpriteTables()
{ {
@ -180,39 +205,27 @@ static void LoadSpriteTables()
* However, we do not want it to show up in the list of used NewGRFs, * However, we do not want it to show up in the list of used NewGRFs,
* so we have to manually add it, and then remove it later. * so we have to manually add it, and then remove it later.
*/ */
GRFConfig *top = _grfconfig;
/* Default extra graphics */ auto default_extra = GetDefaultExtraGRFConfig();
static const char *master_filename = "OPENTTD.GRF"; auto baseset_extra = GetBasesetExtraGRFConfig();
GRFConfig *master = new GRFConfig(master_filename); std::string baseset_filename = baseset_extra->filename;
master->palette |= GRFP_GRF_DOS;
FillGRFDetails(*master, false, BASESET_DIR);
ClrBit(master->flags, GCF_INIT_ONLY);
/* Baseset extra graphics */ _grfconfig.insert(std::begin(_grfconfig), std::move(default_extra));
GRFConfig *extra = new GRFConfig(used_set->GetOrCreateExtraConfig()); _grfconfig.insert(std::next(std::begin(_grfconfig)), std::move(baseset_extra));
if (extra->param.empty()) extra->SetParameterDefaults();
ClrBit(extra->flags, GCF_INIT_ONLY);
extra->next = top;
master->next = extra;
_grfconfig = master;
LoadNewGRF(SPR_NEWGRFS_BASE, 2); LoadNewGRF(SPR_NEWGRFS_BASE, 2);
uint total_extra_graphics = SPR_NEWGRFS_BASE - SPR_OPENTTD_BASE; uint total_extra_graphics = SPR_NEWGRFS_BASE - SPR_OPENTTD_BASE;
Debug(sprite, 4, "Checking sprites from fallback grf"); Debug(sprite, 4, "Checking sprites from fallback grf");
_missing_extra_graphics = GetSpriteCountForFile(master_filename, SPR_OPENTTD_BASE, SPR_NEWGRFS_BASE); _missing_extra_graphics = GetSpriteCountForFile(baseset_filename, SPR_OPENTTD_BASE, SPR_NEWGRFS_BASE);
Debug(sprite, 1, "{} extra sprites, {} from baseset, {} from fallback", total_extra_graphics, total_extra_graphics - _missing_extra_graphics, _missing_extra_graphics); Debug(sprite, 1, "{} extra sprites, {} from baseset, {} from fallback", total_extra_graphics, total_extra_graphics - _missing_extra_graphics, _missing_extra_graphics);
/* The original baseset extra graphics intentionally make use of the fallback graphics. /* The original baseset extra graphics intentionally make use of the fallback graphics.
* Let's say everything which provides less than 500 sprites misses the rest intentionally. */ * Let's say everything which provides less than 500 sprites misses the rest intentionally. */
if (500 + _missing_extra_graphics > total_extra_graphics) _missing_extra_graphics = 0; if (500 + _missing_extra_graphics > total_extra_graphics) _missing_extra_graphics = 0;
/* Free and remove the top element. */ /* Remove the default and baseset extra graphics from the config. */
delete extra; _grfconfig.erase(std::begin(_grfconfig), std::next(std::begin(_grfconfig), 2));
delete master;
_grfconfig = top;
} }
@ -258,7 +271,7 @@ static bool SwitchNewGRFBlitter()
*/ */
uint depth_wanted_by_base = BaseGraphics::GetUsedSet()->blitter == BLT_32BPP ? 32 : 8; uint depth_wanted_by_base = BaseGraphics::GetUsedSet()->blitter == BLT_32BPP ? 32 : 8;
uint depth_wanted_by_grf = _support8bpp != S8BPP_NONE ? 8 : 32; uint depth_wanted_by_grf = _support8bpp != S8BPP_NONE ? 8 : 32;
for (GRFConfig *c = _grfconfig; c != nullptr; c = c->next) { for (const auto &c : _grfconfig) {
if (c->status == GCS_DISABLED || c->status == GCS_NOT_FOUND || HasBit(c->flags, GCF_INIT_ONLY)) continue; if (c->status == GCS_DISABLED || c->status == GCS_NOT_FOUND || HasBit(c->flags, GCF_INIT_ONLY)) continue;
if (c->palette & GRFP_BLT_32BPP) depth_wanted_by_grf = 32; if (c->palette & GRFP_BLT_32BPP) depth_wanted_by_grf = 32;
} }

View File

@ -129,7 +129,7 @@ void CheckGameCompatibility(NetworkGameInfo &ngi)
ngi.compatible = ngi.version_compatible; ngi.compatible = ngi.version_compatible;
/* Check if we have all the GRFs on the client-system too. */ /* Check if we have all the GRFs on the client-system too. */
for (const GRFConfig *c = ngi.grfconfig; c != nullptr; c = c->next) { for (const auto &c : ngi.grfconfig) {
if (c->status == GCS_NOT_FOUND) ngi.compatible = false; if (c->status == GCS_NOT_FOUND) ngi.compatible = false;
} }
} }
@ -148,7 +148,7 @@ void FillStaticNetworkServerGameInfo()
_network_game_info.map_height = Map::SizeY(); _network_game_info.map_height = Map::SizeY();
_network_game_info.landscape = _settings_game.game_creation.landscape; _network_game_info.landscape = _settings_game.game_creation.landscape;
_network_game_info.dedicated = _network_dedicated; _network_game_info.dedicated = _network_dedicated;
_network_game_info.grfconfig = _grfconfig; CopyGRFConfigList(_network_game_info.grfconfig, _grfconfig, false);
_network_game_info.server_name = _settings_client.network.server_name; _network_game_info.server_name = _settings_client.network.server_name;
_network_game_info.server_revision = GetNetworkRevisionString(); _network_game_info.server_revision = GetNetworkRevisionString();
@ -230,17 +230,11 @@ void SerializeNetworkGameInfo(Packet &p, const NetworkServerGameInfo &info, bool
* the GRFs that are needed, i.e. the ones that the server has * the GRFs that are needed, i.e. the ones that the server has
* selected in the NewGRF GUI and not the ones that are used due * selected in the NewGRF GUI and not the ones that are used due
* to the fact that they are in [newgrf-static] in openttd.cfg */ * to the fact that they are in [newgrf-static] in openttd.cfg */
const GRFConfig *c; uint count = std::ranges::count_if(info.grfconfig, [](const auto &c) { return !HasBit(c->flags, GCF_STATIC); });
uint count = 0;
/* Count number of GRFs to send information about */
for (c = info.grfconfig; c != nullptr; c = c->next) {
if (!HasBit(c->flags, GCF_STATIC)) count++;
}
p.Send_uint8 (count); // Send number of GRFs p.Send_uint8 (count); // Send number of GRFs
/* Send actual GRF Identifications */ /* Send actual GRF Identifications */
for (c = info.grfconfig; c != nullptr; c = c->next) { for (const auto &c : info.grfconfig) {
if (HasBit(c->flags, GCF_STATIC)) continue; if (HasBit(c->flags, GCF_STATIC)) continue;
SerializeGRFIdentifier(p, c->ident); SerializeGRFIdentifier(p, c->ident);
@ -311,7 +305,7 @@ void DeserializeNetworkGameInfo(Packet &p, NetworkGameInfo &info, const GameInfo
static_assert(std::numeric_limits<uint8_t>::max() == NETWORK_MAX_GRF_COUNT); static_assert(std::numeric_limits<uint8_t>::max() == NETWORK_MAX_GRF_COUNT);
uint num_grfs = p.Recv_uint8(); uint num_grfs = p.Recv_uint8();
GRFConfig **dst = &info.grfconfig; GRFConfigList &dst = info.grfconfig;
for (uint i = 0; i < num_grfs; i++) { for (uint i = 0; i < num_grfs; i++) {
NamedGRFIdentifier grf; NamedGRFIdentifier grf;
switch (newgrf_serialisation) { switch (newgrf_serialisation) {
@ -335,13 +329,12 @@ void DeserializeNetworkGameInfo(Packet &p, NetworkGameInfo &info, const GameInfo
NOT_REACHED(); NOT_REACHED();
} }
GRFConfig *c = new GRFConfig(); auto c = std::make_unique<GRFConfig>();
c->ident = grf.ident; c->ident = grf.ident;
HandleIncomingNetworkGameInfoGRFConfig(*c, grf.name); HandleIncomingNetworkGameInfoGRFConfig(*c, grf.name);
/* Append GRFConfig to the list */ /* Append GRFConfig to the list */
*dst = c; dst.push_back(std::move(c));
dst = &c->next;
} }
[[fallthrough]]; [[fallthrough]];
} }

View File

@ -243,17 +243,13 @@ bool ClientNetworkCoordinatorSocketHandler::Receive_GC_LISTING(Packet &p)
for (; servers > 0; servers--) { for (; servers > 0; servers--) {
std::string connection_string = p.Recv_string(NETWORK_HOSTNAME_PORT_LENGTH); std::string connection_string = p.Recv_string(NETWORK_HOSTNAME_PORT_LENGTH);
/* Read the NetworkGameInfo from the packet. */
NetworkGameInfo ngi = {};
DeserializeNetworkGameInfo(p, ngi, &this->newgrf_lookup_table);
/* Now we know the connection string, we can add it to our list. */ /* Now we know the connection string, we can add it to our list. */
NetworkGameList *item = NetworkGameListAddItem(connection_string); NetworkGameList *item = NetworkGameListAddItem(connection_string);
/* Clear any existing GRFConfig chain. */ /* Clear any existing GRFConfig chain. */
ClearGRFConfigList(item->info.grfconfig); ClearGRFConfigList(item->info.grfconfig);
/* Copy the new NetworkGameInfo info. */ /* Read the NetworkGameInfo from the packet. */
item->info = ngi; DeserializeNetworkGameInfo(p, item->info, &this->newgrf_lookup_table);
/* Check for compatability with the client. */ /* Check for compatability with the client. */
CheckGameCompatibility(item->info); CheckGameCompatibility(item->info);
/* Mark server as online. */ /* Mark server as online. */

View File

@ -72,8 +72,6 @@ void NetworkGameListRemoveItem(NetworkGameList *remove)
prev_item->next = remove->next; prev_item->next = remove->next;
} }
/* Remove GRFConfig information */
ClearGRFConfigList(remove->info.grfconfig);
delete remove; delete remove;
NetworkRebuildHostList(); NetworkRebuildHostList();
@ -99,8 +97,6 @@ void NetworkGameListRemoveExpired()
item = item->next; item = item->next;
*prev_item = item; *prev_item = item;
/* Remove GRFConfig information */
ClearGRFConfigList(remove->info.grfconfig);
delete remove; delete remove;
} else { } else {
prev_item = &item->next; prev_item = &item->next;
@ -121,7 +117,7 @@ void NetworkAfterNewGRFScan()
/* Reset compatibility state */ /* Reset compatibility state */
item->info.compatible = item->info.version_compatible; item->info.compatible = item->info.version_compatible;
for (GRFConfig *c = item->info.grfconfig; c != nullptr; c = c->next) { for (auto &c : item->info.grfconfig) {
assert(HasBit(c->flags, GCF_COPY)); assert(HasBit(c->flags, GCF_COPY));
const GRFConfig *f = FindGRFConfig(c->ident.grfid, FGCM_EXACT, &c->ident.md5sum); const GRFConfig *f = FindGRFConfig(c->ident.grfid, FGCM_EXACT, &c->ident.md5sum);

View File

@ -585,8 +585,8 @@ public:
/* 'NewGRF Settings' button invisible if no NewGRF is used */ /* 'NewGRF Settings' button invisible if no NewGRF is used */
bool changed = false; bool changed = false;
changed |= this->GetWidget<NWidgetStacked>(WID_NG_NEWGRF_SEL)->SetDisplayedPlane(sel == nullptr || sel->status != NGLS_ONLINE || sel->info.grfconfig == nullptr ? SZSP_NONE : 0); changed |= this->GetWidget<NWidgetStacked>(WID_NG_NEWGRF_SEL)->SetDisplayedPlane(sel == nullptr || sel->status != NGLS_ONLINE || sel->info.grfconfig.empty() ? SZSP_NONE : 0);
changed |= this->GetWidget<NWidgetStacked>(WID_NG_NEWGRF_MISSING_SEL)->SetDisplayedPlane(sel == nullptr || sel->status != NGLS_ONLINE || sel->info.grfconfig == nullptr || !sel->info.version_compatible || sel->info.compatible ? SZSP_NONE : 0); changed |= this->GetWidget<NWidgetStacked>(WID_NG_NEWGRF_MISSING_SEL)->SetDisplayedPlane(sel == nullptr || sel->status != NGLS_ONLINE || sel->info.grfconfig.empty() || !sel->info.version_compatible || sel->info.compatible ? SZSP_NONE : 0);
if (changed) { if (changed) {
this->ReInit(); this->ReInit();
return; return;

View File

@ -411,21 +411,17 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::SendNewGRFCheck()
Debug(net, 9, "client[{}] status = NEWGRFS_CHECK", this->client_id); Debug(net, 9, "client[{}] status = NEWGRFS_CHECK", this->client_id);
this->status = STATUS_NEWGRFS_CHECK; this->status = STATUS_NEWGRFS_CHECK;
if (_grfconfig == nullptr) { if (_grfconfig.empty()) {
/* There are no NewGRFs, so they're welcome. */ /* There are no NewGRFs, so they're welcome. */
return this->SendWelcome(); return this->SendWelcome();
} }
auto p = std::make_unique<Packet>(this, PACKET_SERVER_CHECK_NEWGRFS, TCP_MTU); auto p = std::make_unique<Packet>(this, PACKET_SERVER_CHECK_NEWGRFS, TCP_MTU);
const GRFConfig *c;
uint grf_count = 0;
for (c = _grfconfig; c != nullptr; c = c->next) {
if (!HasBit(c->flags, GCF_STATIC)) grf_count++;
}
uint grf_count = std::ranges::count_if(_grfconfig, [](const auto &c){ return !HasBit(c->flags, GCF_STATIC); });
p->Send_uint8 (grf_count); p->Send_uint8 (grf_count);
for (c = _grfconfig; c != nullptr; c = c->next) {
for (const auto &c : _grfconfig) {
if (!HasBit(c->flags, GCF_STATIC)) SerializeGRFIdentifier(*p, c->ident); if (!HasBit(c->flags, GCF_STATIC)) SerializeGRFIdentifier(*p, c->ident);
} }

View File

@ -8795,7 +8795,7 @@ static void ResetNewGRF()
/** Clear all NewGRF errors */ /** Clear all NewGRF errors */
static void ResetNewGRFErrors() static void ResetNewGRFErrors()
{ {
for (GRFConfig *c = _grfconfig; c != nullptr; c = c->next) { for (const auto &c : _grfconfig) {
c->error.reset(); c->error.reset();
} }
} }
@ -10108,7 +10108,7 @@ void LoadNewGRF(SpriteID load_index, uint num_baseset)
* be reset, the NewGRF would remain disabled even though it should * be reset, the NewGRF would remain disabled even though it should
* have been enabled. * have been enabled.
*/ */
for (GRFConfig *c = _grfconfig; c != nullptr; c = c->next) { for (const auto &c : _grfconfig) {
if (c->status != GCS_NOT_FOUND) c->status = GCS_UNKNOWN; if (c->status != GCS_NOT_FOUND) c->status = GCS_UNKNOWN;
} }
@ -10120,7 +10120,7 @@ void LoadNewGRF(SpriteID load_index, uint num_baseset)
for (GrfLoadingStage stage = GLS_LABELSCAN; stage <= GLS_ACTIVATION; stage++) { for (GrfLoadingStage stage = GLS_LABELSCAN; stage <= GLS_ACTIVATION; stage++) {
/* Set activated grfs back to will-be-activated between reservation- and activation-stage. /* Set activated grfs back to will-be-activated between reservation- and activation-stage.
* This ensures that action7/9 conditions 0x06 - 0x0A work correctly. */ * This ensures that action7/9 conditions 0x06 - 0x0A work correctly. */
for (GRFConfig *c = _grfconfig; c != nullptr; c = c->next) { for (const auto &c : _grfconfig) {
if (c->status == GCS_ACTIVATED) c->status = GCS_INITIALISED; if (c->status == GCS_ACTIVATED) c->status = GCS_INITIALISED;
} }
@ -10139,7 +10139,7 @@ void LoadNewGRF(SpriteID load_index, uint num_baseset)
uint num_non_static = 0; uint num_non_static = 0;
_cur.stage = stage; _cur.stage = stage;
for (GRFConfig *c = _grfconfig; c != nullptr; c = c->next) { for (const auto &c : _grfconfig) {
if (c->status == GCS_DISABLED || c->status == GCS_NOT_FOUND) continue; if (c->status == GCS_DISABLED || c->status == GCS_NOT_FOUND) continue;
if (stage > GLS_INIT && HasBit(c->flags, GCF_INIT_ONLY)) continue; if (stage > GLS_INIT && HasBit(c->flags, GCF_INIT_ONLY)) continue;

View File

@ -194,7 +194,7 @@ inline bool HasGrfMiscBit(GrfMiscBit bit)
/* Indicates which are the newgrf features currently loaded ingame */ /* Indicates which are the newgrf features currently loaded ingame */
extern GRFLoadedFeatures _loaded_newgrf_features; extern GRFLoadedFeatures _loaded_newgrf_features;
void LoadNewGRFFile(struct GRFConfig &config, GrfLoadingStage stage, Subdirectory subdir, bool temporary); void LoadNewGRFFile(GRFConfig &config, GrfLoadingStage stage, Subdirectory subdir, bool temporary);
void LoadNewGRF(SpriteID load_index, uint num_baseset); void LoadNewGRF(SpriteID load_index, uint num_baseset);
void ReloadNewGRFData(); // in saveload/afterload.cpp void ReloadNewGRFData(); // in saveload/afterload.cpp
void ResetNewGRFData(); void ResetNewGRFData();

View File

@ -218,9 +218,9 @@ void GRFParameterInfo::Finalize()
*/ */
void UpdateNewGRFConfigPalette(int32_t) void UpdateNewGRFConfigPalette(int32_t)
{ {
for (GRFConfig *c = _grfconfig_newgame; c != nullptr; c = c->next) c->SetSuitablePalette(); for (const auto &c : _grfconfig_newgame) c->SetSuitablePalette();
for (GRFConfig *c = _grfconfig_static; c != nullptr; c = c->next) c->SetSuitablePalette(); for (const auto &c : _grfconfig_static ) c->SetSuitablePalette();
for (GRFConfig *c = _all_grfs; c != nullptr; c = c->next) c->SetSuitablePalette(); for (const auto &c : _all_grfs ) c->SetSuitablePalette();
} }
/** /**
@ -327,12 +327,7 @@ bool FillGRFDetails(GRFConfig &config, bool is_static, Subdirectory subdir)
*/ */
void ClearGRFConfigList(GRFConfigList &config) void ClearGRFConfigList(GRFConfigList &config)
{ {
GRFConfig *c, *next; config.clear();
for (c = config; c != nullptr; c = next) {
next = c->next;
delete c;
}
config = nullptr;
} }
/** /**
@ -343,16 +338,9 @@ void ClearGRFConfigList(GRFConfigList &config)
*/ */
static void AppendGRFConfigList(GRFConfigList &dst, const GRFConfigList &src, bool init_only) static void AppendGRFConfigList(GRFConfigList &dst, const GRFConfigList &src, bool init_only)
{ {
GRFConfig **tail = &dst; for (const auto &s : src) {
while (*tail != nullptr) tail = &(*tail)->next; auto &c = dst.emplace_back(std::make_unique<GRFConfig>(*s));
for (GRFConfig *s = src; s != nullptr; s = s->next) {
GRFConfig *c = new GRFConfig(*s);
AssignBit(c->flags, GCF_INIT_ONLY, init_only); AssignBit(c->flags, GCF_INIT_ONLY, init_only);
*tail = c;
tail = &c->next;
} }
} }
@ -384,20 +372,13 @@ void CopyGRFConfigList(GRFConfigList &dst, const GRFConfigList &src, bool init_o
*/ */
static void RemoveDuplicatesFromGRFConfigList(GRFConfigList &list) static void RemoveDuplicatesFromGRFConfigList(GRFConfigList &list)
{ {
GRFConfig *prev; if (list.empty()) return;
GRFConfig *cur;
if (list == nullptr) return; auto last = std::end(list);
for (auto it = std::begin(list); it != last; ++it) {
for (prev = list, cur = list->next; cur != nullptr; prev = cur, cur = cur->next) { auto remove = std::remove_if(std::next(it), last, [&grfid = (*it)->ident.grfid](const auto &c) { return grfid == c->ident.grfid; });
if (cur->ident.grfid != list->ident.grfid) continue; last = list.erase(remove, last);
prev->next = cur->next;
delete cur;
cur = prev; // Just go back one so it continues as normal later on
} }
RemoveDuplicatesFromGRFConfigList(list->next);
} }
/** /**
@ -415,12 +396,9 @@ void AppendStaticGRFConfigs(GRFConfigList &dst)
* @param dst the head of the list to add to * @param dst the head of the list to add to
* @param el the new tail to be * @param el the new tail to be
*/ */
void AppendToGRFConfigList(GRFConfigList &dst, GRFConfig *el) void AppendToGRFConfigList(GRFConfigList &dst, std::unique_ptr<GRFConfig> &&el)
{ {
GRFConfig **tail = &dst; dst.push_back(std::move(el));
while (*tail != nullptr) tail = &(*tail)->next;
*tail = el;
RemoveDuplicatesFromGRFConfigList(dst); RemoveDuplicatesFromGRFConfigList(dst);
} }
@ -448,7 +426,7 @@ GRFListCompatibility IsGoodGRFConfigList(GRFConfigList &grfconfig)
{ {
GRFListCompatibility res = GLC_ALL_GOOD; GRFListCompatibility res = GLC_ALL_GOOD;
for (GRFConfig *c = grfconfig; c != nullptr; c = c->next) { for (auto &c : grfconfig) {
const GRFConfig *f = FindGRFConfig(c->ident.grfid, FGCM_EXACT, &c->ident.md5sum); const GRFConfig *f = FindGRFConfig(c->ident.grfid, FGCM_EXACT, &c->ident.md5sum);
if (f == nullptr || HasBit(f->flags, GCF_INVALID)) { if (f == nullptr || HasBit(f->flags, GCF_INVALID)) {
/* If we have not found the exactly matching GRF try to find one with the /* If we have not found the exactly matching GRF try to find one with the
@ -537,51 +515,24 @@ bool GRFFileScanner::AddFile(const std::string &filename, size_t basepath_length
/* Abort if the user stopped the game during a scan. */ /* Abort if the user stopped the game during a scan. */
if (_exit_game) return false; if (_exit_game) return false;
GRFConfig *c = new GRFConfig(filename.c_str() + basepath_length); bool added = false;
auto c = std::make_unique<GRFConfig>(filename.substr(basepath_length));
bool added = true; GRFConfig *grfconfig = c.get();
if (FillGRFDetails(*c, false)) { if (FillGRFDetails(*c, false)) {
if (_all_grfs == nullptr) { if (std::ranges::none_of(_all_grfs, [&c](const auto &gc) { return c->ident.grfid == gc->ident.grfid && c->ident.md5sum == gc->ident.md5sum; })) {
_all_grfs = c; _all_grfs.push_back(std::move(c));
} else { added = true;
/* Insert file into list at a position determined by its
* name, so the list is sorted as we go along */
GRFConfig **pd, *d;
bool stop = false;
for (pd = &_all_grfs; (d = *pd) != nullptr; pd = &d->next) {
if (c->ident.grfid == d->ident.grfid && c->ident.md5sum == d->ident.md5sum) added = false;
/* Because there can be multiple grfs with the same name, make sure we checked all grfs with the same name,
* before inserting the entry. So insert a new grf at the end of all grfs with the same name, instead of
* just after the first with the same name. Avoids doubles in the list. */
if (StrCompareIgnoreCase(c->GetName(), d->GetName()) <= 0) {
stop = true;
} else if (stop) {
break;
}
}
if (added) {
c->next = d;
*pd = c;
}
} }
} else {
added = false;
} }
this->num_scanned++; this->num_scanned++;
const char *name = nullptr; const char *name = nullptr;
if (c->name != nullptr) name = GetGRFStringFromGRFText(c->name); if (grfconfig->name != nullptr) name = GetGRFStringFromGRFText(grfconfig->name);
if (name == nullptr) name = c->filename.c_str(); if (name == nullptr) name = grfconfig->filename.c_str();
UpdateNewGRFScanStatus(this->num_scanned, name); UpdateNewGRFScanStatus(this->num_scanned, name);
VideoDriver::GetInstance()->GameLoopPause(); VideoDriver::GetInstance()->GameLoopPause();
if (!added) {
/* File couldn't be opened, or is either not a NewGRF or is a
* 'system' NewGRF or it's already known, so forget about it. */
delete c;
}
return added; return added;
} }
@ -591,7 +542,7 @@ bool GRFFileScanner::AddFile(const std::string &filename, size_t basepath_length
* @param c2 the second GRFConfig * * @param c2 the second GRFConfig *
* @return true if the name of first NewGRF is before the name of the second. * @return true if the name of first NewGRF is before the name of the second.
*/ */
static bool GRFSorter(GRFConfig * const &c1, GRFConfig * const &c2) static bool GRFSorter(std::unique_ptr<GRFConfig> const &c1, std::unique_ptr<GRFConfig> const &c2)
{ {
return StrNaturalCompare(c1->GetName(), c2->GetName()) < 0; return StrNaturalCompare(c1->GetName(), c2->GetName()) < 0;
} }
@ -609,29 +560,8 @@ void DoScanNewGRFFiles(NewGRFScanCallback *callback)
uint num = GRFFileScanner::DoScan(); uint num = GRFFileScanner::DoScan();
Debug(grf, 1, "Scan complete, found {} files", num); Debug(grf, 1, "Scan complete, found {} files", num);
if (num != 0 && _all_grfs != nullptr) { std::ranges::sort(_all_grfs, GRFSorter);
/* Sort the linked list using quicksort. NetworkAfterNewGRFScan();
* For that we first have to make an array, then sort and
* then remake the linked list. */
std::vector<GRFConfig *> to_sort;
uint i = 0;
for (GRFConfig *p = _all_grfs; p != nullptr; p = p->next, i++) {
to_sort.push_back(p);
}
/* Number of files is not necessarily right */
num = i;
std::sort(to_sort.begin(), to_sort.end(), GRFSorter);
for (i = 1; i < num; i++) {
to_sort[i - 1]->next = to_sort[i];
}
to_sort[num - 1]->next = nullptr;
_all_grfs = to_sort[0];
NetworkAfterNewGRFScan();
}
/* Yes... these are the NewGRF windows */ /* Yes... these are the NewGRF windows */
InvalidateWindowClassesData(WC_SAVELOAD, 0, true); InvalidateWindowClassesData(WC_SAVELOAD, 0, true);
@ -669,17 +599,17 @@ const GRFConfig *FindGRFConfig(uint32_t grfid, FindGRFConfigMode mode, const MD5
{ {
assert((mode == FGCM_EXACT) != (md5sum == nullptr)); assert((mode == FGCM_EXACT) != (md5sum == nullptr));
const GRFConfig *best = nullptr; const GRFConfig *best = nullptr;
for (const GRFConfig *c = _all_grfs; c != nullptr; c = c->next) { for (const auto &c : _all_grfs) {
/* if md5sum is set, we look for an exact match and continue if not found */ /* if md5sum is set, we look for an exact match and continue if not found */
if (!c->ident.HasGrfIdentifier(grfid, md5sum)) continue; if (!c->ident.HasGrfIdentifier(grfid, md5sum)) continue;
/* return it, if the exact same newgrf is found, or if we do not care about finding "the best" */ /* return it, if the exact same newgrf is found, or if we do not care about finding "the best" */
if (md5sum != nullptr || mode == FGCM_ANY) return c; if (md5sum != nullptr || mode == FGCM_ANY) return c.get();
/* Skip incompatible stuff, unless explicitly allowed */ /* Skip incompatible stuff, unless explicitly allowed */
if (mode != FGCM_NEWEST && HasBit(c->flags, GCF_INVALID)) continue; if (mode != FGCM_NEWEST && HasBit(c->flags, GCF_INVALID)) continue;
/* check version compatibility */ /* check version compatibility */
if (mode == FGCM_COMPATIBLE && !c->IsCompatible(desired_version)) continue; if (mode == FGCM_COMPATIBLE && !c->IsCompatible(desired_version)) continue;
/* remember the newest one as "the best" */ /* remember the newest one as "the best" */
if (best == nullptr || c->version > best->version) best = c; if (best == nullptr || c->version > best->version) best = c.get();
} }
return best; return best;
@ -693,11 +623,8 @@ const GRFConfig *FindGRFConfig(uint32_t grfid, FindGRFConfigMode mode, const MD5
*/ */
GRFConfig *GetGRFConfig(uint32_t grfid, uint32_t mask) GRFConfig *GetGRFConfig(uint32_t grfid, uint32_t mask)
{ {
GRFConfig *c; auto it = std::ranges::find_if(_grfconfig, [grfid, mask](const auto &c) { return (c->ident.grfid & mask) == (grfid & mask); });
if (it != std::end(_grfconfig)) return it->get();
for (c = _grfconfig; c != nullptr; c = c->next) {
if ((c->ident.grfid & mask) == (grfid & mask)) return c;
}
return nullptr; return nullptr;
} }

View File

@ -180,8 +180,6 @@ struct GRFConfig {
std::vector<std::optional<GRFParameterInfo>> param_info; ///< NOSAVE: extra information about the parameters std::vector<std::optional<GRFParameterInfo>> param_info; ///< NOSAVE: extra information about the parameters
std::vector<uint32_t> param; ///< GRF parameters std::vector<uint32_t> param; ///< GRF parameters
struct GRFConfig *next = nullptr; ///< NOSAVE: Next item in the linked list
bool IsCompatible(uint32_t old_version) const; bool IsCompatible(uint32_t old_version) const;
void SetParams(std::span<const uint32_t> pars); void SetParams(std::span<const uint32_t> pars);
void CopyParams(const GRFConfig &src); void CopyParams(const GRFConfig &src);
@ -199,7 +197,7 @@ struct GRFConfig {
void FinalizeParameterInfo(); void FinalizeParameterInfo();
}; };
using GRFConfigList = GRFConfig *; using GRFConfigList = std::vector<std::unique_ptr<GRFConfig>>;
/** Method to find GRFs using FindGRFConfig */ /** Method to find GRFs using FindGRFConfig */
enum FindGRFConfigMode : uint8_t { enum FindGRFConfigMode : uint8_t {
@ -231,7 +229,7 @@ const GRFConfig *FindGRFConfig(uint32_t grfid, FindGRFConfigMode mode, const MD5
GRFConfig *GetGRFConfig(uint32_t grfid, uint32_t mask = 0xFFFFFFFF); GRFConfig *GetGRFConfig(uint32_t grfid, uint32_t mask = 0xFFFFFFFF);
void CopyGRFConfigList(GRFConfigList &dst, const GRFConfigList &src, bool init_only); void CopyGRFConfigList(GRFConfigList &dst, const GRFConfigList &src, bool init_only);
void AppendStaticGRFConfigs(GRFConfigList &dst); void AppendStaticGRFConfigs(GRFConfigList &dst);
void AppendToGRFConfigList(GRFConfigList &dst, GRFConfig *el); void AppendToGRFConfigList(GRFConfigList &dst, std::unique_ptr<GRFConfig> &&el);
void ClearGRFConfigList(GRFConfigList &config); void ClearGRFConfigList(GRFConfigList &config);
void ResetGRFConfig(bool defaults); void ResetGRFConfig(bool defaults);
GRFListCompatibility IsGoodGRFConfigList(GRFConfigList &grfconfig); GRFListCompatibility IsGoodGRFConfigList(GRFConfigList &grfconfig);

View File

@ -47,7 +47,7 @@ void ShowNewGRFError()
/* Do not show errors when entering the main screen */ /* Do not show errors when entering the main screen */
if (_game_mode == GM_MENU) return; if (_game_mode == GM_MENU) return;
for (const GRFConfig *c = _grfconfig; c != nullptr; c = c->next) { 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->error.has_value() || (c->error->severity != STR_NEWGRF_ERROR_MSG_FATAL && c->error->severity != STR_NEWGRF_ERROR_MSG_ERROR)) continue;
@ -582,14 +582,13 @@ typedef std::map<uint32_t, const GRFConfig *> GrfIdMap; ///< Map of grfid to the
/** /**
* Add all grf configs from \a c into the map. * Add all grf configs from \a c into the map.
* @param c Grf list to add. * @param lst Grf list to add.
* @param grfid_map Map to add them to. * @param grfid_map Map to add them to.
*/ */
static void FillGrfidMap(const GRFConfig *c, GrfIdMap *grfid_map) static void FillGrfidMap(const GRFConfigList &lst, GrfIdMap &grfid_map)
{ {
while (c != nullptr) { for (const auto &c : lst) {
grfid_map->emplace(c->ident.grfid, c); grfid_map.emplace(c->ident.grfid, c.get());
c = c->next;
} }
} }
@ -617,10 +616,10 @@ struct NewGRFWindow : public Window, NewGRFScanCallback {
StringList grf_presets; ///< List of known NewGRF presets. StringList grf_presets; ///< List of known NewGRF presets.
GRFConfigList actives; ///< Temporary active grf list to which changes are made. GRFConfigList actives; ///< Temporary active grf list to which changes are made.
GRFConfig *active_sel; ///< Selected active grf item. GRFConfig *active_sel; ///< Selected active grf item.
GRFConfigList *orig_list; ///< List active grfs in the game. Used as initial value, may be updated by the window. GRFConfigList &orig_list; ///< List active grfs in the game. Used as initial value, may be updated by the window.
bool editable; ///< Is the window editable? bool editable; ///< Is the window editable?
bool show_params; ///< Are the grf-parameters shown in the info-panel? bool show_params; ///< Are the grf-parameters shown in the info-panel?
bool execute; ///< On pressing 'apply changes' are grf changes applied immediately, or only list is updated. bool execute; ///< On pressing 'apply changes' are grf changes applied immediately, or only list is updated.
@ -631,20 +630,18 @@ struct NewGRFWindow : public Window, NewGRFScanCallback {
Scrollbar *vscroll; Scrollbar *vscroll;
Scrollbar *vscroll2; Scrollbar *vscroll2;
NewGRFWindow(WindowDesc &desc, bool editable, bool show_params, bool execute, GRFConfigList *orig_list) : Window(desc), filter_editbox(EDITBOX_MAX_SIZE) NewGRFWindow(WindowDesc &desc, bool editable, bool show_params, bool execute, GRFConfigList &orig_list) : Window(desc), filter_editbox(EDITBOX_MAX_SIZE), orig_list(orig_list)
{ {
this->avail_sel = nullptr; this->avail_sel = nullptr;
this->avail_pos = -1; this->avail_pos = -1;
this->active_sel = nullptr; this->active_sel = nullptr;
this->actives = nullptr;
this->orig_list = orig_list;
this->editable = editable; this->editable = editable;
this->execute = execute; this->execute = execute;
this->show_params = show_params; this->show_params = show_params;
this->preset = -1; this->preset = -1;
this->active_over = -1; this->active_over = -1;
CopyGRFConfigList(this->actives, *orig_list, false); CopyGRFConfigList(this->actives, orig_list, false);
this->grf_presets = GetGRFPresetList(); this->grf_presets = GetGRFPresetList();
this->CreateNestedTree(); this->CreateNestedTree();
@ -679,7 +676,7 @@ struct NewGRFWindow : public Window, NewGRFScanCallback {
CloseWindowByClass(WC_SAVE_PRESET); CloseWindowByClass(WC_SAVE_PRESET);
if (this->editable && this->modified && !this->execute && !_exit_game) { if (this->editable && this->modified && !this->execute && !_exit_game) {
CopyGRFConfigList(*this->orig_list, this->actives, true); CopyGRFConfigList(this->orig_list, this->actives, true);
ResetGRFConfig(false); ResetGRFConfig(false);
ReloadNewGRFData(); ReloadNewGRFData();
} }
@ -687,10 +684,13 @@ struct NewGRFWindow : public Window, NewGRFScanCallback {
this->Window::Close(); this->Window::Close();
} }
~NewGRFWindow() int GetCurrentActivePosition() const
{ {
/* Remove the temporary copy of grf-list used in window */ if (this->active_sel != nullptr) {
ClearGRFConfigList(this->actives); auto it = std::ranges::find_if(this->actives, [this](const auto &c) { return c.get() == this->active_sel; });
if (it != std::end(this->actives)) return static_cast<int>(std::distance(std::begin(this->actives), it));
}
return -1;
} }
/** /**
@ -700,9 +700,9 @@ struct NewGRFWindow : public Window, NewGRFScanCallback {
bool CanUpgradeCurrent() bool CanUpgradeCurrent()
{ {
GrfIdMap grfid_map; GrfIdMap grfid_map;
FillGrfidMap(this->actives, &grfid_map); FillGrfidMap(this->actives, grfid_map);
for (const GRFConfig *a = _all_grfs; a != nullptr; a = a->next) { for (const auto &a : _all_grfs) {
GrfIdMap::const_iterator iter = grfid_map.find(a->ident.grfid); GrfIdMap::const_iterator iter = grfid_map.find(a->ident.grfid);
if (iter != grfid_map.end() && a->version > iter->second->version) return true; if (iter != grfid_map.end() && a->version > iter->second->version) return true;
} }
@ -713,29 +713,27 @@ struct NewGRFWindow : public Window, NewGRFScanCallback {
void UpgradeCurrent() void UpgradeCurrent()
{ {
GrfIdMap grfid_map; GrfIdMap grfid_map;
FillGrfidMap(this->actives, &grfid_map); FillGrfidMap(this->actives, grfid_map);
for (const GRFConfig *a = _all_grfs; a != nullptr; a = a->next) { for (const auto &a : _all_grfs) {
GrfIdMap::iterator iter = grfid_map.find(a->ident.grfid); GrfIdMap::iterator iter = grfid_map.find(a->ident.grfid);
if (iter == grfid_map.end() || iter->second->version >= a->version) continue; if (iter == grfid_map.end() || iter->second->version >= a->version) continue;
GRFConfig **c = &this->actives; auto c = std::ranges::find_if(this->actives, [&iter](const auto &grfconfig) { return grfconfig.get() == iter->second; });
while (*c != iter->second) c = &(*c)->next; assert(c != std::end(this->actives));
GRFConfig *d = new GRFConfig(*a); auto d = std::make_unique<GRFConfig>(*iter->second);
d->next = (*c)->next;
if (d->IsCompatible((*c)->version)) { if (d->IsCompatible((*c)->version)) {
d->CopyParams(**c); d->CopyParams(**c);
} else { } else {
d->SetParameterDefaults(); d->SetParameterDefaults();
} }
if (this->active_sel == *c) { if (this->active_sel == c->get()) {
CloseWindowByClass(WC_GRF_PARAMETERS); CloseWindowByClass(WC_GRF_PARAMETERS);
CloseWindowByClass(WC_TEXTFILE); CloseWindowByClass(WC_TEXTFILE);
this->active_sel = nullptr; this->active_sel = nullptr;
} }
delete *c; *c = std::move(d);
*c = d; iter->second = c->get();
iter->second = d;
} }
} }
@ -868,18 +866,17 @@ struct NewGRFWindow : public Window, NewGRFScanCallback {
uint warning_left = rtl ? tr.right - square.width - warning.width - 8 : tr.left + square.width + 8; uint warning_left = rtl ? tr.right - square.width - warning.width - 8 : tr.left + square.width + 8;
int i = 0; int i = 0;
for (const GRFConfig *c = this->actives; c != nullptr; c = c->next, i++) { for (const auto &c : this->actives) {
if (this->vscroll->IsVisible(i)) { if (this->vscroll->IsVisible(i)) {
const char *text = c->GetName(); const char *text = c->GetName();
bool h = (this->active_sel == c); bool h = (this->active_sel == c.get());
PaletteID pal = this->GetPalette(*c); PaletteID pal = this->GetPalette(*c);
if (h) { if (h) {
GfxFillRect(br.left, tr.top, br.right, tr.top + step_height - 1, PC_DARK_BLUE); GfxFillRect(br.left, tr.top, br.right, tr.top + step_height - 1, PC_DARK_BLUE);
} else if (i == this->active_over) { } else if (i == this->active_over) {
/* Get index of current selection. */ /* Get index of current selection. */
int active_sel_pos = 0; int active_sel_pos = this->GetCurrentActivePosition();
for (GRFConfig *c = this->actives; c != nullptr && c != this->active_sel; c = c->next, active_sel_pos++) {}
if (active_sel_pos != this->active_over) { if (active_sel_pos != this->active_over) {
uint top = this->active_over < active_sel_pos ? tr.top + 1 : tr.top + step_height - 2; uint top = this->active_over < active_sel_pos ? tr.top + 1 : tr.top + step_height - 2;
GfxFillRect(tr.left, top - 1, tr.right, top + 1, PC_GREY); GfxFillRect(tr.left, top - 1, tr.right, top + 1, PC_GREY);
@ -891,6 +888,7 @@ struct NewGRFWindow : public Window, NewGRFScanCallback {
DrawString(text_left + (rtl ? 0 : txtoffset), text_right - (rtl ? txtoffset : 0), tr.top + offset_y, text, h ? TC_WHITE : TC_ORANGE); DrawString(text_left + (rtl ? 0 : txtoffset), text_right - (rtl ? txtoffset : 0), tr.top + offset_y, text, h ? TC_WHITE : TC_ORANGE);
tr.top += step_height; tr.top += step_height;
} }
i++;
} }
if (i == this->active_over && this->vscroll->IsVisible(i)) { // Highlight is after the last GRF entry. if (i == this->active_over && this->vscroll->IsVisible(i)) { // Highlight is after the last GRF entry.
GfxFillRect(tr.left, tr.top, tr.right, tr.top + 2, PC_GREY); GfxFillRect(tr.left, tr.top, tr.right, tr.top + 2, PC_GREY);
@ -986,17 +984,12 @@ struct NewGRFWindow : public Window, NewGRFScanCallback {
case WID_NS_MOVE_UP: { // Move GRF up case WID_NS_MOVE_UP: { // Move GRF up
if (this->active_sel == nullptr || !this->editable) break; if (this->active_sel == nullptr || !this->editable) break;
int pos = 0; int pos = this->GetCurrentActivePosition();
for (GRFConfig **pc = &this->actives; *pc != nullptr; pc = &(*pc)->next, pos++) { if (pos <= 0) break;
GRFConfig *c = *pc;
if (c->next == this->active_sel) { std::swap(this->actives[pos - 1], this->actives[pos]);
c->next = this->active_sel->next;
this->active_sel->next = c; this->vscroll->ScrollTowards(pos - 1);
*pc = this->active_sel;
break;
}
}
this->vscroll->ScrollTowards(pos);
this->preset = -1; this->preset = -1;
this->InvalidateData(GOID_NEWGRF_LIST_EDITED); this->InvalidateData(GOID_NEWGRF_LIST_EDITED);
break; break;
@ -1005,17 +998,12 @@ struct NewGRFWindow : public Window, NewGRFScanCallback {
case WID_NS_MOVE_DOWN: { // Move GRF down case WID_NS_MOVE_DOWN: { // Move GRF down
if (this->active_sel == nullptr || !this->editable) break; if (this->active_sel == nullptr || !this->editable) break;
int pos = 1; // Start at 1 as we swap the selected newgrf with the next one int pos = this->GetCurrentActivePosition();
for (GRFConfig **pc = &this->actives; *pc != nullptr; pc = &(*pc)->next, pos++) { if (pos == -1 || static_cast<size_t>(pos) >= this->actives.size() - 1) break;
GRFConfig *c = *pc;
if (c == this->active_sel) { std::swap(this->actives[pos], this->actives[pos + 1]);
*pc = c->next;
c->next = c->next->next; this->vscroll->ScrollTowards(pos + 1);
(*pc)->next = c;
break;
}
}
this->vscroll->ScrollTowards(pos);
this->preset = -1; this->preset = -1;
this->InvalidateData(GOID_NEWGRF_LIST_EDITED); this->InvalidateData(GOID_NEWGRF_LIST_EDITED);
break; break;
@ -1024,16 +1012,17 @@ struct NewGRFWindow : public Window, NewGRFScanCallback {
case WID_NS_FILE_LIST: { // Select an active GRF. case WID_NS_FILE_LIST: { // Select an active GRF.
ResetObjectToPlace(); ResetObjectToPlace();
const GRFConfig *old_sel = this->active_sel;
uint i = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_NS_FILE_LIST, WidgetDimensions::scaled.framerect.top); uint i = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_NS_FILE_LIST, WidgetDimensions::scaled.framerect.top);
if (i < this->actives.size()) {
GRFConfig *c; this->active_sel = this->actives[i].get();
for (c = this->actives; c != nullptr && i > 0; c = c->next, i--) {} } else {
this->active_sel = nullptr;
if (this->active_sel != c) { }
if (this->active_sel != old_sel) {
CloseWindowByClass(WC_GRF_PARAMETERS); CloseWindowByClass(WC_GRF_PARAMETERS);
CloseWindowByClass(WC_TEXTFILE); CloseWindowByClass(WC_TEXTFILE);
} }
this->active_sel = c;
this->avail_sel = nullptr; this->avail_sel = nullptr;
this->avail_pos = -1; this->avail_pos = -1;
@ -1052,23 +1041,18 @@ struct NewGRFWindow : public Window, NewGRFScanCallback {
CloseWindowByClass(WC_TEXTFILE); CloseWindowByClass(WC_TEXTFILE);
/* Choose the next GRF file to be the selected file. */ /* Choose the next GRF file to be the selected file. */
GRFConfig *newsel = this->active_sel->next; int pos = this->GetCurrentActivePosition();
for (GRFConfig **pc = &this->actives; *pc != nullptr; pc = &(*pc)->next) { if (pos < 0) break;
GRFConfig *c = *pc;
/* If the new selection is empty (i.e. we're deleting the last item
* in the list, pick the file just before the selected file */
if (newsel == nullptr && c->next == this->active_sel) newsel = c;
if (c == this->active_sel) { auto it = std::next(std::begin(this->actives), pos);
if (newsel == c) newsel = nullptr; it = this->actives.erase(it);
if (this->actives.empty()) {
*pc = c->next; this->active_sel = nullptr;
delete c; } else if (it == std::end(this->actives)) {
break; this->active_sel = this->actives.back().get();
} } else {
this->active_sel = it->get();
} }
this->active_sel = newsel;
this->preset = -1; this->preset = -1;
this->avail_pos = -1; this->avail_pos = -1;
this->avail_sel = nullptr; this->avail_sel = nullptr;
@ -1078,7 +1062,7 @@ struct NewGRFWindow : public Window, NewGRFScanCallback {
} }
case WID_NS_UPGRADE: { // Upgrade GRF. case WID_NS_UPGRADE: { // Upgrade GRF.
if (!this->editable || this->actives == nullptr) break; if (!this->editable || this->actives.empty()) break;
UpgradeCurrent(); UpgradeCurrent();
this->InvalidateData(GOID_NEWGRF_LIST_EDITED); this->InvalidateData(GOID_NEWGRF_LIST_EDITED);
break; break;
@ -1090,10 +1074,10 @@ struct NewGRFWindow : public Window, NewGRFScanCallback {
auto it = this->vscroll2->GetScrolledItemFromWidget(this->avails, pt.y, this, WID_NS_AVAIL_LIST, WidgetDimensions::scaled.framerect.top); auto it = this->vscroll2->GetScrolledItemFromWidget(this->avails, pt.y, this, WID_NS_AVAIL_LIST, WidgetDimensions::scaled.framerect.top);
this->active_sel = nullptr; this->active_sel = nullptr;
CloseWindowByClass(WC_GRF_PARAMETERS); CloseWindowByClass(WC_GRF_PARAMETERS);
if (it != this->avails.end()) { if (it != std::end(this->avails)) {
if (this->avail_sel != *it) CloseWindowByClass(WC_TEXTFILE); if (this->avail_sel != *it) CloseWindowByClass(WC_TEXTFILE);
this->avail_sel = *it; this->avail_sel = *it;
this->avail_pos = it - this->avails.begin(); this->avail_pos = static_cast<int>(std::distance(std::begin(this->avails), it));
} }
this->InvalidateData(); this->InvalidateData();
if (click_count == 1) { if (click_count == 1) {
@ -1120,7 +1104,7 @@ struct NewGRFWindow : public Window, NewGRFScanCallback {
NewGRFConfirmationCallback NewGRFConfirmationCallback
); );
} else { } else {
CopyGRFConfigList(*this->orig_list, this->actives, true); CopyGRFConfigList(this->orig_list, this->actives, true);
ResetGRFConfig(false); ResetGRFConfig(false);
ReloadNewGRFData(); ReloadNewGRFData();
this->InvalidateData(GOID_NEWGRF_CHANGES_APPLIED); this->InvalidateData(GOID_NEWGRF_CHANGES_APPLIED);
@ -1216,10 +1200,7 @@ struct NewGRFWindow : public Window, NewGRFScanCallback {
void UpdateScrollBars() void UpdateScrollBars()
{ {
/* Update scrollbars */ /* Update scrollbars */
int i = 0; this->vscroll->SetCount(this->actives.size() + 1); // Reserve empty space for drag and drop handling.
for (const GRFConfig *c = this->actives; c != nullptr; c = c->next, i++) {}
this->vscroll->SetCount(i + 1); // Reserve empty space for drag and drop handling.
if (this->avail_pos >= 0) this->vscroll2->ScrollTowards(this->avail_pos); if (this->avail_pos >= 0) this->vscroll2->ScrollTowards(this->avail_pos);
} }
@ -1239,20 +1220,14 @@ struct NewGRFWindow : public Window, NewGRFScanCallback {
case GOID_NEWGRF_RESCANNED: case GOID_NEWGRF_RESCANNED:
/* Search the list for items that are now found and mark them as such. */ /* Search the list for items that are now found and mark them as such. */
for (GRFConfig **l = &this->actives; *l != nullptr; l = &(*l)->next) { for (auto &c : this->actives) {
GRFConfig *c = *l;
bool compatible = HasBit(c->flags, GCF_COMPATIBLE); bool compatible = HasBit(c->flags, GCF_COMPATIBLE);
if (c->status != GCS_NOT_FOUND && !compatible) continue; if (c->status != GCS_NOT_FOUND && !compatible) continue;
const GRFConfig *f = FindGRFConfig(c->ident.grfid, FGCM_EXACT, compatible ? &c->original_md5sum : &c->ident.md5sum); const GRFConfig *f = FindGRFConfig(c->ident.grfid, FGCM_EXACT, compatible ? &c->original_md5sum : &c->ident.md5sum);
if (f == nullptr || HasBit(f->flags, GCF_INVALID)) continue; if (f == nullptr || HasBit(f->flags, GCF_INVALID)) continue;
*l = new GRFConfig(*f); c = std::make_unique<GRFConfig>(*f);
(*l)->next = c->next;
if (this->active_sel == c) this->active_sel = *l;
delete c;
} }
this->avails.ForceRebuild(); this->avails.ForceRebuild();
@ -1289,7 +1264,7 @@ struct NewGRFWindow : public Window, NewGRFScanCallback {
WID_NS_TOGGLE_PALETTE WID_NS_TOGGLE_PALETTE
); );
this->SetWidgetDisabledState(WID_NS_ADD, !this->editable || this->avail_sel == nullptr || HasBit(this->avail_sel->flags, GCF_INVALID)); this->SetWidgetDisabledState(WID_NS_ADD, !this->editable || this->avail_sel == nullptr || HasBit(this->avail_sel->flags, GCF_INVALID));
this->SetWidgetDisabledState(WID_NS_UPGRADE, !this->editable || this->actives == nullptr || !this->CanUpgradeCurrent()); this->SetWidgetDisabledState(WID_NS_UPGRADE, !this->editable || this->actives.empty() || !this->CanUpgradeCurrent());
bool disable_all = this->active_sel == nullptr || !this->editable; bool disable_all = this->active_sel == nullptr || !this->editable;
this->SetWidgetsDisabledState(disable_all, this->SetWidgetsDisabledState(disable_all,
@ -1311,15 +1286,15 @@ struct NewGRFWindow : public Window, NewGRFScanCallback {
if (!disable_all) { if (!disable_all) {
/* All widgets are now enabled, so disable widgets we can't use */ /* All widgets are now enabled, so disable widgets we can't use */
if (this->active_sel == this->actives) this->DisableWidget(WID_NS_MOVE_UP); if (this->active_sel == this->actives.front().get()) this->DisableWidget(WID_NS_MOVE_UP);
if (this->active_sel->next == nullptr) this->DisableWidget(WID_NS_MOVE_DOWN); if (this->active_sel == this->actives.back().get()) this->DisableWidget(WID_NS_MOVE_DOWN);
} }
this->SetWidgetDisabledState(WID_NS_PRESET_DELETE, this->preset == -1); this->SetWidgetDisabledState(WID_NS_PRESET_DELETE, this->preset == -1);
bool has_missing = false; bool has_missing = false;
bool has_compatible = false; bool has_compatible = false;
for (const GRFConfig *c = this->actives; !has_missing && c != nullptr; c = c->next) { for (const auto &c : this->actives) {
has_missing |= c->status == GCS_NOT_FOUND; has_missing |= c->status == GCS_NOT_FOUND;
has_compatible |= HasBit(c->flags, GCF_COMPATIBLE); has_compatible |= HasBit(c->flags, GCF_COMPATIBLE);
} }
@ -1374,24 +1349,16 @@ struct NewGRFWindow : public Window, NewGRFScanCallback {
if (widget == WID_NS_FILE_LIST) { if (widget == WID_NS_FILE_LIST) {
if (this->active_sel != nullptr) { if (this->active_sel != nullptr) {
/* Get pointer to the selected file in the active list. */ int from_pos = this->GetCurrentActivePosition();
int from_pos = 0;
GRFConfig **from_prev;
for (from_prev = &this->actives; *from_prev != this->active_sel; from_prev = &(*from_prev)->next, from_pos++) {}
/* Gets the drag-and-drop destination offset. Ignore the last dummy line. */ /* Gets the drag-and-drop destination offset. Ignore the last dummy line. */
int to_pos = std::min(this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_NS_FILE_LIST, WidgetDimensions::scaled.framerect.top), this->vscroll->GetCount() - 2); int to_pos = std::min(this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_NS_FILE_LIST, WidgetDimensions::scaled.framerect.top), this->vscroll->GetCount() - 2);
if (to_pos != from_pos) { // Don't move NewGRF file over itself. if (to_pos != from_pos) { // Don't move NewGRF file over itself.
/* Get pointer to destination position. */ if (to_pos > from_pos) ++to_pos;
GRFConfig **to_prev = &this->actives;
for (int i = from_pos < to_pos ? -1 : 0; *to_prev != nullptr && i < to_pos; to_prev = &(*to_prev)->next, i++) {}
/* Detach NewGRF file from its original position. */ auto from = std::next(std::begin(this->actives), from_pos);
*from_prev = this->active_sel->next; auto to = std::next(std::begin(this->actives), to_pos);
Slide(from, std::next(from), to);
/* Attach NewGRF file to its new position. */
this->active_sel->next = *to_prev;
*to_prev = this->active_sel;
this->vscroll->ScrollTowards(to_pos); this->vscroll->ScrollTowards(to_pos);
this->preset = -1; this->preset = -1;
@ -1470,13 +1437,11 @@ private:
this->avails.clear(); this->avails.clear();
for (const GRFConfig *c = _all_grfs; c != nullptr; c = c->next) { for (const auto &c : _all_grfs) {
bool found = false; if (std::ranges::any_of(this->actives, [&c](const auto &gc) { return gc->ident.HasGrfIdentifier(c->ident.grfid, &c->ident.md5sum); })) continue;
for (const GRFConfig *grf = this->actives; grf != nullptr && !found; grf = grf->next) found = grf->ident.HasGrfIdentifier(c->ident.grfid, &c->ident.md5sum);
if (found) continue;
if (_settings_client.gui.newgrf_show_old_versions) { if (_settings_client.gui.newgrf_show_old_versions) {
this->avails.push_back(c); this->avails.push_back(c.get());
} else { } else {
const GRFConfig *best = FindGRFConfig(c->ident.grfid, HasBit(c->flags, GCF_INVALID) ? FGCM_NEWEST : FGCM_NEWEST_VALID); const GRFConfig *best = FindGRFConfig(c->ident.grfid, HasBit(c->flags, GCF_INVALID) ? FGCM_NEWEST : FGCM_NEWEST_VALID);
/* Never triggers; FindGRFConfig returns either c, or a newer version of c. */ /* Never triggers; FindGRFConfig returns either c, or a newer version of c. */
@ -1490,7 +1455,7 @@ private:
* show that NewGRF!. * show that NewGRF!.
*/ */
if (best->version == 0 || best->ident.HasGrfIdentifier(c->ident.grfid, &c->ident.md5sum)) { if (best->version == 0 || best->ident.HasGrfIdentifier(c->ident.grfid, &c->ident.md5sum)) {
this->avails.push_back(c); this->avails.push_back(c.get());
} }
} }
} }
@ -1520,30 +1485,26 @@ private:
CloseWindowByClass(WC_TEXTFILE); CloseWindowByClass(WC_TEXTFILE);
uint count = 0; /* Get number of non-static NewGRFs. */
GRFConfig **entry = nullptr; size_t count = std::ranges::count_if(this->actives, [](const auto &gc) { return !HasBit(gc->flags, GCF_STATIC); });
GRFConfig **list;
/* Find last entry in the list, checking for duplicate grfid on the way */
for (list = &this->actives; *list != nullptr; list = &(*list)->next, ins_pos--) {
if (ins_pos == 0) entry = list; // Insert position? Save.
if ((*list)->ident.grfid == this->avail_sel->ident.grfid) {
ShowErrorMessage(STR_NEWGRF_DUPLICATE_GRFID, INVALID_STRING_ID, WL_INFO);
return false;
}
if (!HasBit((*list)->flags, GCF_STATIC)) count++;
}
if (entry == nullptr) entry = list;
if (count >= NETWORK_MAX_GRF_COUNT) { if (count >= NETWORK_MAX_GRF_COUNT) {
ShowErrorMessage(STR_NEWGRF_TOO_MANY_NEWGRFS, INVALID_STRING_ID, WL_INFO); ShowErrorMessage(STR_NEWGRF_TOO_MANY_NEWGRFS, INVALID_STRING_ID, WL_INFO);
return false; return false;
} }
GRFConfig *c = new GRFConfig(*this->avail_sel); // Copy GRF details from scanned list. /* Check for duplicate GRF ID. */
c->SetParameterDefaults(); if (std::ranges::any_of(this->actives, [&grfid = this->avail_sel->ident.grfid](const auto &gc) { return gc->ident.grfid == grfid; })) {
ShowErrorMessage(STR_NEWGRF_DUPLICATE_GRFID, INVALID_STRING_ID, WL_INFO);
return false;
}
/* Insert GRF config to configuration list. */ auto entry = (ins_pos >= 0 && static_cast<size_t>(ins_pos) < std::size(this->actives))
c->next = *entry; ? std::next(std::begin(this->actives), ins_pos)
*entry = c; : std::end(this->actives);
/* Copy GRF details from scanned list. */
entry = this->actives.insert(entry, std::make_unique<GRFConfig>(*this->avail_sel));
(*entry)->SetParameterDefaults();
/* Select next (or previous, if last one) item in the list. */ /* Select next (or previous, if last one) item in the list. */
int new_pos = this->avail_pos + 1; int new_pos = this->avail_pos + 1;
@ -1565,7 +1526,7 @@ void ShowMissingContentWindow(const GRFConfigList &list)
{ {
/* Only show the things in the current list, or everything when nothing's selected */ /* Only show the things in the current list, or everything when nothing's selected */
ContentVector cv; ContentVector cv;
for (const GRFConfig *c = list; c != nullptr; c = c->next) { for (const auto &c : list) {
if (c->status != GCS_NOT_FOUND && !HasBit(c->flags, GCF_COMPATIBLE)) continue; if (c->status != GCS_NOT_FOUND && !HasBit(c->flags, GCF_COMPATIBLE)) continue;
ContentInfo *ci = new ContentInfo(); ContentInfo *ci = new ContentInfo();
@ -1983,17 +1944,24 @@ static void NewGRFConfirmationCallback(Window *w, bool confirmed)
_gamelog.StartAction(GLAT_GRF); _gamelog.StartAction(GLAT_GRF);
_gamelog.GRFUpdate(_grfconfig, nw->actives); // log GRF changes _gamelog.GRFUpdate(_grfconfig, nw->actives); // log GRF changes
CopyGRFConfigList(*nw->orig_list, nw->actives, false); CopyGRFConfigList(nw->orig_list, nw->actives, false);
ReloadNewGRFData(); ReloadNewGRFData();
_gamelog.StopAction(); _gamelog.StopAction();
/* Show new, updated list */ /* Show new, updated list */
GRFConfig *c; int pos = nw->GetCurrentActivePosition();
int i = 0;
for (c = nw->actives; c != nullptr && c != nw->active_sel; c = c->next, i++) {} CopyGRFConfigList(nw->actives, nw->orig_list, false);
CopyGRFConfigList(nw->actives, *nw->orig_list, false);
for (c = nw->actives; c != nullptr && i > 0; c = c->next, i--) {} if (nw->active_sel != nullptr) {
nw->active_sel = c; /* Set current selection from position */
if (static_cast<size_t>(pos) >= nw->actives.size()) {
nw->active_sel = nw->actives.back().get();
} else {
auto it = std::next(std::begin(nw->actives), pos);
nw->active_sel = it->get();
}
}
nw->avails.ForceRebuild(); nw->avails.ForceRebuild();
nw->modified = false; nw->modified = false;
@ -2017,7 +1985,7 @@ static void NewGRFConfirmationCallback(Window *w, bool confirmed)
void ShowNewGRFSettings(bool editable, bool show_params, bool exec_changes, GRFConfigList &config) void ShowNewGRFSettings(bool editable, bool show_params, bool exec_changes, GRFConfigList &config)
{ {
CloseWindowByClass(WC_GAME_OPTIONS); CloseWindowByClass(WC_GAME_OPTIONS);
new NewGRFWindow(_newgrf_desc, editable, show_params, exec_changes, &config); new NewGRFWindow(_newgrf_desc, editable, show_params, exec_changes, config);
} }
/** Widget parts of the save preset window. */ /** Widget parts of the save preset window. */

View File

@ -242,7 +242,7 @@ static void WriteSavegameInfo(const std::string &name)
message += "NewGRFs:\n"; message += "NewGRFs:\n";
if (_load_check_data.HasNewGrfs()) { if (_load_check_data.HasNewGrfs()) {
for (GRFConfig *c = _load_check_data.grfconfig; c != nullptr; c = c->next) { for (const auto &c : _load_check_data.grfconfig) {
fmt::format_to(std::back_inserter(message), "{:08X} {} {}\n", std::byteswap(c->ident.grfid), fmt::format_to(std::back_inserter(message), "{:08X} {} {}\n", std::byteswap(c->ident.grfid),
FormatArrayAsHex(HasBit(c->flags, GCF_COMPATIBLE) ? c->original_md5sum : c->ident.md5sum), c->filename); FormatArrayAsHex(HasBit(c->flags, GCF_COMPATIBLE) ? c->original_md5sum : c->ident.md5sum), c->filename);
} }

View File

@ -369,9 +369,7 @@ static void CDECL HandleSavegameLoadCrash(int signum)
message.reserve(1024); message.reserve(1024);
message += "Loading your savegame caused OpenTTD to crash.\n"; message += "Loading your savegame caused OpenTTD to crash.\n";
for (const GRFConfig *c = _grfconfig; !_saveload_crash_with_missing_newgrfs && c != nullptr; c = c->next) { _saveload_crash_with_missing_newgrfs = std::ranges::any_of(_grfconfig, [](const auto &c) { return HasBit(c->flags, GCF_COMPATIBLE) || c->status == GCS_NOT_FOUND; });
_saveload_crash_with_missing_newgrfs = HasBit(c->flags, GCF_COMPATIBLE) || c->status == GCS_NOT_FOUND;
}
if (_saveload_crash_with_missing_newgrfs) { if (_saveload_crash_with_missing_newgrfs) {
message += message +=
@ -387,7 +385,7 @@ static void CDECL HandleSavegameLoadCrash(int signum)
"Please load the savegame with the appropriate NewGRFs installed.\n" "Please load the savegame with the appropriate NewGRFs installed.\n"
"The missing/compatible NewGRFs are:\n"; "The missing/compatible NewGRFs are:\n";
for (const GRFConfig *c = _grfconfig; c != nullptr; c = c->next) { for (const auto &c : _grfconfig) {
if (HasBit(c->flags, GCF_COMPATIBLE)) { if (HasBit(c->flags, GCF_COMPATIBLE)) {
const GRFIdentifier &replaced = _gamelog.GetOverriddenIdentifier(*c); const GRFIdentifier &replaced = _gamelog.GetOverriddenIdentifier(*c);
fmt::format_to(std::back_inserter(message), "NewGRF {:08X} (checksum {}) not found.\n Loaded NewGRF \"{}\" (checksum {}) with same GRF ID instead.\n", fmt::format_to(std::back_inserter(message), "NewGRF {:08X} (checksum {}) not found.\n Loaded NewGRF \"{}\" (checksum {}) with same GRF ID instead.\n",
@ -707,7 +705,7 @@ bool AfterLoadGame()
/* Check if all NewGRFs are present, we are very strict in MP mode */ /* Check if all NewGRFs are present, we are very strict in MP mode */
GRFListCompatibility gcf_res = IsGoodGRFConfigList(_grfconfig); GRFListCompatibility gcf_res = IsGoodGRFConfigList(_grfconfig);
for (GRFConfig *c = _grfconfig; c != nullptr; c = c->next) { for (const auto &c : _grfconfig) {
if (c->status == GCS_NOT_FOUND) { if (c->status == GCS_NOT_FOUND) {
_gamelog.GRFRemove(c->ident.grfid); _gamelog.GRFRemove(c->ident.grfid);
} else if (HasBit(c->flags, GCF_COMPATIBLE)) { } else if (HasBit(c->flags, GCF_COMPATIBLE)) {

View File

@ -91,11 +91,11 @@ struct NGRFChunkHandler : ChunkHandler {
int index = 0; int index = 0;
for (GRFConfig *c = _grfconfig; c != nullptr; c = c->next) { for (const auto &c : _grfconfig) {
if (HasBit(c->flags, GCF_STATIC) || HasBit(c->flags, GCF_INIT_ONLY)) continue; if (HasBit(c->flags, GCF_STATIC) || HasBit(c->flags, GCF_INIT_ONLY)) continue;
this->SaveParameters(*c); this->SaveParameters(*c);
SlSetArrayIndex(index++); SlSetArrayIndex(index++);
SlObject(c, description); SlObject(c.get(), description);
} }
} }
@ -112,11 +112,11 @@ struct NGRFChunkHandler : ChunkHandler {
ClearGRFConfigList(grfconfig); ClearGRFConfigList(grfconfig);
while (SlIterateArray() != -1) { while (SlIterateArray() != -1) {
GRFConfig *c = new GRFConfig(); auto c = std::make_unique<GRFConfig>();
SlObject(c, slt); SlObject(c.get(), slt);
if (IsSavegameVersionBefore(SLV_101)) c->SetSuitablePalette(); if (IsSavegameVersionBefore(SLV_101)) c->SetSuitablePalette();
this->LoadParameters(*c); this->LoadParameters(*c);
AppendToGRFConfigList(grfconfig, c); AppendToGRFConfigList(grfconfig, std::move(c));
} }
} }
@ -126,7 +126,7 @@ struct NGRFChunkHandler : ChunkHandler {
if (_game_mode == GM_MENU) { if (_game_mode == GM_MENU) {
/* Intro game must not have NewGRF. */ /* Intro game must not have NewGRF. */
if (_grfconfig != nullptr) SlErrorCorrupt("The intro game must not use NewGRF"); if (!_grfconfig.empty()) SlErrorCorrupt("The intro game must not use NewGRF");
/* Activate intro NewGRFs (townnames) */ /* Activate intro NewGRFs (townnames) */
ResetGRFConfig(false); ResetGRFConfig(false);

View File

@ -1560,11 +1560,11 @@ static bool LoadTTDPatchExtraChunks(LoadgameState *ls, int)
uint32_t grfid = ReadUint32(ls); uint32_t grfid = ReadUint32(ls);
if (ReadByte(ls) == 1) { if (ReadByte(ls) == 1) {
GRFConfig *c = new GRFConfig("TTDP game, no information"); auto c = std::make_unique<GRFConfig>("TTDP game, no information");
c->ident.grfid = grfid; c->ident.grfid = grfid;
AppendToGRFConfigList(_grfconfig, c);
Debug(oldloader, 3, "TTDPatch game using GRF file with GRFID {:08X}", std::byteswap(c->ident.grfid)); Debug(oldloader, 3, "TTDPatch game using GRF file with GRFID {:08X}", std::byteswap(c->ident.grfid));
AppendToGRFConfigList(_grfconfig, std::move(c));
} }
len -= 5; len -= 5;
} }

View File

@ -307,8 +307,10 @@ static bool MakePNGImage(const char *name, ScreenshotCallback *callb, void *user
message.reserve(1024); message.reserve(1024);
fmt::format_to(std::back_inserter(message), "Graphics set: {} ({})\n", BaseGraphics::GetUsedSet()->name, BaseGraphics::GetUsedSet()->version); fmt::format_to(std::back_inserter(message), "Graphics set: {} ({})\n", BaseGraphics::GetUsedSet()->name, BaseGraphics::GetUsedSet()->version);
message += "NewGRFs:\n"; message += "NewGRFs:\n";
for (const GRFConfig *c = _game_mode == GM_MENU ? nullptr : _grfconfig; c != nullptr; c = c->next) { if (_game_mode != GM_MENU) {
fmt::format_to(std::back_inserter(message), "{:08X} {} {}\n", std::byteswap(c->ident.grfid), FormatArrayAsHex(c->ident.md5sum), c->filename); for (const auto &c : _grfconfig) {
fmt::format_to(std::back_inserter(message), "{:08X} {} {}\n", std::byteswap(c->ident.grfid), FormatArrayAsHex(c->ident.md5sum), c->filename);
}
} }
message += "\nCompanies:\n"; message += "\nCompanies:\n";
for (const Company *c : Company::Iterate()) { for (const Company *c : Company::Iterate()) {

View File

@ -17,7 +17,7 @@
ScriptNewGRFList::ScriptNewGRFList() ScriptNewGRFList::ScriptNewGRFList()
{ {
for (auto c = _grfconfig; c != nullptr; c = c->next) { for (const auto &c : _grfconfig) {
if (!HasBit(c->flags, GCF_STATIC)) { if (!HasBit(c->flags, GCF_STATIC)) {
this->AddItem(std::byteswap(c->ident.grfid)); this->AddItem(std::byteswap(c->ident.grfid));
} }
@ -28,24 +28,15 @@ ScriptNewGRFList::ScriptNewGRFList()
{ {
grfid = std::byteswap(GB(grfid, 0, 32)); // Match people's expectations. grfid = std::byteswap(GB(grfid, 0, 32)); // Match people's expectations.
for (auto c = _grfconfig; c != nullptr; c = c->next) { return std::ranges::any_of(_grfconfig, [grfid](const auto &c) { return !HasBit(c->flags, GCF_STATIC) && c->ident.grfid == grfid; });
if (!HasBit(c->flags, GCF_STATIC) && c->ident.grfid == grfid) {
return true;
}
}
return false;
} }
/* static */ SQInteger ScriptNewGRF::GetVersion(SQInteger grfid) /* static */ SQInteger ScriptNewGRF::GetVersion(SQInteger grfid)
{ {
grfid = std::byteswap(GB(grfid, 0, 32)); // Match people's expectations. grfid = std::byteswap(GB(grfid, 0, 32)); // Match people's expectations.
for (auto c = _grfconfig; c != nullptr; c = c->next) { auto it = std::ranges::find_if(_grfconfig, [grfid](const auto &c) { return !HasBit(c->flags, GCF_STATIC) && c->ident.grfid == grfid; });
if (!HasBit(c->flags, GCF_STATIC) && c->ident.grfid == grfid) { if (it != std::end(_grfconfig)) return (*it)->version;
return c->version;
}
}
return 0; return 0;
} }
@ -54,11 +45,8 @@ ScriptNewGRFList::ScriptNewGRFList()
{ {
grfid = std::byteswap(GB(grfid, 0, 32)); // Match people's expectations. grfid = std::byteswap(GB(grfid, 0, 32)); // Match people's expectations.
for (auto c = _grfconfig; c != nullptr; c = c->next) { auto it = std::ranges::find_if(_grfconfig, [grfid](const auto &c) { return !HasBit(c->flags, GCF_STATIC) && c->ident.grfid == grfid; });
if (!HasBit(c->flags, GCF_STATIC) && c->ident.grfid == grfid) { if (it != std::end(_grfconfig)) return (*it)->GetName();
return c->GetName();
}
}
return std::nullopt; return std::nullopt;
} }

View File

@ -1048,17 +1048,16 @@ static void GraphicsSetLoadConfig(IniFile &ini)
* @param grpname Group name containing the configuration of the GRF. * @param grpname Group name containing the configuration of the GRF.
* @param is_static GRF is static. * @param is_static GRF is static.
*/ */
static GRFConfig *GRFLoadConfig(const IniFile &ini, const char *grpname, bool is_static) static GRFConfigList GRFLoadConfig(const IniFile &ini, const char *grpname, bool is_static)
{ {
const IniGroup *group = ini.GetGroup(grpname); const IniGroup *group = ini.GetGroup(grpname);
GRFConfig *first = nullptr; GRFConfigList list;
GRFConfig **curr = &first;
if (group == nullptr) return nullptr; if (group == nullptr) return list;
uint num_grfs = 0; uint num_grfs = 0;
for (const IniItem &item : group->items) { for (const IniItem &item : group->items) {
GRFConfig *c = nullptr; std::unique_ptr<GRFConfig> c{};
std::array<uint8_t, 4> grfid_buf; std::array<uint8_t, 4> grfid_buf;
MD5Hash md5sum; MD5Hash md5sum;
@ -1084,17 +1083,17 @@ static GRFConfig *GRFLoadConfig(const IniFile &ini, const char *grpname, bool is
uint32_t grfid = grfid_buf[0] | (grfid_buf[1] << 8) | (grfid_buf[2] << 16) | (grfid_buf[3] << 24); uint32_t grfid = grfid_buf[0] | (grfid_buf[1] << 8) | (grfid_buf[2] << 16) | (grfid_buf[3] << 24);
if (has_md5sum) { if (has_md5sum) {
const GRFConfig *s = FindGRFConfig(grfid, FGCM_EXACT, &md5sum); const GRFConfig *s = FindGRFConfig(grfid, FGCM_EXACT, &md5sum);
if (s != nullptr) c = new GRFConfig(*s); if (s != nullptr) c = std::make_unique<GRFConfig>(*s);
} }
if (c == nullptr && !FioCheckFileExists(std::string(item_name), NEWGRF_DIR)) { if (c == nullptr && !FioCheckFileExists(std::string(item_name), NEWGRF_DIR)) {
const GRFConfig *s = FindGRFConfig(grfid, FGCM_NEWEST_VALID); const GRFConfig *s = FindGRFConfig(grfid, FGCM_NEWEST_VALID);
if (s != nullptr) c = new GRFConfig(*s); if (s != nullptr) c = std::make_unique<GRFConfig>(*s);
} }
} }
} }
std::string filename = std::string(item_name); std::string filename = std::string(item_name);
if (c == nullptr) c = new GRFConfig(filename); if (c == nullptr) c = std::make_unique<GRFConfig>(filename);
/* Parse parameters */ /* Parse parameters */
if (item.value.has_value() && !item.value->empty()) { if (item.value.has_value() && !item.value->empty()) {
@ -1123,23 +1122,15 @@ static GRFConfig *GRFLoadConfig(const IniFile &ini, const char *grpname, bool is
SetDParamStr(0, filename.empty() ? item.name.c_str() : filename); SetDParamStr(0, filename.empty() ? item.name.c_str() : filename);
ShowErrorMessage(STR_CONFIG_ERROR, STR_CONFIG_ERROR_INVALID_GRF, WL_CRITICAL); ShowErrorMessage(STR_CONFIG_ERROR, STR_CONFIG_ERROR_INVALID_GRF, WL_CRITICAL);
delete c;
continue; continue;
} }
/* Check for duplicate GRFID (will also check for duplicate filenames) */ /* Check for duplicate GRFID (will also check for duplicate filenames) */
bool duplicate = false; auto found = std::ranges::find_if(list, [&c](const auto &gc) { return gc->ident.grfid == c->ident.grfid; });
for (const GRFConfig *gc = first; gc != nullptr; gc = gc->next) { if (found != std::end(list)) {
if (gc->ident.grfid == c->ident.grfid) { SetDParamStr(0, c->filename);
SetDParamStr(0, c->filename); SetDParamStr(1, (*found)->filename);
SetDParamStr(1, gc->filename); ShowErrorMessage(STR_CONFIG_ERROR, STR_CONFIG_ERROR_DUPLICATE_GRFID, WL_CRITICAL);
ShowErrorMessage(STR_CONFIG_ERROR, STR_CONFIG_ERROR_DUPLICATE_GRFID, WL_CRITICAL);
duplicate = true;
break;
}
}
if (duplicate) {
delete c;
continue; continue;
} }
@ -1153,11 +1144,10 @@ static GRFConfig *GRFLoadConfig(const IniFile &ini, const char *grpname, bool is
} }
/* Add item to list */ /* Add item to list */
*curr = c; list.push_back(std::move(c));
curr = &c->next;
} }
return first; return list;
} }
static IniFileVersion LoadVersionFromConfig(const IniFile &ini) static IniFileVersion LoadVersionFromConfig(const IniFile &ini)
@ -1247,13 +1237,12 @@ static void GraphicsSetSaveConfig(IniFile &ini)
} }
/* Save a GRF configuration to the given group name */ /* Save a GRF configuration to the given group name */
static void GRFSaveConfig(IniFile &ini, const char *grpname, const GRFConfig *list) static void GRFSaveConfig(IniFile &ini, const char *grpname, const GRFConfigList &list)
{ {
IniGroup &group = ini.GetOrCreateGroup(grpname); IniGroup &group = ini.GetOrCreateGroup(grpname);
group.Clear(); group.Clear();
const GRFConfig *c;
for (c = list; c != nullptr; c = c->next) { for (const auto &c : list) {
std::string key = fmt::format("{:08X}|{}|{}", std::byteswap(c->ident.grfid), std::string key = fmt::format("{:08X}|{}|{}", std::byteswap(c->ident.grfid),
FormatArrayAsHex(c->ident.md5sum), c->filename); FormatArrayAsHex(c->ident.md5sum), c->filename);
group.GetOrCreateItem(key).SetValue(GRFBuildParamList(*c)); group.GetOrCreateItem(key).SetValue(GRFBuildParamList(*c));
@ -1558,13 +1547,13 @@ StringList GetGRFPresetList()
* @return NewGRF configuration. * @return NewGRF configuration.
* @see GetGRFPresetList * @see GetGRFPresetList
*/ */
GRFConfig *LoadGRFPresetFromConfig(const char *config_name) GRFConfigList LoadGRFPresetFromConfig(const char *config_name)
{ {
std::string section("preset-"); std::string section("preset-");
section += config_name; section += config_name;
ConfigIniFile ini(_config_file); ConfigIniFile ini(_config_file);
GRFConfig *config = GRFLoadConfig(ini, section.c_str(), false); GRFConfigList config = GRFLoadConfig(ini, section.c_str(), false);
return config; return config;
} }
@ -1575,7 +1564,7 @@ GRFConfig *LoadGRFPresetFromConfig(const char *config_name)
* @param config NewGRF configuration to save. * @param config NewGRF configuration to save.
* @see GetGRFPresetList * @see GetGRFPresetList
*/ */
void SaveGRFPresetToConfig(const char *config_name, GRFConfig *config) void SaveGRFPresetToConfig(const char *config_name, GRFConfigList &config)
{ {
std::string section("preset-"); std::string section("preset-");
section += config_name; section += config_name;

View File

@ -12,6 +12,7 @@
#include "company_type.h" #include "company_type.h"
#include "string_type.h" #include "string_type.h"
#include "newgrf_config.h"
struct IniFile; struct IniFile;
@ -27,8 +28,8 @@ void IniLoadWindowSettings(IniFile &ini, const char *grpname, void *desc);
void IniSaveWindowSettings(IniFile &ini, const char *grpname, void *desc); void IniSaveWindowSettings(IniFile &ini, const char *grpname, void *desc);
StringList GetGRFPresetList(); StringList GetGRFPresetList();
struct GRFConfig *LoadGRFPresetFromConfig(const char *config_name); GRFConfigList LoadGRFPresetFromConfig(const char *config_name);
void SaveGRFPresetToConfig(const char *config_name, struct GRFConfig *config); void SaveGRFPresetToConfig(const char *config_name, GRFConfigList &config);
void DeleteGRFPresetFromConfig(const char *config_name); void DeleteGRFPresetFromConfig(const char *config_name);
void SetDefaultCompanySettings(CompanyID cid); void SetDefaultCompanySettings(CompanyID cid);

View File

@ -354,7 +354,7 @@ void SurveyTimers(nlohmann::json &survey)
*/ */
void SurveyGrfs(nlohmann::json &survey) void SurveyGrfs(nlohmann::json &survey)
{ {
for (GRFConfig *c = _grfconfig; c != nullptr; c = c->next) { for (const auto &c : _grfconfig) {
auto grfid = fmt::format("{:08x}", std::byteswap(c->ident.grfid)); auto grfid = fmt::format("{:08x}", std::byteswap(c->ident.grfid));
auto &grf = survey[grfid]; auto &grf = survey[grfid];