Subject: Potential Memory Leak / Performance Issue in CombatManager: Dictionary colliderToDamageable not cleaned up on object destruction
Game Version: 1.0.6b
Description:
In CombatManager , there is a dictionary colliderToDamageable that caches IDamageable components for quick lookup during combat queries (e.g., GetCombatTargetsInRadius ). The dictionary is populated in GetCombatTargetsInRadius and similar methods:
csharp
if (!colliderToDamageable.TryGetValue(collider, out var value)) { value = collider.gameObject.GetComponent(); colliderToDamageable.Add(collider, value); }
However, when an IDamageable object (e.g., a raider, building, etc.) is destroyed, the corresponding entry in colliderToDamageable is never removed . The ReportDamageableRemoved method (called when a DamageableComponent is destroyed) removes the object from other lists like allDamageables , raiderFocusedDamageables , etc., but does not touch colliderToDamageable .
This leads to:
- Dangling references to already-destroyed
UnityEngine.Objectinstances, which may causeMissingReferenceExceptionif accessed later. - Dictionary bloat over time, increasing memory usage and lookup overhead, especially in long play sessions with many combat units.
- Potential performance degradation as the dictionary grows indefinitely.
Steps to Reproduce:
- Start a game with combat enabled.
- Let multiple raiders/villagers fight and die (or buildings get destroyed).
- Over time, the dictionary
colliderToDamageablewill accumulate entries for every destroyed collider/object that was ever queried. - (Optional) Use a memory profiler to observe the dictionary size and retained entries.
Expected Behavior:
The dictionary should be cleaned up when an object is destroyed, or at least when its IDamageable is removed. A proper implementation could:
- In
ReportDamageableRemoved, also iterate throughcolliderToDamageableto remove any entries referencing thatIDamageable(or its collider). However, since the mapping is fromCollidertoIDamageable, you’d need to know the collider(s) associated with the object. - Alternatively, use a
WeakReferenceor an event system whereIDamageablenotifies the manager upon destruction, allowing removal from the dictionary. - Consider not caching at all, or using a more robust caching strategy that is aware of object lifecycle (e.g., based on instance IDs and cleaned on scene changes).
Suggested Fix:
Add cleanup logic in ReportDamageableRemoved or subscribe to object destruction events to remove entries from colliderToDamageable . For example:
csharp
public void ReportDamageableRemoved(DamageableComponent damageable) { // … existing code … // Remove all colliders associated with this damageable from the dictionary var colliders = damageable.GetComponentsInChildren(true); foreach (var col in colliders) { colliderToDamageable.Remove(col); } }
Additional Context:
This issue was spotted during code review of the CombatManager class. It appears in the game’s source (as decompiled) and may affect long-term gameplay stability and performance. It is not a crash-level bug but could contribute to gradual slowdown.
Thank you for looking into this! Keep up the great work on Farthest Frontier.