1
0
Fork 0

Fix: Rail/road type conversion data is not populated on new game. (#13403)

This means that the rail/road type conversion that happens if NewGRFs are changed does not work the first time for a new game, only with a savegame.
pull/11338/merge
Peter Nelson 2025-01-29 21:45:16 +00:00 committed by GitHub
parent 402aaf3d11
commit bf6293a13f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 166 additions and 134 deletions

View File

@ -37,6 +37,8 @@
#include "error.h"
#include "game/game.hpp"
#include "game/game_instance.hpp"
#include "newgrf_railtype.h"
#include "newgrf_roadtype.h"
#include "string_func.h"
#include "thread.h"
#include "tgp.h"
@ -320,6 +322,8 @@ void GenerateWorld(GenWorldMode mode, uint size_x, uint size_y, bool reset_setti
/* Load the right landscape stuff, and the NewGRFs! */
GfxLoadSprites();
SetCurrentRailTypeLabelList();
SetCurrentRoadTypeLabelList();
InitializeBuildingCounts();
LoadStringWidthTable();

View File

@ -329,4 +329,11 @@ struct GRFFileProps : GRFFilePropsBase<1> {
uint16_t override; ///< id of the entity been replaced by
};
/** 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).
};
#endif /* NEWGRF_COMMONS_H */

View File

@ -14,6 +14,7 @@
#include "timer/timer_game_calendar.h"
#include "depot_base.h"
#include "town.h"
#include "tunnelbridge_map.h"
#include "safeguards.h"
@ -174,3 +175,73 @@ uint8_t GetReverseRailTypeTranslation(RailType railtype, const GRFFile *grffile)
/* If not found, return as invalid */
return 0xFF;
}
std::vector<LabelObject<RailTypeLabel>> _railtype_list;
/**
* Test if any saved rail type labels are different to the currently loaded
* rail types. Rail types stored in the map will be converted if necessary.
*/
void ConvertRailTypes()
{
std::vector<RailType> railtype_conversion_map;
bool needs_conversion = false;
for (auto it = std::begin(_railtype_list); it != std::end(_railtype_list); ++it) {
RailType rt = GetRailTypeByLabel(it->label);
if (rt == INVALID_RAILTYPE) {
rt = RAILTYPE_RAIL;
}
railtype_conversion_map.push_back(rt);
/* Conversion is needed if the rail type is in a different position than the list. */
if (it->label != 0 && rt != std::distance(std::begin(_railtype_list), it)) needs_conversion = true;
}
if (!needs_conversion) return;
for (const auto t : Map::Iterate()) {
switch (GetTileType(t)) {
case MP_RAILWAY:
SetRailType(t, railtype_conversion_map[GetRailType(t)]);
break;
case MP_ROAD:
if (IsLevelCrossing(t)) {
SetRailType(t, railtype_conversion_map[GetRailType(t)]);
}
break;
case MP_STATION:
if (HasStationRail(t)) {
SetRailType(t, railtype_conversion_map[GetRailType(t)]);
}
break;
case MP_TUNNELBRIDGE:
if (GetTunnelBridgeTransportType(t) == TRANSPORT_RAIL) {
SetRailType(t, railtype_conversion_map[GetRailType(t)]);
}
break;
default:
break;
}
}
}
/** Populate railtype label list with current values. */
void SetCurrentRailTypeLabelList()
{
_railtype_list.clear();
for (RailType rt = RAILTYPE_BEGIN; rt != RAILTYPE_END; rt++) {
_railtype_list.push_back({GetRailTypeInfo(rt)->label, 0});
}
}
void ClearRailTypeLabelList()
{
_railtype_list.clear();
}

View File

@ -59,4 +59,8 @@ SpriteID GetCustomSignalSprite(const RailTypeInfo *rti, TileIndex tile, SignalTy
RailType GetRailTypeTranslation(uint8_t railtype, const GRFFile *grffile);
uint8_t GetReverseRailTypeTranslation(RailType railtype, const GRFFile *grffile);
void ConvertRailTypes();
void SetCurrentRailTypeLabelList();
void ClearRailTypeLabelList();
#endif /* NEWGRF_RAILTYPE_H */

View File

@ -14,6 +14,7 @@
#include "timer/timer_game_calendar.h"
#include "depot_base.h"
#include "town.h"
#include "tunnelbridge_map.h"
#include "safeguards.h"
@ -167,3 +168,67 @@ uint8_t GetReverseRoadTypeTranslation(RoadType roadtype, const GRFFile *grffile)
/* If not found, return as invalid */
return 0xFF;
}
std::vector<LabelObject<RoadTypeLabel>> _roadtype_list;
/**
* 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.
*/
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;
}
}
}
/** Populate road type label list with current values. */
void SetCurrentRoadTypeLabelList()
{
_roadtype_list.clear();
for (RoadType rt = ROADTYPE_BEGIN; rt != ROADTYPE_END; rt++) {
_roadtype_list.push_back({GetRoadTypeInfo(rt)->label, GetRoadTramType(rt)});
}
}
void ClearRoadTypeLabelList()
{
_roadtype_list.clear();
}

