diff --git a/src/engine.cpp b/src/engine.cpp index b331ddb7f84..e1220f2b7e3 100644 --- a/src/engine.cpp +++ b/src/engine.cpp @@ -579,6 +579,7 @@ void EngineOverrideManager::ResetToDefaultMapping() eid.substitute_id = internal_id; } } + this->ReIndex(); } /** @@ -592,14 +593,21 @@ void EngineOverrideManager::ResetToDefaultMapping() */ EngineID EngineOverrideManager::GetID(VehicleType type, uint16_t grf_local_id, uint32_t grfid) { + auto iter = this->mapping_index.find(HashKey(type, grf_local_id, grfid)); + EngineID id = (iter != this->mapping_index.end()) ? iter->second : INVALID_ENGINE; + +#ifdef _DEBUG EngineID index = 0; for (const EngineIDMapping &eid : *this) { if (eid.type == type && eid.grfid == grfid && eid.internal_id == grf_local_id) { + assert(id == index); return index; } index++; } - return INVALID_ENGINE; + assert(id == INVALID_ENGINE); +#endif + return id; } /** @@ -620,6 +628,26 @@ bool EngineOverrideManager::ResetToCurrentNewGRFConfig() return true; } +void EngineOverrideManager::AddToIndex(EngineID id) +{ + this->mapping_index.insert({ HashKey((*this)[id]), id }); +} + +void EngineOverrideManager::RemoveFromIndex(EngineID id) +{ + this->mapping_index.erase(HashKey((*this)[id])); +} + +void EngineOverrideManager::ReIndex() +{ + this->mapping_index.clear(); + EngineID index = 0; + for (const EngineIDMapping &eid : *this) { + this->mapping_index.insert({ HashKey(eid), index }); + index++; + } +} + /** * Initialise the engine pool with the data from the original vehicles. */ diff --git a/src/engine_override.h b/src/engine_override.h index 8e6822a796a..fe7872783a3 100644 --- a/src/engine_override.h +++ b/src/engine_override.h @@ -13,6 +13,7 @@ #include "engine_type.h" #include "vehicle_type.h" +#include "3rdparty/robin_hood/robin_hood.h" #include struct EngineIDMapping { @@ -29,9 +30,27 @@ struct EngineIDMapping { struct EngineOverrideManager : std::vector { static const uint NUM_DEFAULT_ENGINES; ///< Number of default entries +private: + static uint64_t HashKey(VehicleType type, uint16_t grf_local_id, uint32_t grfid) + { + return grfid | (static_cast(grf_local_id) << 32) | (static_cast(type) << 48); + } + + static uint64_t HashKey(const EngineIDMapping &eid) + { + return HashKey(eid.type, eid.internal_id, eid.grfid); + } + + robin_hood::unordered_map mapping_index; + +public: void ResetToDefaultMapping(); EngineID GetID(VehicleType type, uint16_t grf_local_id, uint32_t grfid); + void AddToIndex(EngineID id); + void RemoveFromIndex(EngineID id); + void ReIndex(); + static bool ResetToCurrentNewGRFConfig(); }; diff --git a/src/newgrf.cpp b/src/newgrf.cpp index dffab5a9c97..34d70c5411e 100644 --- a/src/newgrf.cpp +++ b/src/newgrf.cpp @@ -569,8 +569,10 @@ static Engine *GetNewEngine(const GRFFile *file, VehicleType type, uint16_t inte /* Reserve the engine slot */ if (!static_access) { + _engine_mngr.RemoveFromIndex(engine); EngineIDMapping *eid = _engine_mngr.data() + engine; eid->grfid = scope_grfid; // Note: this is INVALID_GRFID if dynamic_engines is disabled, so no reservation + _engine_mngr.AddToIndex(engine); } return e; @@ -597,6 +599,7 @@ static Engine *GetNewEngine(const GRFFile *file, VehicleType type, uint16_t inte type, std::min(internal_id, _engine_counts[type]) // substitute_id == _engine_counts[subtype] means "no substitute" }); + _engine_mngr.AddToIndex(e->index); if (engine_pool_size != Engine::GetPoolSize()) { /* Resize temporary engine data ... */ diff --git a/src/saveload/engine_sl.cpp b/src/saveload/engine_sl.cpp index cde7bd55759..99536a0ee11 100644 --- a/src/saveload/engine_sl.cpp +++ b/src/saveload/engine_sl.cpp @@ -115,6 +115,8 @@ struct EIDSChunkHandler : ChunkHandler { EngineIDMapping *eid = &_engine_mngr.emplace_back(); SlObject(eid, slt); } + + _engine_mngr.ReIndex(); } };