dungeonTracking.py (12129B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\client\script\parklife\dungeonTracking.py 2 import localization 3 import signals 4 from carbon.common.script.sys.service import Service 5 from eve.client.script.parklife import dungeon_signals 6 from eve.common.script.sys.rowset import Rowset 7 from eve.common.script.sys.eveCfg import IsDocked 8 from evedungeons.client.anomalyTracker import CombatAnomalyTracker, FactionalWarfareSiteTracker, HomefrontOperationTracker, IceBeltTracker, OreAnomalyTracker, PirateInsurgencySiteTracker, TriglavianSiteTracker, BulwarkMiningSitesTracker 9 from evedungeons.client.data import GetDungeon, GetDungeonObjectivesData 10 from logging import getLogger 11 from nodegraph.common.nodedata import is_client_graph 12 from objectives.client.objective_chain import ObjectiveChain 13 from objectives.common.objective_context import ObjectivesContext, get_authored_parameter_values_as_dict 14 logger = getLogger(__name__) 15 16 def GetDungeonTrackingService(): 17 return sm.GetService('dungeonTracking') 18 19 20 class DungeonTracking(Service): 21 __guid__ = 'svc.dungeonTracking' 22 __notifyevents__ = ['ProcessSessionChange', 23 'OnCharacterSessionChanged', 24 'OnDistributionDungeonEntered', 25 'OnEscalatingPathDungeonEntered', 26 'OnEnteringDungeonRoom', 27 'OnExitingDungeon', 28 'OnDungeonMessage', 29 'OnDungeonValues', 30 'OnDungeonCompleted'] 31 32 def __init__(self): 33 super(DungeonTracking, self).__init__() 34 self.distributionDungeonsEntered = None 35 self.escalatingPathDungeonsEntered = None 36 self.trackers = {'combat_anomalies': CombatAnomalyTracker(), 37 'factional_warfare': FactionalWarfareSiteTracker(), 38 'homefront_operations': HomefrontOperationTracker(), 39 'ice_belts': IceBeltTracker(), 40 'ore_anomalies': OreAnomalyTracker(), 41 'pirate_insurgency': PirateInsurgencySiteTracker(), 42 'triglavian': TriglavianSiteTracker(), 43 'bulwark_mining_sites': BulwarkMiningSitesTracker()} 44 self.current_dungeon = None 45 46 def Run(self, memStream = None): 47 super(DungeonTracking, self).Run(memStream) 48 for tracker in self.trackers.values(): 49 tracker.initialize() 50 51 def ProcessSessionChange(self, isRemote, session, change): 52 if 'locationid' in change: 53 self.distributionDungeonsEntered = None 54 self.escalatingPathDungeonsEntered = None 55 self._clear_dungeon() 56 57 def OnCharacterSessionChanged(self, oldCharacterID, newCharacterID): 58 if not newCharacterID or IsDocked(): 59 return 60 dungeon_info = sm.RemoteSvc('keeper').GetCurrentDungeonForCharacter() 61 if dungeon_info: 62 dungeon_id, room_id, instance_id, dungeon_values = dungeon_info 63 self.OnEnteringDungeonRoom(dungeon_id=dungeon_id, room_id=room_id, room_position=None, instance_id=instance_id, dungeon_values=dungeon_values) 64 65 def OnDistributionDungeonEntered(self, row): 66 if self.distributionDungeonsEntered is None: 67 self.distributionDungeonsEntered = Rowset(row.header) 68 self.distributionDungeonsEntered.append(row) 69 70 def OnEscalatingPathDungeonEntered(self, row): 71 if self.escalatingPathDungeonsEntered is None: 72 self.escalatingPathDungeonsEntered = Rowset(row.header) 73 if getattr(row, 'dungeonNameID', None): 74 row.name = localization.GetByMessageID(row.dungeonNameID) 75 self.escalatingPathDungeonsEntered.append(row) 76 77 def GetDistributionDungeonsEntered(self): 78 return self.distributionDungeonsEntered 79 80 def GetEscalatingPathDungeonsEntered(self): 81 return self.escalatingPathDungeonsEntered 82 83 def GetCurrentDungeonID(self): 84 if self.current_dungeon: 85 return self.current_dungeon.dungeon_id 86 else: 87 return None 88 89 def get_current_dungeon(self): 90 return self.current_dungeon 91 92 def OnEnteringDungeonRoom(self, dungeon_id, room_id, room_position, instance_id, dungeon_values): 93 if not self.current_dungeon or self.current_dungeon.dungeon_id != dungeon_id: 94 logger.info('Dungeon Entered - dungeon_id: %s - room_id: %s - instance_id: %s - values: %s', dungeon_id, room_id, instance_id, dungeon_values) 95 self.current_dungeon = ActiveDungeon(dungeon_id, room_id, instance_id, dungeon_values) 96 self.current_dungeon.start() 97 sm.ScatterEvent('OnDungeonEntered', dungeon_id, instance_id) 98 dungeon_signals.on_dungeon_room_entered(dungeon_id, room_id, instance_id) 99 else: 100 self.current_dungeon.room_id = room_id 101 102 def OnExitingDungeon(self, dungeon_id): 103 self._clear_dungeon(dungeon_id) 104 105 def OnDungeonMessage(self, dungeon_id, message_key, message_value): 106 if self.current_dungeon and self.current_dungeon.dungeon_id == dungeon_id: 107 self.current_dungeon.message(message_key, message_value) 108 109 def OnDungeonValues(self, dungeon_id, values): 110 logger.info('Dungeon Values received - current_dungeon_id: %s - dungeon_id: %s - values: %s', self.GetCurrentDungeonID(), dungeon_id, values) 111 if self.current_dungeon and self.current_dungeon.dungeon_id == dungeon_id: 112 self.current_dungeon.update_dungeon_values(values) 113 for key, value in values.iteritems(): 114 self.current_dungeon.update_context_value(key, value) 115 116 def OnDungeonCompleted(self, dungeon_id): 117 if self.current_dungeon and self.current_dungeon.dungeon_id == dungeon_id: 118 self.current_dungeon.update_context_value('dungeon_completed', True) 119 120 def _clear_dungeon(self, dungeon_id = None): 121 if not self.current_dungeon: 122 return 123 if not dungeon_id or self.current_dungeon.dungeon_id == dungeon_id: 124 instance_id = self.current_dungeon.instance_id 125 self.current_dungeon.stop() 126 self.current_dungeon = None 127 sm.ScatterEvent('OnDungeonExited', dungeon_id, instance_id) 128 129 def get_tracker(self, tracker_id): 130 return self.trackers[tracker_id] 131 132 133 class ActiveDungeon(object): 134 135 def __init__(self, dungeon_id, room_id, instance_id, dungeon_values): 136 self._context = ObjectivesContext() 137 self._context.set_values(dungeon_id=dungeon_id, dungeon_room_id=room_id) 138 self.update_dungeon_values(dungeon_values or {}) 139 self._mission = None 140 self._node_graph = None 141 self._objective_chain = None 142 self._instance_id = instance_id 143 self.on_room_changed = signals.Signal('on_room_changed') 144 145 def message(self, key, value): 146 if not key.startswith('dungeon_'): 147 key = u'dungeon_{}'.format(key) 148 self._context.send_message(key, value=value) 149 150 def update_dungeon_values(self, values): 151 for key, value in values.iteritems(): 152 keys = key.split('.') 153 self._context.update_value(keys[0], value, object_path=keys[1:]) 154 155 def update_context_value(self, key, value): 156 self._context.update_value(key, value) 157 158 @property 159 def objective_chain(self): 160 return self._objective_chain 161 162 @property 163 def dungeon_id(self): 164 return self._context.get_value('dungeon_id') 165 166 @property 167 def instance_id(self): 168 return self._instance_id 169 170 @property 171 def room_id(self): 172 return self._context.get_value('dungeon_room_id') 173 174 @room_id.setter 175 def room_id(self, value): 176 if self.room_id == value: 177 return 178 self.update_context_value('dungeon_room_id', value) 179 self.on_room_changed() 180 181 @property 182 def data(self): 183 return GetDungeon(self.dungeon_id) 184 185 @property 186 def title(self): 187 return localization.GetByMessageID(self.data.dungeonNameID) 188 189 @property 190 def description(self): 191 return localization.GetByMessageID(self.data.descriptionID) 192 193 @property 194 def archetype_id(self): 195 return self.data.archetypeID 196 197 @property 198 def faction_id(self): 199 return self.data.factionID 200 201 @property 202 def difficulty(self): 203 return self.data.factionID 204 205 @property 206 def mission_briefing_id(self): 207 return self.data.missionBriefingID 208 209 @property 210 def entry_type_id(self): 211 return self.data.entryTypeID 212 213 @property 214 def standing_restrictions(self): 215 return self.data.standingRestrictions 216 217 @property 218 def objectives_data(self): 219 return GetDungeonObjectivesData(self.dungeon_id) 220 221 def start(self): 222 sm.RegisterForNotifyEvent(self, 'OnExpandedMissionChanged') 223 self.OnExpandedMissionChanged(**sm.GetService('infoPanel').GetExpandedMission()) 224 dungeon_objectives = self.objectives_data 225 if dungeon_objectives: 226 self._context.set_values(**get_authored_parameter_values_as_dict(dungeon_objectives.blackboardParameters)) 227 self._start_objective_chain(dungeon_objectives.objectiveChainID, dungeon_objectives.overrides) 228 self._start_node_graph(dungeon_objectives.nodeGraphID) 229 230 def stop(self): 231 sm.UnregisterForNotifyEvent(self, 'OnExpandedMissionChanged') 232 self.update_context_value('dungeon_room_id', None) 233 self._stop_node_graph() 234 if self._mission: 235 self._mission = None 236 if self._objective_chain: 237 self._objective_chain.stop() 238 self._objective_chain = None 239 self._context.clear() 240 241 def _start_objective_chain(self, objective_chain_id, overrides): 242 if not objective_chain_id: 243 return 244 self._objective_chain = ObjectiveChain(content_id=objective_chain_id, context=self._context, overrides=overrides) 245 self._objective_chain.start() 246 247 def _start_node_graph(self, node_graph_id): 248 if not node_graph_id or self._node_graph: 249 return 250 if is_client_graph(node_graph_id): 251 self._node_graph = sm.GetService('node_graph').start_node_graph(node_graph_id=node_graph_id, context=self._context) 252 253 def get_context_menu(self): 254 from carbonui.control.contextMenu.menuData import MenuData 255 from objectives.client.qa_tools import is_qa, key_value_entry 256 data = MenuData() 257 if not is_qa(): 258 return data 259 result = MenuData() 260 dungeon_objectives_id = GetDungeon(self.dungeon_id).objectivesID 261 if dungeon_objectives_id: 262 result.AddEntry(text='Open Dungeon Objectives in FSD Editor', func=lambda : _open_fsd_dungeon_objectives(dungeon_objectives_id)) 263 if self._node_graph: 264 result.AddEntry(text='Open Dungeon Node Graph', func=lambda : _open_active_node_graph(self._node_graph.instance_id)) 265 result.AddSeparator() 266 if self.objective_chain: 267 result.entrylist.extend(self.objective_chain.get_context_menu()) 268 result.entrylist.append(key_value_entry('Blackboard Values', self._context.values, self._context)) 269 data.AddEntry('QA', subMenuData=result) 270 return data 271 272 def OnExpandedMissionChanged(self, featureID = None, missionID = None): 273 is_focused = False 274 if featureID == 'opportunities' and missionID and missionID != -1: 275 provider_id, instance_id = missionID.split(':') 276 if instance_id == str(self.instance_id) and _is_dungeon_provider(provider_id): 277 is_focused = True 278 self._context.update_value('mission_focused', is_focused) 279 280 def _stop_node_graph(self): 281 if self._node_graph: 282 sm.GetService('node_graph').stop_node_graph(self._node_graph.instance_id) 283 self._node_graph = None 284 285 286 def _is_dungeon_provider(provider_id): 287 from jobboard.client.provider_type import DUNGEON_PROVIDERS 288 return provider_id in DUNGEON_PROVIDERS 289 290 291 def _open_fsd_dungeon_objectives(content_id): 292 import webbrowser 293 webbrowser.open_new('http://localhost:8000/dungeons/dungeon_objectives/{}/'.format(content_id)) 294 295 296 def _open_active_node_graph(node_graph_instance_id): 297 from nodegraph.client.ui.window import NodeGraphEditorWindow 298 NodeGraphEditorWindow.Open(node_graph_id=node_graph_instance_id)