View File

@ -59,4 +59,8 @@ SpriteID GetCustomRoadSprite(const RoadTypeInfo *rti, TileIndex tile, RoadTypeSp
RoadType GetRoadTypeTranslation(RoadTramType rtt, uint8_t tracktype, const GRFFile *grffile);
uint8_t GetReverseRoadTypeTranslation(RoadType roadtype, const GRFFile *grffile);
void ConvertRoadTypes();
void SetCurrentRoadTypeLabelList();
void ClearRoadTypeLabelList();
#endif /* NEWGRF_ROADTYPE_H */

View File

@ -15,134 +15,13 @@
#include "saveload_internal.h"
#include "../rail.h"
#include "../road.h"
#include "../station_map.h"
#include "../tunnelbridge_map.h"
#include "../newgrf_railtype.h"
#include "../newgrf_roadtype.h"
#include "../safeguards.h"
/** 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
* rail types. Rail types stored in the map will be converted if necessary.
*/
static void ConvertRailTypes()
{
std::vector<RailType> railtype_conversion_map;
bool needs_conversion = false;
for (auto it = std::begin(_railtype_list); it != std::end(_railtype_list); ++it) {
RailType rt = GetRailTypeByLabel(it->label);
if (rt == INVALID_RAILTYPE) {
rt = RAILTYPE_RAIL;
}
railtype_conversion_map.push_back(rt);
/* Conversion is needed if the rail type is in a different position than the list. */
if (it->label != 0 && rt != std::distance(std::begin(_railtype_list), it)) needs_conversion = true;
}
if (!needs_conversion) return;
for (const auto t : Map::Iterate()) {
switch (GetTileType(t)) {
case MP_RAILWAY:
SetRailType(t, railtype_conversion_map[GetRailType(t)]);
break;
case MP_ROAD:
if (IsLevelCrossing(t)) {
SetRailType(t, railtype_conversion_map[GetRailType(t)]);
}
break;
case MP_STATION:
if (HasStationRail(t)) {
SetRailType(t, railtype_conversion_map[GetRailType(t)]);
}
break;
case MP_TUNNELBRIDGE:
if (GetTunnelBridgeTransportType(t) == TRANSPORT_RAIL) {
SetRailType(t, railtype_conversion_map[GetRailType(t)]);
}
break;
default:
break;
}
}
}
/**
* 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;
}
}
}
/** Populate label lists with current values. */
static void SetCurrentLabelLists()
{
_railtype_list.clear();
for (RailType rt = RAILTYPE_BEGIN; rt != RAILTYPE_END; rt++) {
_railtype_list.push_back({GetRailTypeInfo(rt)->label, 0});
}
_roadtype_list.clear();
for (RoadType rt = ROADTYPE_BEGIN; rt != ROADTYPE_END; rt++) {
_roadtype_list.push_back({GetRoadTypeInfo(rt)->label, GetRoadTramType(rt)});
}
}
extern std::vector<LabelObject<RailTypeLabel>> _railtype_list;
extern std::vector<LabelObject<RoadTypeLabel>> _roadtype_list;
/** Perform rail type and road type conversion if necessary. */
void AfterLoadLabelMaps()
@ -150,13 +29,8 @@ void AfterLoadLabelMaps()
ConvertRailTypes();
ConvertRoadTypes();
SetCurrentLabelLists();
}
void ResetLabelMaps()
{
_railtype_list.clear();
_roadtype_list.clear();
SetCurrentRailTypeLabelList();
SetCurrentRoadTypeLabelList();
}
struct RAILChunkHandler : ChunkHandler {

View File

@ -42,6 +42,9 @@
#include "../string_func.h"
#include "../fios.h"
#include "../error.h"
#include "../newgrf_railtype.h"
#include "../newgrf_roadtype.h"
#include <atomic>
#ifdef __EMSCRIPTEN__
# include <emscripten.h>
@ -2789,7 +2792,8 @@ extern bool LoadOldSaveGame(const std::string &file);
static void ResetSaveloadData()
{
ResetTempEngineData();
ResetLabelMaps();
ClearRailTypeLabelList();
ClearRoadTypeLabelList();
ResetOldWaypoints();
}

View File

@ -29,7 +29,6 @@ void AfterLoadVehiclesPhase2(bool part_of_load);
void FixupTrainLengths();
void AfterLoadStations();
void AfterLoadRoadStops();
void ResetLabelMaps();
void AfterLoadLabelMaps();
void AfterLoadStoryBook();
void AfterLoadLinkGraphs();