NovaBryan/EVE_Dump
Log | Files | 📦 下载最新源码 (.zip) | Refs | README

scanSvc.py (28688B)


      1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\client\script\parklife\scanSvc.py
      2 import blue
      3 import carbonui.const as uiconst
      4 import evetypes
      5 import functools
      6 import geo2
      7 import localization
      8 import probescanning.customFormations as customFormations
      9 import probescanning.probeTracker as probeTracker
     10 import probescanning.resultFilter as resultFilter
     11 import probescanning.scanHandler as scanHandler
     12 import uthread
     13 import utillib
     14 from carbon.client.script.environment.AudioUtil import PlaySound
     15 from carbon.common.script.sys.service import Service
     16 from carbon.common.script.sys.serviceConst import ROLE_ANY, ROLE_GML, ROLE_QA, ROLE_WORLDMOD
     17 from carbon.common.script.util.format import FmtDist
     18 from carbonui.uicore import uicore
     19 from eve.client.script.ui.inflight.probeScannerWindow import ProbeScannerWindow as Scanner
     20 from eve.client.script.ui.shared.maps import mapcommon
     21 from eve.common.script.sys import idCheckers
     22 from eveexceptions import ExceptionEater, UserError
     23 from eveservices.menu import GetMenuService
     24 from menu import MenuLabel
     25 from player_messaging.client.ui_message import prompt_player_fsd_dialog
     26 from probescanning.const import COMBAT_TARGETS
     27 from probescanning.explorationSites import get_exploration_site_group_name
     28 from probescanning.fiFoDict import FiFoDict
     29 from probescanning.formations import SELF_CENTER_FORMATION
     30 from probescanning.util import IsExplorationSite
     31 RECONNECT_DELAY_MINUTES = 1
     32 MIN_PROBE_RECOVER_DISTANCE = 2000
     33 NAME_BY_SCANGROUPID = {const.probeScanGroupAnomalies: 'UI/Inflight/Scanner/CosmicAnomaly',
     34  const.probeScanGroupSignatures: 'UI/Inflight/Scanner/CosmicSignature',
     35  const.probeScanGroupShips: 'UI/Inflight/Scanner/Ship',
     36  const.probeScanGroupStructures: 'UI/Inflight/Scanner/Structure',
     37  const.probeScanGroupDrones: 'UI/Inflight/Scanner/Drone',
     38  const.probeScanGroupCharges: 'UI/Inflight/Scanner/Charge',
     39  const.probeScanGroupNPCs: 'UI/Inflight/Scanner/NPC',
     40  const.probeScanGroupFighters: 'UI/Inflight/Scanner/Fighter',
     41  const.probeScanGroupStarBase: 'UI/Inflight/Scanner/StarBase',
     42  const.probeScanGroupOrbitals: 'UI/Inflight/Scanner/Orbital',
     43  const.probeScanGroupDeployable: 'UI/Inflight/Scanner/Deployable',
     44  const.probeScanGroupSovereignty: 'UI/Inflight/Scanner/Sovereignty',
     45  const.probeScanGroupAbyssalTraces: 'UI/Inflight/Scanner/AbyssalTrace'}
     46 
     47 def UserErrorIfScanning(action, *args, **kwargs):
     48 
     49     @functools.wraps(action)
     50     def wrapper(*args, **kwargs):
     51         if sm.StartService('scanSvc').IsScanning():
     52             raise UserError('ScanInProgressGeneric')
     53         return action(*args, **kwargs)
     54 
     55     return wrapper
     56 
     57 
     58 class ScanSvc(Service):
     59     __guid__ = 'svc.scanSvc'
     60     __servicename__ = 'svc.scanSvc'
     61     __displayname__ = 'Scanner Probe Service'
     62     __notifyevents__ = ['OnSessionChanged',
     63      'OnSystemScanStarted',
     64      'OnSystemScanStopped',
     65      'OnProbeWarpStart',
     66      'OnProbesIdle',
     67      'OnProbeStateChanged',
     68      'OnNewProbe',
     69      'OnRemoveProbe',
     70      'OnScannerInfoRemoved',
     71      'DoSimClockRebase',
     72      'OnCustomFormationDeleted']
     73     __dependencies__ = ['michelle', 'godma', 'audio']
     74     __uthreads__ = []
     75     __exportedcalls__ = {'SetProbeDestination': [ROLE_ANY],
     76      'SetProbeRangeStep': [ROLE_ANY],
     77      'GetProbeData': [ROLE_ANY],
     78      'GetScanResults': [ROLE_ANY],
     79      'RequestScans': [ROLE_ANY],
     80      'RecoverProbe': [ROLE_ANY],
     81      'RecoverProbes': [ROLE_ANY],
     82      'ReconnectToLostProbes': [ROLE_ANY],
     83      'DestroyProbe': [ROLE_ANY],
     84      'GetScanRangeStepsByTypeID': [ROLE_ANY],
     85      'QAScanSites': [ROLE_QA]}
     86     __configvalues__ = {'max_scan_systems_stored': 50}
     87 
     88     def __init__(self):
     89         Service.__init__(self)
     90         self.lastResults = None
     91         self.probeLabels = {}
     92         self.selectedSites = set()
     93         self.lastReconnection = None
     94         self.lastRangeStepUsed = 5
     95         self.remoteObject = None
     96         self.probeTracker = None
     97         self.resultFilter = None
     98         self.scanHandlerBySystem = None
     99 
    100     def Run(self, memStream = None):
    101         self.probeTracker = probeTracker.ProbeTracker(self, sm.ScatterEvent)
    102         self.resultFilter = resultFilter.ResultFilter()
    103         self.scanHandlerBySystem = FiFoDict(max_size=self.max_scan_systems_stored, default_factory=scanHandler.ScanHandler, factory_params=(self, self.resultFilter))
    104 
    105     def GetScanMan(self):
    106         if self.remoteObject is None:
    107             self.remoteObject = sm.RemoteSvc('scanMgr').GetSystemScanMgr()
    108         return self.remoteObject
    109 
    110     def OnNewProbe(self, probe):
    111         self.probeTracker.AddProbe(probe)
    112 
    113     def OnRemoveProbe(self, probeID):
    114         self.probeTracker.RemoveProbe(probeID)
    115 
    116     def DoSimClockRebase(self, times):
    117         if not self.lastReconnection:
    118             return
    119         oldSimTime, newSimTime = times
    120         self.lastReconnection += newSimTime - oldSimTime
    121 
    122     def GetActiveProbes(self):
    123         return self.probeTracker.GetActiveProbes()
    124 
    125     def HasAvailableProbes(self):
    126         return self.probeTracker.HasAvailableProbes()
    127 
    128     def GetProbeState(self, probeID):
    129         return self.probeTracker.GetProbeState(probeID)
    130 
    131     def IsProbeActive(self, probeID):
    132         return self.probeTracker.IsProbeActive(probeID)
    133 
    134     def GetProbeData(self):
    135         return self.probeTracker.GetProbeData()
    136 
    137     def GetScaledProbes(self, point, probeIDs):
    138         return self.probeTracker.GetScaledProbes(point, probeIDs, mapcommon.SYSTEMMAP_SCALE)
    139 
    140     def OnSessionChanged(self, isRemote, sess, change):
    141         if 'charid' in change and change['charid'][1] is not None:
    142             self.probeTracker.Refresh()
    143             self.scanHandlerBySystem.clear()
    144         if 'solarsystemid' in change or 'shipid' in change or 'structureid' in change:
    145             if self.IsScanning():
    146                 self.OnSystemScanStopped(self.GetScanningProbes(), None, None)
    147             self.FlushScannerState(reinjectSites='solarsystemid' not in change)
    148             if sess.charid is None and 'charid' in change:
    149                 self.scanHandlerBySystem.clear()
    150             if sess.solarsystemid:
    151                 self.ClearCombatTargets()
    152 
    153     def ClearCombatTargets(self):
    154         self.scanHandlerBySystem[session.solarsystemid].ClearCombatTargets()
    155 
    156     def SetProbeDestination(self, probeID, location):
    157         self.probeTracker.SetProbeDestination(probeID, location)
    158 
    159     def SetProbeRangeStep(self, probeID, rangeStep):
    160         self.probeTracker.SetProbeRangeStep(probeID, rangeStep)
    161 
    162     def SetProbeActiveState(self, probeID, state):
    163         self.probeTracker.SetProbeActiveState(probeID, state)
    164 
    165     @UserErrorIfScanning
    166     def RequestScans_Check(self):
    167         if idCheckers.IsAbyssalSpaceSystem(session.solarsystemid2):
    168             key = 'ProbeScannerAbyssalSpaceWarning'
    169             response = prompt_player_fsd_dialog(key, buttons=uiconst.YESNO, suppress=uiconst.ID_YES)
    170             if response == uiconst.ID_NO:
    171                 return
    172         elif idCheckers.IsVoidSpaceSystem(session.solarsystemid2):
    173             raise UserError('ProbeScannerVoidSpaceHint')
    174         self.RequestScans()
    175 
    176     def RequestScans(self):
    177         probes = self.probeTracker.GetProbesForScanning()
    178         self.GetScanMan().RequestScans(probes)
    179         probeIDs = probes.keys() if probes is not None else [session.shipid]
    180         self.scanHandlerBySystem[session.solarsystemid].SetProbesAsScanning(probeIDs)
    181         self.probeTracker.SetProbesAsMoving(probes)
    182 
    183     def OnProbeStateChanged(self, probeID, probeState):
    184         self.probeTracker.OnProbeStateChanged(probeID, probeState)
    185 
    186     def OnCustomFormationDeleted(self, formationID):
    187         self.probeTracker.OnFormationDeleted(formationID)
    188 
    189     def GetScanningProbes(self):
    190         return self.scanHandlerBySystem[session.solarsystemid].GetScanningProbes()
    191 
    192     def GetScanResults(self):
    193         return self.scanHandlerBySystem[session.solarsystemid].GetScanResults()
    194 
    195     def GetCurrentScan(self):
    196         return self.scanHandlerBySystem[session.solarsystemid].GetCurrentScan()
    197 
    198     def GetIgnoredResults(self):
    199         return self.scanHandlerBySystem[session.solarsystemid].GetIgnoredResults()
    200 
    201     def GetIgnoredResultsDesc(self):
    202         resultIDs = self.GetIgnoredResults()
    203         descList = []
    204         for id in resultIDs:
    205             result = self.scanHandlerBySystem[session.solarsystemid].resultsHistory.GetResult(id)
    206             if result.id:
    207                 descList.append((id, self.GetDisplayName(result)))
    208 
    209         return descList
    210 
    211     def OnProbeWarpStart(self, probeID, fromPos, toPos, startTime, duration):
    212         self.LogInfo('OnProbeWarpStart', probeID)
    213 
    214     def OnProbesIdle(self, probes):
    215         self.probeTracker.OnProbesIdle(probes)
    216 
    217     def UpdateProbeState(self, probeID, state, caller = None, notify = True):
    218         self.probeTracker.UpdateProbeState(probeID, state, caller=None, notify=True)
    219 
    220     def UpdateProbePosition(self, probeID, position):
    221         self.probeTracker.UpdateProbePosition(probeID, position)
    222 
    223     def OnSystemScanStarted(self, startTime, durationMs, probes):
    224         self.scanHandlerBySystem[session.solarsystemid].OnSystemScanStarted(startTime, durationMs, probes)
    225         sm.ScatterEvent('OnSystemScanBegun')
    226         PlaySound('msg_newscan_probe_analyze_play')
    227 
    228     def OnSystemScanStopped(self, probes, results, absentTargets):
    229         PlaySound('msg_newscan_probe_analyze_play')
    230         PlaySound('msg_newscan_probe_analyze_stop')
    231         if not results:
    232             prompt_player_fsd_dialog('ScnNoResults')
    233         self.scanHandlerBySystem[session.solarsystemid].OnSystemScanStopped(probes, results, absentTargets)
    234         sm.ScatterEvent('OnSystemScanDone')
    235 
    236     def GetScanRangeStepsByTypeID(self, typeID):
    237         return self.probeTracker.GetScanRangeStepsByTypeID(typeID)
    238 
    239     def DestroyProbe(self, probeID):
    240         self.probeTracker.DestroyProbe(probeID, self.GetScanMan().DestroyProbe)
    241 
    242     def ReconnectToLostProbes(self):
    243         if not session.solarsystemid2:
    244             return
    245         ship = sm.StartService('michelle').GetItem(session.shipid)
    246         if ship and ship.groupID == const.groupCapsule:
    247             raise UserError('ScnProbeRecoverToPod')
    248         if self.CanClaimProbes():
    249             self.lastReconnection = blue.os.GetSimTime()
    250             try:
    251                 self.lastReconnection = blue.os.GetSimTime()
    252                 self.GetScanMan().ReconnectToLostProbes()
    253             finally:
    254                 uthread.new(self.Thread_ShowReconnectToProbesAvailable, self.lastReconnection)
    255 
    256         else:
    257             seconds = RECONNECT_DELAY_MINUTES * const.MIN - (blue.os.GetSimTime() - self.lastReconnection)
    258             raise UserError('ScannerProbeReconnectWait', {'when': seconds})
    259 
    260     def Thread_ShowReconnectToProbesAvailable(self, lastReconnection):
    261         snooze = (RECONNECT_DELAY_MINUTES * const.MIN - (blue.os.GetSimTime() - self.lastReconnection)) / const.MSEC
    262         while snooze > 0:
    263             blue.pyos.synchro.SleepSim(snooze)
    264             if self.lastReconnection is None:
    265                 break
    266             snooze = (RECONNECT_DELAY_MINUTES * const.MIN - (blue.os.GetSimTime() - self.lastReconnection)) / const.MSEC
    267 
    268         sm.ScatterEvent('OnReconnectToProbesAvailable')
    269 
    270     def CanClaimProbes(self):
    271         if self.HasOnlineProbeLauncher() and (self.lastReconnection is None or blue.os.GetSimTime() - self.lastReconnection > RECONNECT_DELAY_MINUTES * const.MIN):
    272             return True
    273         return False
    274 
    275     def HasOnlineProbeLauncher(self):
    276         shipItem = sm.GetService('godma').GetStateManager().GetItem(session.shipid)
    277         if shipItem is not None:
    278             for module in shipItem.modules:
    279                 if module.groupID == const.groupScanProbeLauncher and module.isOnline:
    280                     return True
    281 
    282         return False
    283 
    284     def GetProbeLabel(self, probeID):
    285         if probeID in self.probeLabels:
    286             return self.probeLabels[probeID]
    287         newlabel = localization.GetByLabel('UI/Inflight/Scanner/ProbeLabel', probeIndex=len(self.probeLabels) + 1)
    288         self.probeLabels[probeID] = newlabel
    289         return newlabel
    290 
    291     def RecoverProbe(self, probeID):
    292         self.RecoverProbes([probeID])
    293 
    294     def RecoverProbes(self, probeIDs):
    295         ship = sm.StartService('michelle').GetItem(session.shipid)
    296         if ship and ship.groupID == const.groupCapsule:
    297             raise UserError('ScnProbeRecoverToPod')
    298         ballpark = sm.GetService('michelle').GetBallpark()
    299         for id in probeIDs:
    300             try:
    301                 if ballpark.GetBall(id).surfaceDist < MIN_PROBE_RECOVER_DISTANCE:
    302                     raise UserError('ProbesTooCloseToRecover')
    303             except AttributeError:
    304                 continue
    305 
    306         PlaySound('msg_newscan_probe_recover_play')
    307         self.probeTracker.RecoverProbes(probeIDs, self.AskServerToRecallProbes)
    308 
    309     def AskServerToRecallProbes(self, probeIDs):
    310         return self.GetScanMan().RecoverProbes(probeIDs)
    311 
    312     def OnScannerInfoRemoved(self):
    313         self.LogInfo('OnScannerInfoRemoved received: flushing scanner state')
    314         self.FlushScannerState(clearResults=True)
    315 
    316     def QAOverrideProbeExpiry(self, duration):
    317         self.GetScanMan().QAOverrideProbeExpiry(duration)
    318         for probe in self.probeTracker.GetProbeData().values():
    319             probe.expiry = blue.os.GetSimTime() + long(10000 * duration)
    320 
    321     def FlushScannerState(self, reinjectSites = True, clearResults = False):
    322         self.LogInfo('FlushScannerState: resetting state and scattering OnScannerDisconnected')
    323         if clearResults:
    324             del self.scanHandlerBySystem[session.solarsystemid2]
    325         self.probeTracker.Refresh()
    326         if reinjectSites:
    327             with ExceptionEater('Failure Reinjecting Anomalies'):
    328                 self.InjectSitesAsScanResults(sm.GetService('sensorSuite').probeScannerController.GetAllSites())
    329         self.remoteObject = None
    330         PlaySound('msg_newscan_probe_analyze_stop')
    331         sm.ScatterEvent('OnScannerDisconnected')
    332 
    333     def PruneSites(self):
    334         sites = [ site['id'] for site in sm.GetService('sensorSuite').probeScannerController.GetAllSites() ]
    335         sitesToPrune = []
    336         for site in self.GetResults(applyFiltering=False)[0]:
    337             if site['id'] not in sites and site['scanGroupID'] not in COMBAT_TARGETS:
    338                 sitesToPrune.append(site['id'])
    339 
    340         self.ClearResults(*sitesToPrune)
    341 
    342     def IsScanning(self):
    343         return self.scanHandlerBySystem[session.solarsystemid].IsScanning()
    344 
    345     def GetProbeMenu(self, probeID, probeIDs = None, *args):
    346         menu = []
    347         if probeID == session.shipid:
    348             return menu
    349         bp = sm.StartService('michelle').GetBallpark(doWait=True)
    350         if bp is None:
    351             return menu
    352         probeIDs = probeIDs or [probeID]
    353         if probeID not in probeIDs:
    354             probeIDs.append(probeID)
    355         if session.role & (ROLE_GML | ROLE_WORLDMOD):
    356             menu.append(('CopyID', self._GMCopyID, (probeID,)))
    357             menu.append(None)
    358         probes = self.GetProbeData()
    359         if probeID in probes:
    360             probe = probes[probeID]
    361             scanRanges = self.GetScanRangeStepsByTypeID(probe.typeID)
    362             menu.append((MenuLabel('UI/Inflight/Scanner/ScanRange'), [ (FmtDist(range), self.SetScanRange_Check, (probeID,
    363                probeIDs,
    364                range,
    365                index + 1)) for index, range in enumerate(scanRanges) ]))
    366         menu.append((MenuLabel('UI/Inflight/Scanner/RecoverProbe'), self.RecoverProbe_Check, (probeID, probeIDs)))
    367         return menu
    368 
    369     def _GMCopyID(self, id):
    370         blue.pyos.SetClipboardData(str(id))
    371 
    372     @UserErrorIfScanning
    373     def SetScanRange_Check(self, probeID, probeIDs, range, rangeStep):
    374         for _probeID in probeIDs:
    375             self.SetProbeRangeStep(_probeID, rangeStep)
    376 
    377     @UserErrorIfScanning
    378     def RecoverProbe_Check(self, probeID, probeIDs):
    379         for _probeID in probeIDs:
    380             self.RecoverProbe(_probeID)
    381 
    382     @UserErrorIfScanning
    383     def SetProbeActiveStateOn_Check(self, probeID, probeIDs):
    384         for _probeID in probeIDs:
    385             self.GetScanMan().SetActivityState(probeIDs, True)
    386             self.SetProbeActiveState(_probeID, True)
    387 
    388     @UserErrorIfScanning
    389     def SetProbeActiveStateOff_Check(self, probeID, probeIDs):
    390         for _probeID in probeIDs:
    391             self.GetScanMan().SetActivityState(probeIDs, False)
    392             self.SetProbeActiveState(_probeID, False)
    393 
    394     @UserErrorIfScanning
    395     def DestroyProbe_Check(self, probeID, probeIDs):
    396         if probeIDs and prompt_player_fsd_dialog('DestroySelectedProbes', {}, uiconst.YESNO, suppress=uiconst.ID_YES) == uiconst.ID_YES:
    397             for _probeID in probeIDs:
    398                 self.DestroyProbe(_probeID)
    399 
    400     def IgnoreResult(self, *targets):
    401         self.scanHandlerBySystem[session.solarsystemid2].IgnoreResult(*targets)
    402 
    403     def ClearIgnoredResults(self):
    404         self.scanHandlerBySystem[session.solarsystemid2].ClearIgnoredResults()
    405 
    406     def ClearResults(self, *targets):
    407         self.scanHandlerBySystem[session.solarsystemid2].ClearResults(*targets)
    408 
    409     def AlignToPosition(self, position):
    410         ballpark = self.michelle.GetBallpark()
    411         myBall = self.michelle.GetBall(ballpark.ego)
    412         myPosition = (myBall.x, myBall.y, myBall.z)
    413         directionalVector = geo2.Vec3SubtractD(position, myPosition)
    414         rbp = self.michelle.GetRemotePark()
    415         rbp.CmdGotoDirection(directionalVector[0], directionalVector[1], directionalVector[2])
    416 
    417     def IgnoreOtherResults(self, *targets):
    418         self.scanHandlerBySystem[session.solarsystemid].IgnoreOtherResults(*targets)
    419 
    420     def ShowIgnoredResult(self, targetID):
    421         self.scanHandlerBySystem[session.solarsystemid].ShowIgnoredResult(targetID)
    422 
    423     def GetProbeLauncher(self):
    424         ship = self.godma.GetItem(session.shipid)
    425         if ship:
    426             for module in ship.modules:
    427                 if not module.isOnline:
    428                     continue
    429                 if module.groupID == const.groupScanProbeLauncher:
    430                     return module
    431 
    432     def FindModuleAndLaunchProbes(self, numProbes):
    433         ship = self.godma.GetItem(session.shipid)
    434         module = self.GetProbeLauncher()
    435         if ship and module and any((s.locationID == session.shipid and s.flagID == module.flagID for s in ship.sublocations)):
    436             for effect in module.effects.itervalues():
    437                 if effect.isDefault:
    438                     dogmaLM = self.godma.GetStateManager().GetDogmaLM()
    439                     dogmaLM.LaunchProbes(module.itemID, numProbes)
    440                     PlaySound('msg_newscan_probe_launch_play')
    441                     return
    442 
    443     def GetNumChargesInProbeLauncher(self):
    444         charge = self.GetChargesInProbeLauncher()
    445         if charge is None:
    446             return 0
    447         return charge.quantity
    448 
    449     def GetChargesInProbeLauncher(self):
    450         launcher = self.GetProbeLauncher()
    451         if launcher is None:
    452             return
    453         flagID = launcher.flagID
    454         return self.godma.GetStateManager().GetSubLocation(session.shipid, flagID)
    455 
    456     def CanLaunchFormation(self, formationID):
    457         if formationID == SELF_CENTER_FORMATION:
    458             return bool(self.GetActiveProbes())
    459         charges = self.GetNumChargesInProbeLauncher()
    460         return self.probeTracker.CanCreateFormation(formationID, charges)
    461 
    462     def MoveProbesToFormation(self, formationID, initialPosition = None):
    463         self.probeTracker.MoveProbesToFormation(formationID, self.FindModuleAndLaunchProbes, self.GetNumChargesInProbeLauncher(), initialPosition=initialPosition)
    464 
    465     def ScaleFormationSpread(self, scaling):
    466         self.probeTracker.ScaleAllProbes(scaling, scaleScanRange=False)
    467 
    468     def ScaleFormation(self, scaling):
    469         probeData = self.probeTracker.GetProbeData()
    470         for probeID, probe in probeData.iteritems():
    471             currentRange = probe.scanRange
    472             newRange = currentRange * scaling
    473             rangeSteps = self.probeTracker.GetScanRangeStepsByTypeID(probe.typeID)
    474             if newRange not in rangeSteps:
    475                 return
    476 
    477         self.probeTracker.ScaleAllProbes(scaling)
    478 
    479     def GetProbeTracker(self):
    480         return self.probeTracker
    481 
    482     def SetProbesAsScanning(self, probes):
    483         return self.probeTracker.SetProbesAsScanning(probes)
    484 
    485     def ProbeControlSelect(self):
    486         uicore.layer.systemmapBrackets.state = uiconst.UI_DISABLED
    487 
    488     def ProbeControlDeselected(self):
    489         uicore.layer.systemmapBrackets.state = uiconst.UI_PICKCHILDREN
    490 
    491     def FocusOnProbe(self, probeID):
    492         try:
    493             probeID = int(probeID)
    494         except ValueError:
    495             uicore.layer.systemmap.FocusOnPoint(self.probeTracker.GetCenterOfActiveProbes())
    496         else:
    497             uicore.layer.systemmap.FocusOnPoint(self.probeTracker.GetProbe(probeID).destination)
    498 
    499     def GetFilterOptions(self):
    500         return self.resultFilter.GetFilters()
    501 
    502     def GetActiveFilterSet(self):
    503         return self.resultFilter.GetActiveFilterSet()
    504 
    505     def AddToActiveFilterSet(self, filterID):
    506         self.resultFilter.AddToActiveFilterSet(filterID)
    507         sm.ScatterEvent('OnSystemScanFilterChanged')
    508 
    509     def RemoveFromActiveFilterSet(self, filterID):
    510         self.resultFilter.RemoveFromActiveFilterSet(filterID)
    511         sm.ScatterEvent('OnSystemScanFilterChanged')
    512 
    513     def DeleteFilter(self, filterID):
    514         self.resultFilter.DeleteFilter(filterID)
    515 
    516     def GetResults(self, applyFiltering = True):
    517         results, ignored, filtered, anomalies = self.scanHandlerBySystem[session.solarsystemid].GetResults(applyFiltering)
    518         results = [ utillib.KeyVal(**r) for r in results ]
    519         return (results,
    520          ignored,
    521          filtered,
    522          anomalies)
    523 
    524     def GetResultFilter(self, filterID):
    525         return self.resultFilter.GetFilter(filterID)
    526 
    527     def CreateResultFilter(self, name, groups):
    528         self.resultFilter.CreateFilter(name, groups)
    529 
    530     def EditResultFilter(self, filterID, name, groups):
    531         self.resultFilter.EditFilter(filterID, name, groups)
    532 
    533     def GetDisplayName(self, result):
    534         displayName = ''
    535         if result.typeID:
    536             displayName = self.GetTypeName(result)
    537         if not displayName and result.groupID:
    538             displayName = self.GetGroupName(result)
    539         if not displayName:
    540             displayName = self.GetScanGroupName(result)
    541         return displayName
    542 
    543     def GetTypeName(self, result):
    544         if IsExplorationSite(result):
    545             if result.dungeonNameID is not None:
    546                 return localization.GetByMessageID(result.dungeonNameID)
    547             return ''
    548         if result.typeID is not None:
    549             return evetypes.GetName(result.typeID)
    550         return ''
    551 
    552     def GetGroupName(self, result):
    553         if IsExplorationSite(result):
    554             if result.strengthAttributeID is None:
    555                 return ''
    556             return self.GetExplorationSiteType(result.strengthAttributeID, result.archetypeID)
    557         elif result.groupID is not None:
    558             return evetypes.GetGroupNameByGroup(result.groupID)
    559         else:
    560             return ''
    561 
    562     def GetExplorationSiteType(self, attributeID, archetypeID):
    563         return get_exploration_site_group_name(site_type=attributeID, archetype_id=archetypeID)
    564 
    565     def GetScanGroupName(self, result):
    566         return localization.GetByLabel(NAME_BY_SCANGROUPID[result.scanGroupID])
    567 
    568     def RestoreProbesFromBackup(self):
    569         self.probeTracker.RestoreProbesFromBackup()
    570 
    571     def CenterProbesOnMe(self, formationID):
    572         ballpark = sm.GetService('michelle').GetBallpark()
    573         egoBall = ballpark.GetBall(ballpark.ego)
    574         if not egoBall:
    575             return
    576         oldFormation = customFormations.GetSelectedFormationID()
    577         probeInfo = self.probeTracker.GetProbePositionAndRangeInfo()
    578         formationID = customFormations.PersistFormation('tempFormation', probeInfo.values(), formationID)
    579         self.MoveProbesToFormation(formationID, initialPosition=(egoBall.x, egoBall.y, egoBall.z))
    580         customFormations.SelectFormation(oldFormation)
    581 
    582     def StartMoveMode(self):
    583         self.probeTracker.StartMoveMode()
    584 
    585     def PurgeBackupData(self):
    586         self.probeTracker.PurgeBackupData()
    587 
    588     def GetResultForTargetID(self, targetID):
    589         return self.scanHandlerBySystem[session.solarsystemid].resultsHistory.GetResultAsDict(targetID)
    590 
    591     def GetIgnoreResultMenu(self, targetID, scanGroupID = None):
    592         menu = []
    593         menu.append(None)
    594         menu.append((MenuLabel('UI/Inflight/Scanner/IngoreResult'), self.IgnoreResult, (targetID,)))
    595         menu.append((MenuLabel('UI/Inflight/Scanner/IgnoreOtherResults'), self.IgnoreOtherResults, (targetID,)))
    596         return menu
    597 
    598     def GetAccurateScannedDownMenu(self, scanResult):
    599         menu = []
    600         if scanResult.IsAccurate():
    601             menu.extend(self.GetScannedDownMenu(scanResult))
    602         return menu
    603 
    604     def GetScanResultMenuWithIgnore(self, scanResult, scanGroupId):
    605         menu = []
    606         menu.extend(self.GetAccurateScannedDownMenu(scanResult))
    607         menu.extend(self.GetIgnoreResultMenu(scanResult.targetID, scanGroupId))
    608         return menu
    609 
    610     def GetScanResultMenuWithoutIgnore(self, scanResult):
    611         return self.GetAccurateScannedDownMenu(scanResult)
    612 
    613     def GetScannedDownMenu(self, scanResult):
    614         menu = []
    615         if self.michelle.IsPositionWithinWarpDistance(scanResult.position):
    616             menu.extend(GetMenuService().SolarsystemScanMenu(scanResult.targetID))
    617             menu.append(None)
    618         _scanResultNameID, scanResultName = scanResult.GetScanName()
    619         menu.extend(self.GetAlignToMenu(scanResult.position))
    620         bookmarkData = utillib.KeyVal(id=scanResult.targetID, position=scanResult.position, name='%s %s' % (scanResult.targetID, scanResultName))
    621         menu.append((MenuLabel('UI/Inflight/BookmarkLocation'), sm.GetService('addressbook').BookmarkLocationPopup, (session.solarsystemid,
    622           None,
    623           None,
    624           None,
    625           bookmarkData)))
    626         return menu
    627 
    628     def GetAlignToMenu(self, position):
    629         return [(MenuLabel('UI/Inflight/AlignTo'), self.AlignToPosition, (position,))]
    630 
    631     def InjectSitesAsScanResults(self, sites, force = False):
    632         if session.solarsystemid:
    633             self.scanHandlerBySystem[session.solarsystemid].InjectResults(sites, force=force)
    634 
    635     def ShowAnomalies(self):
    636         self.resultFilter.ShowAnomalies()
    637         sm.ScatterEvent('OnSystemScanFilterChanged')
    638 
    639     def StopShowingAnomalies(self):
    640         self.resultFilter.StopShowingAnomalies()
    641         sm.ScatterEvent('OnSystemScanFilterChanged')
    642 
    643     def ClickLink(self, action):
    644         if action == 'ShowAnomalies':
    645             self.ShowAnomalies()
    646         elif action == 'HideAnomalies':
    647             self.StopShowingAnomalies()
    648         elif action == 'ClearIgnored':
    649             self.scanHandlerBySystem[session.solarsystemid].ClearIgnoredResults()
    650         else:
    651             raise RuntimeError('scanSvc::ClickLink - Not supported action (%s)' % action)
    652         wnd = Scanner.GetIfOpen()
    653         if wnd is not None:
    654             wnd.LoadFilterOptionsAndResults()
    655 
    656     def IsShowingAnomalies(self):
    657         return self.resultFilter.IsShowingAnomalies()
    658 
    659     def PersistCurrentFormation(self, name):
    660         probeInfo = self.probeTracker.GetProbePositionAndRangeInfo()
    661         customFormations.PersistFormation(name, probeInfo.values())
    662 
    663     def SetSelectedSites(self, siteIDs):
    664         self.selectedSites.clear()
    665         for siteID in siteIDs:
    666             self.selectedSites.add(siteID)
    667 
    668         sm.ScatterEvent('OnSiteSelectionChanged')
    669 
    670     def SelectSite(self, siteID):
    671         multiSelect = uicore.uilib.Key(uiconst.VK_SHIFT) or uicore.uilib.Key(uiconst.VK_CONTROL)
    672         if not multiSelect:
    673             self.selectedSites.clear()
    674         if siteID not in self.selectedSites:
    675             self.selectedSites.add(siteID)
    676         elif multiSelect:
    677             self.selectedSites.remove(siteID)
    678         sm.ScatterEvent('OnSiteSelectionChanged')
    679 
    680     def DeselectSite(self, siteID):
    681         if siteID in self.selectedSites:
    682             self.selectedSites.remove(siteID)
    683             sm.ScatterEvent('OnSiteSelectionChanged')
    684 
    685     def IsSiteSelected(self, siteID):
    686         return siteID in self.selectedSites
    687 
    688     def GetActiveProbeTypeID(self):
    689         typeID = self.probeTracker.GetProbeTypeID()
    690         if typeID:
    691             return typeID
    692         charges = self.GetChargesInProbeLauncher()
    693         if charges:
    694             return charges.typeID
    695 
    696     def QAScanSites(self, *siteIDs):
    697         sites = self.GetScanMan().QAScanSites(siteIDs)
    698         if sites:
    699             self.scanHandlerBySystem[session.solarsystemid].InjectResults(sites, True)