From 5664b1e2f6ca4f668d7f3a378d9aabf676c7fba0 Mon Sep 17 00:00:00 2001 From: Peter Nelson Date: Fri, 31 Jan 2025 17:09:09 +0000 Subject: [PATCH] Codechange: Use std::vector for GRFConfig lists. (#10835) This replaces the C-style custom managed linked-list and allows use of iterators etc. --- src/fios.h | 5 +- src/fios_gui.cpp | 2 +- src/gamelog.cpp | 8 +- src/gfxinit.cpp | 55 +++--- src/network/core/network_game_info.cpp | 21 +-- src/network/network_coordinator.cpp | 8 +- src/network/network_gamelist.cpp | 6 +- src/network/network_gui.cpp | 4 +- src/network/network_server.cpp | 12 +- src/newgrf.cpp | 8 +- src/newgrf.h | 2 +- src/newgrf_config.cpp | 133 +++---------- src/newgrf_config.h | 6 +- src/newgrf_gui.cpp | 250 +++++++++++-------------- src/openttd.cpp | 2 +- src/saveload/afterload.cpp | 8 +- src/saveload/newgrf_sl.cpp | 12 +- src/saveload/oldloader_sl.cpp | 4 +- src/screenshot.cpp | 6 +- src/script/api/script_newgrf.cpp | 24 +-- src/settings.cpp | 49 ++--- src/settings_func.h | 5 +- src/survey.cpp | 2 +- 23 files changed, 248 insertions(+), 384 deletions(-) diff --git a/src/fios.h b/src/fios.h index f93f01e3c2..971294b0aa 100644 --- a/src/fios.h +++ b/src/fios.h @@ -47,8 +47,7 @@ struct LoadCheckData { Gamelog gamelog; ///< Gamelog actions - LoadCheckData() : grfconfig(nullptr), - grf_compatibility(GLC_NOT_FOUND) + LoadCheckData() : grf_compatibility(GLC_NOT_FOUND) { } @@ -67,7 +66,7 @@ struct LoadCheckData { */ 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(); diff --git a/src/fios_gui.cpp b/src/fios_gui.cpp index 6511c625c8..8903b2d053 100644 --- a/src/fios_gui.cpp +++ b/src/fios_gui.cpp @@ -590,7 +590,7 @@ public: if (tr.top > tr.bottom) return; /* 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); DrawString(tr, STR_SAVELOAD_DETAIL_GRFSTATUS); tr.top += GetCharacterHeight(FS_NORMAL); diff --git a/src/gamelog.cpp b/src/gamelog.cpp index c73028b9aa..c4499f47ae 100644 --- a/src/gamelog.cpp +++ b/src/gamelog.cpp @@ -579,8 +579,8 @@ void Gamelog::GRFAddList(const GRFConfigList &newg) { assert(this->action_type == GLAT_START || this->action_type == GLAT_LOAD); - for (GRFConfig *gc = newg; gc != nullptr; gc = gc->next) { - this->GRFAdd(*gc); + for (const auto &c : newg) { + this->GRFAdd(*c); } } @@ -591,8 +591,8 @@ void Gamelog::GRFAddList(const GRFConfigList &newg) static std::vector GenerateGRFList(const GRFConfigList &grfc) { std::vector list; - for (const GRFConfig *g = grfc; g != nullptr; g = g->next) { - if (IsLoggableGrfConfig(*g)) list.push_back(g); + for (const auto &g : grfc) { + if (IsLoggableGrfConfig(*g)) list.push_back(g.get()); } return list; diff --git a/src/gfxinit.cpp b/src/gfxinit.cpp index b1c32131c6..87101795a2 100644 --- a/src/gfxinit.cpp +++ b/src/gfxinit.cpp @@ -144,6 +144,31 @@ void CheckExternalFiles() 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 GetDefaultExtraGRFConfig() +{ + auto gc = std::make_unique("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 GetBasesetExtraGRFConfig() +{ + auto gc = std::make_unique(BaseGraphics::GetUsedSet()->GetOrCreateExtraConfig()); + if (gc->param.empty()) gc->SetParameterDefaults(); + ClrBit(gc->flags, GCF_INIT_ONLY); + return gc; +} + /** Actually load the sprite tables. */ 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, * so we have to manually add it, and then remove it later. */ - GRFConfig *top = _grfconfig; - /* Default extra graphics */ - static const char *master_filename = "OPENTTD.GRF"; - GRFConfig *master = new GRFConfig(master_filename); - master->palette |= GRFP_GRF_DOS; - FillGRFDetails(*master, false, BASESET_DIR); - ClrBit(master->flags, GCF_INIT_ONLY); + auto default_extra = GetDefaultExtraGRFConfig(); + auto baseset_extra = GetBasesetExtraGRFConfig(); + std::string baseset_filename = baseset_extra->filename; - /* Baseset extra graphics */ - GRFConfig *extra = new GRFConfig(used_set->GetOrCreateExtraConfig()); - if (extra->param.empty()) extra->SetParameterDefaults(); - ClrBit(extra->flags, GCF_INIT_ONLY); - - extra->next = top; - master->next = extra; - _grfconfig = master; + _grfconfig.insert(std::begin(_grfconfig), std::move(default_extra)); + _grfconfig.insert(std::next(std::begin(_grfconfig)), std::move(baseset_extra)); LoadNewGRF(SPR_NEWGRFS_BASE, 2); uint total_extra_graphics = SPR_NEWGRFS_BASE - SPR_OPENTTD_BASE; 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); /* 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. */ if (500 + _missing_extra_graphics > total_extra_graphics) _missing_extra_graphics = 0; - /* Free and remove the top element. */ - delete extra; - delete master; - _grfconfig = top; + /* Remove the default and baseset extra graphics from the config. */ + _grfconfig.erase(std::begin(_grfconfig), std::next(std::begin(_grfconfig), 2)); } @@ -258,7 +271,7 @@ static bool SwitchNewGRFBlitter() */ uint depth_wanted_by_base = BaseGraphics::GetUsedSet()->blitter == BLT_32BPP ? 32 : 8; 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->palette & GRFP_BLT_32BPP) depth_wanted_by_grf = 32; } diff --git a/src/network/core/network_game_info.cpp b/src/network/core/network_game_info.cpp index 7446e7e3d6..9fcfc47120 100644 --- a/src/network/core/network_game_info.cpp +++ b/src/network/core/network_game_info.cpp @@ -129,7 +129,7 @@ void CheckGameCompatibility(NetworkGameInfo &ngi) ngi.compatible = ngi.version_compatible; /* 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; } } @@ -148,7 +148,7 @@ void FillStaticNetworkServerGameInfo() _network_game_info.map_height = Map::SizeY(); _network_game_info.landscape = _settings_game.game_creation.landscape; _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_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 * 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 */ - const GRFConfig *c; - 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++; - } + uint count = std::ranges::count_if(info.grfconfig, [](const auto &c) { return !HasBit(c->flags, GCF_STATIC); }); p.Send_uint8 (count); // Send number of GRFs /* 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; SerializeGRFIdentifier(p, c->ident); @@ -311,7 +305,7 @@ void DeserializeNetworkGameInfo(Packet &p, NetworkGameInfo &info, const GameInfo static_assert(std::numeric_limits::max() == NETWORK_MAX_GRF_COUNT); uint num_grfs = p.Recv_uint8(); - GRFConfig **dst = &info.grfconfig; + GRFConfigList &dst = info.grfconfig; for (uint i = 0; i < num_grfs; i++) { NamedGRFIdentifier grf; switch (newgrf_serialisation) { @@ -335,13 +329,12 @@ void DeserializeNetworkGameInfo(Packet &p, NetworkGameInfo &info, const GameInfo NOT_REACHED(); } - GRFConfig *c = new GRFConfig(); + auto c = std::make_unique(); c->ident = grf.ident; HandleIncomingNetworkGameInfoGRFConfig(*c, grf.name); /* Append GRFConfig to the list */ - *dst = c; - dst = &c->next; + dst.push_back(std::move(c)); } [[fallthrough]]; } diff --git a/src/network/network_coordinator.cpp b/src/network/network_coordinator.cpp index eb455219ea..841568b806 100644 --- a/src/network/network_coordinator.cpp +++ b/src/network/network_coordinator.cpp @@ -243,17 +243,13 @@ bool ClientNetworkCoordinatorSocketHandler::Receive_GC_LISTING(Packet &p) for (; servers > 0; servers--) { 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. */ NetworkGameList *item = NetworkGameListAddItem(connection_string); /* Clear any existing GRFConfig chain. */ ClearGRFConfigList(item->info.grfconfig); - /* Copy the new NetworkGameInfo info. */ - item->info = ngi; + /* Read the NetworkGameInfo from the packet. */ + DeserializeNetworkGameInfo(p, item->info, &this->newgrf_lookup_table); /* Check for compatability with the client. */ CheckGameCompatibility(item->info); /* Mark server as online. */ diff --git a/src/network/network_gamelist.cpp b/src/network/network_gamelist.cpp index 832d9ecc08..afbc9e3ce9 100644 --- a/src/network/network_gamelist.cpp +++ b/src/network/network_gamelist.cpp @@ -72,8 +72,6 @@ void NetworkGameListRemoveItem(NetworkGameList *remove) prev_item->next = remove->next; } - /* Remove GRFConfig information */ - ClearGRFConfigList(remove->info.grfconfig); delete remove; NetworkRebuildHostList(); @@ -99,8 +97,6 @@ void NetworkGameListRemoveExpired() item = item->next; *prev_item = item; - /* Remove GRFConfig information */ - ClearGRFConfigList(remove->info.grfconfig); delete remove; } else { prev_item = &item->next; @@ -121,7 +117,7 @@ void NetworkAfterNewGRFScan() /* Reset compatibility state */ 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)); const GRFConfig *f = FindGRFConfig(c->ident.grfid, FGCM_EXACT, &c->ident.md5sum); diff --git a/src/network/network_gui.cpp b/src/network/network_gui.cpp index e497c90a91..d6ab659e1d 100644 --- a/src/network/network_gui.cpp +++ b/src/network/network_gui.cpp @@ -585,8 +585,8 @@ public: /* 'NewGRF Settings' button invisible if no NewGRF is used */ bool changed = false; - changed |= this->GetWidget(WID_NG_NEWGRF_SEL)->SetDisplayedPlane(sel == nullptr || sel->status != NGLS_ONLINE || sel->info.grfconfig == nullptr ? SZSP_NONE : 0); - changed |= this->GetWidget(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(WID_NG_NEWGRF_SEL)->SetDisplayedPlane(sel == nullptr || sel->status != NGLS_ONLINE || sel->info.grfconfig.empty() ? SZSP_NONE : 0); + changed |= this->GetWidget(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) { this->ReInit(); return; diff --git a/src/network/network_server.cpp b/src/network/network_server.cpp index 61bc46bf49..82f46d340a 100644 --- a/src/network/network_server.cpp +++ b/src/network/network_server.cpp @@ -411,21 +411,17 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::SendNewGRFCheck() Debug(net, 9, "client[{}] status = NEWGRFS_CHECK", this->client_id); this->status = STATUS_NEWGRFS_CHECK; - if (_grfconfig == nullptr) { + if (_grfconfig.empty()) { /* There are no NewGRFs, so they're welcome. */ return this->SendWelcome(); } auto p = std::make_unique(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); - for (c = _grfconfig; c != nullptr; c = c->next) { + + for (const auto &c : _grfconfig) { if (!HasBit(c->flags, GCF_STATIC)) SerializeGRFIdentifier(*p, c->ident); } diff --git a/src/newgrf.cpp b/src/newgrf.cpp index 4fb54e19b0..a1c9da216b 100644 --- a/src/newgrf.cpp +++ b/src/newgrf.cpp @@ -8795,7 +8795,7 @@ static void ResetNewGRF() /** Clear all NewGRF errors */ static void ResetNewGRFErrors() { - for (GRFConfig *c = _grfconfig; c != nullptr; c = c->next) { + for (const auto &c : _grfconfig) { 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 * 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; } @@ -10120,7 +10120,7 @@ void LoadNewGRF(SpriteID load_index, uint num_baseset) for (GrfLoadingStage stage = GLS_LABELSCAN; stage <= GLS_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. */ - for (GRFConfig *c = _grfconfig; c != nullptr; c = c->next) { + for (const auto &c : _grfconfig) { 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; _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 (stage > GLS_INIT && HasBit(c->flags, GCF_INIT_ONLY)) continue; diff --git a/src/newgrf.h b/src/newgrf.h index b5160503eb..b0e0852ddd 100644 --- a/src/newgrf.h +++ b/src/newgrf.h @@ -194,7 +194,7 @@ inline bool HasGrfMiscBit(GrfMiscBit bit) /* Indicates which are the newgrf features currently loaded ingame */ 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 ReloadNewGRFData(); // in saveload/afterload.cpp void ResetNewGRFData(); diff --git a/src/newgrf_config.cpp b/src/newgrf_config.cpp index 18c0e93e8f..98191302f8 100644 --- a/src/newgrf_config.cpp +++ b/src/newgrf_config.cpp @@ -218,9 +218,9 @@ void GRFParameterInfo::Finalize() */ void UpdateNewGRFConfigPalette(int32_t) { - for (GRFConfig *c = _grfconfig_newgame; c != nullptr; c = c->next) c->SetSuitablePalette(); - for (GRFConfig *c = _grfconfig_static; c != nullptr; c = c->next) c->SetSuitablePalette(); - for (GRFConfig *c = _all_grfs; c != nullptr; c = c->next) c->SetSuitablePalette(); + for (const auto &c : _grfconfig_newgame) c->SetSuitablePalette(); + for (const auto &c : _grfconfig_static ) 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) { - GRFConfig *c, *next; - for (c = config; c != nullptr; c = next) { - next = c->next; - delete c; - } - config = nullptr; + config.clear(); } /** @@ -343,16 +338,9 @@ void ClearGRFConfigList(GRFConfigList &config) */ static void AppendGRFConfigList(GRFConfigList &dst, const GRFConfigList &src, bool init_only) { - GRFConfig **tail = &dst; - while (*tail != nullptr) tail = &(*tail)->next; - - for (GRFConfig *s = src; s != nullptr; s = s->next) { - GRFConfig *c = new GRFConfig(*s); - + for (const auto &s : src) { + auto &c = dst.emplace_back(std::make_unique(*s)); 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) { - GRFConfig *prev; - GRFConfig *cur; + if (list.empty()) return; - if (list == nullptr) return; - - for (prev = list, cur = list->next; cur != nullptr; prev = cur, cur = cur->next) { - if (cur->ident.grfid != list->ident.grfid) continue; - - prev->next = cur->next; - delete cur; - cur = prev; // Just go back one so it continues as normal later on + auto last = std::end(list); + for (auto it = std::begin(list); it != last; ++it) { + auto remove = std::remove_if(std::next(it), last, [&grfid = (*it)->ident.grfid](const auto &c) { return grfid == c->ident.grfid; }); + last = list.erase(remove, last); } - - RemoveDuplicatesFromGRFConfigList(list->next); } /** @@ -415,12 +396,9 @@ void AppendStaticGRFConfigs(GRFConfigList &dst) * @param dst the head of the list to add to * @param el the new tail to be */ -void AppendToGRFConfigList(GRFConfigList &dst, GRFConfig *el) +void AppendToGRFConfigList(GRFConfigList &dst, std::unique_ptr &&el) { - GRFConfig **tail = &dst; - while (*tail != nullptr) tail = &(*tail)->next; - *tail = el; - + dst.push_back(std::move(el)); RemoveDuplicatesFromGRFConfigList(dst); } @@ -448,7 +426,7 @@ GRFListCompatibility IsGoodGRFConfigList(GRFConfigList &grfconfig) { 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); if (f == nullptr || HasBit(f->flags, GCF_INVALID)) { /* 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. */ if (_exit_game) return false; - GRFConfig *c = new GRFConfig(filename.c_str() + basepath_length); - - bool added = true; + bool added = false; + auto c = std::make_unique(filename.substr(basepath_length)); + GRFConfig *grfconfig = c.get(); if (FillGRFDetails(*c, false)) { - if (_all_grfs == nullptr) { - _all_grfs = c; - } else { - /* 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; - } + 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.push_back(std::move(c)); + added = true; } - } else { - added = false; } this->num_scanned++; const char *name = nullptr; - if (c->name != nullptr) name = GetGRFStringFromGRFText(c->name); - if (name == nullptr) name = c->filename.c_str(); + if (grfconfig->name != nullptr) name = GetGRFStringFromGRFText(grfconfig->name); + if (name == nullptr) name = grfconfig->filename.c_str(); UpdateNewGRFScanStatus(this->num_scanned, name); 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; } @@ -591,7 +542,7 @@ bool GRFFileScanner::AddFile(const std::string &filename, size_t basepath_length * @param c2 the second GRFConfig * * @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 const &c1, std::unique_ptr const &c2) { return StrNaturalCompare(c1->GetName(), c2->GetName()) < 0; } @@ -609,29 +560,8 @@ void DoScanNewGRFFiles(NewGRFScanCallback *callback) uint num = GRFFileScanner::DoScan(); Debug(grf, 1, "Scan complete, found {} files", num); - if (num != 0 && _all_grfs != nullptr) { - /* Sort the linked list using quicksort. - * For that we first have to make an array, then sort and - * then remake the linked list. */ - std::vector 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(); - } + std::ranges::sort(_all_grfs, GRFSorter); + NetworkAfterNewGRFScan(); /* Yes... these are the NewGRF windows */ 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)); 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 (!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" */ - if (md5sum != nullptr || mode == FGCM_ANY) return c; + if (md5sum != nullptr || mode == FGCM_ANY) return c.get(); /* Skip incompatible stuff, unless explicitly allowed */ if (mode != FGCM_NEWEST && HasBit(c->flags, GCF_INVALID)) continue; /* check version compatibility */ if (mode == FGCM_COMPATIBLE && !c->IsCompatible(desired_version)) continue; /* 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; @@ -693,11 +623,8 @@ const GRFConfig *FindGRFConfig(uint32_t grfid, FindGRFConfigMode mode, const MD5 */ GRFConfig *GetGRFConfig(uint32_t grfid, uint32_t mask) { - GRFConfig *c; - - for (c = _grfconfig; c != nullptr; c = c->next) { - if ((c->ident.grfid & mask) == (grfid & mask)) return 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(); return nullptr; } diff --git a/src/newgrf_config.h b/src/newgrf_config.h index 27bc906207..b2554ebc8b 100644 --- a/src/newgrf_config.h +++ b/src/newgrf_config.h @@ -180,8 +180,6 @@ struct GRFConfig { std::vector> param_info; ///< NOSAVE: extra information about the parameters std::vector param; ///< GRF parameters - struct GRFConfig *next = nullptr; ///< NOSAVE: Next item in the linked list - bool IsCompatible(uint32_t old_version) const; void SetParams(std::span pars); void CopyParams(const GRFConfig &src); @@ -199,7 +197,7 @@ struct GRFConfig { void FinalizeParameterInfo(); }; -using GRFConfigList = GRFConfig *; +using GRFConfigList = std::vector>; /** Method to find GRFs using FindGRFConfig */ 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); void CopyGRFConfigList(GRFConfigList &dst, const GRFConfigList &src, bool init_only); void AppendStaticGRFConfigs(GRFConfigList &dst); -void AppendToGRFConfigList(GRFConfigList &dst, GRFConfig *el); +void AppendToGRFConfigList(GRFConfigList &dst, std::unique_ptr &&el); void ClearGRFConfigList(GRFConfigList &config); void ResetGRFConfig(bool defaults); GRFListCompatibility IsGoodGRFConfigList(GRFConfigList &grfconfig); diff --git a/src/newgrf_gui.cpp b/src/newgrf_gui.cpp index 517849e4fd..b3691415cc 100644 --- a/src/newgrf_gui.cpp +++ b/src/newgrf_gui.cpp @@ -47,7 +47,7 @@ void ShowNewGRFError() /* Do not show errors when entering the main screen */ 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 */ 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 GrfIdMap; ///< Map of grfid to the /** * 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. */ -static void FillGrfidMap(const GRFConfig *c, GrfIdMap *grfid_map) +static void FillGrfidMap(const GRFConfigList &lst, GrfIdMap &grfid_map) { - while (c != nullptr) { - grfid_map->emplace(c->ident.grfid, c); - c = c->next; + for (const auto &c : lst) { + grfid_map.emplace(c->ident.grfid, c.get()); } } @@ -617,10 +616,10 @@ struct NewGRFWindow : public Window, NewGRFScanCallback { 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. - 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 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. @@ -631,20 +630,18 @@ struct NewGRFWindow : public Window, NewGRFScanCallback { Scrollbar *vscroll; 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_pos = -1; this->active_sel = nullptr; - this->actives = nullptr; - this->orig_list = orig_list; this->editable = editable; this->execute = execute; this->show_params = show_params; this->preset = -1; this->active_over = -1; - CopyGRFConfigList(this->actives, *orig_list, false); + CopyGRFConfigList(this->actives, orig_list, false); this->grf_presets = GetGRFPresetList(); this->CreateNestedTree(); @@ -679,7 +676,7 @@ struct NewGRFWindow : public Window, NewGRFScanCallback { CloseWindowByClass(WC_SAVE_PRESET); 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); ReloadNewGRFData(); } @@ -687,10 +684,13 @@ struct NewGRFWindow : public Window, NewGRFScanCallback { this->Window::Close(); } - ~NewGRFWindow() + int GetCurrentActivePosition() const { - /* Remove the temporary copy of grf-list used in window */ - ClearGRFConfigList(this->actives); + if (this->active_sel != nullptr) { + 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(std::distance(std::begin(this->actives), it)); + } + return -1; } /** @@ -700,9 +700,9 @@ struct NewGRFWindow : public Window, NewGRFScanCallback { bool CanUpgradeCurrent() { 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); if (iter != grfid_map.end() && a->version > iter->second->version) return true; } @@ -713,29 +713,27 @@ struct NewGRFWindow : public Window, NewGRFScanCallback { void UpgradeCurrent() { 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); if (iter == grfid_map.end() || iter->second->version >= a->version) continue; - GRFConfig **c = &this->actives; - while (*c != iter->second) c = &(*c)->next; - GRFConfig *d = new GRFConfig(*a); - d->next = (*c)->next; + auto c = std::ranges::find_if(this->actives, [&iter](const auto &grfconfig) { return grfconfig.get() == iter->second; }); + assert(c != std::end(this->actives)); + auto d = std::make_unique(*iter->second); if (d->IsCompatible((*c)->version)) { d->CopyParams(**c); } else { d->SetParameterDefaults(); } - if (this->active_sel == *c) { + if (this->active_sel == c->get()) { CloseWindowByClass(WC_GRF_PARAMETERS); CloseWindowByClass(WC_TEXTFILE); this->active_sel = nullptr; } - delete *c; - *c = d; - iter->second = d; + *c = std::move(d); + iter->second = c->get(); } } @@ -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; 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)) { const char *text = c->GetName(); - bool h = (this->active_sel == c); + bool h = (this->active_sel == c.get()); PaletteID pal = this->GetPalette(*c); if (h) { GfxFillRect(br.left, tr.top, br.right, tr.top + step_height - 1, PC_DARK_BLUE); } else if (i == this->active_over) { /* Get index of current selection. */ - int active_sel_pos = 0; - for (GRFConfig *c = this->actives; c != nullptr && c != this->active_sel; c = c->next, active_sel_pos++) {} + int active_sel_pos = this->GetCurrentActivePosition(); if (active_sel_pos != this->active_over) { 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); @@ -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); tr.top += step_height; } + i++; } 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); @@ -986,17 +984,12 @@ struct NewGRFWindow : public Window, NewGRFScanCallback { case WID_NS_MOVE_UP: { // Move GRF up if (this->active_sel == nullptr || !this->editable) break; - int pos = 0; - for (GRFConfig **pc = &this->actives; *pc != nullptr; pc = &(*pc)->next, pos++) { - GRFConfig *c = *pc; - if (c->next == this->active_sel) { - c->next = this->active_sel->next; - this->active_sel->next = c; - *pc = this->active_sel; - break; - } - } - this->vscroll->ScrollTowards(pos); + int pos = this->GetCurrentActivePosition(); + if (pos <= 0) break; + + std::swap(this->actives[pos - 1], this->actives[pos]); + + this->vscroll->ScrollTowards(pos - 1); this->preset = -1; this->InvalidateData(GOID_NEWGRF_LIST_EDITED); break; @@ -1005,17 +998,12 @@ struct NewGRFWindow : public Window, NewGRFScanCallback { case WID_NS_MOVE_DOWN: { // Move GRF down if (this->active_sel == nullptr || !this->editable) break; - int pos = 1; // Start at 1 as we swap the selected newgrf with the next one - for (GRFConfig **pc = &this->actives; *pc != nullptr; pc = &(*pc)->next, pos++) { - GRFConfig *c = *pc; - if (c == this->active_sel) { - *pc = c->next; - c->next = c->next->next; - (*pc)->next = c; - break; - } - } - this->vscroll->ScrollTowards(pos); + int pos = this->GetCurrentActivePosition(); + if (pos == -1 || static_cast(pos) >= this->actives.size() - 1) break; + + std::swap(this->actives[pos], this->actives[pos + 1]); + + this->vscroll->ScrollTowards(pos + 1); this->preset = -1; this->InvalidateData(GOID_NEWGRF_LIST_EDITED); break; @@ -1024,16 +1012,17 @@ struct NewGRFWindow : public Window, NewGRFScanCallback { case WID_NS_FILE_LIST: { // Select an active GRF. ResetObjectToPlace(); + const GRFConfig *old_sel = this->active_sel; uint i = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_NS_FILE_LIST, WidgetDimensions::scaled.framerect.top); - - GRFConfig *c; - for (c = this->actives; c != nullptr && i > 0; c = c->next, i--) {} - - if (this->active_sel != c) { + if (i < this->actives.size()) { + this->active_sel = this->actives[i].get(); + } else { + this->active_sel = nullptr; + } + if (this->active_sel != old_sel) { CloseWindowByClass(WC_GRF_PARAMETERS); CloseWindowByClass(WC_TEXTFILE); } - this->active_sel = c; this->avail_sel = nullptr; this->avail_pos = -1; @@ -1052,23 +1041,18 @@ struct NewGRFWindow : public Window, NewGRFScanCallback { CloseWindowByClass(WC_TEXTFILE); /* Choose the next GRF file to be the selected file. */ - GRFConfig *newsel = this->active_sel->next; - for (GRFConfig **pc = &this->actives; *pc != nullptr; pc = &(*pc)->next) { - 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; + int pos = this->GetCurrentActivePosition(); + if (pos < 0) break; - if (c == this->active_sel) { - if (newsel == c) newsel = nullptr; - - *pc = c->next; - delete c; - break; - } + auto it = std::next(std::begin(this->actives), pos); + it = this->actives.erase(it); + if (this->actives.empty()) { + this->active_sel = nullptr; + } else if (it == std::end(this->actives)) { + this->active_sel = this->actives.back().get(); + } else { + this->active_sel = it->get(); } - - this->active_sel = newsel; this->preset = -1; this->avail_pos = -1; this->avail_sel = nullptr; @@ -1078,7 +1062,7 @@ struct NewGRFWindow : public Window, NewGRFScanCallback { } case WID_NS_UPGRADE: { // Upgrade GRF. - if (!this->editable || this->actives == nullptr) break; + if (!this->editable || this->actives.empty()) break; UpgradeCurrent(); this->InvalidateData(GOID_NEWGRF_LIST_EDITED); 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); this->active_sel = nullptr; CloseWindowByClass(WC_GRF_PARAMETERS); - if (it != this->avails.end()) { + if (it != std::end(this->avails)) { if (this->avail_sel != *it) CloseWindowByClass(WC_TEXTFILE); this->avail_sel = *it; - this->avail_pos = it - this->avails.begin(); + this->avail_pos = static_cast(std::distance(std::begin(this->avails), it)); } this->InvalidateData(); if (click_count == 1) { @@ -1120,7 +1104,7 @@ struct NewGRFWindow : public Window, NewGRFScanCallback { NewGRFConfirmationCallback ); } else { - CopyGRFConfigList(*this->orig_list, this->actives, true); + CopyGRFConfigList(this->orig_list, this->actives, true); ResetGRFConfig(false); ReloadNewGRFData(); this->InvalidateData(GOID_NEWGRF_CHANGES_APPLIED); @@ -1216,10 +1200,7 @@ struct NewGRFWindow : public Window, NewGRFScanCallback { void UpdateScrollBars() { /* Update scrollbars */ - int i = 0; - 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. + this->vscroll->SetCount(this->actives.size() + 1); // Reserve empty space for drag and drop handling. if (this->avail_pos >= 0) this->vscroll2->ScrollTowards(this->avail_pos); } @@ -1239,20 +1220,14 @@ struct NewGRFWindow : public Window, NewGRFScanCallback { case GOID_NEWGRF_RESCANNED: /* Search the list for items that are now found and mark them as such. */ - for (GRFConfig **l = &this->actives; *l != nullptr; l = &(*l)->next) { - GRFConfig *c = *l; + for (auto &c : this->actives) { bool compatible = HasBit(c->flags, GCF_COMPATIBLE); if (c->status != GCS_NOT_FOUND && !compatible) continue; 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; - *l = new GRFConfig(*f); - (*l)->next = c->next; - - if (this->active_sel == c) this->active_sel = *l; - - delete c; + c = std::make_unique(*f); } this->avails.ForceRebuild(); @@ -1289,7 +1264,7 @@ struct NewGRFWindow : public Window, NewGRFScanCallback { 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_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; this->SetWidgetsDisabledState(disable_all, @@ -1311,15 +1286,15 @@ struct NewGRFWindow : public Window, NewGRFScanCallback { if (!disable_all) { /* 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->next == nullptr) this->DisableWidget(WID_NS_MOVE_DOWN); + if (this->active_sel == this->actives.front().get()) this->DisableWidget(WID_NS_MOVE_UP); + if (this->active_sel == this->actives.back().get()) this->DisableWidget(WID_NS_MOVE_DOWN); } this->SetWidgetDisabledState(WID_NS_PRESET_DELETE, this->preset == -1); bool has_missing = 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_compatible |= HasBit(c->flags, GCF_COMPATIBLE); } @@ -1374,24 +1349,16 @@ struct NewGRFWindow : public Window, NewGRFScanCallback { if (widget == WID_NS_FILE_LIST) { if (this->active_sel != nullptr) { - /* Get pointer to the selected file in the active list. */ - int from_pos = 0; - GRFConfig **from_prev; - for (from_prev = &this->actives; *from_prev != this->active_sel; from_prev = &(*from_prev)->next, from_pos++) {} + int from_pos = this->GetCurrentActivePosition(); /* 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); if (to_pos != from_pos) { // Don't move NewGRF file over itself. - /* Get pointer to destination position. */ - 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++) {} + if (to_pos > from_pos) ++to_pos; - /* Detach NewGRF file from its original position. */ - *from_prev = this->active_sel->next; - - /* Attach NewGRF file to its new position. */ - this->active_sel->next = *to_prev; - *to_prev = this->active_sel; + auto from = std::next(std::begin(this->actives), from_pos); + auto to = std::next(std::begin(this->actives), to_pos); + Slide(from, std::next(from), to); this->vscroll->ScrollTowards(to_pos); this->preset = -1; @@ -1470,13 +1437,11 @@ private: this->avails.clear(); - for (const GRFConfig *c = _all_grfs; c != nullptr; c = c->next) { - bool found = false; - 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; + for (const auto &c : _all_grfs) { + if (std::ranges::any_of(this->actives, [&c](const auto &gc) { return gc->ident.HasGrfIdentifier(c->ident.grfid, &c->ident.md5sum); })) continue; if (_settings_client.gui.newgrf_show_old_versions) { - this->avails.push_back(c); + this->avails.push_back(c.get()); } else { 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. */ @@ -1490,7 +1455,7 @@ private: * show that NewGRF!. */ 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); - uint count = 0; - GRFConfig **entry = nullptr; - 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; + /* Get number of non-static NewGRFs. */ + size_t count = std::ranges::count_if(this->actives, [](const auto &gc) { return !HasBit(gc->flags, GCF_STATIC); }); if (count >= NETWORK_MAX_GRF_COUNT) { ShowErrorMessage(STR_NEWGRF_TOO_MANY_NEWGRFS, INVALID_STRING_ID, WL_INFO); return false; } - GRFConfig *c = new GRFConfig(*this->avail_sel); // Copy GRF details from scanned list. - c->SetParameterDefaults(); + /* Check for duplicate GRF ID. */ + 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. */ - c->next = *entry; - *entry = c; + auto entry = (ins_pos >= 0 && static_cast(ins_pos) < std::size(this->actives)) + ? std::next(std::begin(this->actives), ins_pos) + : std::end(this->actives); + + /* Copy GRF details from scanned list. */ + entry = this->actives.insert(entry, std::make_unique(*this->avail_sel)); + (*entry)->SetParameterDefaults(); /* Select next (or previous, if last one) item in the list. */ 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 */ 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; ContentInfo *ci = new ContentInfo(); @@ -1983,17 +1944,24 @@ static void NewGRFConfirmationCallback(Window *w, bool confirmed) _gamelog.StartAction(GLAT_GRF); _gamelog.GRFUpdate(_grfconfig, nw->actives); // log GRF changes - CopyGRFConfigList(*nw->orig_list, nw->actives, false); + CopyGRFConfigList(nw->orig_list, nw->actives, false); ReloadNewGRFData(); _gamelog.StopAction(); /* Show new, updated list */ - GRFConfig *c; - int i = 0; - for (c = nw->actives; c != nullptr && c != nw->active_sel; c = c->next, i++) {} - CopyGRFConfigList(nw->actives, *nw->orig_list, false); - for (c = nw->actives; c != nullptr && i > 0; c = c->next, i--) {} - nw->active_sel = c; + int pos = nw->GetCurrentActivePosition(); + + CopyGRFConfigList(nw->actives, nw->orig_list, false); + + if (nw->active_sel != nullptr) { + /* Set current selection from position */ + if (static_cast(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->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) { 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. */ diff --git a/src/openttd.cpp b/src/openttd.cpp index 803cfbdf70..03ad68ba49 100644 --- a/src/openttd.cpp +++ b/src/openttd.cpp @@ -242,7 +242,7 @@ static void WriteSavegameInfo(const std::string &name) message += "NewGRFs:\n"; 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), FormatArrayAsHex(HasBit(c->flags, GCF_COMPATIBLE) ? c->original_md5sum : c->ident.md5sum), c->filename); } diff --git a/src/saveload/afterload.cpp b/src/saveload/afterload.cpp index 35d493a9c9..20eb12dd1c 100644 --- a/src/saveload/afterload.cpp +++ b/src/saveload/afterload.cpp @@ -369,9 +369,7 @@ static void CDECL HandleSavegameLoadCrash(int signum) message.reserve(1024); 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 = HasBit(c->flags, GCF_COMPATIBLE) || c->status == GCS_NOT_FOUND; - } + _saveload_crash_with_missing_newgrfs = std::ranges::any_of(_grfconfig, [](const auto &c) { return HasBit(c->flags, GCF_COMPATIBLE) || c->status == GCS_NOT_FOUND; }); if (_saveload_crash_with_missing_newgrfs) { message += @@ -387,7 +385,7 @@ static void CDECL HandleSavegameLoadCrash(int signum) "Please load the savegame with the appropriate NewGRFs installed.\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)) { 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", @@ -707,7 +705,7 @@ bool AfterLoadGame() /* Check if all NewGRFs are present, we are very strict in MP mode */ 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) { _gamelog.GRFRemove(c->ident.grfid); } else if (HasBit(c->flags, GCF_COMPATIBLE)) { diff --git a/src/saveload/newgrf_sl.cpp b/src/saveload/newgrf_sl.cpp index 13569c749c..6de82bb511 100644 --- a/src/saveload/newgrf_sl.cpp +++ b/src/saveload/newgrf_sl.cpp @@ -91,11 +91,11 @@ struct NGRFChunkHandler : ChunkHandler { 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; this->SaveParameters(*c); SlSetArrayIndex(index++); - SlObject(c, description); + SlObject(c.get(), description); } } @@ -112,11 +112,11 @@ struct NGRFChunkHandler : ChunkHandler { ClearGRFConfigList(grfconfig); while (SlIterateArray() != -1) { - GRFConfig *c = new GRFConfig(); - SlObject(c, slt); + auto c = std::make_unique(); + SlObject(c.get(), slt); if (IsSavegameVersionBefore(SLV_101)) c->SetSuitablePalette(); this->LoadParameters(*c); - AppendToGRFConfigList(grfconfig, c); + AppendToGRFConfigList(grfconfig, std::move(c)); } } @@ -126,7 +126,7 @@ struct NGRFChunkHandler : ChunkHandler { if (_game_mode == GM_MENU) { /* 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) */ ResetGRFConfig(false); diff --git a/src/saveload/oldloader_sl.cpp b/src/saveload/oldloader_sl.cpp index 1c5aa8be16..94740de7a2 100644 --- a/src/saveload/oldloader_sl.cpp +++ b/src/saveload/oldloader_sl.cpp @@ -1560,11 +1560,11 @@ static bool LoadTTDPatchExtraChunks(LoadgameState *ls, int) uint32_t grfid = ReadUint32(ls); if (ReadByte(ls) == 1) { - GRFConfig *c = new GRFConfig("TTDP game, no information"); + auto c = std::make_unique("TTDP game, no information"); c->ident.grfid = grfid; - AppendToGRFConfigList(_grfconfig, c); Debug(oldloader, 3, "TTDPatch game using GRF file with GRFID {:08X}", std::byteswap(c->ident.grfid)); + AppendToGRFConfigList(_grfconfig, std::move(c)); } len -= 5; } diff --git a/src/screenshot.cpp b/src/screenshot.cpp index f48838b167..01dec7a1f1 100644 --- a/src/screenshot.cpp +++ b/src/screenshot.cpp @@ -307,8 +307,10 @@ static bool MakePNGImage(const char *name, ScreenshotCallback *callb, void *user message.reserve(1024); fmt::format_to(std::back_inserter(message), "Graphics set: {} ({})\n", BaseGraphics::GetUsedSet()->name, BaseGraphics::GetUsedSet()->version); message += "NewGRFs:\n"; - for (const GRFConfig *c = _game_mode == GM_MENU ? nullptr : _grfconfig; c != nullptr; c = c->next) { - fmt::format_to(std::back_inserter(message), "{:08X} {} {}\n", std::byteswap(c->ident.grfid), FormatArrayAsHex(c->ident.md5sum), c->filename); + if (_game_mode != GM_MENU) { + 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"; for (const Company *c : Company::Iterate()) { diff --git a/src/script/api/script_newgrf.cpp b/src/script/api/script_newgrf.cpp index 7548081036..e04b7a6b4e 100644 --- a/src/script/api/script_newgrf.cpp +++ b/src/script/api/script_newgrf.cpp @@ -17,7 +17,7 @@ ScriptNewGRFList::ScriptNewGRFList() { - for (auto c = _grfconfig; c != nullptr; c = c->next) { + for (const auto &c : _grfconfig) { if (!HasBit(c->flags, GCF_STATIC)) { this->AddItem(std::byteswap(c->ident.grfid)); } @@ -28,24 +28,15 @@ ScriptNewGRFList::ScriptNewGRFList() { grfid = std::byteswap(GB(grfid, 0, 32)); // Match people's expectations. - for (auto c = _grfconfig; c != nullptr; c = c->next) { - if (!HasBit(c->flags, GCF_STATIC) && c->ident.grfid == grfid) { - return true; - } - } - - return false; + return std::ranges::any_of(_grfconfig, [grfid](const auto &c) { return !HasBit(c->flags, GCF_STATIC) && c->ident.grfid == grfid; }); } /* static */ SQInteger ScriptNewGRF::GetVersion(SQInteger grfid) { grfid = std::byteswap(GB(grfid, 0, 32)); // Match people's expectations. - for (auto c = _grfconfig; c != nullptr; c = c->next) { - if (!HasBit(c->flags, GCF_STATIC) && c->ident.grfid == grfid) { - return c->version; - } - } + auto it = std::ranges::find_if(_grfconfig, [grfid](const auto &c) { return !HasBit(c->flags, GCF_STATIC) && c->ident.grfid == grfid; }); + if (it != std::end(_grfconfig)) return (*it)->version; return 0; } @@ -54,11 +45,8 @@ ScriptNewGRFList::ScriptNewGRFList() { grfid = std::byteswap(GB(grfid, 0, 32)); // Match people's expectations. - for (auto c = _grfconfig; c != nullptr; c = c->next) { - if (!HasBit(c->flags, GCF_STATIC) && c->ident.grfid == grfid) { - return c->GetName(); - } - } + auto it = std::ranges::find_if(_grfconfig, [grfid](const auto &c) { return !HasBit(c->flags, GCF_STATIC) && c->ident.grfid == grfid; }); + if (it != std::end(_grfconfig)) return (*it)->GetName(); return std::nullopt; } diff --git a/src/settings.cpp b/src/settings.cpp index b3430b62eb..83269f3ab6 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -1048,17 +1048,16 @@ static void GraphicsSetLoadConfig(IniFile &ini) * @param grpname Group name containing the configuration of the GRF. * @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); - GRFConfig *first = nullptr; - GRFConfig **curr = &first; + GRFConfigList list; - if (group == nullptr) return nullptr; + if (group == nullptr) return list; uint num_grfs = 0; for (const IniItem &item : group->items) { - GRFConfig *c = nullptr; + std::unique_ptr c{}; std::array grfid_buf; 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); if (has_md5sum) { const GRFConfig *s = FindGRFConfig(grfid, FGCM_EXACT, &md5sum); - if (s != nullptr) c = new GRFConfig(*s); + if (s != nullptr) c = std::make_unique(*s); } if (c == nullptr && !FioCheckFileExists(std::string(item_name), NEWGRF_DIR)) { const GRFConfig *s = FindGRFConfig(grfid, FGCM_NEWEST_VALID); - if (s != nullptr) c = new GRFConfig(*s); + if (s != nullptr) c = std::make_unique(*s); } } } std::string filename = std::string(item_name); - if (c == nullptr) c = new GRFConfig(filename); + if (c == nullptr) c = std::make_unique(filename); /* Parse parameters */ 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); ShowErrorMessage(STR_CONFIG_ERROR, STR_CONFIG_ERROR_INVALID_GRF, WL_CRITICAL); - delete c; continue; } /* Check for duplicate GRFID (will also check for duplicate filenames) */ - bool duplicate = false; - for (const GRFConfig *gc = first; gc != nullptr; gc = gc->next) { - if (gc->ident.grfid == c->ident.grfid) { - SetDParamStr(0, c->filename); - SetDParamStr(1, gc->filename); - ShowErrorMessage(STR_CONFIG_ERROR, STR_CONFIG_ERROR_DUPLICATE_GRFID, WL_CRITICAL); - duplicate = true; - break; - } - } - if (duplicate) { - delete c; + auto found = std::ranges::find_if(list, [&c](const auto &gc) { return gc->ident.grfid == c->ident.grfid; }); + if (found != std::end(list)) { + SetDParamStr(0, c->filename); + SetDParamStr(1, (*found)->filename); + ShowErrorMessage(STR_CONFIG_ERROR, STR_CONFIG_ERROR_DUPLICATE_GRFID, WL_CRITICAL); continue; } @@ -1153,11 +1144,10 @@ static GRFConfig *GRFLoadConfig(const IniFile &ini, const char *grpname, bool is } /* Add item to list */ - *curr = c; - curr = &c->next; + list.push_back(std::move(c)); } - return first; + return list; } static IniFileVersion LoadVersionFromConfig(const IniFile &ini) @@ -1247,13 +1237,12 @@ static void GraphicsSetSaveConfig(IniFile &ini) } /* 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); 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), FormatArrayAsHex(c->ident.md5sum), c->filename); group.GetOrCreateItem(key).SetValue(GRFBuildParamList(*c)); @@ -1558,13 +1547,13 @@ StringList GetGRFPresetList() * @return NewGRF configuration. * @see GetGRFPresetList */ -GRFConfig *LoadGRFPresetFromConfig(const char *config_name) +GRFConfigList LoadGRFPresetFromConfig(const char *config_name) { std::string section("preset-"); section += config_name; ConfigIniFile ini(_config_file); - GRFConfig *config = GRFLoadConfig(ini, section.c_str(), false); + GRFConfigList config = GRFLoadConfig(ini, section.c_str(), false); return config; } @@ -1575,7 +1564,7 @@ GRFConfig *LoadGRFPresetFromConfig(const char *config_name) * @param config NewGRF configuration to save. * @see GetGRFPresetList */ -void SaveGRFPresetToConfig(const char *config_name, GRFConfig *config) +void SaveGRFPresetToConfig(const char *config_name, GRFConfigList &config) { std::string section("preset-"); section += config_name; diff --git a/src/settings_func.h b/src/settings_func.h index 490ce9605f..935cf2d82b 100644 --- a/src/settings_func.h +++ b/src/settings_func.h @@ -12,6 +12,7 @@ #include "company_type.h" #include "string_type.h" +#include "newgrf_config.h" struct IniFile; @@ -27,8 +28,8 @@ void IniLoadWindowSettings(IniFile &ini, const char *grpname, void *desc); void IniSaveWindowSettings(IniFile &ini, const char *grpname, void *desc); StringList GetGRFPresetList(); -struct GRFConfig *LoadGRFPresetFromConfig(const char *config_name); -void SaveGRFPresetToConfig(const char *config_name, struct GRFConfig *config); +GRFConfigList LoadGRFPresetFromConfig(const char *config_name); +void SaveGRFPresetToConfig(const char *config_name, GRFConfigList &config); void DeleteGRFPresetFromConfig(const char *config_name); void SetDefaultCompanySettings(CompanyID cid); diff --git a/src/survey.cpp b/src/survey.cpp index ea87304859..313606361b 100644 --- a/src/survey.cpp +++ b/src/survey.cpp @@ -354,7 +354,7 @@ void SurveyTimers(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 &grf = survey[grfid];