From 155d7de132d921869441fd30b84e0da2d1dd6255 Mon Sep 17 00:00:00 2001 From: Rubidium Date: Sat, 8 Feb 2025 15:02:13 +0100 Subject: [PATCH] Codechange: change Source into a class with conversion helpers A Source is either a CompanyID (Headquarters), IndustryID or TownID. When making those types stronger a lot of casts would be needed, but with these simple helpers the intent is shown more clearly. --- src/CMakeLists.txt | 1 + src/cargo_type.h | 19 ------------ src/cargomonitor.cpp | 6 ++-- src/cargopacket.cpp | 2 +- src/cargopacket.h | 6 ++-- src/economy.cpp | 2 +- src/economy_func.h | 1 + src/saveload/afterload.cpp | 10 +++---- src/script/api/script_subsidy.cpp | 4 +-- src/source_type.h | 48 +++++++++++++++++++++++++++++++ src/subsidy.cpp | 32 ++++++++++----------- src/subsidy_base.h | 1 + src/subsidy_cmd.h | 1 + src/subsidy_gui.cpp | 8 +++--- 14 files changed, 87 insertions(+), 54 deletions(-) create mode 100644 src/source_type.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 599d45aa5e..05db4c1d05 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -427,6 +427,7 @@ add_files( soundloader_type.h soundloader_raw.cpp soundloader_wav.cpp + source_type.h sprite.cpp sprite.h spritecache.cpp diff --git a/src/cargo_type.h b/src/cargo_type.h index 1f1ab69585..9f882bdd3e 100644 --- a/src/cargo_type.h +++ b/src/cargo_type.h @@ -130,23 +130,4 @@ struct CargoArray : std::array { } }; - -/** Types of cargo source and destination */ -enum class SourceType : uint8_t { - Industry, ///< Source/destination is an industry - Town, ///< Source/destination is a town - Headquarters, ///< Source/destination are company headquarters -}; - -typedef uint16_t SourceID; ///< Contains either industry ID, town ID or company ID (or INVALID_SOURCE) -static const SourceID INVALID_SOURCE = 0xFFFF; ///< Invalid/unknown index of source - -/** A location from where cargo can come from (or go to). Specifically industries, towns and headquarters. */ -struct Source { - SourceID id; ///< Index of industry/town/HQ, INVALID_SOURCE if unknown/invalid. - SourceType type; ///< Type of \c source_id. - - auto operator<=>(const Source &source) const = default; -}; - #endif /* CARGO_TYPE_H */ diff --git a/src/cargomonitor.cpp b/src/cargomonitor.cpp index 86e459526c..046e0b2e0b 100644 --- a/src/cargomonitor.cpp +++ b/src/cargomonitor.cpp @@ -118,17 +118,17 @@ void AddCargoDelivery(CargoType cargo_type, CompanyID company, uint32_t amount, { if (amount == 0) return; - if (src.id != INVALID_SOURCE) { + if (src.IsValid()) { /* Handle pickup update. */ switch (src.type) { case SourceType::Industry: { - CargoMonitorID num = EncodeCargoIndustryMonitor(company, cargo_type, src.id); + CargoMonitorID num = EncodeCargoIndustryMonitor(company, cargo_type, src.ToIndustryID()); CargoMonitorMap::iterator iter = _cargo_pickups.find(num); if (iter != _cargo_pickups.end()) iter->second += amount; break; } case SourceType::Town: { - CargoMonitorID num = EncodeCargoTownMonitor(company, cargo_type, src.id); + CargoMonitorID num = EncodeCargoTownMonitor(company, cargo_type, src.ToTownID()); CargoMonitorMap::iterator iter = _cargo_pickups.find(num); if (iter != _cargo_pickups.end()) iter->second += amount; break; diff --git a/src/cargopacket.cpp b/src/cargopacket.cpp index 03846a1d5f..6117f1f5e9 100644 --- a/src/cargopacket.cpp +++ b/src/cargopacket.cpp @@ -132,7 +132,7 @@ void CargoPacket::Reduce(uint count) /* static */ void CargoPacket::InvalidateAllFrom(Source src) { for (CargoPacket *cp : CargoPacket::Iterate()) { - if (cp->source == src) cp->source.id = INVALID_SOURCE; + if (cp->source == src) cp->source.MakeInvalid(); } } diff --git a/src/cargopacket.h b/src/cargopacket.h index e9394b089f..f0983b0786 100644 --- a/src/cargopacket.h +++ b/src/cargopacket.h @@ -15,6 +15,7 @@ #include "station_type.h" #include "order_type.h" #include "cargo_type.h" +#include "source_type.h" #include "vehicle_type.h" #include "core/multimap.hpp" #include "saveload/saveload.h" @@ -53,7 +54,7 @@ private: TileIndex source_xy = INVALID_TILE; ///< The origin of the cargo. Vector travelled{0, 0}; ///< If cargo is in station: the vector from the unload tile to the source tile. If in vehicle: an intermediate value. - Source source{INVALID_SOURCE, SourceType::Industry}; ///< Source of the cargo + Source source{Source::Invalid, SourceType::Industry}; ///< Source of the cargo #ifdef WITH_ASSERT bool in_vehicle = false; ///< NOSAVE: Whether this cargo is in a vehicle or not. @@ -504,9 +505,8 @@ public: { return cp1->source_xy == cp2->source_xy && cp1->periods_in_transit == cp2->periods_in_transit && - cp1->source.type == cp2->source.type && cp1->first_station == cp2->first_station && - cp1->source.id == cp2->source.id; + cp1->source == cp2->source; } }; diff --git a/src/economy.cpp b/src/economy.cpp index 8bbe2b9e5f..a4ec35c19b 100644 --- a/src/economy.cpp +++ b/src/economy.cpp @@ -1114,7 +1114,7 @@ static Money DeliverGoods(int num_pieces, CargoType cargo_type, StationID dest, Station *st = Station::Get(dest); /* Give the goods to the industry. */ - uint accepted_ind = DeliverGoodsToIndustry(st, cargo_type, num_pieces, src.type == SourceType::Industry ? src.id : INVALID_INDUSTRY, company->index); + uint accepted_ind = DeliverGoodsToIndustry(st, cargo_type, num_pieces, src.type == SourceType::Industry ? src.ToIndustryID() : INVALID_INDUSTRY, company->index); /* If this cargo type is always accepted, accept all */ uint accepted_total = HasBit(st->always_accepted, cargo_type) ? num_pieces : accepted_ind; diff --git a/src/economy_func.h b/src/economy_func.h index 9551cb6087..993b88add2 100644 --- a/src/economy_func.h +++ b/src/economy_func.h @@ -16,6 +16,7 @@ #include "vehicle_type.h" #include "company_type.h" #include "settings_type.h" +#include "source_type.h" #include "core/random_func.hpp" void ResetPriceBaseMultipliers(); diff --git a/src/saveload/afterload.cpp b/src/saveload/afterload.cpp index e79e491ddd..bfeb97c42b 100644 --- a/src/saveload/afterload.cpp +++ b/src/saveload/afterload.cpp @@ -2280,19 +2280,19 @@ bool AfterLoadGame() case TAE_MAIL: /* Town -> Town */ s->src.type = s->dst.type = SourceType::Town; - if (Town::IsValidID(s->src.id) && Town::IsValidID(s->dst.id)) continue; + if (Town::IsValidID(s->src.ToTownID()) && Town::IsValidID(s->dst.ToTownID())) continue; break; case TAE_GOODS: case TAE_FOOD: /* Industry -> Town */ s->src.type = SourceType::Industry; s->dst.type = SourceType::Town; - if (Industry::IsValidID(s->src.id) && Town::IsValidID(s->dst.id)) continue; + if (Industry::IsValidID(s->src.ToIndustryID()) && Town::IsValidID(s->dst.ToTownID())) continue; break; default: /* Industry -> Industry */ s->src.type = s->dst.type = SourceType::Industry; - if (Industry::IsValidID(s->src.id) && Industry::IsValidID(s->dst.id)) continue; + if (Industry::IsValidID(s->src.ToIndustryID()) && Industry::IsValidID(s->dst.ToIndustryID())) continue; break; } } else { @@ -2310,8 +2310,8 @@ bool AfterLoadGame() if (ss != nullptr && sd != nullptr && ss->owner == sd->owner && Company::IsValidID(ss->owner)) { s->src.type = s->dst.type = SourceType::Town; - s->src.id = ss->town->index; - s->dst.id = sd->town->index; + s->src.SetIndex(ss->town->index); + s->dst.SetIndex(sd->town->index); s->awarded = ss->owner; continue; } diff --git a/src/script/api/script_subsidy.cpp b/src/script/api/script_subsidy.cpp index 15a0990fab..9d2ba601b2 100644 --- a/src/script/api/script_subsidy.cpp +++ b/src/script/api/script_subsidy.cpp @@ -82,7 +82,7 @@ /* static */ SQInteger ScriptSubsidy::GetSourceIndex(SubsidyID subsidy_id) { - if (!IsValidSubsidy(subsidy_id)) return INVALID_SOURCE; + if (!IsValidSubsidy(subsidy_id)) return Source::Invalid; return ::Subsidy::Get(subsidy_id)->src.id; } @@ -96,7 +96,7 @@ /* static */ SQInteger ScriptSubsidy::GetDestinationIndex(SubsidyID subsidy_id) { - if (!IsValidSubsidy(subsidy_id)) return INVALID_SOURCE; + if (!IsValidSubsidy(subsidy_id)) return Source::Invalid; return ::Subsidy::Get(subsidy_id)->dst.id; } diff --git a/src/source_type.h b/src/source_type.h new file mode 100644 index 0000000000..2906dc1857 --- /dev/null +++ b/src/source_type.h @@ -0,0 +1,48 @@ +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + */ + +/** @file source_type.h Type for the source of cargo. */ + +#ifndef SOURCE_TYPE_H +#define SOURCE_TYPE_H + +#include "company_type.h" +#include "industry_type.h" +#include "town_type.h" + +/** Types of cargo source and destination */ +enum class SourceType : uint8_t { + Industry = 0, ///< Source/destination is an industry + Town = 1, ///< Source/destination is a town + Headquarters = 2, ///< Source/destination are company headquarters +}; + +using SourceID = uint16_t; ///< Contains either industry ID, town ID or company ID (or Source::Invalid) +static_assert(sizeof(SourceID) >= sizeof(CompanyID)); +static_assert(sizeof(SourceID) >= sizeof(IndustryID)); +static_assert(sizeof(SourceID) >= sizeof(TownID)); + +/** A location from where cargo can come from (or go to). Specifically industries, towns and headquarters. */ +struct Source { +public: + static constexpr SourceID Invalid = 0xFFFF; ///< Invalid/unknown index of source + + SourceID id; ///< Index of industry/town/HQ, Source::Invalid if unknown/invalid. + SourceType type; ///< Type of \c source_id. + + constexpr CompanyID ToCompanyID() const { assert(this->type == SourceType::Headquarters); return static_cast(this->id); } + constexpr IndustryID ToIndustryID() const { assert(this->type == SourceType::Industry); return static_cast(this->id); } + constexpr TownID ToTownID() const { assert(this->type == SourceType::Town); return static_cast(this->id); } + + constexpr void MakeInvalid() { this->id = Source::Invalid; } + constexpr void SetIndex(SourceID index) { this->id = index; } + + constexpr bool IsValid() const noexcept { return this->id != Source::Invalid; } + auto operator<=>(const Source &source) const = default; +}; + +#endif /* SOURCE_TYPE_H */ diff --git a/src/subsidy.cpp b/src/subsidy.cpp index 3f761b7abc..a71486306e 100644 --- a/src/subsidy.cpp +++ b/src/subsidy.cpp @@ -123,8 +123,8 @@ std::pair SetupSubsidyDecodeParam(const Su static inline void SetPartOfSubsidyFlag(Source source, PartOfSubsidy flag) { switch (source.type) { - case SourceType::Industry: Industry::Get(source.id)->part_of_subsidy |= flag; return; - case SourceType::Town: Town::Get(source.id)->cache.part_of_subsidy |= flag; return; + case SourceType::Industry: Industry::Get(source.ToIndustryID())->part_of_subsidy |= flag; return; + case SourceType::Town: Town::Get(source.ToTownID())->cache.part_of_subsidy |= flag; return; default: NOT_REACHED(); } } @@ -188,8 +188,8 @@ static bool CheckSubsidyDuplicate(CargoType cargo, Source src, Source dst) */ static bool CheckSubsidyDistance(Source src, Source dst) { - TileIndex tile_src = (src.type == SourceType::Town) ? Town::Get(src.id)->xy : Industry::Get(src.id)->location.tile; - TileIndex tile_dst = (dst.type == SourceType::Town) ? Town::Get(dst.id)->xy : Industry::Get(dst.id)->location.tile; + TileIndex tile_src = (src.type == SourceType::Town) ? Town::Get(src.ToTownID())->xy : Industry::Get(src.ToIndustryID())->location.tile; + TileIndex tile_dst = (dst.type == SourceType::Town) ? Town::Get(dst.ToTownID())->xy : Industry::Get(dst.ToIndustryID())->location.tile; return (DistanceManhattan(tile_src, tile_dst) <= SUBSIDY_MAX_DISTANCE); } @@ -237,20 +237,20 @@ CommandCost CmdCreateSubsidy(DoCommandFlag flags, CargoType cargo_type, Source s switch (src.type) { case SourceType::Town: - if (!Town::IsValidID(src.id)) return CMD_ERROR; + if (!Town::IsValidID(src.ToTownID())) return CMD_ERROR; break; case SourceType::Industry: - if (!Industry::IsValidID(src.id)) return CMD_ERROR; + if (!Industry::IsValidID(src.ToIndustryID())) return CMD_ERROR; break; default: return CMD_ERROR; } switch (dst.type) { case SourceType::Town: - if (!Town::IsValidID(dst.id)) return CMD_ERROR; + if (!Town::IsValidID(dst.ToTownID())) return CMD_ERROR; break; case SourceType::Industry: - if (!Industry::IsValidID(dst.id)) return CMD_ERROR; + if (!Industry::IsValidID(dst.ToIndustryID())) return CMD_ERROR; break; default: return CMD_ERROR; @@ -403,7 +403,7 @@ bool FindSubsidyIndustryCargoRoute() bool FindSubsidyCargoDestination(CargoType cargo_type, Source src) { /* Choose a random destination. */ - Source dst{INVALID_SOURCE, Chance16(1, 2) ? SourceType::Town : SourceType::Industry}; + Source dst{Source::Invalid, Chance16(1, 2) ? SourceType::Town : SourceType::Industry}; switch (dst.type) { case SourceType::Town: { @@ -422,7 +422,7 @@ bool FindSubsidyCargoDestination(CargoType cargo_type, Source src) /* Check if the town can accept this cargo. */ if (town_cargo_accepted[cargo_type] < 8) return false; - dst.id = dst_town->index; + dst.SetIndex(dst_town->index); break; } @@ -434,7 +434,7 @@ bool FindSubsidyCargoDestination(CargoType cargo_type, Source src) /* The industry must accept the cargo */ if (!dst_ind->IsCargoAccepted(cargo_type)) return false; - dst.id = dst_ind->index; + dst.SetIndex(dst_ind->index); break; } @@ -539,13 +539,13 @@ static IntervalTimer _economy_subsidies_monthly({TimerGameEcon bool CheckSubsidised(CargoType cargo_type, CompanyID company, Source src, const Station *st) { /* If the source isn't subsidised, don't continue */ - if (src.id == INVALID_SOURCE) return false; + if (!src.IsValid()) return false; switch (src.type) { case SourceType::Industry: - if (!(Industry::Get(src.id)->part_of_subsidy & POS_SRC)) return false; + if (!(Industry::Get(src.ToIndustryID())->part_of_subsidy & POS_SRC)) return false; break; case SourceType::Town: - if (!(Town::Get(src.id)->cache.part_of_subsidy & POS_SRC)) return false; + if (!(Town::Get(src.ToTownID())->cache.part_of_subsidy & POS_SRC)) return false; break; default: return false; } @@ -579,7 +579,7 @@ bool CheckSubsidised(CargoType cargo_type, CompanyID company, Source src, const switch (s->dst.type) { case SourceType::Industry: for (const auto &i : st->industries_near) { - if (s->dst.id == i.industry->index) { + if (s->dst.ToIndustryID() == i.industry->index) { assert(i.industry->part_of_subsidy & POS_DST); subsidised = true; if (!s->IsAwarded()) s->AwardTo(company); @@ -588,7 +588,7 @@ bool CheckSubsidised(CargoType cargo_type, CompanyID company, Source src, const break; case SourceType::Town: for (const Town *tp : towns_near) { - if (s->dst.id == tp->index) { + if (s->dst.ToTownID() == tp->index) { assert(tp->cache.part_of_subsidy & POS_DST); subsidised = true; if (!s->IsAwarded()) s->AwardTo(company); diff --git a/src/subsidy_base.h b/src/subsidy_base.h index 38043a6d7c..07e526aec7 100644 --- a/src/subsidy_base.h +++ b/src/subsidy_base.h @@ -12,6 +12,7 @@ #include "cargo_type.h" #include "company_type.h" +#include "source_type.h" #include "subsidy_type.h" #include "core/pool_type.hpp" diff --git a/src/subsidy_cmd.h b/src/subsidy_cmd.h index 2fa9d3b871..cfe939e109 100644 --- a/src/subsidy_cmd.h +++ b/src/subsidy_cmd.h @@ -12,6 +12,7 @@ #include "command_type.h" #include "cargo_type.h" +#include "source_type.h" #include "misc/endian_buffer.hpp" CommandCost CmdCreateSubsidy(DoCommandFlag flags, CargoType cargo_type, Source src, Source dst); diff --git a/src/subsidy_gui.cpp b/src/subsidy_gui.cpp index 016653cc87..e374fa0464 100644 --- a/src/subsidy_gui.cpp +++ b/src/subsidy_gui.cpp @@ -83,8 +83,8 @@ struct SubsidyListWindow : Window { /* determine src coordinate for subsidy and try to scroll to it */ TileIndex xy; switch (s->src.type) { - case SourceType::Industry: xy = Industry::Get(s->src.id)->location.tile; break; - case SourceType::Town: xy = Town::Get(s->src.id)->xy; break; + case SourceType::Industry: xy = Industry::Get(s->src.ToIndustryID())->location.tile; break; + case SourceType::Town: xy = Town::Get(s->src.ToTownID())->xy; break; default: NOT_REACHED(); } @@ -93,8 +93,8 @@ struct SubsidyListWindow : Window { /* otherwise determine dst coordinate for subsidy and scroll to it */ switch (s->dst.type) { - case SourceType::Industry: xy = Industry::Get(s->dst.id)->location.tile; break; - case SourceType::Town: xy = Town::Get(s->dst.id)->xy; break; + case SourceType::Industry: xy = Industry::Get(s->dst.ToIndustryID())->location.tile; break; + case SourceType::Town: xy = Town::Get(s->dst.ToTownID())->xy; break; default: NOT_REACHED(); }