Codechange: Add NewGRFSpecsBase class to hold class/index information.

Standardises how the class index is stored in the spec, instead of relying ot the Spec structs having the same members.

This allows retrieving class_index and index without searching or using pointer arithmetic.

'cls_id' is renamed to 'class_index' to make it clearer that it is an index rather than the multichar label of the class.
pull/730/head
Peter Nelson 5 months ago committed by Peter Nelson
parent 733284cc16
commit d5671030b1

@ -1945,7 +1945,7 @@ static ChangeInfoResult StationChangeInfo(uint stid, int numinfo, int prop, Byte
/* Swap classid because we read it in BE meaning WAYP or DFLT */
uint32_t classid = buf->ReadDWord();
statspec->cls_id = StationClass::Allocate(BSWAP32(classid));
statspec->class_index = StationClass::Allocate(BSWAP32(classid));
break;
}
@ -2141,7 +2141,7 @@ static ChangeInfoResult StationChangeInfo(uint stid, int numinfo, int prop, Byte
break;
case 0x1D: // Station Class name
AddStringForMapping(buf->ReadWord(), [statspec](StringID str) { StationClass::Get(statspec->cls_id)->name = str; });
AddStringForMapping(buf->ReadWord(), [statspec](StringID str) { StationClass::Get(statspec->class_index)->name = str; });
break;
default:
@ -4103,12 +4103,12 @@ static ChangeInfoResult ObjectChangeInfo(uint id, int numinfo, int prop, ByteRea
/* Swap classid because we read it in BE. */
uint32_t classid = buf->ReadDWord();
spec->cls_id = ObjectClass::Allocate(BSWAP32(classid));
spec->class_index = ObjectClass::Allocate(BSWAP32(classid));
break;
}
case 0x09: { // Class name
AddStringForMapping(buf->ReadWord(), [spec](StringID str) { ObjectClass::Get(spec->cls_id)->name = str; });
AddStringForMapping(buf->ReadWord(), [spec](StringID str) { ObjectClass::Get(spec->class_index)->name = str; });
break;
}
@ -4790,7 +4790,7 @@ static ChangeInfoResult RoadStopChangeInfo(uint id, int numinfo, int prop, ByteR
}
uint32_t classid = buf->ReadDWord();
rs->cls_id = RoadStopClass::Allocate(BSWAP32(classid));
rs->class_index = RoadStopClass::Allocate(BSWAP32(classid));
break;
}
@ -4803,7 +4803,7 @@ static ChangeInfoResult RoadStopChangeInfo(uint id, int numinfo, int prop, ByteR
break;
case 0x0B: // Road Stop Class name
AddStringForMapping(buf->ReadWord(), [rs](StringID str) { RoadStopClass::Get(rs->cls_id)->name = str; });
AddStringForMapping(buf->ReadWord(), [rs](StringID str) { RoadStopClass::Get(rs->class_index)->name = str; });
break;
case 0x0C: // The draw mode
@ -6270,8 +6270,8 @@ static void FeatureNewName(ByteReader *buf)
if (GB(id, 0, 8) >= _cur.grffile->stations.size() || _cur.grffile->stations[GB(id, 0, 8)] == nullptr) {
GrfMsg(1, "FeatureNewName: Attempt to name undefined station 0x{:X}, ignoring", GB(id, 0, 8));
} else {
StationClassID cls_id = _cur.grffile->stations[GB(id, 0, 8)]->cls_id;
StationClass::Get(cls_id)->name = AddGRFString(_cur.grffile->grfid, id, lang, new_scheme, false, name, STR_UNDEFINED);
StationClassID class_index = _cur.grffile->stations[GB(id, 0, 8)]->class_index;
StationClass::Get(class_index)->name = AddGRFString(_cur.grffile->grfid, id, lang, new_scheme, false, name, STR_UNDEFINED);
}
break;

@ -102,7 +102,7 @@ struct AirportTileLayout {
/**
* Defines the data structure for an airport.
*/
struct AirportSpec {
struct AirportSpec : NewGRFSpecBase<AirportClassID> {
const struct AirportFTAClass *fsm; ///< the finite statemachine for the default airports
std::vector<AirportTileLayout> layouts; ///< List of layouts composing the airport.
std::span<const HangarTileTable> depots; ///< Position of the depots on the airports.
@ -114,7 +114,6 @@ struct AirportSpec {
TimerGameCalendar::Year max_year; ///< last year the airport is available
StringID name; ///< name of this airport
TTDPAirportType ttd_airport_type; ///< ttdpatch airport type (Small/Large/Helipad/Oilrig)
AirportClassID cls_id; ///< the class to which this airport type belongs
SpriteID preview_sprite; ///< preview sprite for this airport
uint16_t maintenance_cost; ///< maintenance cost multiplier
/* Newgrf data */

@ -12,21 +12,31 @@
#include "strings_type.h"
/* Base for each type of NewGRF spec to be used with NewGRFClass. */
template <typename Tindex>
struct NewGRFSpecBase {
Tindex class_index; ///< Class index of this spec, invalid until class is allocated.
uint16_t index; ///< Index within class of this spec, invalid until inserted into class.
};
/**
* Struct containing information relating to NewGRF classes for stations and airports.
*/
template <typename Tspec, typename Tid, Tid Tmax>
template <typename Tspec, typename Tindex, Tindex Tmax>
class NewGRFClass {
private:
/* Tspec must be of NewGRFSpecBase<Tindex>. */
static_assert(std::is_base_of_v<NewGRFSpecBase<Tindex>, Tspec>);
uint ui_count = 0; ///< Number of specs in this class potentially available to the user.
Tindex index; ///< Index of class within the list of classes.
std::vector<Tspec *> spec; ///< List of specifications.
/**
* The actual classes.
* @note This may be reallocated during initialization so pointers may be invalidated.
*/
static inline std::vector<NewGRFClass<Tspec, Tid, Tmax>> classes;
static inline std::vector<NewGRFClass<Tspec, Tindex, Tmax>> classes;
/** Initialise the defaults. */
static void InsertDefaults();
@ -48,11 +58,11 @@ public:
* Get read-only span of all classes of this type.
* @return Read-only span of classes.
*/
static std::span<NewGRFClass<Tspec, Tid, Tmax> const> Classes() { return NewGRFClass::classes; }
static std::span<NewGRFClass<Tspec, Tindex, Tmax> const> Classes() { return NewGRFClass::classes; }
void Insert(Tspec *spec);
Tid Index() const { return static_cast<Tid>(std::distance(&*std::cbegin(NewGRFClass::classes), this)); }
Tindex Index() const { return this->index; }
/** Get the number of allocated specs within the class. */
uint GetSpecCount() const { return static_cast<uint>(this->spec.size()); }
/** Get the number of potentially user-available specs within the class. */
@ -66,14 +76,14 @@ public:
bool IsUIAvailable(uint index) const;
static void Reset();
static Tid Allocate(uint32_t global_id);
static Tindex Allocate(uint32_t global_id);
static void Assign(Tspec *spec);
static uint GetClassCount();
static uint GetUIClassCount();
static Tid GetUIClass(uint index);
static NewGRFClass *Get(Tid cls_id);
static Tindex GetUIClass(uint index);
static NewGRFClass *Get(Tindex class_index);
static const Tspec *GetByGrf(uint32_t grfid, uint16_t local_id, int *index);
static const Tspec *GetByGrf(uint32_t grfid, uint16_t local_id);
};
#endif /* NEWGRF_CLASS_H */

@ -12,8 +12,8 @@
#include "table/strings.h"
/** Reset the classes, i.e. clear everything. */
template <typename Tspec, typename Tid, Tid Tmax>
void NewGRFClass<Tspec, Tid, Tmax>::Reset()
template <typename Tspec, typename Tindex, Tindex Tmax>
void NewGRFClass<Tspec, Tindex, Tmax>::Reset()
{
NewGRFClass::classes.clear();
NewGRFClass::classes.shrink_to_fit();
@ -28,8 +28,8 @@ void NewGRFClass<Tspec, Tid, Tmax>::Reset()
* @note Upon allocating the same global class ID for a
* second time, this first allocation will be given.
*/
template <typename Tspec, typename Tid, Tid Tmax>
Tid NewGRFClass<Tspec, Tid, Tmax>::Allocate(uint32_t global_id)
template <typename Tspec, typename Tindex, Tindex Tmax>
Tindex NewGRFClass<Tspec, Tindex, Tmax>::Allocate(uint32_t global_id)
{
auto found = std::find_if(std::begin(NewGRFClass::classes), std::end(NewGRFClass::classes), [global_id](const auto &cls) { return cls.global_id == global_id; });
@ -38,56 +38,59 @@ Tid NewGRFClass<Tspec, Tid, Tmax>::Allocate(uint32_t global_id)
/* More slots available, allocate a slot to the global id. */
if (NewGRFClass::classes.size() < Tmax) {
auto &cls = NewGRFClass::classes.emplace_back(global_id, STR_EMPTY);
return cls.Index();
auto it = NewGRFClass::classes.emplace(std::end(NewGRFClass::classes), global_id, STR_EMPTY);
it->index = static_cast<Tindex>(std::distance(std::begin(NewGRFClass::classes), it));
return it->Index();
}
GrfMsg(2, "ClassAllocate: already allocated {} classes, using default", Tmax);
return static_cast<Tid>(0);
return static_cast<Tindex>(0);
}
/**
* Insert a spec into the class.
* Insert a spec into the class, and update its index.
* @param spec The spec to insert.
*/
template <typename Tspec, typename Tid, Tid Tmax>
void NewGRFClass<Tspec, Tid, Tmax>::Insert(Tspec *spec)
template <typename Tspec, typename Tindex, Tindex Tmax>
void NewGRFClass<Tspec, Tindex, Tmax>::Insert(Tspec *spec)
{
this->spec.push_back(spec);
auto it = this->spec.insert(std::end(this->spec), spec);
uint16_t index = static_cast<uint16_t>(std::distance(std::begin(this->spec), it));
if (spec != nullptr) (*it)->index = index;
if (this->IsUIAvailable(static_cast<uint>(this->spec.size() - 1))) this->ui_count++;
if (this->IsUIAvailable(index)) this->ui_count++;
}
/**
* Assign a spec to one of the classes.
* @param spec The spec to assign.
* @note The spec must have a valid class id set.
* @note The spec must have a valid class index set.
*/
template <typename Tspec, typename Tid, Tid Tmax>
void NewGRFClass<Tspec, Tid, Tmax>::Assign(Tspec *spec)
template <typename Tspec, typename Tindex, Tindex Tmax>
void NewGRFClass<Tspec, Tindex, Tmax>::Assign(Tspec *spec)
{
assert(static_cast<size_t>(spec->cls_id) < NewGRFClass::classes.size());
Get(spec->cls_id)->Insert(spec);
assert(static_cast<size_t>(spec->class_index) < NewGRFClass::classes.size());
Get(spec->class_index)->Insert(spec);
}
/**
* Get a particular class.
* @param cls_id The id for the class.
* @pre cls_id < Tmax
* @param class_index The index of the class.
* @pre class_index < Tmax
*/
template <typename Tspec, typename Tid, Tid Tmax>
NewGRFClass<Tspec, Tid, Tmax> *NewGRFClass<Tspec, Tid, Tmax>::Get(Tid cls_id)
template <typename Tspec, typename Tindex, Tindex Tmax>
NewGRFClass<Tspec, Tindex, Tmax> *NewGRFClass<Tspec, Tindex, Tmax>::Get(Tindex class_index)
{
assert(static_cast<size_t>(cls_id) < NewGRFClass::classes.size());
return &NewGRFClass::classes[cls_id];
assert(static_cast<size_t>(class_index) < NewGRFClass::classes.size());
return &NewGRFClass::classes[class_index];
}
/**
* Get the number of allocated classes.
* @return The number of classes.
*/
template <typename Tspec, typename Tid, Tid Tmax>
uint NewGRFClass<Tspec, Tid, Tmax>::GetClassCount()
template <typename Tspec, typename Tindex, Tindex Tmax>
uint NewGRFClass<Tspec, Tindex, Tmax>::GetClassCount()
{
return static_cast<uint>(NewGRFClass::classes.size());
}
@ -96,8 +99,8 @@ uint NewGRFClass<Tspec, Tid, Tmax>::GetClassCount()
* Get the number of classes available to the user.
* @return The number of classes.
*/
template <typename Tspec, typename Tid, Tid Tmax>
uint NewGRFClass<Tspec, Tid, Tmax>::GetUIClassCount()
template <typename Tspec, typename Tindex, Tindex Tmax>
uint NewGRFClass<Tspec, Tindex, Tmax>::GetUIClassCount()
{
return std::count_if(std::begin(NewGRFClass::classes), std::end(NewGRFClass::classes), [](const auto &cls) { return cls.GetUISpecCount() > 0; });
}
@ -107,8 +110,8 @@ uint NewGRFClass<Tspec, Tid, Tmax>::GetUIClassCount()
* @param index UI index of a class.
* @return The class ID of the class.
*/
template <typename Tspec, typename Tid, Tid Tmax>
Tid NewGRFClass<Tspec, Tid, Tmax>::GetUIClass(uint index)
template <typename Tspec, typename Tindex, Tindex Tmax>
Tindex NewGRFClass<Tspec, Tindex, Tmax>::GetUIClass(uint index)
{
for (const auto &cls : NewGRFClass::classes) {
if (cls.GetUISpecCount() == 0) continue;
@ -122,8 +125,8 @@ Tid NewGRFClass<Tspec, Tid, Tmax>::GetUIClass(uint index)
* @param index The index where to find the spec.
* @return The spec at given location.
*/
template <typename Tspec, typename Tid, Tid Tmax>
const Tspec *NewGRFClass<Tspec, Tid, Tmax>::GetSpec(uint index) const
template <typename Tspec, typename Tindex, Tindex Tmax>
const Tspec *NewGRFClass<Tspec, Tindex, Tmax>::GetSpec(uint index) const
{
/* If the custom spec isn't defined any more, then the GRF file probably was not loaded. */
return index < this->GetSpecCount() ? this->spec[index] : nullptr;
@ -134,8 +137,8 @@ const Tspec *NewGRFClass<Tspec, Tid, Tmax>::GetSpec(uint index) const
* @param ui_index UI index of the spec.
* @return index of the spec, or -1 if out of range.
*/
template <typename Tspec, typename Tid, Tid Tmax>
int NewGRFClass<Tspec, Tid, Tmax>::GetIndexFromUI(int ui_index) const
template <typename Tspec, typename Tindex, Tindex Tmax>
int NewGRFClass<Tspec, Tindex, Tmax>::GetIndexFromUI(int ui_index) const
{
if (ui_index < 0) return -1;
for (uint i = 0; i < this->GetSpecCount(); i++) {
@ -150,8 +153,8 @@ int NewGRFClass<Tspec, Tid, Tmax>::GetIndexFromUI(int ui_index) const
* @param index index of the spec.
* @return UI index of the spec, or -1 if out of range.
*/
template <typename Tspec, typename Tid, Tid Tmax>
int NewGRFClass<Tspec, Tid, Tmax>::GetUIFromIndex(int index) const
template <typename Tspec, typename Tindex, Tindex Tmax>
int NewGRFClass<Tspec, Tindex, Tmax>::GetUIFromIndex(int index) const
{
if ((uint)index >= this->GetSpecCount()) return -1;
uint ui_index = 0;
@ -168,16 +171,13 @@ int NewGRFClass<Tspec, Tid, Tmax>::GetUIFromIndex(int index) const
* @param index Pointer to return the index of the spec in its class. If nullptr then not used.
* @return The spec.
*/
template <typename Tspec, typename Tid, Tid Tmax>
const Tspec *NewGRFClass<Tspec, Tid, Tmax>::GetByGrf(uint32_t grfid, uint16_t local_id, int *index)
template <typename Tspec, typename Tindex, Tindex Tmax>
const Tspec *NewGRFClass<Tspec, Tindex, Tmax>::GetByGrf(uint32_t grfid, uint16_t local_id)
{
for (const auto &cls : NewGRFClass::classes) {
for (const auto &spec : cls.spec) {
if (spec == nullptr) continue;
if (spec->grf_prop.grffile->grfid == grfid && spec->grf_prop.local_id == local_id) {
if (index != nullptr) *index = static_cast<int>(std::distance(cls.spec.data(), &spec));
return spec;
}
if (spec->grf_prop.grffile->grfid == grfid && spec->grf_prop.local_id == local_id) return spec;
}
}

@ -111,7 +111,7 @@ uint ObjectSpec::Index() const
/* static */ void ObjectSpec::BindToClasses()
{
for (auto &spec : _object_specs) {
if (spec.IsEnabled() && spec.cls_id != INVALID_OBJECT_CLASS) {
if (spec.IsEnabled() && spec.class_index != INVALID_OBJECT_CLASS) {
ObjectClass::Assign(&spec);
}
}
@ -132,8 +132,8 @@ void ResetObjects()
}
/* Set class for originals. */
_object_specs[OBJECT_LIGHTHOUSE].cls_id = ObjectClass::Allocate('LTHS');
_object_specs[OBJECT_TRANSMITTER].cls_id = ObjectClass::Allocate('TRNS');
_object_specs[OBJECT_LIGHTHOUSE].class_index = ObjectClass::Allocate('LTHS');
_object_specs[OBJECT_TRANSMITTER].class_index = ObjectClass::Allocate('TRNS');
}
template <>

@ -57,11 +57,10 @@ DECLARE_POSTFIX_INCREMENT(ObjectClassID)
* @note If you change this struct, adopt the initialization of
* default objects in table/object_land.h
*/
struct ObjectSpec {
struct ObjectSpec : NewGRFSpecBase<ObjectClassID> {
/* 2 because of the "normal" and "buy" sprite stacks. */
GRFFilePropsBase<2> grf_prop; ///< Properties related the the grf file
AnimationInfo animation; ///< Information about the animation.
ObjectClassID cls_id; ///< The class to which this spec belongs.
StringID name; ///< The name for this object.
uint8_t climate; ///< In which climates is this object available?

@ -118,7 +118,7 @@ struct RoadStopResolverObject : public ResolverObject {
};
/** Road stop specification. */
struct RoadStopSpec {
struct RoadStopSpec : NewGRFSpecBase<RoadStopClassID> {
/**
* Properties related the the grf file.
* NUM_CARGO real cargo plus three pseudo cargo sprite groups.
@ -126,7 +126,6 @@ struct RoadStopSpec {
* evaluating callbacks.
*/
GRFFilePropsBase<NUM_CARGO + 3> grf_prop;
RoadStopClassID cls_id; ///< The class to which this spec belongs.
StringID name; ///< Name of this stop
RoadStopAvailabilityType stop_type = ROADSTOPTYPE_ALL;

@ -108,8 +108,8 @@ enum StationRandomTrigger {
};
/** Station specification. */
struct StationSpec {
StationSpec() : cls_id(STAT_CLASS_DFLT), name(0),
struct StationSpec : NewGRFSpecBase<StationClassID> {
StationSpec() : name(0),
disallowed_platforms(0), disallowed_lengths(0),
cargo_threshold(0), cargo_triggers(0),
callback_mask(0), flags(0), pylons(0), wires(0), blocked(0),
@ -121,7 +121,6 @@ struct StationSpec {
* evaluating callbacks.
*/
GRFFilePropsBase<NUM_CARGO + 3> grf_prop;
StationClassID cls_id; ///< The class to which this spec belongs.
StringID name; ///< Name of this station.
/**

@ -114,11 +114,11 @@ void AfterLoadStations()
for (BaseStation *st : BaseStation::Iterate()) {
for (auto &sm : GetStationSpecList<StationSpec>(st)) {
if (sm.grfid == 0) continue;
sm.spec = StationClass::GetByGrf(sm.grfid, sm.localidx, nullptr);
sm.spec = StationClass::GetByGrf(sm.grfid, sm.localidx);
}
for (auto &sm : GetStationSpecList<RoadStopSpec>(st)) {
if (sm.grfid == 0) continue;
sm.spec = RoadStopClass::GetByGrf(sm.grfid, sm.localidx, nullptr);
sm.spec = RoadStopClass::GetByGrf(sm.grfid, sm.localidx);
}
if (Station::IsExpected(st)) {

@ -193,13 +193,12 @@
bool adjacent = station_id != ScriptStation::STATION_JOIN_ADJACENT;
StationID to_join = ScriptStation::IsValidStation(station_id) ? station_id : INVALID_STATION;
if (res != CALLBACK_FAILED) {
int index = 0;
const StationSpec *spec = StationClass::GetByGrf(file->grfid, res, &index);
const StationSpec *spec = StationClass::GetByGrf(file->grfid, res);
if (spec == nullptr) {
Debug(grf, 1, "{} returned an invalid station ID for 'AI construction/purchase selection (18)' callback", file->filename);
} else {
/* We might have gotten an usable station spec. Try to build it, but if it fails we'll fall back to the original station. */
if (ScriptObject::Command<CMD_BUILD_RAIL_STATION>::Do(tile, (::RailType)GetCurrentRailType(), axis, num_platforms, platform_length, spec->cls_id, index, to_join, adjacent)) return true;
if (ScriptObject::Command<CMD_BUILD_RAIL_STATION>::Do(tile, (::RailType)GetCurrentRailType(), axis, num_platforms, platform_length, spec->class_index, spec->index, to_join, adjacent)) return true;
}
}

@ -3346,7 +3346,7 @@ void FillTileDescRailStation(TileIndex tile, TileDesc *td)
const StationSpec *spec = GetStationSpec(tile);
if (spec != nullptr) {
td->station_class = StationClass::Get(spec->cls_id)->name;
td->station_class = StationClass::Get(spec->class_index)->name;
td->station_name = spec->name;
if (spec->grf_prop.grffile != nullptr) {
@ -3363,7 +3363,7 @@ void FillTileDescRailStation(TileIndex tile, TileDesc *td)
void FillTileDescAirport(TileIndex tile, TileDesc *td)
{
const AirportSpec *as = Station::GetByTile(tile)->airport.GetSpec();
td->airport_class = AirportClass::Get(as->cls_id)->name;
td->airport_class = AirportClass::Get(as->class_index)->name;
td->airport_name = as->name;
const AirportTileSpec *ats = AirportTileSpec::GetByTile(tile);

@ -378,7 +378,7 @@ static const std::initializer_list<AirportTileLayout> _tile_table_helistation =
/** General AirportSpec definition. */
#define AS_GENERIC(fsm, layouts, depots, size_x, size_y, noise, catchment, min_year, max_year, maint_cost, ttdpatch_type, class_id, name, preview, enabled) \
{fsm, layouts, depots, size_x, size_y, noise, catchment, min_year, max_year, name, ttdpatch_type, class_id, preview, maint_cost, enabled, GRFFileProps(AT_INVALID)}
{{class_id, 0}, fsm, layouts, depots, size_x, size_y, noise, catchment, min_year, max_year, name, ttdpatch_type, preview, maint_cost, enabled, GRFFileProps(AT_INVALID)}
/** AirportSpec definition for airports without any depot. */
#define AS_ND(ap_name, size_x, size_y, min_year, max_year, catchment, noise, maint_cost, ttdpatch_type, class_id, name, preview) \

@ -121,7 +121,7 @@ static const DrawTileSprites _object_hq[] = {
#undef TILE_SPRITE_LINE
#define M(name, size, build_cost_multiplier, clear_cost_multiplier, height, climate, gen_amount, flags) { GRFFilePropsBase<2>(), {0, 0, 0, 0}, INVALID_OBJECT_CLASS, name, climate, size, build_cost_multiplier, clear_cost_multiplier, 0, CalendarTime::MAX_DATE + 1, flags, 0, height, 1, gen_amount }
#define M(name, size, build_cost_multiplier, clear_cost_multiplier, height, climate, gen_amount, flags) {{INVALID_OBJECT_CLASS, 0}, GRFFilePropsBase<2>(), {0, 0, 0, 0}, name, climate, size, build_cost_multiplier, clear_cost_multiplier, 0, CalendarTime::MAX_DATE + 1, flags, 0, height, 1, gen_amount}
/* Climates
* T = Temperate

Loading…
Cancel
Save