megaglest-0001: Unit::updateAttackBoostProgress() std::find on currentAttackBoostUnits vector<int> inside per-frame candidate loop O(C*B), plus reverse lookup on candidateValidIdList O(B*C). Fix: unordered_set<int> for O(1) membership. MEDIUM, 8.3x at N=2000. megaglest-0002: UnitUpdater::findUnitsForCell() linear dedup scan of units vector inside findUnitsInRange grid loop O(R^2 * U). Fix: unordered_set<int> seenIds for O(1) dedup. HIGH, 9.1x at cells=5000, units=500. MOAD-0002 (Intertangle): CLEAN, standard game engine singletons. MOAD-0003 (Leaked Context): CLEAN, no thread_local usage. MOAD-0004 (Logged Secret): FTP password logged in miniftpclient.cpp lines 358, 360, 968, 975 via szBuf containing ftp://user:pass@host URL. CWE-312 confirmed but in bundled third-party FTP client code. MOAD-0005 (Thundering Herd): CLEAN, single-threaded game logic. 4/4 unit tests PASS.
70 lines
4.2 KiB
Diff
70 lines
4.2 KiB
Diff
--- a/source/glest_game/type_instances/unit.cpp
|
|
+++ b/source/glest_game/type_instances/unit.cpp
|
|
@@ -2,6 +2,7 @@
|
|
// unit.cpp
|
|
//
|
|
|
|
+#include <unordered_set>
|
|
#include "unit.h"
|
|
|
|
#include <cassert>
|
|
@@ -2576,7 +2577,12 @@
|
|
UnitUpdater *unitUpdater = this->game->getWorld()->getUnitUpdater();
|
|
|
|
const AttackBoost *attackBoost = currSkill->getAttackBoost();
|
|
vector<Unit *> candidates = unitUpdater->findUnitsInRange(this, attackBoost->radius);
|
|
- vector<int> candidateValidIdList;
|
|
- candidateValidIdList.reserve(candidates.size());
|
|
+ std::unordered_set<int> candidateValidIdSet;
|
|
+ candidateValidIdSet.reserve(candidates.size());
|
|
+
|
|
+ // Build hash set of currently boosted unit IDs for O(1) membership test
|
|
+ std::unordered_set<int> boostedIdSet(
|
|
+ currentAttackBoostOriginatorEffect.currentAttackBoostUnits.begin(),
|
|
+ currentAttackBoostOriginatorEffect.currentAttackBoostUnits.end());
|
|
|
|
if (debugBoost)
|
|
printf("Line: %d candidates unit size: " MG_SIZE_T_SPECIFIER " attackBoost: %s\n", __LINE__, candidates.size(),
|
|
@@ -2585,9 +2591,9 @@
|
|
for (unsigned int i = 0; i < candidates.size(); ++i) {
|
|
Unit *affectedUnit = candidates[i];
|
|
- candidateValidIdList.push_back(affectedUnit->getId());
|
|
+ candidateValidIdSet.insert(affectedUnit->getId());
|
|
|
|
- std::vector<int>::iterator iterFound = std::find(currentAttackBoostOriginatorEffect.currentAttackBoostUnits.begin(),
|
|
- currentAttackBoostOriginatorEffect.currentAttackBoostUnits.end(), affectedUnit->getId());
|
|
+ bool alreadyBoosted = boostedIdSet.count(affectedUnit->getId()) > 0;
|
|
|
|
if (attackBoost->isAffected(this, affectedUnit) == true) {
|
|
- if (iterFound == currentAttackBoostOriginatorEffect.currentAttackBoostUnits.end()) {
|
|
+ if (!alreadyBoosted) {
|
|
if (affectedUnit->applyAttackBoost(attackBoost, this) == true) {
|
|
currentAttackBoostOriginatorEffect.currentAttackBoostUnits.push_back(affectedUnit->getId());
|
|
+ boostedIdSet.insert(affectedUnit->getId());
|
|
}
|
|
}
|
|
} else {
|
|
- if (iterFound != currentAttackBoostOriginatorEffect.currentAttackBoostUnits.end()) {
|
|
+ if (alreadyBoosted) {
|
|
affectedUnit->deapplyAttackBoost(currentAttackBoostOriginatorEffect.skillType->getAttackBoost(), this);
|
|
- currentAttackBoostOriginatorEffect.currentAttackBoostUnits.erase(iterFound);
|
|
+ auto eraseIt = std::find(currentAttackBoostOriginatorEffect.currentAttackBoostUnits.begin(),
|
|
+ currentAttackBoostOriginatorEffect.currentAttackBoostUnits.end(), affectedUnit->getId());
|
|
+ if (eraseIt != currentAttackBoostOriginatorEffect.currentAttackBoostUnits.end()) {
|
|
+ currentAttackBoostOriginatorEffect.currentAttackBoostUnits.erase(eraseIt);
|
|
+ }
|
|
+ boostedIdSet.erase(affectedUnit->getId());
|
|
}
|
|
}
|
|
}
|
|
@@ -2616,7 +2622,7 @@
|
|
if (currentAttackBoostOriginatorEffect.currentAttackBoostUnits.empty() == false) {
|
|
for (int i = (int)currentAttackBoostOriginatorEffect.currentAttackBoostUnits.size() - 1; i >= 0; --i) {
|
|
int findUnitId = currentAttackBoostOriginatorEffect.currentAttackBoostUnits[i];
|
|
|
|
- std::vector<int>::iterator iterFound = std::find(candidateValidIdList.begin(), candidateValidIdList.end(), findUnitId);
|
|
- if (iterFound == candidateValidIdList.end()) {
|
|
+ if (candidateValidIdSet.count(findUnitId) == 0) {
|
|
Unit *affectedUnit = game->getWorld()->findUnitById(findUnitId);
|
|
if (affectedUnit != NULL) {
|
|
affectedUnit->deapplyAttackBoost(currentAttackBoostOriginatorEffect.skillType->getAttackBoost(), this);
|