diff --git a/src/saveload/tunnel_sl.cpp b/src/saveload/tunnel_sl.cpp index 310b25a0b2..470de84590 100644 --- a/src/saveload/tunnel_sl.cpp +++ b/src/saveload/tunnel_sl.cpp @@ -41,6 +41,7 @@ static void Load_TUNN() while ((index = SlIterateArray()) != -1) { Tunnel *tunnel = new (index) Tunnel(); SlObject(tunnel, _tunnel_desc); + tunnel->UpdateIndexes(); } } diff --git a/src/tunnel_base.h b/src/tunnel_base.h index 6d088bb8f3..92408abde8 100644 --- a/src/tunnel_base.h +++ b/src/tunnel_base.h @@ -17,7 +17,7 @@ struct Tunnel; -typedef Pool TunnelPool; +typedef Pool TunnelPool; extern TunnelPool _tunnel_pool; struct Tunnel : TunnelPool::PoolItem<&_tunnel_pool> { @@ -27,13 +27,21 @@ struct Tunnel : TunnelPool::PoolItem<&_tunnel_pool> { bool is_chunnel; Tunnel() {} - Tunnel(TileIndex tile_n, TileIndex tile_s, bool is_chunnel) : tile_n(tile_n), tile_s(tile_s), is_chunnel(is_chunnel) {} ~Tunnel(); + Tunnel(TileIndex tile_n, TileIndex tile_s, bool is_chunnel) : tile_n(tile_n), tile_s(tile_s), is_chunnel(is_chunnel) + { + this->UpdateIndexes(); + } + + void UpdateIndexes(); + static inline Tunnel *GetByTile(TileIndex tile) { return Tunnel::Get(GetTunnelIndex(tile)); } + + static void PreCleanPool(); }; #define FOR_ALL_TUNNELS_FROM(var, start) FOR_ALL_ITEMS_FROM(Tunnel, tunnel_index, var, start) diff --git a/src/tunnel_map.cpp b/src/tunnel_map.cpp index 5ffb409c47..cd049f7397 100644 --- a/src/tunnel_map.cpp +++ b/src/tunnel_map.cpp @@ -13,6 +13,7 @@ #include "tunnelbridge_map.h" #include "core/pool_func.hpp" +#include #include "safeguards.h" @@ -20,12 +21,45 @@ TunnelPool _tunnel_pool("Tunnel"); INSTANTIATE_POOL_METHODS(Tunnel) +static std::unordered_map tunnel_tile_index_map; + /** * Clean up a tunnel tile */ Tunnel::~Tunnel() { if (CleaningPool()) return; + + if (this->index >= TUNNEL_ID_MAP_LOOKUP) { + tunnel_tile_index_map.erase(this->tile_n); + tunnel_tile_index_map.erase(this->tile_s); + } +} + +/** + * Update tunnel indexes + */ +void Tunnel::UpdateIndexes() +{ + if (this->index >= TUNNEL_ID_MAP_LOOKUP) { + tunnel_tile_index_map[this->tile_n] = this->index; + tunnel_tile_index_map[this->tile_s] = this->index; + } +} + +/** + * Tunnel pool is about to be cleaned + */ +void Tunnel::PreCleanPool() +{ + tunnel_tile_index_map.clear(); +} + +TunnelID GetTunnelIndexByLookup(TileIndex t) +{ + auto iter = tunnel_tile_index_map.find(t); + assert_msg(iter != tunnel_tile_index_map.end(), "tile: 0x%X", t); + return iter->second; } /** diff --git a/src/tunnel_map.h b/src/tunnel_map.h index b684437057..55f6ce7eea 100644 --- a/src/tunnel_map.h +++ b/src/tunnel_map.h @@ -14,7 +14,9 @@ #include "road_map.h" -typedef uint16 TunnelID; ///< Type for the unique identifier of tunnels. +typedef uint32 TunnelID; ///< Type for the unique identifier of tunnels. + +static const TunnelID TUNNEL_ID_MAP_LOOKUP = 0xFFFF; ///< Sentinel ID value to store in m2 to indiciate that the ID should be looked up instead /** * Is this a tunnel (entrance)? @@ -46,8 +48,11 @@ static inline bool IsTunnelTile(TileIndex t) */ static inline TunnelID GetTunnelIndex(TileIndex t) { + extern TunnelID GetTunnelIndexByLookup(TileIndex t); + assert(IsTunnelTile(t)); - return _m[t].m2; + TunnelID map_id = _m[t].m2; + return map_id == TUNNEL_ID_MAP_LOOKUP ? GetTunnelIndexByLookup(t) : map_id; } TileIndex GetOtherTunnelEnd(TileIndex); @@ -65,7 +70,7 @@ static inline void MakeRoadTunnel(TileIndex t, Owner o, TunnelID id, DiagDirecti { SetTileType(t, MP_TUNNELBRIDGE); SetTileOwner(t, o); - _m[t].m2 = id; + _m[t].m2 = (id >= TUNNEL_ID_MAP_LOOKUP) ? TUNNEL_ID_MAP_LOOKUP : id; _m[t].m3 = 0; _m[t].m4 = 0; _m[t].m5 = TRANSPORT_ROAD << 2 | d; @@ -88,7 +93,7 @@ static inline void MakeRailTunnel(TileIndex t, Owner o, TunnelID id, DiagDirecti { SetTileType(t, MP_TUNNELBRIDGE); SetTileOwner(t, o); - _m[t].m2 = id; + _m[t].m2 = (id >= TUNNEL_ID_MAP_LOOKUP) ? TUNNEL_ID_MAP_LOOKUP : id; SB(_m[t].m1, 7, 1, GB(r, 4, 1)); SB(_m[t].m3, 0, 4, GB(r, 0, 4)); SB(_m[t].m3, 4, 4, 0);