spawning.py (13082B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\packages\behaviors\utility\spawning.py 2 from ballpark.entities.spawndataforentities import get_spawn_data_for_entities_with_custom_behavior_overrides 3 from ballpark.entities.spawndataforentities import get_spawn_data_for_entities 4 from ballparkCommon.docking import GetUndockVector 5 from behaviors.const.blackboardchannels import UNDOCK_DIRECTION_CHANNEL_NAME 6 from behaviors.utility import security 7 from behaviors.utility.ballparks import get_slim_item 8 from behaviors.utility.blackboards import get_response_thresholds 9 from behaviors.utility.context import get_extra_context 10 from behaviors.utility.entity_groups import entity_group_exists 11 from behaviors.utility.owner import get_owner_id 12 from ccpProfile import TimedFunction 13 from npcs.server.npcspawning.npcgrouping import generate_grouping 14 from npcs.server.npcspawning.spawn_const import DEFAULT_DEPLOYMENT_OFFSET_METERS 15 from npcs.server.npcspawning.spawntableloader import SpawnTableLoader 16 from spawnlists.data import select_probability_items 17 try: 18 from ballpark.locationgenerator import GetRandomDeepSpaceLocation 19 except ImportError: 20 21 def GetRandomDeepSpaceLocation(): 22 return (0, 0, 0) 23 24 25 import logging 26 logger = logging.getLogger(__name__) 27 28 def get_deployment_range(task): 29 if getattr(task.attributes, 'deploymentRange', None): 30 return task.attributes.deploymentRange 31 else: 32 return DEFAULT_DEPLOYMENT_OFFSET_METERS 33 34 35 def get_spawn_table_id(task): 36 return task.GetLastBlackboardValue(task.attributes.spawnTableIdAddress) 37 38 39 class EntityGetter(object): 40 41 def __init__(self, task): 42 self.task = task 43 44 @TimedFunction('behaviors::utility::spawning::EntityGetter::get_entities') 45 def get_spawn_data_for_entities(self, max_npc_count = None): 46 entities = getattr(self.task.attributes, 'entities', {}) 47 behavior_override_id = self.task.get_behavior_override_id() 48 return self._get_spawn_data_for_entities(entities.iteritems(), behavior_override_id) 49 50 def _get_spawn_data_for_entities(self, entity_types_and_count, behavior_override_id): 51 return get_spawn_data_for_entities(entity_types_and_count, None, get_deployment_range(self.task), behavior_override_id) 52 53 def on_spawn_entities(self, entity_group_id): 54 pass 55 56 57 class EntityGetterBySpawnlistAndOwner(EntityGetter): 58 59 @TimedFunction('behaviors::utility::spawning::EntityGetterBySpawnlistAndOwner::get_entities') 60 def get_spawn_data_for_entities(self, max_npc_count = None): 61 spawn_list_id = security.get_spawnlist_by_group_owner_and_security_level(self.task) 62 if not spawn_list_id: 63 return None 64 entity_group_list = select_probability_items(spawn_list_id) 65 if not entity_group_list: 66 return None 67 entity_group_id = entity_group_list.keys()[0] 68 entities_iterator = generate_grouping(entity_group_id) 69 behavior_override_id = self.task.get_behavior_override_id() 70 return self._get_spawn_data_for_entities(entities_iterator, behavior_override_id) 71 72 73 class EntityGetterFromSpawnPointPool(EntityGetter): 74 75 @TimedFunction('behaviors::utility::spawning::EntityGetterFromSpawnPointPool::get_entities') 76 def get_spawn_data_for_entities(self, max_npc_count = None): 77 spawn_pool_id = self.task.get_spawn_pool_id() 78 spawn_point_amount = self._get_spawn_point_amount(spawn_pool_id) 79 if not spawn_point_amount > 0: 80 logger.error('Bad authoring for behavior type %s - missing spawn points', self.task.context.mySlimItem.typeID) 81 return 82 if spawn_pool_id is not None: 83 npcs_and_remaining_points = self._get_entities_using_spawn_point_pool(spawn_point_amount, spawn_pool_id, max_npc_count) 84 else: 85 npcs_and_remaining_points = self._pick_entities_from_spawn_table(spawn_point_amount, max_npc_count) 86 if npcs_and_remaining_points is None: 87 return 88 npcs, remaining_points = npcs_and_remaining_points 89 logger.debug('Picked from spawn_pool_id=%s with available points=%s npcs=%s remaining points=%s max_npc_count=%s', spawn_pool_id, spawn_point_amount, npcs, remaining_points, max_npc_count) 90 return self._get_spawn_data_for_entities(npcs.iteritems(), None) 91 92 def _get_spawn_point_amount(self, spawn_pool_id): 93 spawn_points = 0 94 if self.task.HasAttribute('spawnPoints'): 95 spawn_points = self.task.attributes.spawnPoints 96 elif spawn_pool_id: 97 spawn_pool_manager = self._get_spawn_point_pool_manager() 98 spawn_points = spawn_pool_manager.get_current_spawn_points(spawn_pool_id) 99 return spawn_points 100 101 def _get_entities_using_spawn_point_pool(self, spawn_point_amount, spawn_pool_id, max_npc_count): 102 spawn_pool_manager = self._get_spawn_point_pool_manager() 103 if spawn_pool_id: 104 available_spawn_points = spawn_pool_manager.get_current_spawn_points(spawn_pool_id) 105 if spawn_point_amount > available_spawn_points: 106 logger.debug('Not enough spawn points in pool for spawning new NPCs') 107 return 108 npc_and_remaining_points = self._pick_entities_from_spawn_table(spawn_point_amount, max_npc_count) 109 if npc_and_remaining_points is None: 110 logger.debug('No npcs picked spawn_point_amount=%s, spawn_pool_id=%s, max_npc_count=%s', spawn_point_amount, spawn_pool_id, max_npc_count) 111 return 112 npcs, remaining_points = npc_and_remaining_points 113 if spawn_pool_id: 114 spawn_pool_manager.consume_spawn_points(spawn_pool_id, spawn_point_amount - remaining_points) 115 return npc_and_remaining_points 116 117 def _pick_entities_from_spawn_table(self, spawn_point_amount, max_npc_count): 118 spawn_table_picker = self._get_spawn_table_picker() 119 required_npc_tags = self.task.get_required_npc_tags() 120 spawn_table_id = get_spawn_table_id(self.task) 121 npc_and_remaining_points = spawn_table_picker.pick_npcs_from_table_by_points_and_tags(spawn_table_id, spawn_point_amount, required_npc_tags, max_npc_count=max_npc_count) 122 return npc_and_remaining_points 123 124 def _get_spawn_point_pool_manager(self): 125 return self.task.context.entityLocation.spawnPointPoolManager 126 127 def _get_spawn_table_picker(self): 128 return self.task.context.entityLocation.spawnTablePicker 129 130 def on_spawn_entities(self, entity_group_id): 131 awareness_manager = self.task.context.entityLocation.GetGroupAwarenessManager() 132 awareness_manager.on_entity_group_spawn(self.task.get_spawn_pool_id(), entity_group_id) 133 134 def _get_spawn_data_for_entities(self, entities_iterator, _): 135 return get_spawn_data_for_entities_with_custom_behavior_overrides(entities_iterator, None, get_deployment_range(self.task)) 136 137 138 class EntitySpawner(object): 139 140 def __init__(self, task): 141 self.task = task 142 143 @TimedFunction('behaviors::utility::spawning::EntitySpawner::spawn_new_entities') 144 def spawn_new_entities(self, spawn_data_for_entities): 145 owner_id = self.get_owner_id() 146 group_id = self.get_group_id() 147 self._update_spawn_position(spawn_data_for_entities) 148 behavior_group_tree_name = self._get_behavior_group_tree_name() 149 extra_content = get_extra_context(self.task) 150 group, entity_item_ids = self.task.context.entityLocation.DeployBehaviorEntities(owner_id, spawn_data_for_entities, group_id, groupBehaviorTreeName=behavior_group_tree_name, extraContext=extra_content, spawnTags=self.task.get_required_npc_tags(), standingThresholds=get_response_thresholds(self.task), objectiveTargetGroup=self._get_objective_target_group()) 151 self._register_entity_bounty_multiplier(entity_item_ids) 152 self.update_entity_group_id(group.GetID()) 153 return (group, entity_item_ids) 154 155 def get_owner_id(self): 156 return get_owner_id(self.task) 157 158 def _update_spawn_position(self, spawn_data_for_entities): 159 spawn_position = self.task.get_spawn_position() 160 for entity_spawn_data in spawn_data_for_entities: 161 entity_spawn_data.update_spawn_position(spawn_position) 162 163 def _get_spawn_position(self): 164 if getattr(self.task.attributes, 'spawnPositionAddress', None): 165 return self.task.GetLastBlackboardValue(self.task.attributes.spawnPositionAddress) 166 else: 167 return GetRandomDeepSpaceLocation(self.task.context.ballpark.solarsystemID) 168 169 def get_group_id(self): 170 if self.task.attributes.spawnNewGroup: 171 return None 172 if self.task.HasAttribute('entityGroupIdAddress'): 173 entity_group_id = self.task.GetLastBlackboardValue(self.task.attributes.entityGroupIdAddress) 174 if entity_group_exists(self.task, entity_group_id): 175 return entity_group_id 176 return None 177 return self.task.context.myEntityGroupId 178 179 def _get_behavior_group_tree_name(self): 180 return getattr(self.task.attributes, 'behaviorTreeGroupName', None) 181 182 def update_entity_group_id(self, entity_group_id): 183 if self.task.HasAttribute('entityGroupIdAddress'): 184 self.task.SendBlackboardValue(self.task.attributes.entityGroupIdAddress, entity_group_id) 185 186 def _register_entity_bounty_multiplier(self, entity_item_ids): 187 bounty_pay_out_multiplier = self.task.get_bounty_pay_out_multiplier() 188 if bounty_pay_out_multiplier is None: 189 return 190 self.task.context.entityLocation.RegisterBountyPayOutMultiplierForEntities(entity_item_ids, bounty_pay_out_multiplier) 191 192 def _get_objective_target_group(self): 193 if getattr(self.task.attributes, 'objectiveTargetGroupAddress', None): 194 return self.task.GetLastBlackboardValue(self.task.attributes.objectiveTargetGroupAddress) 195 196 197 class EntitySpawnTableSpawner(EntitySpawner): 198 199 def get_owner_id(self): 200 spawn_table_id = get_spawn_table_id(self.task) 201 return SpawnTableLoader().get_spawn_table(spawn_table_id).npcowner 202 203 204 class EntitySpawnerWithUndock(EntitySpawner): 205 206 @TimedFunction('behaviors::utility::spawning::EntitySpawnerWithUndock::spawn_new_entities') 207 def spawn_new_entities(self, spawn_data_for_entities): 208 owner_id = get_owner_id(self.task) 209 group_id = self.get_group_id() 210 direction_by_entity_type = self._update_spawn_parameters_and_get_direction(spawn_data_for_entities) 211 behavior_group_tree_name = self._get_behavior_group_tree_name() 212 extra_content = get_extra_context(self.task) 213 group, entity_item_ids = self.task.context.entityLocation.DeployBehaviorEntities(owner_id, spawn_data_for_entities, group_id, groupBehaviorTreeName=behavior_group_tree_name, extraContext=extra_content, spawnTags=self.task.get_required_npc_tags(), standingThresholds=get_response_thresholds(self.task), objectiveTargetGroup=self._get_objective_target_group()) 214 self._register_entity_bounty_multiplier(entity_item_ids) 215 self.update_entity_group_id(group.GetID()) 216 self._set_undock_direction(entity_item_ids, direction_by_entity_type) 217 return (group, entity_item_ids) 218 219 def _update_spawn_parameters_and_get_direction(self, spawn_data_for_entities): 220 structure_id = self._get_structure_id() 221 direction_by_entity_type = {} 222 for entity_spawn_data in spawn_data_for_entities: 223 entity_type_id = entity_spawn_data.entity_type_id 224 spawn_position, direction = self._get_spawn_position_and_direction(structure_id, entity_type_id) 225 entity_spawn_data.spawn_position = spawn_position 226 entity_spawn_data.direction = direction 227 direction_by_entity_type[entity_type_id] = direction 228 229 return direction_by_entity_type 230 231 def _get_structure_id(self): 232 return self.task.GetLastBlackboardValue(self.task.attributes.structureIdAddress) 233 234 def _get_spawn_position_and_direction(self, structure_id, entity_type_id): 235 return GetUndockVector(self.task.context.ballpark, structure_id, entity_type_id) 236 237 def _set_undock_direction(self, entity_ids, direction_by_entity_type): 238 for entity_id in entity_ids: 239 entity_type_id = get_slim_item(self.task, entity_id).typeID 240 direction = direction_by_entity_type[entity_type_id] 241 self._post_undock_direction_to_entity(entity_id, direction) 242 243 def _post_undock_direction_to_entity(self, entity_id, directional_position): 244 self.task.GetMessageChannelForItemId(entity_id, UNDOCK_DIRECTION_CHANNEL_NAME).SendMessage(directional_position) 245 246 247 def get_spawn_point_pool_manager(task): 248 return task.context.entityLocation.spawnPointPoolManager 249 250 251 def get_current_spawn_points(task, spawn_pool_id): 252 try: 253 return get_spawn_point_pool_manager(task).get_current_spawn_points(spawn_pool_id) 254 except: 255 logger.exception('failed to get the current spawn pool points') 256 raise 257 258 259 def add_spawn_points(task, spawn_pool_id, amount): 260 get_spawn_point_pool_manager(task).add_spawn_points(spawn_pool_id, amount)