subwaySvc.py (22422B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\client\script\parklife\subwaySvc.py 2 import logging 3 import blue 4 import evecamera 5 import evegraphics.settings as gfxsettings 6 import geo2 7 import telemetry 8 import trinity 9 import uthread2 10 from carbon.common.script.sys.service import Service 11 from carbon.common.script.util import mathCommon 12 from carbonui.uicore import uicore 13 from eve.client.script.environment.effects import jump_signals 14 from eve.client.script.parklife import states 15 from eve.client.script.parklife.sceneManager import GetSceneManager 16 from eve.client.script.ui.camera.jumpCamera import JumpCamera 17 from eve.client.script.ui.inflight.overview.overviewWindowUtil import GetOverviewWndIfOpen 18 from eve.common.lib import appConst 19 from eve.common.script.sys.idCheckers import IsSolarSystem, IsStargate 20 from evegraphics.spaceSubway.spaceSubwayEffect import SpaceSubwayEffect, SpaceSubwayCamera 21 from fsdBuiltData.client.travelEffects import IsTravelEffect 22 from tacticalNavigation.ballparkFunctions import GetBallpark, GetBall 23 log = logging.getLogger(__name__) 24 25 def GetSubwayService(): 26 return sm.GetService('subway') 27 28 29 def FadeUI(out = False): 30 fadePanels = [ child for child in uicore.layer.inflight.children if getattr(child, '__renderObject__', None) != trinity.Tr2Sprite2d ] 31 try: 32 overView = GetOverviewWndIfOpen() 33 fadePanels.append(overView.GetScrollContent()) 34 except AttributeError: 35 log.error('FadeUI: Could not gather overview content for fading') 36 37 fadeFunction = uicore.animations.FadeIn 38 if out: 39 fadeFunction = uicore.animations.FadeOut 40 for fadePanel in fadePanels: 41 fadeFunction(fadePanel, duration=1) 42 43 fadeValue = 0.0 if out else 1.0 44 for fadePanel in fadePanels: 45 fadePanel.opacity = fadeValue 46 47 48 def PreJumpServiceCalls(gateID, destinationID): 49 sm.ScatterEvent('OnJumpStarted', gateID, destinationID) 50 sm.GetService('flightControls').Stop() 51 uthread2.StartTasklet(FadeUI, True) 52 53 54 def PostJumpServiceCalls(gateID): 55 uthread2.StartTasklet(FadeUI, False) 56 ballpark = sm.GetService('michelle').GetBallpark(doWait=True) 57 if ballpark is None: 58 return 59 sm.GetService('flightControls').Start() 60 sm.ScatterEvent('OnJumpExecuted', gateID) 61 62 63 def GetPriorityLoads(gateID): 64 priorityList = [gateID] 65 if gateID and IsStargate(gateID): 66 gateItem = GetBallpark().GetInvItem(gateID) 67 if gateItem is not None: 68 destGate, destSystem = gateItem.jumps[0] 69 systemItems = sm.GetService('map').GetSolarsystemItems(destSystem, False) 70 stargateRow = systemItems.Filter('itemID')[destGate][0] 71 stargatePos = (stargateRow.x, stargateRow.y, stargateRow.z) 72 maxDistSq = (appConst.AU * 0.5) ** 2 73 for each in systemItems: 74 if each.itemID == gateID: 75 continue 76 pos = (each.x, each.y, each.z) 77 dist = geo2.Vec3DistanceSq(stargatePos, pos) 78 if dist < maxDistSq: 79 priorityList.append(each.itemID) 80 81 return priorityList 82 83 84 class EveSpaceSubwayCamera(SpaceSubwayCamera): 85 86 def __init__(self): 87 super(EveSpaceSubwayCamera, self).__init__() 88 self.camera = GetSceneManager().GetOrCreateCamera(evecamera.CAM_JUMP) 89 GetSceneManager().SetPrimaryCamera(JumpCamera.cameraID) 90 self._hasLoggedInvalidPosition = False 91 92 def SetPositionAndPointOfInterest(self, newPos, newPoi): 93 if self.camera.SetEyeAndAtPosition(newPos, newPoi): 94 return 95 if not self._hasLoggedInvalidPosition: 96 self._hasLoggedInvalidPosition = True 97 log.warning('Jump effect produced an invalid camera position, ignoring it. pos=%r, poi=%r, %s', newPos, newPoi, self.camera) 98 99 @property 100 def position(self): 101 return self.camera.eyePosition 102 103 @position.setter 104 def position(self, pos): 105 self.camera.eyePosition = pos 106 107 @property 108 def fov(self): 109 return self.camera.fov 110 111 @fov.setter 112 def fov(self, fov): 113 self.camera.fov = fov 114 115 @property 116 def pointOfInterest(self): 117 return self.camera.atPosition 118 119 @pointOfInterest.setter 120 def pointOfInterest(self, poi): 121 self.camera.atPosition = poi 122 123 def UnLink(self): 124 super(EveSpaceSubwayCamera, self).UnLink() 125 primaryView = sm.GetService('viewState').GetPrimaryView() 126 cam = primaryView.ActivatePrimaryCamera() 127 cam.StopShaking() 128 129 def TransitionToShip(self, endLookatID): 130 camera = GetSceneManager().GetActivePrimaryCamera() 131 uthread2.Sleep(self.camera.transitionDelay + 0.1) 132 if camera.cameraID == evecamera.CAM_SHIPORBIT: 133 if sm.GetService('autoPilot').GetState(): 134 uthread2.Sleep(1.0) 135 camera.Track(endLookatID, speed=10, duration=5.5) 136 137 138 class EveSpaceSubwayEffectState(object): 139 SCENE_STATE_SOURCE = 0 140 SCENE_STATE_TRANSITION = 1 141 SCENE_STATE_DESTINATION = 2 142 CAMERA_STATE_NOT_SET = -1 143 CAMERA_STATE_DETACHED = 0 144 CAMERA_STATE_ATTACHED = 1 145 POST_JUMP_CALLBACKS_STATE_NOT_CALLED = 0 146 POST_JUMP_CALLBACKS_STATE_CALLED = 1 147 CLEANUP_STATE_NOT_DONE = 0 148 CLEANUP_STATE_STARTED = 1 149 CLEANUP_STATE_DONE = 2 150 STOP_REQUESTED_STATE_NO = 0 151 STOP_REQUESTED_STATE_YES = 1 152 153 def __init__(self): 154 self.scene = self.SCENE_STATE_SOURCE 155 self.camera = self.CAMERA_STATE_NOT_SET 156 self.postJumpCallback = self.POST_JUMP_CALLBACKS_STATE_NOT_CALLED 157 self.cleanup = self.CLEANUP_STATE_NOT_DONE 158 self.stopRequested = self.STOP_REQUESTED_STATE_NO 159 160 def StartedCleaning(self): 161 return self.cleanup >= self.CLEANUP_STATE_STARTED 162 163 def StartCleaning(self): 164 self.cleanup = self.CLEANUP_STATE_STARTED 165 166 def IsCameraDetached(self): 167 return self.camera == self.CAMERA_STATE_DETACHED 168 169 def AttachCamera(self): 170 self.camera = self.CAMERA_STATE_ATTACHED 171 172 def DetachCamera(self): 173 self.camera = self.CAMERA_STATE_DETACHED 174 175 def IsInDestScene(self): 176 return self.scene == self.SCENE_STATE_DESTINATION 177 178 def IsInTranitionScene(self): 179 return self.scene == self.SCENE_STATE_TRANSITION 180 181 def EnterDestinationScene(self): 182 self.scene = self.SCENE_STATE_DESTINATION 183 184 def EnterTransitionScene(self): 185 self.scene = self.SCENE_STATE_TRANSITION 186 187 def CallPostJumpCallbacks(self): 188 self.postJumpCallback = self.POST_JUMP_CALLBACKS_STATE_CALLED 189 190 def HavePostJumpCallbacksBeenCalled(self): 191 return self.postJumpCallback == self.POST_JUMP_CALLBACKS_STATE_CALLED 192 193 def Stop(self): 194 self.stopRequested = self.STOP_REQUESTED_STATE_YES 195 196 def HasStopped(self): 197 return self.stopRequested == self.STOP_REQUESTED_STATE_YES 198 199 def info(self): 200 return {'scene': self.scene, 201 'camera': self.camera, 202 'postJumpCallback': self.postJumpCallback, 203 'cleanup': self.cleanup, 204 'stopRequested': self.stopRequested} 205 206 207 class EveSpaceSubwayEffect(SpaceSubwayEffect): 208 209 def __init__(self, cleanupCallback = None, endFocusID = None, jumpInfo = None): 210 super(EveSpaceSubwayEffect, self).__init__() 211 self.endFocusID = endFocusID 212 self.camera = None 213 self.cleanupCallback = cleanupCallback 214 self.cleanupCallbackEnabled = True 215 self.jumpInfo = jumpInfo 216 self.killThread = None 217 self.state = EveSpaceSubwayEffectState() 218 self._isCameraDetachPending = False 219 220 def DisableCleanupCallback(self): 221 self.cleanupCallbackEnabled = False 222 223 def CleanupLite(self): 224 super(EveSpaceSubwayEffect, self).Cleanup() 225 226 def Cleanup(self): 227 if self.state.StartedCleaning(): 228 return 229 self.state.StartCleaning() 230 log.info('Cleaning up EveSpaceSubwayEffect') 231 if not self.state.IsInDestScene(): 232 log.warning('Destination scene not enabled when we started cleaning, fixing that') 233 self.SetScene(self.destinationScene) 234 if not self.state.IsCameraDetached(): 235 log.warning('Camera not detached when we started cleaning, fixing that') 236 self.DetachCamera() 237 if not self.state.HavePostJumpCallbacksBeenCalled(): 238 log.warning('Post Jump Service calls not called when we started cleaning, fixing that') 239 self.PostJumpServiceCalls() 240 super(EveSpaceSubwayEffect, self).Cleanup() 241 if self.cleanupCallback and self.cleanupCallbackEnabled: 242 self.cleanupCallback() 243 244 def StartedCleaning(self): 245 return self.state.StartedCleaning() 246 247 def GetCamera(self): 248 if self.camera is None: 249 self.camera = EveSpaceSubwayCamera() 250 return self.camera 251 252 def AttachCamera(self): 253 self.state.AttachCamera() 254 super(EveSpaceSubwayEffect, self).AttachCamera() 255 256 def SetLook(self, nebulaPath, security, propagateToEffect = False): 257 super(EveSpaceSubwayEffect, self).SetLook(nebulaPath, security, self.inTransitionScene) 258 259 def GetJumpEndLookAtID(self): 260 lookatID = self.endFocusID 261 autoPilot = sm.GetService('autoPilot') 262 starmapSvc = sm.GetService('starmap') 263 destinationPath = starmapSvc.GetDestinationPath() 264 if destinationPath is not None and len(destinationPath) > 0 and destinationPath[0] is not None: 265 bp = GetBallpark() 266 if bp is not None: 267 destID = autoPilot.GetGateOrStationID(bp, destinationPath[0]) 268 if destID is not None: 269 lookatID = destID 270 return lookatID 271 272 def DetachCamera(self): 273 if not self.state.IsInDestScene() and not self.state.StartedCleaning(): 274 self._isCameraDetachPending = True 275 return 276 self._DetachCamera() 277 278 def _DetachCamera(self): 279 self._isCameraDetachPending = False 280 if self.state.IsCameraDetached(): 281 return 282 self.state.DetachCamera() 283 if self.IsWithinSystem(): 284 shipBall = sm.GetService('michelle').GetBall(session.shipid) 285 shipBall.fitted = False 286 shipBall.Prepare() 287 super(EveSpaceSubwayEffect, self).DetachCamera() 288 289 def TurnOnTransitionScene(self): 290 super(EveSpaceSubwayEffect, self).TurnOnTransitionScene() 291 if self.ship: 292 self.ship.rotationCurve.value = self.tunnelEffect.rotationCurve.value 293 for m in self.skinChangeModels: 294 m.rotationCurve.value = self.tunnelEffect.rotationCurve.value 295 296 self.state.EnterTransitionScene() 297 298 def TurnOnEndScene(self): 299 super(EveSpaceSubwayEffect, self).TurnOnEndScene() 300 if self._isCameraDetachPending: 301 self._DetachCamera() 302 uthread2.StartTasklet(self.PostJumpServiceCalls) 303 self.state.EnterDestinationScene() 304 305 def PostJumpServiceCalls(self): 306 PostJumpServiceCalls(self.jumpInfo['gateID']) 307 self.JumpToSpaceTransitionCallback() 308 self.state.CallPostJumpCallbacks() 309 310 def JumpToSpaceTransitionCallback(self): 311 endLookatID = self.GetJumpEndLookAtID() 312 self.camera.TransitionToShip(endLookatID) 313 sm.GetService('stateSvc').SetState(endLookatID, states.selected, 1) 314 sm.ScatterEvent('OnJumpFinished', self.jumpInfo['gateID'], self.jumpInfo['originSystemID']) 315 if self.jumpInfo['originSystemID'] is not None and self.jumpInfo['destinationSystemID'] is not None: 316 jump_signals.on_jump_arrived_at(self.jumpInfo['originSystemID'], self.jumpInfo['destinationSystemID']) 317 318 def SetScene(self, scene): 319 if scene is None: 320 log.error('Stopping you from setting the current scene to None, this would not have had good consequences. Good thing I caught you bro, but fix up your shitty code!') 321 return 322 if scene is self.transitionScene: 323 log.info('Setting scene to transition scene') 324 GetSceneManager().ApplyScene(scene, 'transition') 325 else: 326 log.info('Setting scene to destination scene') 327 GetSceneManager().ApplyScene(scene, 'default') 328 GetSceneManager().ApplySpaceScene() 329 GetSceneManager().UnregisterScene('transition', ignoreCamera=True) 330 331 def KillShot(self): 332 uthread2.SleepSim(10) 333 if not self.state.StartedCleaning(): 334 self.jumpInfo['effect_state'] = self.state.info() 335 log.warning("The space subway effect didn't get cleaned up properly after 10 seconds in simtime. Killing it!", extra=self.jumpInfo) 336 self.Cleanup() 337 338 def Stop(self, forceKillSwitch = False): 339 self.state.Stop() 340 self.killThread = uthread2.StartTasklet(self.KillShot) 341 if forceKillSwitch: 342 return 343 super(EveSpaceSubwayEffect, self).Stop() 344 345 def IsShakeEnabled(self): 346 setting = gfxsettings.Get(gfxsettings.UI_CAMERA_SHAKE_ENABLED) 347 return setting is None or setting 348 349 def OutOfSourceSystem(self): 350 return self.state.IsInTranitionScene() or self.state.IsInDestScene() 351 352 353 class SubwayService(Service): 354 __guid__ = 'svc.subway' 355 __servicename__ = 'subway' 356 __displayname__ = 'Space Subway Service' 357 __exportedcalls__ = {} 358 __notifyevents__ = ['OnSpecialFX', 'OnSessionChanged', 'OnGraphicSettingsChanged'] 359 __dependencies__ = ['sceneManager', 'michelle'] 360 __startupdependencies__ = [] 361 ENABLED = True 362 JUMP_FINISH_DELAY = 0 363 JUMP_EFFECT_OVERRIDE = None 364 FORCE_KILL_SWITCH = False 365 366 def __init__(self): 367 super(SubwayService, self).__init__() 368 self.originScene = None 369 self.destinationScene = None 370 self.spaceSubwayEffect = None 371 self.gateID = None 372 self.shipID = None 373 self.originSystemID = None 374 self.destSystemID = None 375 self.lockedBalls = [] 376 377 def Enabled(self): 378 return self.ENABLED 379 380 def InJump(self): 381 return self.spaceSubwayEffect is not None and not self.spaceSubwayEffect.StartedCleaning() 382 383 def Toggle(self): 384 self.ENABLED = not self.ENABLED 385 386 def ToggleKillSwitch(self): 387 self.FORCE_KILL_SWITCH = not self.FORCE_KILL_SWITCH 388 389 def SetEffectOverride(self, effect_guid): 390 self.JUMP_EFFECT_OVERRIDE = effect_guid 391 392 def OkToDumpBallPark(self): 393 return self.spaceSubwayEffect is not None and self.spaceSubwayEffect.OutOfSourceSystem() 394 395 @telemetry.ZONE_METHOD 396 def OnSpecialFX(self, shipID, moduleID, moduleTypeID, targetID, otherTypeID, guid, isOffensive, start, active, duration = -1, repeat = None, startTime = None, timeFromStart = 0, graphicInfo = None): 397 if self.ENABLED and IsTravelEffect(guid): 398 destinationSystem = None 399 if graphicInfo: 400 destinationSystem = graphicInfo[0] 401 guid = self.JUMP_EFFECT_OVERRIDE or guid 402 if shipID == session.shipid: 403 self.shipID = shipID 404 self.gateID = targetID 405 self.originSystemID = session.solarsystemid 406 self.destSystemID = destinationSystem 407 try: 408 self.StartJump(shipID, targetID, guid, destinationSystem) 409 except Exception as e: 410 log.exception('Exception caught while jumping %s' % e) 411 PostJumpServiceCalls(self.gateID) 412 self.Cleanup() 413 414 sm.GetService('space').PrioritizeLoadingForIDs(GetPriorityLoads(self.gateID)) 415 else: 416 try: 417 self.StartJumpForAudience(shipID, guid, destinationSystem) 418 except Exception as e: 419 log.exception('Exception caught while making non-ego ball jump %s' % e) 420 421 def OnSessionChanged(self, isremote, session, change): 422 if 'locationid' in change and self.InJump(): 423 oldLocation, newLocation = change['locationid'] 424 try: 425 if IsSolarSystem(newLocation): 426 destinationScenePath, security = self._GetPathAndSecurity(self.destSystemID) 427 GetSceneManager().UnregisterScene('default', ignoreCamera=True) 428 GetSceneManager().RegisterScene(self.destinationScene, 'default') 429 if self.JUMP_FINISH_DELAY > 0: 430 log.error('DELAYING THE JUMP END BY %d ms' % self.JUMP_FINISH_DELAY) 431 blue.synchro.SleepSim(self.JUMP_FINISH_DELAY) 432 self.spaceSubwayEffect.SetLook(destinationScenePath, security) 433 self.spaceSubwayEffect.SetDestinationScene(self.destinationScene) 434 else: 435 log.error('Jump got a session change without a new system location, got change from %s to %s. Ending this!' % (oldLocation, newLocation)) 436 finally: 437 self.FinishJump() 438 439 def StartJumpForAudience(self, shipID, jumpType, destinationSystem): 440 self.LogInfo("Starting jump '%s' of %s for players on grid" % (jumpType, shipID)) 441 shipModel = self._GetModel(shipID, makeFake=False) 442 if shipModel is None: 443 self.LogInfo("Couldn't find the jumping ball, so no effect for you") 444 return 445 effect = EveSpaceSubwayEffect() 446 effect.SetOriginScene(self.GetScene()) 447 effect.SetEffect(jumpType) 448 originOrientation = None 449 if destinationSystem is not None: 450 originOrientation = self._GetOriginOrientation(destinationSystem) 451 effect.HideJumpingShip(shipModel, originOrientation=originOrientation, callback=effect.CleanupLite) 452 453 def StartJump(self, shipID, targetID, jumpType, destinationSystem): 454 self.LogInfo("Starting jump '%s' for %s through %s (%s to %s)" % (jumpType, 455 shipID, 456 targetID, 457 self.originSystemID, 458 self.destSystemID)) 459 if self.spaceSubwayEffect is not None: 460 self.spaceSubwayEffect.DisableCleanupCallback() 461 self.spaceSubwayEffect = None 462 self.LogInfo('Starting a jump with another still active, trying my best to make it not mess up anything') 463 PreJumpServiceCalls(self.gateID, self.destSystemID) 464 self.originScene = self.GetScene() 465 if self.destSystemID is not None: 466 destinationScenePath, security = self._GetPathAndSecurity(self.destSystemID) 467 self.destinationScene, _ = GetSceneManager().LoadScene(destinationScenePath, registerKey='default', applyScene=False) 468 destinationStargate = cfg.mapSolarSystemContentCache[session.solarsystemid].stargates.get(targetID, None) 469 destinationID = None 470 if destinationStargate is not None: 471 destinationID = destinationStargate.destination 472 jumpInfo = {'jumpType': jumpType, 473 'shipID': self.shipID, 474 'gateID': self.gateID, 475 'originSystemID': self.originSystemID, 476 'destinationSystemID': self.destSystemID} 477 self.spaceSubwayEffect = EveSpaceSubwayEffect(self.Cleanup, destinationID, jumpInfo) 478 self.spaceSubwayEffect.SetOriginScene(self.originScene) 479 self.spaceSubwayEffect.SetEffect(jumpType) 480 scenePath, security = self._GetPathAndSecurity(session.solarsystemid) 481 self.spaceSubwayEffect.SetLook(scenePath, security) 482 self.lockedBalls = [] 483 for ballID in [targetID, shipID]: 484 ball = GetBall(ballID) 485 if ball and hasattr(ball, 'LockFromRelease'): 486 self.lockedBalls.append(ball) 487 ball.LockFromRelease() 488 489 shipModel = self._GetModel(shipID) 490 if GetSceneManager().GetActivePrimaryCamera().cameraID == evecamera.CAM_SHIPPOV: 491 shipModel.display = False 492 shipModel = None 493 targetBall = GetBall(targetID) 494 gateModel = None 495 originOrientation = None 496 if targetBall: 497 gateModel = targetBall.GetModel() 498 elif destinationSystem is not None: 499 originOrientation = self._GetOriginOrientation(destinationSystem) 500 if IsStargate(targetID): 501 sm.GetService('audio').SendUIEvent('global_stop_all_stargate') 502 self.spaceSubwayEffect.StartEffectForOwner(gateModel, shipModel, originOrientation) 503 504 def FinishJump(self): 505 self.LogInfo('Finishing jump. Activating destination') 506 self.spaceSubwayEffect.Stop(self.FORCE_KILL_SWITCH) 507 508 def Cleanup(self): 509 self.LogInfo('Final clean up. Releasing all balls from last system ') 510 self.spaceSubwayEffect = None 511 for ball in self.lockedBalls: 512 ball.UnlockFromRelease(self.originScene) 513 514 self.lockedBalls = [] 515 self.originScene = None 516 self.destinationScene = None 517 518 def GetScene(self): 519 return GetSceneManager().GetRegisteredScene('default') 520 521 def _GetOriginOrientation(self, destinationSystem): 522 here = sm.GetService('map').GetItem(session.solarsystemid2) 523 there = sm.GetService('map').GetItem(destinationSystem) 524 yaw, pitch = mathCommon.GetYawAndPitchAnglesRad((here.x, here.y, here.z), (there.x, there.y, there.z)) 525 return geo2.QuaternionRotationSetYawPitchRoll(yaw, pitch, 0) 526 527 def _GetPathAndSecurity(self, solarsystemID): 528 system = cfg.mapSystemCache.get(solarsystemID, None) 529 if system is None: 530 return (None, None) 531 security = system.securityStatus 532 scenePath = GetSceneManager().GetSceneForSystem(solarsystemID) 533 return (scenePath, security) 534 535 def _GetModel(self, ballID, makeFake = True): 536 model = None 537 ball = GetBall(ballID) 538 if ball is not None: 539 try: 540 model = ball.GetModel() 541 except AttributeError: 542 pass 543 544 if not model and makeFake: 545 model = trinity.EveEffectRoot2() 546 model.translationCurve = ball 547 model.rotationCurve = ball 548 elif makeFake: 549 model = trinity.EveEffectRoot2() 550 return model 551 552 def HandleSkinChange(self, newModel): 553 if self.spaceSubwayEffect is not None: 554 self.spaceSubwayEffect.ChangeSkin(newModel) 555 return True 556 return False 557 558 def OnGraphicSettingsChanged(self, changes): 559 if self.InJump() and gfxsettings.UI_CAMERA_SHAKE_ENABLED in changes: 560 self.spaceSubwayEffect.SetShake(self.spaceSubwayEffect.IsShakeEnabled())