sensorSuiteService.py (31760B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\client\script\parklife\sensorSuiteService.py 2 import math 3 import audio2 4 import bluepy 5 import gametime 6 import locks 7 import signals 8 import trinity 9 import uthread 10 import uthread2 11 from carbon.common.lib.const import SEC 12 from carbon.common.script.sys import service 13 from carbon.common.script.util.logUtil import LogException 14 from carbon.common.script.util.timerstuff import AutoTimer 15 from carbonui import uiconst 16 from carbonui.uianimations import animations 17 from carbonui.uicore import uicore 18 from carbonui.util.various_unsorted import IsUnder 19 from eve.common.lib.appConst import AU 20 from eve.common.script.sys import eveCfg 21 from eveexceptions import UserError 22 from eveuniverse.solar_systems import is_sensor_overlay_suppressed 23 from sensorsuite.error import InvalidClientStateError 24 import sensorsuite.overlay.const as overlayConst 25 from sensorsuite.overlay import sitetype 26 from sensorsuite.overlay.const import SWEEP_CYCLE_TIME, SWEEP_START_GRACE_TIME_SEC, SWEEP_START_GRACE_TIME, SUPPRESS_GFX_WARPING, SUPPRESS_GFX_NO_UI 27 from sensorsuite.overlay.anomalies import AnomalyHandler 28 from sensorsuite.overlay.bookmarks import BookmarkHandler, SharedBookmarkHandler 29 from sensorsuite.overlay.controllers.probescanner import ProbeScannerController 30 from sensorsuite.overlay.gfxhandler import GfxHandler 31 from sensorsuite.overlay.missions import MissionHandler 32 from sensorsuite.overlay.signatures import SignatureHandler 33 from sensorsuite.overlay.spacesitecontroller import SpaceSiteController 34 from sensorsuite.overlay.staticsites import StaticSiteHandler 35 from sensorsuite.overlay.structures import StructureHandler 36 SENSOR_SUITE_ENABLED = 'sensorSuiteEnabled' 37 MAX_MOUSEOVER_RANGE = 40.0 38 MAX_MOUSEOVER_RANGE_SQUARED = MAX_MOUSEOVER_RANGE ** 2 39 MAX_OVERLAPPING_RANGE_SQUARED = 900.0 40 MAX_RTPC_VALUE = 99 41 BRACKET_OVERLAP_DISTANCE = 8 42 SWEEP_CYCLE_TIME_SEC = float(SWEEP_CYCLE_TIME) / SEC 43 UPDATE_STRUCTURES_DELAY = 1000 44 UPDATE_SITES_DELAY = 200 45 46 def GetSensorSuiteService(): 47 return sm.GetService('sensorSuite') 48 49 50 class SensorSuiteService(service.Service): 51 __guid__ = 'svc.sensorSuite' 52 __notifyevents__ = ['DoBallRemove', 53 'DoBallsRemove', 54 'OnAgentMissionChanged', 55 'OnBallAdded', 56 'OnBallparkSetState', 57 'OnEnterSpace', 58 'OnHideUI', 59 'OnClientEvent_JumpStarted', 60 'OnClientEvent_JumpExecuted', 61 'OnRefreshBookmarks', 62 'OnReleaseBallpark', 63 'OnShowUI', 64 'OnSignalTrackerAnomalyUpdate', 65 'OnSignalTrackerFullState', 66 'OnSignalTrackerSignatureUpdate', 67 'OnSignalTrackerStructureUpdate', 68 'OnSpecialFX', 69 'OnStructuresVisibilityUpdated', 70 'OnSystemScanDone', 71 'OnUpdateWindowPosition', 72 'OnClientEvent_WarpStarted', 73 'OnClientEvent_WarpFinished'] 74 __dependencies__ = ['audio', 75 'bookmarkSvc', 76 'michelle', 77 'scanSvc', 78 'sceneManager', 79 'viewState'] 80 __startupdependencies__ = [] 81 82 def Run(self, *args): 83 service.Service.Run(self) 84 self.isOverlayActive = True 85 self.toggleLock = locks.RLock() 86 self.resultEffectsThread = None 87 self.messenger = signals.Messenger() 88 self.gfxHandler = GfxHandler(self, self.sceneManager, self.michelle) 89 self.siteController = SpaceSiteController(self, self.michelle) 90 self.siteController.AddSiteHandler(sitetype.ANOMALY, AnomalyHandler()) 91 self.siteController.AddSiteHandler(sitetype.SIGNATURE, SignatureHandler()) 92 self.siteController.AddSiteHandler(sitetype.STATIC_SITE, StaticSiteHandler()) 93 self.siteController.AddSiteHandler(sitetype.BOOKMARK, BookmarkHandler(self, self.bookmarkSvc)) 94 self.siteController.AddSiteHandler(sitetype.SHARED_BOOKMARK, SharedBookmarkHandler(self, self.bookmarkSvc)) 95 self.siteController.AddSiteHandler(sitetype.MISSION, MissionHandler(self.bookmarkSvc)) 96 self.siteController.AddSiteHandler(sitetype.STRUCTURE, StructureHandler()) 97 self.Initialize() 98 self.UpdateVisibleStructures() 99 100 def IsSweepDone(self): 101 return self.systemReadyTime and not self.sensorSweepActive 102 103 def IsSolarSystemReady(self): 104 if session.solarsystemid is None: 105 return False 106 bp = self.michelle.GetBallpark() 107 if bp is None: 108 return False 109 if not bp.ego: 110 return False 111 return True 112 113 def NotifySweepStartedIfRequired(self, handler, messageName): 114 if messageName is overlayConst.MESSAGE_ON_SENSOR_OVERLAY_SWEEP_STARTED and self.sweepStartedData is not None: 115 uthread.new(handler, *self.sweepStartedData) 116 117 def Subscribe(self, messageName, handler): 118 self.NotifySweepStartedIfRequired(handler, messageName) 119 self.messenger.SubscribeToMessage(messageName, handler) 120 121 def Unsubscribe(self, messageName, handler): 122 self.messenger.UnsubscribeFromMessage(messageName, handler) 123 124 def SendMessage(self, messageName, *args, **kwargs): 125 self.messenger.SendMessage(messageName, *args, **kwargs) 126 127 def Initialize(self): 128 self.siteController.Clear() 129 self.probeScannerController = ProbeScannerController(self.scanSvc, self.michelle, self.siteController) 130 self.locatorFadeInTimeSec = 0.25 131 self.doMouseTrackingUpdates = False 132 self.systemReadyTime = None 133 self.sitesUnderCursor = set() 134 leftPush, rightPush = uicore.layer.sidePanels.GetSideOffset() 135 self.OnUpdateWindowPosition(leftPush, rightPush) 136 self.sensorSweepActive = False 137 self.sweepStartedData = None 138 139 def UpdateScanner(self, removedSites): 140 targetIDs = [] 141 for siteData in removedSites: 142 if siteData.GetSiteType() in (sitetype.ANOMALY, sitetype.SIGNATURE): 143 targetIDs.append(siteData.targetID) 144 145 if targetIDs: 146 self.scanSvc.ClearResults(*targetIDs) 147 148 def InjectScannerResults(self, siteType): 149 sitesById = self.siteController.siteMaps.GetSiteMapByKey(siteType) 150 self.probeScannerController.InjectSiteScanResults(sitesById.itervalues()) 151 152 def OnSpecialFX(self, shipID, moduleID, moduleTypeID, targetID, otherTypeID, guid, *args, **kw): 153 if shipID == session.shipid: 154 if guid is not None and 'effects.JumpOut' in guid: 155 self.LogInfo('Jumping out, hiding the overlay') 156 self._Hide() 157 158 def OnEnterSpace(self): 159 self.Reset() 160 if session.solarsystemid and session.structureid is None: 161 self.Initialize() 162 self._SetOverlayActive(settings.char.ui.Get(SENSOR_SUITE_ENABLED, True)) 163 self.LogInfo('Entered new system', session.solarsystemid) 164 try: 165 sm.RemoteSvc('scanMgr').SignalTrackerRegister() 166 except UserError as e: 167 if e.msg == 'UnMachoDestination': 168 self.LogInfo('Entered new system failed due to match as session seems to have changed') 169 return 170 raise 171 172 for siteType in (sitetype.BOOKMARK, sitetype.MISSION, sitetype.SHARED_BOOKMARK): 173 self.siteController.GetSiteHandler(siteType).LoadSites(session.solarsystemid) 174 175 if self.IsOverlaySuppressed(): 176 self._Hide() 177 self.messenger.SendMessage(overlayConst.MESSAGE_ON_SENSOR_OVERLAY_DISABLED) 178 elif self.isOverlayActive: 179 self._Show() 180 self.messenger.SendMessage(overlayConst.MESSAGE_ON_SENSOR_OVERLAY_ENABLED) 181 ballpark = self.michelle.GetBallpark() 182 if ballpark and ballpark.ego: 183 self._InitiateSensorSweep() 184 185 def OnReleaseBallpark(self): 186 self.Reset() 187 188 def OnBallparkSetState(self): 189 if session.solarsystemid and session.structureid is None and not sm.GetService('subway').InJump(): 190 self._InitiateSensorSweep() 191 192 def _InitiateSensorSweep(self): 193 self.LogInfo('Ballpark is ready so we start the sweep timer') 194 self.systemReadyTime = gametime.GetSimTime() 195 self.StartSensorSweep() 196 197 def Reset(self): 198 self.LogInfo('Clearing all overlay objects') 199 if self.resultEffectsThread: 200 self.resultEffectsThread.kill() 201 self.resultEffectsThread = None 202 self.siteController.ClearFromBallpark() 203 self.siteController.Clear() 204 uicore.layer.sensorSuite.Flush() 205 self.gfxHandler.StopGfxSwipe() 206 self.gfxHandler.StopSwipeThread() 207 208 def IsOverlaySuppressed(self): 209 return is_sensor_overlay_suppressed(session.solarsystemid) 210 211 def IsOverlayActive(self): 212 if self.IsOverlaySuppressed(): 213 return False 214 return self.isOverlayActive 215 216 def ToggleOverlay(self): 217 if self.IsOverlaySuppressed(): 218 return 219 with self.toggleLock: 220 self.LogInfo('Toggle Overlay') 221 if self.isOverlayActive: 222 self.DisableSensorOverlay() 223 else: 224 self.EnableSensorOverlay() 225 226 def DisableSensorOverlay(self): 227 self.LogInfo('DisableSensorOverlay') 228 if self.isOverlayActive: 229 self._SetOverlayActive(False) 230 if not self.sensorSweepActive: 231 self._Hide() 232 self.messenger.SendMessage(overlayConst.MESSAGE_ON_SENSOR_OVERLAY_DISABLED) 233 234 def EnableSensorOverlay(self): 235 self.LogInfo('EnableSensorOverlay') 236 if not self.isOverlayActive: 237 self._SetOverlayActive(True) 238 if not self.sensorSweepActive: 239 self._Show() 240 self.messenger.SendMessage(overlayConst.MESSAGE_ON_SENSOR_OVERLAY_ENABLED) 241 242 def _SetOverlayActive(self, isActive): 243 self.isOverlayActive = isActive 244 settings.char.ui.Set(SENSOR_SUITE_ENABLED, isActive) 245 246 def _Show(self): 247 self.LogInfo('Showing overlay') 248 try: 249 if not self.sensorSweepActive: 250 self.UpdateVisibleSites() 251 self.UpdateVisibleStructures() 252 self.audio.SendUIEvent('ui_scanner_stop') 253 self.EnableMouseTracking() 254 except InvalidClientStateError: 255 pass 256 257 def _Hide(self): 258 self.LogInfo('Hiding overlay') 259 self.gfxHandler.StopGfxSwipe() 260 self.UpdateVisibleSites() 261 self.UpdateVisibleStructures() 262 self.audio.SendUIEvent('ui_scanner_stop') 263 self.doMouseTrackingUpdates = False 264 265 def EnableMouseTracking(self): 266 if not self.doMouseTrackingUpdates: 267 self.doMouseTrackingUpdates = True 268 uthread.new(self.UpdateMouseTracking).context = 'sensorSuite::UpdateMouseTracking' 269 270 def StartSensorSweep(self): 271 uthread.new(self._DoSystemEnterScan) 272 273 def TryFadeOutBracketAndReturnCurveSet(self, curveSet, points, siteData, totalDuration): 274 try: 275 locatorData = self.siteController.spaceLocations.GetBySiteID(siteData.siteID) 276 curveSet = animations.FadeTo(locatorData.bracket, startVal=0.0, endVal=1.0, duration=totalDuration, curveType=points, curveSet=curveSet) 277 except KeyError: 278 pass 279 280 return curveSet 281 282 def GetSiteListOrderedByDelay(self, ballpark, sweepCycleTimeSec, viewAngleInPlane): 283 if ballpark is None: 284 raise InvalidClientStateError("We don't have a ballpark") 285 myBall = ballpark.GetBall(ballpark.ego) 286 if myBall is None: 287 raise InvalidClientStateError("We don't have an active ship in the park") 288 mx, mz = myBall.x, myBall.z 289 sitesOrdered = [] 290 pi2 = math.pi * 2 291 for siteData in self.GetVisibleSites(): 292 if sitetype.IsSiteInstantlyAccessible(siteData): 293 sitesOrdered.append((0, siteData)) 294 continue 295 x, y, z = siteData.position 296 dx, dz = x - mx, z - mz 297 angle = math.atan2(-dz, dx) - viewAngleInPlane 298 angle %= pi2 299 ratioOfCircle = angle / pi2 300 delay = SWEEP_START_GRACE_TIME_SEC + sweepCycleTimeSec * ratioOfCircle 301 sitesOrdered.append((delay, siteData)) 302 303 sitesOrdered.sort() 304 return sitesOrdered 305 306 def GetVisibleSites(self): 307 return self.siteController.GetVisibleSites() 308 309 def SetupSiteSweepAnimation(self, sitesOrdered): 310 curveSet = animations.CreateCurveSet(useRealTime=False) 311 for delay, siteData in sitesOrdered: 312 points, totalDuration = self.GetLocationFlashCurve(delay) 313 curveSet = self.TryFadeOutBracketAndReturnCurveSet(curveSet, points, siteData, totalDuration) 314 315 def _DoSystemEnterScan(self): 316 self.LogInfo('_DoSystemEnterScan entered') 317 if not eveCfg.InSpace(): 318 return 319 self.sensorSweepActive = True 320 try: 321 self.CreateResults() 322 viewAngleInPlane = self.gfxHandler.GetViewAngleInPlane() 323 self.LogInfo('Sensor sweep stating from angle', viewAngleInPlane) 324 ballpark = self.michelle.GetBallpark() 325 sitesOrdered = self.GetSiteListOrderedByDelay(ballpark, SWEEP_CYCLE_TIME_SEC, viewAngleInPlane) 326 except InvalidClientStateError: 327 self.sensorSweepActive = False 328 return 329 330 if self.IsOverlayActive(): 331 self.SetupSiteSweepAnimation(sitesOrdered) 332 self.gfxHandler.StartGfxSwipeThread(viewAngleInPlane=viewAngleInPlane) 333 self.audio.SendUIEvent('ui_scanner_start') 334 self.resultEffectsThread = uthread.new(self.PlayResultEffects, sitesOrdered) 335 else: 336 self.sensorSweepActive = False 337 self._Hide() 338 self.LogInfo('Sweep started observers notified') 339 self.sweepStartedData = (self.systemReadyTime, 340 SWEEP_CYCLE_TIME_SEC, 341 viewAngleInPlane, 342 sitesOrdered, 343 SWEEP_START_GRACE_TIME_SEC) 344 self.SendMessage(overlayConst.MESSAGE_ON_SENSOR_OVERLAY_SWEEP_STARTED, *self.sweepStartedData) 345 346 def ShowSiteDuringSweep(self, locatorData, scene, siteData, sleepTimeSec, soundLocators, vectorCurve): 347 ball = locatorData.ballRef() 348 if ball is None: 349 return 350 audio = audio2.AudEmitter('sensor_overlay_site_%s' % str(siteData.siteID)) 351 obs = trinity.TriObserverLocal() 352 obs.observer = audio 353 vectorSequencer = trinity.TriVectorSequencer() 354 vectorSequencer.operator = trinity.TRIOP_MULTIPLY 355 vectorSequencer.functions.append(ball) 356 vectorSequencer.functions.append(vectorCurve) 357 tr = trinity.EveRootTransform() 358 tr.name = 'sensorSuiteSoundLocator_%s' % str(siteData.siteID) 359 tr.translationCurve = vectorSequencer 360 tr.observers.append(obs) 361 scene.objects.append(tr) 362 soundLocators.append(tr) 363 uthread2.SleepSim(sleepTimeSec) 364 if siteData.GetSiteType() == sitetype.ANOMALY: 365 audio.SendEvent('ui_scanner_result_anomaly') 366 elif siteData.GetSiteType() == sitetype.SIGNATURE: 367 audio.SendEvent('ui_scanner_result_signature') 368 locatorData.bracket.DoEntryAnimation(enable=False) 369 locatorData.bracket.state = uiconst.UI_DISABLED 370 371 def PlayResultEffects(self, sitesOrdered): 372 self.LogInfo('PlayResultEffects') 373 scene = self.sceneManager.GetRegisteredScene('default') 374 soundLocators = [] 375 invAU = 1.0 / AU 376 vectorCurve = trinity.Tr2CurveVector3() 377 vectorCurve.AddKey(0, (invAU, invAU, invAU)) 378 try: 379 if self.systemReadyTime is None: 380 return 381 startTimeSec = float(self.systemReadyTime) / SEC 382 for delaySec, siteData in sitesOrdered: 383 if not self.siteController.spaceLocations.ContainsSite(siteData.siteID): 384 continue 385 if sitetype.IsSiteInstantlyAccessible(siteData): 386 continue 387 locatorData = self.siteController.spaceLocations.GetBySiteID(siteData.siteID) 388 playTimeSec = startTimeSec + delaySec 389 now = float(gametime.GetSimTime()) / SEC 390 sleepTimeSec = max(0, playTimeSec - now) 391 self.ShowSiteDuringSweep(locatorData, scene, siteData, sleepTimeSec, soundLocators, vectorCurve) 392 393 currentTimeSec = float(gametime.GetSimTime()) / SEC 394 endTimeSec = startTimeSec + SWEEP_START_GRACE_TIME_SEC + SWEEP_CYCLE_TIME_SEC 395 timeLeftSec = endTimeSec - currentTimeSec 396 if timeLeftSec > 0: 397 uthread2.SleepSim(timeLeftSec) 398 self.audio.SendUIEvent('ui_scanner_stop') 399 self.sensorSweepActive = False 400 if not self.IsOverlayActive(): 401 self._Hide() 402 else: 403 for locatorData in self.siteController.spaceLocations.IterLocations(): 404 if not sitetype.IsSiteInstantlyAccessible(locatorData.siteData): 405 locatorData.bracket.DoEnableAnimation() 406 locatorData.bracket.state = uiconst.UI_NORMAL 407 408 uthread2.SleepSim(1.0) 409 self.DoScanEnded(sitesOrdered) 410 self.audio.SendUIEvent('ui_scanner_stop') 411 self.SendMessage(overlayConst.MESSAGE_ON_SENSOR_OVERLAY_SWEEP_ENDED) 412 self.UpdateVisibleSites() 413 finally: 414 self.sensorSweepActive = False 415 if scene is not None: 416 for tr in soundLocators: 417 if tr in scene.objects: 418 scene.objects.remove(tr) 419 420 def DoScanEnded(self, sitesOrdered): 421 self.LogInfo('DoScanEnded') 422 if len(sitesOrdered) > 0: 423 self.audio.SendUIEvent('ui_scanner_result_positive') 424 else: 425 self.audio.SendUIEvent('ui_scanner_result_negative') 426 427 def CreateResults(self): 428 self.LogInfo('CreateResults') 429 self.gfxHandler.WaitForSceneReady() 430 for siteData in self.GetVisibleSites(): 431 self.siteController.AddSiteToSpace(siteData, animate=False) 432 433 def GetLocationFlashCurve(self, delay): 434 totalDuration = delay + self.locatorFadeInTimeSec 435 points = [] 436 totalTime = 0 437 for keyDuration, keyValue in ((delay, 0.0), (self.locatorFadeInTimeSec, 1.0)): 438 totalTime += keyDuration 439 points.append((totalTime / totalDuration, keyValue)) 440 441 return (points, totalDuration) 442 443 def IsSiteBall(self, ballID): 444 return self.GetBracketByBallID(ballID) is not None 445 446 def GetBracketByBallID(self, ballID): 447 return self.siteController.spaceLocations.GetBracketByBallID(ballID) 448 449 def GetBracketBySiteID(self, siteID): 450 return self.siteController.spaceLocations.GetBracketBySiteID(siteID) 451 452 def OnRefreshBookmarks(self): 453 self.LogInfo('OnRefreshBookmarks') 454 if session.solarsystemid: 455 for siteType in (sitetype.BOOKMARK, sitetype.SHARED_BOOKMARK): 456 self.siteController.GetSiteHandler(siteType).UpdateSites(session.solarsystemid) 457 458 self.UpdateVisibleSites() 459 460 def OnAgentMissionChanged(self, *args, **kwargs): 461 self.siteController.GetSiteHandler(sitetype.MISSION).UpdateSites(session.solarsystemid) 462 463 def OnSignalTrackerFullState(self, solarSystemID, fullState, shouldRemoveOldSites = False): 464 self.LogInfo('OnSignalTrackerFullState', solarSystemID, fullState) 465 anomalies, signatures, staticSites, structures = fullState 466 for siteType, rawSites in ((sitetype.ANOMALY, anomalies), 467 (sitetype.SIGNATURE, signatures), 468 (sitetype.STATIC_SITE, staticSites), 469 (sitetype.STRUCTURE, structures)): 470 addedSites = rawSites or dict() 471 removedSites = set() 472 siteHandler = self.siteController.GetSiteHandler(siteType) 473 if shouldRemoveOldSites: 474 sites = siteHandler.GetSites().keys() 475 for siteID in sites: 476 if siteID not in addedSites: 477 removedSites.add(siteID) 478 479 if addedSites or removedSites: 480 siteHandler.ProcessSiteUpdate(addedSites, removedSites) 481 482 self.probeScannerController.InjectSiteScanResults(self.siteController.siteMaps.IterSitesByKeys(sitetype.ANOMALY, sitetype.SIGNATURE)) 483 sm.GetService('scanSvc').PruneSites() 484 485 def OnSignalTrackerAnomalyUpdate(self, solarSystemID, addedAnomalies, removedAnomalies): 486 self.LogInfo('OnSignalTrackerAnomalyUpdate', solarSystemID, addedAnomalies, removedAnomalies) 487 self.siteController.GetSiteHandler(sitetype.ANOMALY).ProcessSiteUpdate(addedAnomalies, removedAnomalies) 488 489 def OnSignalTrackerSignatureUpdate(self, solarSystemID, addedSignatures, removedSignatures): 490 self.LogInfo('OnSignalTrackerSignatureUpdate', solarSystemID, addedSignatures, removedSignatures) 491 self.siteController.GetSiteHandler(sitetype.SIGNATURE).ProcessSiteUpdate(addedSignatures, removedSignatures) 492 493 def OnSignalTrackerStructureUpdate(self, solarSystemID, addedStructures, removedStructures): 494 self.LogInfo('OnSignalTrackerStructureUpdate', solarSystemID, addedStructures, removedStructures) 495 self.siteController.GetSiteHandler(sitetype.STRUCTURE).ProcessSiteUpdate(addedStructures, removedStructures) 496 497 def OnUpdateWindowPosition(self, leftPush, rightPush): 498 uicore.layer.sensorsuite.padLeft = -leftPush 499 uicore.layer.sensorsuite.padRight = -rightPush 500 501 def IsMouseInSpaceView(self): 502 if self.viewState.IsViewActive('inflight'): 503 mouseOver = uicore.uilib.mouseOver 504 for uiContainer in (uicore.layer.inflight, uicore.layer.sensorsuite, uicore.layer.bracket): 505 if mouseOver is uiContainer or IsUnder(mouseOver, uiContainer): 506 return True 507 508 return False 509 510 @bluepy.TimedFunction('sensorSuiteService::UpdateMouseHoverSound') 511 def UpdateMouseHoverSound(self, activeBracket, bestProximity, closestBracket, lastSoundStrength): 512 soundStrength = bestProximity or 0 513 if closestBracket is not None: 514 if soundStrength != 0 or lastSoundStrength != 0: 515 if lastSoundStrength == 0 or activeBracket != closestBracket: 516 signalStrength = MAX_RTPC_VALUE 517 self.audio.SendUIEvent(closestBracket.data.hoverSoundEvent) 518 self.audio.SetGlobalRTPC('scanner_signal_strength', min(signalStrength, MAX_RTPC_VALUE)) 519 self.audio.SendUIEvent('ui_scanner_state_difficulty_easy') 520 self.audio.SendUIEvent('ui_scanner_mouseover') 521 activeBracket = closestBracket 522 self.audio.SetGlobalRTPC('scanner_mouseover', soundStrength) 523 elif soundStrength == 0 and lastSoundStrength > 0: 524 self.DisableMouseOverSound() 525 activeBracket = None 526 lastSoundStrength = soundStrength 527 return (activeBracket, lastSoundStrength) 528 529 @bluepy.TimedFunction('sensorSuiteService::UpdateMouseTracking') 530 def UpdateMouseTracking(self): 531 self.LogInfo('Mouse tracking update thread started') 532 lastSoundStrength = 0.0 533 activeBracket = None 534 self.sitesUnderCursor = set() 535 self.audio.SetGlobalRTPC('scanner_mouseover', 0) 536 while self.doMouseTrackingUpdates: 537 try: 538 if not self.IsMouseInSpaceView(): 539 if activeBracket is not None: 540 self.DisableMouseOverSound() 541 activeBracket = None 542 lastSoundStrength = 0.0 543 continue 544 desktopWidth = uicore.desktop.width 545 desktopHeight = uicore.desktop.height 546 mouseX = uicore.uilib.x 547 mouseY = uicore.uilib.y 548 self.currentOverlapCoordinates = (mouseX, mouseY) 549 closestBracket = None 550 bestProximity = None 551 for data in self.siteController.spaceLocations.IterLocations(): 552 self.sitesUnderCursor.discard(data.siteData) 553 bracket = data.bracket 554 if bracket is None or bracket.destroyed: 555 continue 556 if bracket.state == uiconst.UI_DISABLED: 557 continue 558 centerX = bracket.left + bracket.width / 2 559 centerY = bracket.top + bracket.height / 2 560 if centerX < 0: 561 continue 562 if centerX > desktopWidth: 563 continue 564 if centerY < 0: 565 continue 566 if centerY > desktopHeight: 567 continue 568 if mouseX < centerX - MAX_MOUSEOVER_RANGE: 569 continue 570 if mouseX > centerX + MAX_MOUSEOVER_RANGE: 571 continue 572 if mouseY < centerY - MAX_MOUSEOVER_RANGE: 573 continue 574 if mouseY > centerY + MAX_MOUSEOVER_RANGE: 575 continue 576 dx = centerX - mouseX 577 dy = centerY - mouseY 578 if -BRACKET_OVERLAP_DISTANCE <= dx <= BRACKET_OVERLAP_DISTANCE and -BRACKET_OVERLAP_DISTANCE <= dy <= BRACKET_OVERLAP_DISTANCE: 579 self.sitesUnderCursor.add(data.siteData) 580 if data.siteData.hoverSoundEvent is None: 581 continue 582 distanceSquared = dx * dx + dy * dy 583 if distanceSquared >= MAX_MOUSEOVER_RANGE_SQUARED: 584 continue 585 proximity = MAX_RTPC_VALUE - distanceSquared / MAX_MOUSEOVER_RANGE_SQUARED * MAX_RTPC_VALUE 586 if closestBracket is not None: 587 if proximity < bestProximity: 588 closestBracket = bracket 589 bestProximity = proximity 590 else: 591 closestBracket = bracket 592 bestProximity = proximity 593 594 activeBracket, lastSoundStrength = self.UpdateMouseHoverSound(activeBracket, bestProximity, closestBracket, lastSoundStrength) 595 except (ValueError, OverflowError): 596 pass 597 except Exception: 598 LogException('The sound update loop errored out') 599 finally: 600 uthread2.Sleep(0.025) 601 602 if activeBracket is not None: 603 self.DisableMouseOverSound() 604 self.LogInfo('Mouse tracking update thread ended') 605 606 def DisableMouseOverSound(self): 607 self.audio.SendUIEvent('ui_scanner_mouseover_stop') 608 self.audio.SetGlobalRTPC('scanner_mouseover', 0) 609 610 def OnClientEvent_WarpStarted(self, *args): 611 self.LogInfo('OnClientEvent_WarpStarted hiding the sweep gfx') 612 self.gfxHandler.DisableGfx(SUPPRESS_GFX_WARPING) 613 614 def OnClientEvent_WarpFinished(self, *args): 615 self.LogInfo('OnClientEvent_WarpFinished showing the sweep gfx') 616 self.gfxHandler.EnableGfx(SUPPRESS_GFX_WARPING) 617 618 def OnShowUI(self): 619 self.LogInfo('OnShowUI showing the sweep gfx') 620 uicore.layer.sensorsuite.display = True 621 self.gfxHandler.EnableGfx(SUPPRESS_GFX_NO_UI) 622 623 def OnHideUI(self): 624 self.LogInfo('OnHideUI hiding the sweep gfx') 625 uicore.layer.sensorsuite.display = False 626 self.gfxHandler.DisableGfx(SUPPRESS_GFX_NO_UI) 627 628 def OnSystemScanDone(self): 629 self.probeScannerController.UpdateProbeResultBrackets() 630 631 def GetOverlappingSites(self): 632 overlappingBrackets = [] 633 for siteData in self.sitesUnderCursor: 634 bracket = self.siteController.spaceLocations.GetBracketBySiteID(siteData.siteID) 635 if bracket: 636 overlappingBrackets.append(bracket) 637 638 return overlappingBrackets 639 640 def GetAnomalies(self): 641 return self.siteController.GetSiteHandler(sitetype.ANOMALY).GetSites().values() 642 643 def GetAnomaly(self, instanceID): 644 anomalies = self.GetAnomalies() 645 for anomaly in anomalies: 646 if anomaly.instanceID == instanceID: 647 return anomaly 648 649 def GetStaticSites(self): 650 return self.siteController.GetSiteHandler(sitetype.STATIC_SITE).GetSites().values() 651 652 @uthread2.debounce(1.0) 653 def FullyUpdateSignalTrackerDebounced(self): 654 self.OnSignalTrackerFullState(session.solarsystemid2, self.scanSvc.GetScanMan().GetFullState(), shouldRemoveOldSites=True) 655 656 def UpdateSignalTracker(self): 657 self.OnSignalTrackerFullState(session.solarsystemid2, self.scanSvc.GetScanMan().GetFullState(), shouldRemoveOldSites=False) 658 659 def GetSignatures(self): 660 return self.siteController.GetSiteHandler(sitetype.SIGNATURE).GetSites().values() 661 662 def GetLocatedSignatures(self): 663 return [ signature for signature in self.GetSignatures() if signature.IsAccurate() ] 664 665 def GetUnknownSignatures(self): 666 return [ signature for signature in self.GetSignatures() if not signature.IsAccurate() ] 667 668 def SetSiteFilter(self, siteType, enabled): 669 handler = self.siteController.GetSiteHandler(siteType) 670 handler.SetFilterEnabled(enabled) 671 if siteType in sitetype.STRUCTURE_SITE_TYPES: 672 self.UpdateVisibleStructures() 673 else: 674 self.UpdateVisibleSites() 675 676 def OnStructuresVisibilityUpdated(self): 677 self.UpdateVisibleStructures() 678 679 def OnBallAdded(self, slimItem): 680 if slimItem.categoryID == const.categoryStructure: 681 self.UpdateVisibleStructures() 682 683 def DoBallRemove(self, ball, slimItem, terminal): 684 if slimItem.categoryID == const.categoryStructure: 685 self.UpdateVisibleStructures() 686 687 def DoBallsRemove(self, pythonBalls, isRelease): 688 for _ball, slimItem, _terminal in pythonBalls: 689 if slimItem.categoryID == const.categoryStructure: 690 self.UpdateVisibleStructures() 691 return 692 693 @bluepy.TimedFunction('sensorSuiteService::UpdateVisibleStructures') 694 def UpdateVisibleStructures(self): 695 setattr(self, 'updateVisibleStructuresTimerThread', AutoTimer(UPDATE_STRUCTURES_DELAY, self._UpdateVisibleStructures)) 696 697 @bluepy.TimedFunction('sensorSuiteService::_UpdateVisibleStructures') 698 def _UpdateVisibleStructures(self): 699 self.LogInfo('UpdateVisibleStructures') 700 try: 701 if not self.IsSolarSystemReady(): 702 return 703 self.siteController.UpdateSiteVisibility(siteTypesToUpdate=sitetype.STRUCTURE_SITE_TYPES) 704 finally: 705 self.updateVisibleStructuresTimerThread = None 706 707 @bluepy.TimedFunction('sensorSuiteService::UpdateVisibleSites') 708 def UpdateVisibleSites(self): 709 setattr(self, 'updateVisibleSitesTimerThread', AutoTimer(UPDATE_SITES_DELAY, self._UpdateVisibleSites)) 710 711 @bluepy.TimedFunction('sensorSuiteService::_UpdateVisibleSites') 712 def _UpdateVisibleSites(self): 713 self.LogInfo('UpdateVisibleSites') 714 try: 715 if not self.IsSolarSystemReady(): 716 return 717 self.siteController.UpdateSiteVisibility(siteTypesToUpdate=sitetype.NON_STRUCTURE_SITE_TYPES) 718 finally: 719 self.updateVisibleSitesTimerThread = None 720 721 def GetPositionalSiteItemIDFromTargetID(self, targetID): 722 for site in self.siteController.siteMaps.IterSitesByKeys(sitetype.ANOMALY, sitetype.STRUCTURE): 723 if site.targetID == targetID: 724 return (site.siteID, site.groupID) 725 726 return (None, None) 727 728 def OnClientEvent_JumpStarted(self, *args): 729 self._Hide() 730 731 def OnClientEvent_JumpExecuted(self, itemID): 732 self._Show() 733 self._InitiateSensorSweep()