clientPathfinderService.py (15970B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\client\script\util\clientPathfinderService.py 2 import gametime 3 import logging 4 import pyEvePathfinder 5 import uthread2 6 import six 7 from carbon.common.lib import telemetry 8 from carbon.common.script.sys.service import Service 9 from eve.common.lib import appConst as const 10 from eve.common.script.sys import idCheckers 11 from eve.common.script.sys.idCheckers import IsSolarSystem 12 from evePathfinder.eveMapWrapper import EveMapWrapper 13 from evePathfinder.lightYearDistances import LightYearDistanceFinder 14 from evePathfinder.pathfinder import ClientPathfinder 15 from evePathfinder.stateinterface import AutopilotPathfinderInterface, StandardPathfinderInterface 16 from signals import Signal 17 from stargate.client.gate_signals import on_lock_changed, on_lock_added, on_lock_removed, on_lock_changed_in_restricted_system 18 from stargate.client.gateLockController import GateLockController 19 from stargate.client import get_gate_lock_messenger 20 from threadutils import be_nice 21 logger = logging.getLogger(__name__) 22 PATHFINDER_WAIT_TIMEOUT_SECONDS = 60 23 24 def ConvertStationIDToSolarSystemIDIfNecessary(waypointID): 25 if idCheckers.IsStation(waypointID): 26 return cfg.stations.Get(waypointID).solarSystemID 27 if idCheckers.IsSolarSystem(waypointID): 28 return waypointID 29 structure = sm.GetService('structureDirectory').GetStructureInfo(waypointID) 30 if structure is not None: 31 return structure.solarSystemID 32 return waypointID 33 34 35 def GetCurrentSolarSystemID(): 36 return session.solarsystemid2 37 38 39 def UpdatesAutopilot(func): 40 41 def Wrapper(*args, **kwargs): 42 func(*args, **kwargs) 43 sm.ScatterEvent('OnAutopilotUpdated') 44 45 return Wrapper 46 47 48 class PathfinderWaitTimoutError(Exception): 49 pass 50 51 52 def WaitForPathfinderInitialization(func): 53 54 def Wrapper(self, *args, **kwargs): 55 startTime = gametime.GetWallclockTime() 56 while not self.initialized or self.clientPathfinder is None: 57 if gametime.GetSecondsSinceWallclockTime(startTime) > PATHFINDER_WAIT_TIMEOUT_SECONDS: 58 raise PathfinderWaitTimoutError() 59 uthread2.sleep(0.1) 60 61 return func(self, *args, **kwargs) 62 63 return Wrapper 64 65 66 class ClientPathfinderService(Service): 67 __exportedcalls__ = {} 68 __guid__ = 'svc.clientPathfinderService' 69 __servicename__ = 'pathfinderSvc' 70 __displayname__ = 'Client Pathfinder Service' 71 __dependencies__ = ['settings', 72 'map', 73 'objectCaching', 74 'securitySvc'] 75 __notifyevents__ = ['OnCharacterSessionChanged', 'OnSecurityModified', 'OnSessionReset'] 76 _PATHFINDER_IGNORED_GATES = () 77 78 def Run(self, memStream = None): 79 self.clientPathfinder = None 80 self.lastJumpGatesLoaded = {} 81 self.lightYearDistanceFinder = None 82 self._gate_lock_controller = GateLockController.get_instance(get_gate_lock_messenger(sm.GetService('publicGatewaySvc'))) 83 self.on_pathfinder_initialized = Signal('on_pathfinder_initialized') 84 self.initialized = False 85 self.LogInfo('Starting Client Pathfinder Service') 86 87 def OnCharacterSessionChanged(self, _oldCharacterID, newCharacterID): 88 if newCharacterID is not None: 89 self.Initialize() 90 91 def OnSessionReset(self): 92 self.lastJumpGatesLoaded.clear() 93 self.initialized = False 94 95 def OnSecurityModified(self, solarSystemID, modifierAmount, newSecurity): 96 if self.clientPathfinder is not None: 97 self.clientPathfinder.pathfinderCore.newPathfinderMap.SetSolarSystemSecurity(solarSystemID, newSecurity) 98 sm.GetService('autoPilot').OptimizeRoute() 99 sm.ScatterEvent('OnAutopilotUpdated') 100 101 def UpdateJumpGates(self): 102 availableJumpThroughStructures = self.GetAvailableJumpGateJumps(cfg.mapJumpCache) 103 if self.lastJumpGatesLoaded == availableJumpThroughStructures: 104 return 105 self.lastJumpGatesLoaded = availableJumpThroughStructures 106 self.ForceUpdatePathfinderCore() 107 108 def ForceUpdatePathfinderCore(self): 109 pathfinderCore = self.CreatePathfinderCore(cfg.mapRegionCache, cfg.mapSystemCache, cfg.mapJumpCache, self.securitySvc.get_modified_security_level, self.GetJumpGateTuple(self.lastJumpGatesLoaded), ClientPathfinderService._PATHFINDER_IGNORED_GATES) 110 self.clientPathfinder.UpdatePathfinderCore(pathfinderCore) 111 112 @telemetry.ZONE_METHOD 113 def CreatePathfinderCore(self, mapRegionCache, mapSystemCache, mapJumpCache, get_security_level_func, one_way_jump_tuples = (), ignored_stargate_ids = ()): 114 eve_map = EveMapWrapper() 115 eve_map.add_regions(mapRegionCache) 116 eve_map.add_solar_systems(mapSystemCache, get_security_level_func) 117 restricted_system_ids = self._gate_lock_controller.get_restricted_systems() 118 solar_system_to_emanation_lock_details_dict = self._gate_lock_controller.get_solar_system_to_lock_details_dict() 119 for jump in mapJumpCache: 120 if jump.stargateID in ignored_stargate_ids: 121 logger.info('ClientPathfinderService - client pathfinder has ignored (excluded) jump from Stargate %s (in SolarSystem %s) to reach SolarSystem %s', jump.stargateID, jump.fromSystemID, jump.toSystemID) 122 elif jump.fromSystemID in restricted_system_ids or jump.toSystemID in restricted_system_ids: 123 opposite_gate_id = cfg.mapStargateIdMappingCache[jump.stargateID] 124 for fromSystemID, toSystemID, stargateID in ((jump.fromSystemID, jump.toSystemID, jump.stargateID), (jump.toSystemID, jump.fromSystemID, opposite_gate_id)): 125 if session.solarsystemid2 != fromSystemID and fromSystemID in restricted_system_ids: 126 logger.info('Emanation Lock - client pathfinder has excluded jumping from Stargate %s (in SolarSystem %s) to reach SolarSystem %s', stargateID, fromSystemID, toSystemID) 127 continue 128 emanation_lock_details = solar_system_to_emanation_lock_details_dict.get(fromSystemID) 129 logger.info('Emanation Lock - %s', emanation_lock_details) 130 if emanation_lock_details is not None and stargateID != emanation_lock_details.gate_id: 131 logger.info('Emanation Lock - client pathfinder has excluded jumping from Stargate %s (in SolarSystem %s) to reach SolarSystem %s', stargateID, fromSystemID, toSystemID) 132 continue 133 logger.info('Emanation Lock - client pathfinder has included jump from Stargate %s (in SolarSystem %s) to reach SolarSystem %s', stargateID, fromSystemID, toSystemID) 134 eve_map.add_jump(fromSystemID, toSystemID) 135 136 else: 137 eve_map.add_jump(jump.fromSystemID, jump.toSystemID) 138 eve_map.add_jump(jump.toSystemID, jump.fromSystemID) 139 be_nice() 140 141 eve_map.add_one_way_jumps(one_way_jump_tuples) 142 eve_map.finalize() 143 return eve_map.create_core() 144 145 def on_emanation_lock_added(self, lock_details): 146 if not self.initialized: 147 self.on_pathfinder_initialized.connect(self._on_emanation_lock_updated_delayed) 148 return 149 self._on_emanation_locks_updated() 150 151 def _on_emanation_lock_updated_delayed(self): 152 self.on_pathfinder_initialized.disconnect(self._on_emanation_lock_updated_delayed) 153 self._on_emanation_locks_updated() 154 155 def on_emanation_lock_removed(self, lock_details): 156 self._on_emanation_locks_updated() 157 158 def on_lock_changed_in_restricted_system(self, lock_details, previous_lock): 159 if not self.initialized: 160 self.on_pathfinder_initialized.connect(self._on_emanation_lock_updated_delayed) 161 return 162 self._on_emanation_locks_updated() 163 164 def on_emanation_lock_changed(self, lock_details, previous_lock): 165 if lock_details is None and previous_lock is None: 166 return 167 self._on_emanation_locks_updated() 168 169 def _on_emanation_locks_updated(self): 170 self.ForceUpdatePathfinderCore() 171 sm.GetService('starmap').UpdateRoute() 172 173 def Initialize(self): 174 self.LogInfo('Initializing the pathfinding internals') 175 self.lastPKversionNumber = -1 176 self.lastTrigTaleVersionNumber = -1 177 if self.clientPathfinder is None: 178 on_lock_changed.connect(self.on_emanation_lock_changed) 179 on_lock_changed_in_restricted_system.connect(self.on_lock_changed_in_restricted_system) 180 on_lock_added.connect(self.on_emanation_lock_added) 181 on_lock_removed.connect(self.on_emanation_lock_removed) 182 availableJumpThroughStructures = self.GetAvailableJumpGateJumps(cfg.mapJumpCache) 183 self.lastJumpGatesLoaded = availableJumpThroughStructures 184 pathfinderCore = self.CreatePathfinderCore(cfg.mapRegionCache, cfg.mapSystemCache, cfg.mapJumpCache, self.securitySvc.get_modified_security_level, self.GetJumpGateTuple(availableJumpThroughStructures), ClientPathfinderService._PATHFINDER_IGNORED_GATES) 185 autopilotStateInterface = AutopilotPathfinderInterface(self.map, self.UpdatePodKillList, self.GetTriglavianTaleAvoidanceSystems, self.GetEdencomSystemsAvoidanceList, settings.char.ui) 186 standardStateInterface = StandardPathfinderInterface() 187 self.clientPathfinder = ClientPathfinder(pathfinderCore, standardStateInterface, autopilotStateInterface, ConvertStationIDToSolarSystemIDIfNecessary, GetCurrentSolarSystemID) 188 self.initialized = True 189 self.on_pathfinder_initialized() 190 191 def GetAvailableJumpGateJumps(self, mapJumpCache): 192 availableJumpGates = {} 193 if not settings.char.ui.Get('pathFinder_includeJumpGates', False): 194 return availableJumpGates 195 stargateJumps = set() 196 for jump in mapJumpCache: 197 stargateJumps.add((jump.fromSystemID, jump.toSystemID)) 198 stargateJumps.add((jump.toSystemID, jump.fromSystemID)) 199 200 mapsSvc = sm.GetService('map') 201 mapsSvc.GetJumpBridgesWithMyAccess.clear_memoized() 202 jumpBridgesGates, hasAccessTo, hasNoAccessTo = mapsSvc.GetJumpBridgesWithMyAccess() 203 for structureA, structureB in jumpBridgesGates: 204 solarSystemA = structureA.solarSystemID 205 solarSystemB = structureB.solarSystemID 206 if not IsSolarSystem(solarSystemA) or not IsSolarSystem(solarSystemB): 207 continue 208 if structureA.structureID in hasAccessTo and (solarSystemA, solarSystemB) not in stargateJumps: 209 availableJumpGates[solarSystemA, solarSystemB] = structureA.structureID 210 if structureB.structureID in hasAccessTo and (solarSystemB, solarSystemA) not in stargateJumps: 211 availableJumpGates[solarSystemB, solarSystemA] = structureB.structureID 212 213 return availableJumpGates 214 215 def GetJumpGateTuple(self, availableJumps): 216 return [ (k[0], k[1], v) for k, v in availableJumps.iteritems() ] 217 218 def UpdatePodKillList(self, podKillList): 219 args = (const.mapHistoryStatKills, 24) 220 if self.lastPKversionNumber == -1 or self.lastPKversionNumber != self.objectCaching.GetCachedMethodCallVersion(None, 'map', 'GetHistory', args): 221 unfilteredSystemHistory = sm.RemoteSvc('map').GetHistory(*args) 222 self.lastPKversionNumber = self.objectCaching.GetCachedMethodCallVersion(None, 'map', 'GetHistory', args) 223 podKillList = [] 224 for system in unfilteredSystemHistory: 225 if system.value3 > 0: 226 podKillList.append(system.solarSystemID) 227 228 podKillList.sort() 229 return podKillList 230 231 def GetTriglavianTaleAvoidanceSystems(self): 232 return sm.GetService('map').GetTriglavianMinorVictorySystems() 233 234 def GetEdencomSystemsAvoidanceList(self): 235 return sm.GetService('map').GetEdencomAvoidanceSystems() 236 237 def AddAvoidanceItem(self, *args, **kwds): 238 self.clientPathfinder.AddAvoidanceItem(*args, **kwds) 239 sm.ScatterEvent('OnAutopilotUpdated') 240 sm.ScatterEvent('OnAvoidanceItemsChanged') 241 242 def RemoveAvoidanceItem(self, *args, **kwds): 243 self.clientPathfinder.RemoveAvoidanceItem(*args, **kwds) 244 sm.ScatterEvent('OnAutopilotUpdated') 245 sm.ScatterEvent('OnAvoidanceItemsChanged') 246 247 def GetLastKnownJumpGates(self): 248 return self.lastJumpGatesLoaded 249 250 def GetMandatoryAvoidanceItems(self): 251 return self._gate_lock_controller.get_restricted_systems() 252 253 @WaitForPathfinderInitialization 254 def GetAvoidanceItems(self, *args, **kwargs): 255 return self.clientPathfinder.GetAvoidanceItems(*args, **kwargs) 256 257 @WaitForPathfinderInitialization 258 def GetAutopilotRouteType(self, *args, **kwargs): 259 return self.clientPathfinder.GetAutopilotRouteType(*args, **kwargs) 260 261 @WaitForPathfinderInitialization 262 def GetWaypointPath(self, *args, **kwargs): 263 return self.clientPathfinder.GetWaypointPath(*args, **kwargs) 264 265 @WaitForPathfinderInitialization 266 def GetJumpCountsBetweenSystemPairs(self, *args, **kwargs): 267 return self.clientPathfinder.GetJumpCountsBetweenSystemPairs(*args, **kwargs) 268 269 @WaitForPathfinderInitialization 270 def GetPathBetween(self, *args, **kwargs): 271 return self.clientPathfinder.GetPathBetween(*args, **kwargs) 272 273 @WaitForPathfinderInitialization 274 def GetAutopilotPathBetween(self, *args, **kwargs): 275 return self.clientPathfinder.GetAutopilotPathBetween(*args, **kwargs) 276 277 @WaitForPathfinderInitialization 278 def GetJumpCount(self, *args, **kwargs): 279 return self.clientPathfinder.GetJumpCount(*args, **kwargs) 280 281 @WaitForPathfinderInitialization 282 def GetAutopilotJumpCount(self, *args, **kwargs): 283 return self.clientPathfinder.GetAutopilotJumpCount(*args, **kwargs) 284 285 @WaitForPathfinderInitialization 286 def GetJumpCountFromCurrent(self, *args, **kwargs): 287 return self.clientPathfinder.GetJumpCountFromCurrent(*args, **kwargs) 288 289 @WaitForPathfinderInitialization 290 def GetSystemsWithinAutopilotJumpRange(self, *args, **kwargs): 291 return self.clientPathfinder.GetSystemsWithinAutopilotJumpRange(*args, **kwargs) 292 293 @WaitForPathfinderInitialization 294 def GetSystemsWithinJumpRange(self, *args, **kwargs): 295 return self.clientPathfinder.GetSystemsWithinJumpRange(*args, **kwargs) 296 297 @WaitForPathfinderInitialization 298 def GetExpandedAvoidanceItems(self, *args, **kwargs): 299 return self.clientPathfinder.GetExpandedAvoidanceItems(*args, **kwargs) 300 301 @WaitForPathfinderInitialization 302 def GetNoRouteFoundText(self, *args, **kwargs): 303 return self.clientPathfinder.GetNoRouteFoundText(*args, **kwargs) 304 305 @WaitForPathfinderInitialization 306 def GetNoRouteFoundTextAutopilot(self, *args, **kwargs): 307 return self.clientPathfinder.GetNoRouteFoundTextAutopilot(*args, **kwargs) 308 309 @UpdatesAutopilot 310 def SetPodKillAvoidance(self, *args, **kwargs): 311 self.clientPathfinder.SetPodKillAvoidance(*args, **kwargs) 312 313 @UpdatesAutopilot 314 def SetTriglavianTaleAvoidance(self, *args, **kwargs): 315 self.clientPathfinder.SetTriglavianTaleAvoidance(*args, **kwargs) 316 317 @UpdatesAutopilot 318 def SetEdencomSystemsAvoidance(self, *args, **kwargs): 319 self.clientPathfinder.SetEdencomSystemsAvoidance(*args, **kwargs) 320 321 @UpdatesAutopilot 322 def SetSystemAvoidance(self, *args, **kwargs): 323 self.clientPathfinder.SetSystemAvoidance(*args, **kwargs) 324 325 @UpdatesAutopilot 326 def SetAutopilotRouteType(self, *args, **kwargs): 327 self.clientPathfinder.SetAutopilotRouteType(*args, **kwargs) 328 329 @UpdatesAutopilot 330 def SetSecurityPenaltyFactor(self, *args, **kwargs): 331 self.clientPathfinder.SetSecurityPenaltyFactor(*args, **kwargs) 332 333 def GetLightYearDistanceFinder(self): 334 if not self.lightYearDistanceFinder: 335 self.lightYearDistanceFinder = LightYearDistanceFinder() 336 return self.lightYearDistanceFinder