awareness.py (9975B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\packages\behaviors\actions\awareness.py 2 from ballpark.entities.awareness.enemy_cluster_generator import THREAT_TIME_WINDOW_SECONDS 3 from behaviors.blackboards.scopes import GetBlackboardIdFromScopeAndContext, GetBlackboardScopeFromAddress 4 from behaviors.const.combat import THREAT_MAX_DISTANCE_FROM_GUARD_OBJECT, FW_ATTACK_NONE 5 from behaviors.tasks import Task 6 from behaviors.utility.awareness import get_fleet_awareness, get_awareness_config 7 from behaviors.utility.ballparks import get_ball_positions, is_coordinate_in_range_of_ball, is_ball_in_park, is_ball_cloaked, get_ball_position 8 from behaviors.utility.dogmatic import get_dogma_lm 9 from behaviors.utility.owner import get_owner_id 10 from behaviors.utility.threat import get_damage_tracker, evaluate_target 11 from ccpProfile import TimedFunction 12 from evemath import weighted_choice, get_center_point, get_farthest_distance_from_point 13 import logging 14 logger = logging.getLogger(__name__) 15 MIN_CLUSTER_QUALITY = 0.1 16 17 class ClusterData(object): 18 19 def __init__(self, item_ids, centroid, radius, threat): 20 self.item_ids = item_ids 21 self.centroid = centroid 22 self.radius = radius 23 self.quality = threat * self._calculate_cluster_quality() 24 25 def _calculate_cluster_quality(self): 26 cluster_radius_over_max_distance = self.radius / THREAT_MAX_DISTANCE_FROM_GUARD_OBJECT 27 cluster_proportion = min(cluster_radius_over_max_distance, 1.0) / len(self.item_ids) 28 return max(1.0 - cluster_proportion, MIN_CLUSTER_QUALITY) 29 30 31 class SendCentroidOfBallIds(Task): 32 33 @TimedFunction('behaviors::actions::awareness::SendCentroidOfBallIds::OnEnter') 34 def OnEnter(self): 35 centroid = None 36 ball_ids = self.GetLastBlackboardValue(self.attributes.ballIdListAddress) 37 if ball_ids: 38 position_list = get_ball_positions(self, ball_ids) 39 try: 40 centroid = get_center_point(position_list) 41 except ValueError: 42 logger.debug('No valid positions left in list with id %s', ball_ids) 43 44 self.SendBlackboardValue(self.attributes.centroidPositionAddress, centroid) 45 self.SetStatusToSuccess() 46 47 48 class ComputeCentroidAndRadiusOfItemIds(Task): 49 50 @TimedFunction('behaviors::actions::awareness::ComputeCentroidAndRadiusOfItemIds::OnEnter') 51 def OnEnter(self): 52 centroid = None 53 radius = None 54 ball_ids = self.GetLastBlackboardValue(self.attributes.itemIdsAddress) 55 if ball_ids: 56 position_list = get_ball_positions(self, ball_ids) 57 if position_list: 58 centroid = get_center_point(position_list) 59 radius = get_farthest_distance_from_point(centroid, position_list) 60 self.SendBlackboardValue(self.attributes.centroidPositionAddress, centroid) 61 self.SendBlackboardValue(self.attributes.radiusPositionAddress, radius) 62 self.SetStatusToSuccess() 63 64 65 class InitializeGroupAwareness(Task): 66 67 @TimedFunction('behaviors::actions::awareness::InitializeGroupAwareness::OnEnter') 68 def OnEnter(self): 69 manager = self.context.entityLocation.GetGroupAwarenessManager() 70 member_collection_id = self.get_member_collection_id() 71 if manager.is_registered(member_collection_id): 72 logger.debug('Group %s already registered, ignoring.', member_collection_id) 73 self.SetStatusToFailed() 74 else: 75 manager.register_group_awareness(member_collection_id, self.get_awareness_config()) 76 self.SetStatusToSuccess() 77 78 def get_member_collection_id(self): 79 return self.context.myEntityGroupId 80 81 def get_awareness_config(self): 82 config = get_awareness_config(self) 83 config.standings_enabled = self.attributes.standingsEnabled 84 config.react_to_disapproval = self.attributes.reactToDisapproval or False 85 fwAttackMethod = self.attributes.fwAttackMethod 86 if fwAttackMethod == FW_ATTACK_NONE: 87 fwAttackMethod = None 88 config.fw_attack_method = fwAttackMethod 89 return config 90 91 92 class InitializeSpawnPoolFleetAwareness(InitializeGroupAwareness): 93 94 def __init__(self, attributes = None): 95 super(InitializeSpawnPoolFleetAwareness, self).__init__(attributes=attributes) 96 self.spawn_pool_id = None 97 98 @TimedFunction('behaviors::actions::awareness::InitializeSpawnPoolFleetAwareness::OnEnter') 99 def OnEnter(self): 100 self.spawn_pool_id = self.GetLastBlackboardValue(self.attributes.spawnPoolIdAddress) 101 get_owner_id(self) 102 manager = self._get_awareness_manager() 103 blackboard_scope = GetBlackboardScopeFromAddress(self.attributes.combatTargetsSetAddress) 104 blackboard_id = GetBlackboardIdFromScopeAndContext(blackboard_scope, self.context) 105 manager.register_spawn_pool_fleet_awareness(self.spawn_pool_id, get_owner_id(self), blackboard_id, self.behaviorTree.GetBehaviorId(), self.get_awareness_config()) 106 self.SetStatusToSuccess() 107 108 def get_member_collection_id(self): 109 return self.spawn_pool_id 110 111 def _get_awareness_manager(self): 112 return self.context.entityLocation.GetGroupAwarenessManager() 113 114 def get_awareness_config(self): 115 config = get_awareness_config(self) 116 config.standings_enabled = False 117 config.fw_attack_method = None 118 return config 119 120 121 class AddMyItemIdToSpawnPoolFleetAwareness(Task): 122 123 @TimedFunction('behaviors::actions::awareness::AddMyItemIdToSpawnPoolFleetAwareness::OnEnter') 124 def OnEnter(self): 125 spawn_pool_id = self.GetLastBlackboardValue(self.attributes.spawnPoolIdAddress) 126 manager = self._get_awareness_manager() 127 awareness = manager.get_spawn_pool_fleet_awareness(spawn_pool_id) 128 if awareness is None: 129 logger.error('Unable to find a spawn pool fleet awareness instance for spawn pool %s', spawn_pool_id, self.attributes.spawnPoolIdAddress) 130 self.SetStatusToFailed() 131 else: 132 member_collection = awareness.get_member_collection() 133 member_collection.add_item_id(self.context.myItemId) 134 self.SetStatusToSuccess() 135 136 def _get_awareness_manager(self): 137 return self.context.entityLocation.GetGroupAwarenessManager() 138 139 140 class InitializeEnemyClusterGeneration(Task): 141 142 @TimedFunction('behaviors::actions::awareness::InitializeEnemyClusterGeneration::OnEnter') 143 def OnEnter(self): 144 spawn_pool_id = self.get_spawn_pool_id() 145 group_awareness = get_fleet_awareness(self, spawn_pool_id) 146 if group_awareness.get_enemy_cluster_generator() is None: 147 group_awareness.enable_enemy_cluster_generator(get_dogma_lm(self), get_damage_tracker(self), self.attributes.updateIntervalSeconds, self.GetChannelFromAddress(self.attributes.enemyClustersAddress)) 148 self.SetStatusToSuccess() 149 150 def get_awareness_manager(self): 151 return self.context.entityLocation.GetGroupAwarenessManager() 152 153 def get_spawn_pool_id(self): 154 return self.GetLastBlackboardValue(self.attributes.spawnPoolIdAddress) 155 156 157 class SelectClusterWeightedByThreat(Task): 158 159 @TimedFunction('behaviors::actions::awareness::SelectClusterWeightedByThreat::OnEnter') 160 def OnEnter(self): 161 enemy_clusters = self.get_updated_enemy_clusters(self.get_enemy_clusters()) 162 cluster = None 163 if enemy_clusters: 164 cluster = self.select_cluster_weighted_by_threat(enemy_clusters) 165 if cluster: 166 self.SendBlackboardValue(self.attributes.clusterCentroidAddress, cluster.centroid) 167 self.SendBlackboardValue(self.attributes.clusterRadiusAddress, cluster.radius) 168 self.SendBlackboardValue(self.attributes.clusterItemIdsAddress, cluster.item_ids) 169 self.SetStatusToSuccess() 170 else: 171 self.SetStatusToFailed() 172 173 def select_cluster_weighted_by_threat(self, enemy_clusters): 174 return weighted_choice([ (cluster, cluster.quality) for cluster in enemy_clusters ]) 175 176 def get_updated_enemy_clusters(self, enemy_clusters): 177 updated_enemy_clusters = [] 178 for cluster in enemy_clusters: 179 item_ids = {item_id for item_id in cluster['item_ids'] if is_ball_in_park(self, item_id) and not is_ball_cloaked(self, item_id)} 180 if not item_ids: 181 continue 182 points = [ get_ball_position(self, ball_id) for ball_id in item_ids ] 183 centroid = get_center_point(points) 184 if not self._is_in_range(centroid): 185 continue 186 updated_cluster = ClusterData(item_ids, centroid, get_farthest_distance_from_point(centroid, points), self._get_cluster_threat(item_ids)) 187 updated_enemy_clusters.append(updated_cluster) 188 189 return updated_enemy_clusters 190 191 def get_enemy_clusters(self): 192 return self.GetLastBlackboardValue(self.attributes.enemyClustersAddress) 193 194 def _is_in_range(self, cluster_coordinates): 195 guard_object_id = self._get_guard_object_id() 196 if guard_object_id is None: 197 return True 198 return is_coordinate_in_range_of_ball(self, guard_object_id, cluster_coordinates, THREAT_MAX_DISTANCE_FROM_GUARD_OBJECT) 199 200 def _get_guard_object_id(self): 201 if not self.HasAttribute('guardObjectIdAddress'): 202 return 203 guard_object_id = self.GetLastBlackboardValue(self.attributes.guardObjectIdAddress) 204 if guard_object_id is None: 205 return 206 if not is_ball_in_park(self, guard_object_id): 207 return 208 return guard_object_id 209 210 @TimedFunction('behaviors::actions::awareness::SelectClusterWeightedByThreat::_update_cluster_threat') 211 def _get_cluster_threat(self, item_ids): 212 return sum((self._get_item_threat(item_id) for item_id in item_ids)) 213 214 def _get_item_threat(self, item_id): 215 return evaluate_target(self.context.damageTracker, self.context.dogmaLM, item_id, THREAT_TIME_WINDOW_SECONDS)