From 84d32b6c1631c9a9173f78fb3b275af116125cfd Mon Sep 17 00:00:00 2001 From: Malte Langkabel Date: Sun, 2 Aug 2026 20:42:24 +0200 Subject: [PATCH] add findShipDef/findModuleDef/findRecipeDef to config structs Ships/Modules/RecipesConfig now carry lookup helpers mirroring BuildingsConfig::findBuildingDef. The hand-rolled linear scans in BuildingSystem, ShipSystem, ShipStatsCalculator, ThreatCostCalculator, ShipLayoutDialog, SelectedBuildingPanel and SchematicChoiceDialog now call them instead. Co-Authored-By: Claude Claude-Session: https://claude.ai/code/session_01GH8ZMRY3vhxxXcaUxBqxkk --- src/lib/config/ModulesConfig.h | 14 +++++++ src/lib/config/RecipesConfig.h | 28 +++++++++++++ src/lib/config/ShipsConfig.h | 14 +++++++ src/lib/ecs/system/ShipSystem.cpp | 30 ++------------ src/lib/ecs/system/ShipSystem.h | 3 -- src/lib/sim/BuildingSystem.cpp | 55 ++++-------------------- src/lib/sim/BuildingSystem.h | 3 -- src/lib/sim/ShipStatsCalculator.cpp | 19 ++------- src/lib/sim/ThreatCostCalculator.cpp | 20 +-------- src/ui/SchematicChoiceDialog.cpp | 11 +---- src/ui/SelectedBuildingPanel.cpp | 62 +++++++++------------------- src/ui/ShipLayoutDialog.cpp | 30 +++----------- 12 files changed, 100 insertions(+), 189 deletions(-) diff --git a/src/lib/config/ModulesConfig.h b/src/lib/config/ModulesConfig.h index 402bbf7..fd82ac1 100644 --- a/src/lib/config/ModulesConfig.h +++ b/src/lib/config/ModulesConfig.h @@ -59,4 +59,18 @@ struct ModuleDef struct ModulesConfig { std::vector modules; + + // Returns the definition for the given module id, or nullptr if the id has + // no entry in modules.toml. + const ModuleDef* findModuleDef(const std::string& id) const + { + for (const ModuleDef& def : modules) + { + if (def.id == id) + { + return &def; + } + } + return nullptr; + } }; diff --git a/src/lib/config/RecipesConfig.h b/src/lib/config/RecipesConfig.h index de484ea..08fdcc1 100644 --- a/src/lib/config/RecipesConfig.h +++ b/src/lib/config/RecipesConfig.h @@ -47,4 +47,32 @@ struct RecipeDef struct RecipesConfig { std::vector recipes; + + // Returns the definition for the given recipe id, or nullptr if the id has + // no entry in recipes.toml. + const RecipeDef* findRecipeDef(const std::string& id) const + { + for (const RecipeDef& recipe : recipes) + { + if (recipe.id == id) + { + return &recipe; + } + } + return nullptr; + } + + // Same, but additionally requires the recipe to belong to the given building + // type — recipe ids are only unique per building type. + const RecipeDef* findRecipeDef(const std::string& id, BuildingType building) const + { + for (const RecipeDef& recipe : recipes) + { + if (recipe.id == id && recipe.building == building) + { + return &recipe; + } + } + return nullptr; + } }; diff --git a/src/lib/config/ShipsConfig.h b/src/lib/config/ShipsConfig.h index 278a721..28cae28 100644 --- a/src/lib/config/ShipsConfig.h +++ b/src/lib/config/ShipsConfig.h @@ -49,4 +49,18 @@ struct ShipDef struct ShipsConfig { std::vector ships; + + // Returns the definition for the given ship schematic id, or nullptr if the + // id has no entry in ships.toml. + const ShipDef* findShipDef(const std::string& id) const + { + for (const ShipDef& def : ships) + { + if (def.id == id) + { + return &def; + } + } + return nullptr; + } }; diff --git a/src/lib/ecs/system/ShipSystem.cpp b/src/lib/ecs/system/ShipSystem.cpp index 6b7182f..4e5c0b2 100644 --- a/src/lib/ecs/system/ShipSystem.cpp +++ b/src/lib/ecs/system/ShipSystem.cpp @@ -41,35 +41,11 @@ ShipSystem::ShipSystem(const GameConfig& config, EntityAdmin& admin) { } -const ShipDef* ShipSystem::findShipDef(const std::string& schematicId) const -{ - for (const ShipDef& def : m_config.ships.ships) - { - if (def.id == schematicId) - { - return &def; - } - } - return nullptr; -} - -const ModuleDef* ShipSystem::findModuleDef(const std::string& id) const -{ - for (const ModuleDef& def : m_config.modules.modules) - { - if (def.id == id) - { - return &def; - } - } - return nullptr; -} - entt::entity ShipSystem::spawn(const std::string& schematicId, QVector2D position, bool isEnemy, const std::optional& layout) { - const ShipDef* def = findShipDef(schematicId); + const ShipDef* def = m_config.ships.findShipDef(schematicId); assert(def != nullptr); const float tickRate = static_cast(kTickRateHz); @@ -116,7 +92,7 @@ entt::entity ShipSystem::spawn(const std::string& schematicId, for (const PlacedModule& pm : modules) { - const ModuleDef* modDef = findModuleDef(pm.moduleId); + const ModuleDef* modDef = m_config.modules.findModuleDef(pm.moduleId); if (!modDef) { throw std::runtime_error("unknown module id '" + pm.moduleId + "'"); } if (modDef->weaponCapability) @@ -184,7 +160,7 @@ entt::entity ShipSystem::spawn(const std::string& schematicId, for (const PlacedModule& pm : modules) { - const ModuleDef* modDef = findModuleDef(pm.moduleId); + const ModuleDef* modDef = m_config.modules.findModuleDef(pm.moduleId); if (!modDef) { throw std::runtime_error("unknown module id '" + pm.moduleId + "'"); } for (const ModuleStatModifier& sm : modDef->statModifiers) diff --git a/src/lib/ecs/system/ShipSystem.h b/src/lib/ecs/system/ShipSystem.h index 610a52a..62f2145 100644 --- a/src/lib/ecs/system/ShipSystem.h +++ b/src/lib/ecs/system/ShipSystem.h @@ -38,9 +38,6 @@ public: void setRetreatEnabled(bool enabled); private: - const ShipDef* findShipDef(const std::string& schematicId) const; - const ModuleDef* findModuleDef(const std::string& id) const; - const GameConfig& m_config; EntityAdmin& m_admin; QVector2D m_rallyPoint; diff --git a/src/lib/sim/BuildingSystem.cpp b/src/lib/sim/BuildingSystem.cpp index f9f9954..a634aa2 100644 --- a/src/lib/sim/BuildingSystem.cpp +++ b/src/lib/sim/BuildingSystem.cpp @@ -107,43 +107,6 @@ const BuildingDef* BuildingSystem::findBuildingDef(BuildingType type) const return nullptr; } -const RecipeDef* BuildingSystem::findRecipe(const std::string& id, - BuildingType type) const -{ - for (const RecipeDef& recipe : m_config.recipes.recipes) - { - if (recipe.id == id && recipe.building == type) - { - return &recipe; - } - } - return nullptr; -} - -const ShipDef* BuildingSystem::findShipDef(const std::string& id) const -{ - for (const ShipDef& def : m_config.ships.ships) - { - if (def.id == id) - { - return &def; - } - } - return nullptr; -} - -const ModuleDef* BuildingSystem::findModuleDef(const std::string& id) const -{ - for (const ModuleDef& def : m_config.modules.modules) - { - if (def.id == id) - { - return &def; - } - } - return nullptr; -} - void BuildingSystem::initBuffers(Building& b, const RecipeDef& recipe) const { b.inputBuffer.counts.clear(); @@ -237,7 +200,7 @@ void BuildingSystem::initShipyardBuffers(Building& b) const b.inputBuffer.caps.clear(); b.outputBuffer.items.clear(); b.outputBuffer.capacity = 0; - const ShipDef* def = findShipDef(b.recipeId); + const ShipDef* def = m_config.ships.findShipDef(b.recipeId); if (!def) { return; @@ -252,7 +215,7 @@ void BuildingSystem::initShipyardBuffers(Building& b) const { for (const PlacedModule& pm : b.shipLayout->placedModules) { - const ModuleDef* modDef = findModuleDef(pm.moduleId); + const ModuleDef* modDef = m_config.modules.findModuleDef(pm.moduleId); if (!modDef) { continue; @@ -646,7 +609,7 @@ void BuildingSystem::setRecipe(BuildingId id, const std::string& recipeId) } else { - const RecipeDef* recipe = findRecipe(recipeId, building.type); + const RecipeDef* recipe = m_config.recipes.findRecipeDef(recipeId, building.type); if (recipe) { initBuffers(building, *recipe); @@ -809,7 +772,7 @@ void BuildingSystem::tickConstruction(Tick currentTick) } else { - const RecipeDef* recipe = findRecipe(building.recipeId, building.type); + const RecipeDef* recipe = m_config.recipes.findRecipeDef(building.recipeId, building.type); if (recipe) { initBuffers(building, *recipe); @@ -1187,7 +1150,7 @@ void BuildingSystem::tickShipyardProduction(Tick currentTick) { continue; } - const ShipDef* shipDef = findShipDef(building.recipeId); + const ShipDef* shipDef = m_config.ships.findShipDef(building.recipeId); if (!shipDef) { continue; @@ -1252,7 +1215,7 @@ void BuildingSystem::tickShipyardProduction(Tick currentTick) { for (const PlacedModule& pm : building.shipLayout->placedModules) { - const ModuleDef* modDef = findModuleDef(pm.moduleId); + const ModuleDef* modDef = m_config.modules.findModuleDef(pm.moduleId); if (modDef) { totalTime += modDef->productionTimeSeconds; @@ -1466,7 +1429,7 @@ BuildingSystem::gatherCandidateRecipes(const Building& b) const } else { - const RecipeDef* recipe = findRecipe(b.recipeId, b.type); + const RecipeDef* recipe = m_config.recipes.findRecipeDef(b.recipeId, b.type); if (recipe) { candidates.push_back(recipe); @@ -1495,7 +1458,7 @@ std::map BuildingSystem::computeShipyardRequiredMaterials(const Building& b) const { std::map requiredMaterials; - const ShipDef* shipDef = findShipDef(b.recipeId); + const ShipDef* shipDef = m_config.ships.findShipDef(b.recipeId); if (!shipDef) { return requiredMaterials; @@ -1508,7 +1471,7 @@ BuildingSystem::computeShipyardRequiredMaterials(const Building& b) const { for (const PlacedModule& pm : b.shipLayout->placedModules) { - const ModuleDef* modDef = findModuleDef(pm.moduleId); + const ModuleDef* modDef = m_config.modules.findModuleDef(pm.moduleId); if (!modDef) { continue; diff --git a/src/lib/sim/BuildingSystem.h b/src/lib/sim/BuildingSystem.h index 6a24f5c..e29a3bb 100644 --- a/src/lib/sim/BuildingSystem.h +++ b/src/lib/sim/BuildingSystem.h @@ -268,9 +268,6 @@ private: bool hasInputsToStart(const Building& b) const; const BuildingDef* findBuildingDef(BuildingType type) const; - const RecipeDef* findRecipe(const std::string& id, BuildingType type) const; - const ShipDef* findShipDef(const std::string& id) const; - const ModuleDef* findModuleDef(const std::string& id) const; void initBuffers(Building& b, const RecipeDef& recipe) const; // Buffers for an auto-recipe building (Smelter, Reprocessing Plant): input // caps span the union of every recipe of the building's type; no player diff --git a/src/lib/sim/ShipStatsCalculator.cpp b/src/lib/sim/ShipStatsCalculator.cpp index 48a2cb6..e0ca7aa 100644 --- a/src/lib/sim/ShipStatsCalculator.cpp +++ b/src/lib/sim/ShipStatsCalculator.cpp @@ -21,22 +21,9 @@ ShipStats calculateShipStats(const GameConfig& config, { ShipStats result{}; - const ShipDef* shipDef = nullptr; - for (const ShipDef& d : config.ships.ships) - { - if (d.id == shipId) { shipDef = &d; break; } - } + const ShipDef* shipDef = config.ships.findShipDef(shipId); if (!shipDef) { return result; } - auto findModuleDef = [&](const std::string& id) -> const ModuleDef* - { - for (const ModuleDef& d : config.modules.modules) - { - if (d.id == id) { return &d; } - } - return nullptr; - }; - const double tileSize = config.world.tileSize_m; // --- Base hull stats (convert from SI to display units) ------------------ @@ -67,7 +54,7 @@ ShipStats calculateShipStats(const GameConfig& config, for (const PlacedModule& pm : modules) { - const ModuleDef* def = findModuleDef(pm.moduleId); + const ModuleDef* def = config.modules.findModuleDef(pm.moduleId); if (!def) { throw std::runtime_error("unknown module id '" + pm.moduleId + "'"); } if (def->weaponCapability) @@ -107,7 +94,7 @@ ShipStats calculateShipStats(const GameConfig& config, for (const PlacedModule& pm : modules) { - const ModuleDef* def = findModuleDef(pm.moduleId); + const ModuleDef* def = config.modules.findModuleDef(pm.moduleId); if (!def) { throw std::runtime_error("unknown module id '" + pm.moduleId + "'"); } for (const ModuleStatModifier& sm : def->statModifiers) diff --git a/src/lib/sim/ThreatCostCalculator.cpp b/src/lib/sim/ThreatCostCalculator.cpp index 51c458f..1941ceb 100644 --- a/src/lib/sim/ThreatCostCalculator.cpp +++ b/src/lib/sim/ThreatCostCalculator.cpp @@ -335,15 +335,7 @@ double calculateShipThreatCost(const ThreatCostTable& table, const std::string& shipId, const std::vector& modules) { - const ShipDef* shipDef = nullptr; - for (const ShipDef& d : config.ships.ships) - { - if (d.id == shipId) - { - shipDef = &d; - break; - } - } + const ShipDef* shipDef = config.ships.findShipDef(shipId); if (shipDef == nullptr) { return 0.0; @@ -357,15 +349,7 @@ double calculateShipThreatCost(const ThreatCostTable& table, // Add module production times and material threats. for (const PlacedModule& pm : modules) { - const ModuleDef* moduleDef = nullptr; - for (const ModuleDef& d : config.modules.modules) - { - if (d.id == pm.moduleId) - { - moduleDef = &d; - break; - } - } + const ModuleDef* moduleDef = config.modules.findModuleDef(pm.moduleId); if (moduleDef == nullptr) { continue; diff --git a/src/ui/SchematicChoiceDialog.cpp b/src/ui/SchematicChoiceDialog.cpp index ddab1c7..8d831bb 100644 --- a/src/ui/SchematicChoiceDialog.cpp +++ b/src/ui/SchematicChoiceDialog.cpp @@ -12,15 +12,6 @@ namespace { -const RecipeDef* findRecipe(const RecipesConfig& recipes, const std::string& id) -{ - for (const RecipeDef& recipe : recipes.recipes) - { - if (recipe.id == id) { return &recipe; } - } - return nullptr; -} - QString grantKindLabel(SchematicType type) { switch (type) @@ -120,7 +111,7 @@ SchematicChoiceDialog::SchematicChoiceDialog( QLabel* recipeLabel = new QLabel( QString::fromStdString(toDisplayName(recipeId)), card); recipeLabel->setAlignment(Qt::AlignCenter); - if (const RecipeDef* def = findRecipe(recipes, recipeId)) + if (const RecipeDef* def = recipes.findRecipeDef(recipeId)) { recipeLabel->setToolTip(buildRecipeTooltip(*def)); } diff --git a/src/ui/SelectedBuildingPanel.cpp b/src/ui/SelectedBuildingPanel.cpp index aa6ce54..f5a61b4 100644 --- a/src/ui/SelectedBuildingPanel.cpp +++ b/src/ui/SelectedBuildingPanel.cpp @@ -430,14 +430,7 @@ void SelectedBuildingPanel::refreshBuffers(const Building* b) // the cycle time and progress can be shown (REQ-UI-PRODUCTION-PROGRESS). if (!recipe && isAutoRecipeBuilding(b->type) && b->production.has_value()) { - for (const RecipeDef& r : m_config->recipes.recipes) - { - if (r.id == b->production->recipeId && r.building == b->type) - { - recipe = &r; - break; - } - } + recipe = m_config->recipes.findRecipeDef(b->production->recipeId, b->type); } QString bufText; @@ -465,18 +458,14 @@ void SelectedBuildingPanel::refreshBuffers(const Building* b) { for (const PlacedModule& pm : b->shipLayout->placedModules) { - for (const ModuleDef& modDef : m_config->modules.modules) + const ModuleDef* modDef = + m_config->modules.findModuleDef(pm.moduleId); + if (!modDef) { continue; } + for (const RecipeIngredient& ing : modDef->materials) { - if (modDef.id == pm.moduleId) + if (ing.item == entry.first.id) { - for (const RecipeIngredient& ing : modDef.materials) - { - if (ing.item == entry.first.id) - { - perCycle += ing.amount; - } - } - break; + perCycle += ing.amount; } } } @@ -545,13 +534,11 @@ void SelectedBuildingPanel::refreshBuffers(const Building* b) { for (const PlacedModule& pm : b->shipLayout->placedModules) { - for (const ModuleDef& modDef : m_config->modules.modules) + const ModuleDef* modDef = + m_config->modules.findModuleDef(pm.moduleId); + if (modDef) { - if (modDef.id == pm.moduleId) - { - durationSeconds += modDef.productionTimeSeconds; - break; - } + durationSeconds += modDef->productionTimeSeconds; } } } @@ -633,21 +620,13 @@ void SelectedBuildingPanel::updateShipyardLayoutWidgets( const RecipeDef* SelectedBuildingPanel::findRecipe(const Building* b) const { if (b->recipeId.empty()) { return nullptr; } - for (const RecipeDef& r : m_config->recipes.recipes) - { - if (r.id == b->recipeId && r.building == b->type) { return &r; } - } - return nullptr; + return m_config->recipes.findRecipeDef(b->recipeId, b->type); } const ShipDef* SelectedBuildingPanel::findShipDef(const std::string& id) const { if (id.empty()) { return nullptr; } - for (const ShipDef& s : m_config->ships.ships) - { - if (s.id == id) { return &s; } - } - return nullptr; + return m_config->ships.findShipDef(id); } void SelectedBuildingPanel::handleEvent(std::shared_ptr /*event*/) @@ -1088,15 +1067,14 @@ void SelectedBuildingPanel::buildEntityShip(entt::entity entity) admin.get(entity).winner); m_entityStatsPanel->setDebugDrawEnabled(m_debugDraw); - for (const ShipDef& def : m_config->ships.ships) + const ShipDef* schematicDef = + m_config->ships.findShipDef(identity.schematicId); + if (schematicDef) { - if (def.id == identity.schematicId) - { - double threat = calculateShipThreatCost( - m_config->threatCosts, *m_config, def.id, def.defaultModules); - m_entityStatsPanel->setThreatCost(threat); - break; - } + const double threat = calculateShipThreatCost( + m_config->threatCosts, *m_config, schematicDef->id, + schematicDef->defaultModules); + m_entityStatsPanel->setThreatCost(threat); } m_entityStatsPanel->show(); diff --git a/src/ui/ShipLayoutDialog.cpp b/src/ui/ShipLayoutDialog.cpp index 226daf8..5551ad3 100644 --- a/src/ui/ShipLayoutDialog.cpp +++ b/src/ui/ShipLayoutDialog.cpp @@ -243,14 +243,7 @@ private: { return nullptr; } - for (const ModuleDef& def : m_config->modules.modules) - { - if (def.id == id) - { - return &def; - } - } - return nullptr; + return m_config->modules.findModuleDef(id); } std::vector rotateMask(const std::vector& mask, @@ -426,13 +419,10 @@ ShipLayoutDialog::ShipLayoutDialog(const GameConfig* config, setModal(true); // Find the ship's layout grid. - for (const ShipDef& def : config->ships.ships) + const ShipDef* shipDef = config->ships.findShipDef(shipId); + if (shipDef) { - if (def.id == shipId) - { - m_shipLayout = def.layout; - break; - } + m_shipLayout = shipDef->layout; } m_rows = static_cast(m_shipLayout.size()); @@ -706,11 +696,7 @@ void ShipLayoutDialog::rebuildOccupancy() for (int i = 0; i < static_cast(m_placedModules.size()); ++i) { const PlacedModule& pm = m_placedModules[i]; - const ModuleDef* def = nullptr; - for (const ModuleDef& d : m_config->modules.modules) - { - if (d.id == pm.moduleId) { def = &d; break; } - } + const ModuleDef* def = m_config->modules.findModuleDef(pm.moduleId); if (!def) { continue; @@ -807,11 +793,7 @@ void ShipLayoutDialog::loadLayoutBlueprint(const std::vector& modu for (const PlacedModule& pm : modules) { // Validate module type exists and is unlocked. - const ModuleDef* def = nullptr; - for (const ModuleDef& d : m_config->modules.modules) - { - if (d.id == pm.moduleId) { def = &d; break; } - } + const ModuleDef* def = m_config->modules.findModuleDef(pm.moduleId); if (!def || m_unlockedModuleIds.count(def->id) == 0) { continue; } const std::vector mask = rotatedMask(*def, pm.rotation);