1
0
Fork 0

Add: Implement missing road type label conversion.

This was implemented for rail types but missed for road types.

This lets road type labels to be reordered, allowing for upgrades of NewGRF.
pull/12879/head
Peter Nelson 2024-04-19 20:31:19 +01:00 committed by Peter Nelson
parent 157d028915
commit 8bb6572943
2 changed files with 118 additions and 19 deletions

View File

@ -13,12 +13,22 @@
#include "compat/labelmaps_sl_compat.h"
#include "saveload_internal.h"
#include "../rail.h"
#include "../road.h"
#include "../station_map.h"
#include "../tunnelbridge_map.h"
#include "../safeguards.h"
static std::vector<RailTypeLabel> _railtype_list;
/** Container for a label for rail or road type conversion. */
template <typename T>
struct LabelObject {
T label = {}; ///< Label of rail or road type.
uint8_t subtype = 0; ///< Subtype of type (road or tram).
};
static std::vector<LabelObject<RailTypeLabel>> _railtype_list;
static std::vector<LabelObject<RoadTypeLabel>> _roadtype_list;
/**
* Test if any saved rail type labels are different to the currently loaded
@ -30,7 +40,7 @@ static void ConvertRailTypes()
bool needs_conversion = false;
for (auto it = std::begin(_railtype_list); it != std::end(_railtype_list); ++it) {
RailType rt = GetRailTypeByLabel(*it);
RailType rt = GetRailTypeByLabel(it->label);
if (rt == INVALID_RAILTYPE) {
rt = RAILTYPE_RAIL;
}
@ -38,7 +48,7 @@ static void ConvertRailTypes()
railtype_conversion_map.push_back(rt);
/* Conversion is needed if the rail type is in a different position than the list. */
if (*it != 0 && rt != std::distance(std::begin(_railtype_list), it)) needs_conversion = true;
if (it->label != 0 && rt != std::distance(std::begin(_railtype_list), it)) needs_conversion = true;
}
if (!needs_conversion) return;
@ -72,58 +82,146 @@ static void ConvertRailTypes()
}
}
/**
* Test if any saved road type labels are different to the currently loaded
* road types. Road types stored in the map will be converted if necessary.
*/
static void ConvertRoadTypes()
{
std::vector<RoadType> roadtype_conversion_map;
bool needs_conversion = false;
for (auto it = std::begin(_roadtype_list); it != std::end(_roadtype_list); ++it) {
RoadType rt = GetRoadTypeByLabel(it->label);
if (rt == INVALID_ROADTYPE || GetRoadTramType(rt) != it->subtype) {
rt = it->subtype ? ROADTYPE_TRAM : ROADTYPE_ROAD;
}
roadtype_conversion_map.push_back(rt);
/* Conversion is needed if the road type is in a different position than the list. */
if (it->label != 0 && rt != std::distance(std::begin(_roadtype_list), it)) needs_conversion = true;
}
if (!needs_conversion) return;
for (TileIndex t : Map::Iterate()) {
switch (GetTileType(t)) {
case MP_ROAD:
if (RoadType rt = GetRoadTypeRoad(t); rt != INVALID_ROADTYPE) SetRoadTypeRoad(t, roadtype_conversion_map[rt]);
if (RoadType rt = GetRoadTypeTram(t); rt != INVALID_ROADTYPE) SetRoadTypeTram(t, roadtype_conversion_map[rt]);
break;
case MP_STATION:
if (IsStationRoadStop(t) || IsRoadWaypoint(t)) {
if (RoadType rt = GetRoadTypeRoad(t); rt != INVALID_ROADTYPE) SetRoadTypeRoad(t, roadtype_conversion_map[rt]);
if (RoadType rt = GetRoadTypeTram(t); rt != INVALID_ROADTYPE) SetRoadTypeTram(t, roadtype_conversion_map[rt]);
}
break;
case MP_TUNNELBRIDGE:
if (GetTunnelBridgeTransportType(t) == TRANSPORT_ROAD) {
if (RoadType rt = GetRoadTypeRoad(t); rt != INVALID_ROADTYPE) SetRoadTypeRoad(t, roadtype_conversion_map[rt]);
if (RoadType rt = GetRoadTypeTram(t); rt != INVALID_ROADTYPE) SetRoadTypeTram(t, roadtype_conversion_map[rt]);
}
break;
default:
break;
}
}
}
/** Perform rail type and road type conversion if necessary. */
void AfterLoadLabelMaps()
{
ConvertRailTypes();
ConvertRoadTypes();
}
void ResetLabelMaps()
{
_railtype_list.clear();
_roadtype_list.clear();
}
/** Container for a label for SaveLoad system */
struct LabelObject {
uint32_t label;
};
static const SaveLoad _label_object_desc[] = {
SLE_VAR(LabelObject, label, SLE_UINT32),
};
struct RAILChunkHandler : ChunkHandler {
RAILChunkHandler() : ChunkHandler('RAIL', CH_TABLE) {}
static inline const SaveLoad description[] = {
SLE_VAR(LabelObject<RailTypeLabel>, label, SLE_UINT32),
};
void Save() const override
{
SlTableHeader(_label_object_desc);
LabelObject lo;
SlTableHeader(description);
LabelObject<RailTypeLabel> lo;
for (RailType r = RAILTYPE_BEGIN; r != RAILTYPE_END; r++) {
lo.label = GetRailTypeInfo(r)->label;
SlSetArrayIndex(r);
SlObject(&lo, _label_object_desc);
SlObject(&lo, description);
}
}
void Load() const override
{
const std::vector<SaveLoad> slt = SlCompatTableHeader(_label_object_desc, _label_object_sl_compat);
const std::vector<SaveLoad> slt = SlCompatTableHeader(description, _label_object_sl_compat);
LabelObject lo;
_railtype_list.reserve(RAILTYPE_END);
LabelObject<RailTypeLabel> lo;
while (SlIterateArray() != -1) {
SlObject(&lo, slt);
_railtype_list.push_back((RailTypeLabel)lo.label);
_railtype_list.push_back(lo);
}
}
};
struct ROTTChunkHandler : ChunkHandler {
ROTTChunkHandler() : ChunkHandler('ROTT', CH_TABLE) {}
static inline const SaveLoad description[] = {
SLE_VAR(LabelObject<RoadTypeLabel>, label, SLE_UINT32),
SLE_VAR(LabelObject<RoadTypeLabel>, subtype, SLE_UINT8),
};
void Save() const override
{
SlTableHeader(description);
LabelObject<RoadTypeLabel> lo;
for (RoadType r = ROADTYPE_BEGIN; r != ROADTYPE_END; r++) {
const RoadTypeInfo *rti = GetRoadTypeInfo(r);
lo.label = rti->label;
lo.subtype = GetRoadTramType(r);
SlSetArrayIndex(r);
SlObject(&lo, description);
}
}
void Load() const override
{
const std::vector<SaveLoad> slt = SlCompatTableHeader(description, _label_object_sl_compat);
_roadtype_list.reserve(ROADTYPE_END);
LabelObject<RoadTypeLabel> lo;
while (SlIterateArray() != -1) {
SlObject(&lo, slt);
_roadtype_list.push_back(lo);
}
}
};
static const RAILChunkHandler RAIL;
static const ROTTChunkHandler ROTT;
static const ChunkHandlerRef labelmaps_chunk_handlers[] = {
RAIL,
ROTT,
};
extern const ChunkHandlerTable _labelmaps_chunk_handlers(labelmaps_chunk_handlers);

View File

@ -389,6 +389,7 @@ enum SaveLoadVersion : uint16_t {
SLV_COMPANY_ALLOW_LIST_V2, ///< 341 PR#12908 Fixed savegame format for saving of list of client keys that are allowed to join this company.
SLV_WATER_TILE_TYPE, ///< 342 PR#13030 Simplify water tile type.
SLV_PRODUCTION_HISTORY, ///< 343 PR#10541 Industry production history.
SLV_ROAD_TYPE_LABEL_MAP, ///< 344 PR#13021 Add road type label map to allow upgrade/conversion of road types.
SL_MAX_VERSION, ///< Highest possible saveload version
};