shipOrbitCamera.py (19873B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\client\script\ui\camera\shipOrbitCamera.py 2 import math 3 import destiny 4 import gametime 5 import uthread2 6 from eve.client.script.environment.spaceObject.spaceObject import SpaceObject 7 from eve.client.script.parklife import states 8 from eve.client.script.ui.camera.cameraUtil import GetDurationByDistance, GetBallPosition, GetBall, GetBallMaxZoom, Vector3Chaser, VectorLerper, IsAutoTrackingEnabled, CheckShowModelTurrets, GetSpeedDirection, GetInitialLookAtDistance, IsDynamicCameraMovementEnabled, IsNanVector3, IsValidSpaceCameraPosition 9 from eve.client.script.ui.camera.baseSpaceCamera import BaseSpaceCamera 10 import evecamera 11 import blue 12 import geo2 13 import evetypes 14 import uthread 15 import evegraphics.settings as gfxsettings 16 import inventorycommon.const as invconst 17 from eve.client.script.ui.camera.util.cameraSpeedOffsetter import CameraSpeedOffsetter 18 from evegraphics.explosions.spaceObjectExplosionManager import SpaceObjectExplosionManager 19 from carbonui.uicore import uicore 20 from destructionEffect import destructionType as destructionEffectType 21 TRACK_RESET_SPEED = 60.0 22 TRACK_DEFAULT_SPEED = 30.0 23 24 class ShipOrbitCamera(BaseSpaceCamera): 25 __notifyevents__ = BaseSpaceCamera.__notifyevents__[:] + ['OnBallparkSetState', 26 'OnStateChange', 27 'OnDungeonCameraInterest', 28 'OnBallAdded'] 29 cameraID = evecamera.CAM_SHIPORBIT 30 isBobbingCamera = True 31 minFov = 0.8 32 maxFov = 1.2 33 minZoom = 800000 34 name = 'ShipOrbitCamera' 35 36 def __init__(self): 37 BaseSpaceCamera.__init__(self) 38 self.lookAtBall = None 39 self.trackBall = None 40 self.trackPendingItemIDSpeedDuration = None 41 self.orbitFreezeProp = 0.0 42 self._zoomPropCache = None 43 self._eyeOffsetChaser = Vector3Chaser() 44 self._trackOffsetChaser = Vector3Chaser() 45 self.trackLerper = VectorLerper(duration=1.5) 46 self.speedOffsetter = CameraSpeedOffsetter() 47 self.isManualFovEnabled = False 48 self._trackSpeedMultiplier = 1.0 49 self._trackSpeed = TRACK_DEFAULT_SPEED 50 self._handleTargetKilledThread = None 51 self.speedDir = None 52 53 def OnActivated(self, itemID = None, lastCamera = None, **kwargs): 54 BaseSpaceCamera.OnActivated(self, **kwargs) 55 self.speedOffsetter.OnActivated() 56 self.RegisterActivated() 57 if lastCamera and lastCamera.cameraID in (evecamera.CAM_TACTICAL, 58 evecamera.CAM_SHIPPOV, 59 evecamera.CAM_JUMP, 60 evecamera.CAM_UNDOCK, 61 evecamera.CAM_ENTERSPACE, 62 evecamera.CAM_EXPLOSION): 63 itemID = itemID or getattr(lastCamera, 'lastLookAtID', None) or self.ego 64 self._SetLookAtBall(itemID) 65 atPos1 = self.GetTrackPosition(self.lookAtBall) 66 direction = lastCamera.GetLookAtDirection() 67 if IsNanVector3(direction): 68 direction = geo2.Vec3Direction(self.default_eyePosition, self.default_atPosition) 69 eyePos1 = geo2.Vec3Add(atPos1, geo2.Vec3Scale(direction, self.GetInitialZoomDist(lastCamera))) 70 canTransitFromLastCamera = IsValidSpaceCameraPosition(lastCamera.atPosition) and IsValidSpaceCameraPosition(lastCamera.eyePosition) 71 if canTransitFromLastCamera and lastCamera.cameraID in (evecamera.CAM_TACTICAL, 72 evecamera.CAM_JUMP, 73 evecamera.CAM_UNDOCK, 74 evecamera.CAM_ENTERSPACE, 75 evecamera.CAM_EXPLOSION): 76 if hasattr(lastCamera, 'transitionDelay'): 77 duration = lastCamera.transitionDelay 78 else: 79 duration = GetDurationByDistance(lastCamera.eyePosition, eyePos1, 0.4, 0.6) 80 self.Transit(lastCamera.atPosition, lastCamera.eyePosition, atPos1, eyePos1, duration=duration, smoothing=0.0) 81 currFov = self.fov 82 self.fov = lastCamera.fov 83 if not IsDynamicCameraMovementEnabled(): 84 self.SetFovTarget(currFov) 85 else: 86 self.SetAtPosition(atPos1) 87 self.SetEyePosition(eyePos1) 88 elif itemID: 89 self._SetLookAtBall(itemID) 90 elif not self.lookAtBall: 91 self._SetLookAtBall(self.ego) 92 93 def RegisterActivated(self): 94 settings.char.ui.Set('spaceCameraID', evecamera.CAM_SHIPORBIT) 95 96 def GetInitialZoomDist(self, lastCamera): 97 if lastCamera.cameraID == evecamera.CAM_ENTERSPACE: 98 dist = lastCamera.GetZoomDistance() 99 elif self._zoomPropCache is not None: 100 dist = self.GetZoomDistanceByZoomProportion(self._zoomPropCache) 101 else: 102 dist = self.GetLookAtDistance() 103 return dist 104 105 def StopHandleTargetKilledThread(self): 106 if self._handleTargetKilledThread: 107 self._handleTargetKilledThread.kill() 108 self._handleTargetKilledThread = None 109 110 def GetLookAtItemID(self): 111 return self.GetItemID() 112 113 def LookAt(self, itemID, forceUpdate = False, objRadius = None): 114 lookAtBall = self._TrySetLookAtBall(itemID, forceUpdate, objRadius) 115 if lookAtBall: 116 radius = self.GetLookAtDistance(objRadius) 117 self._LookAtAnimate(itemID, radius) 118 self.StopHandleTargetKilledThread() 119 120 def _TrySetLookAtBall(self, itemID, forceUpdate = False, objRadius = None): 121 if not self.IsLookAtAllowed(itemID): 122 return 123 self.Track(None, speed=TRACK_RESET_SPEED) 124 self.DisableManualFov() 125 isAlreadyLookingAt = self.lookAtBall and self.lookAtBall.id == itemID 126 if not forceUpdate and isAlreadyLookingAt and not objRadius: 127 if itemID != self.ego: 128 self._SetLookAtBall(self.ego) 129 return self.lookAtBall 130 else: 131 return 132 self._ScatterLookAtEvent(itemID) 133 if self.CheckObjectTooFar(itemID): 134 self.Track(itemID) 135 return 136 self._SetLookAtBall(itemID) 137 return self.lookAtBall 138 139 def _ScatterLookAtEvent(self, itemID): 140 sm.ScatterEvent('OnCameraLookAt', itemID == self.ego, itemID) 141 142 def IsLookAtAllowed(self, itemID): 143 if not self.IsManualControlEnabled(): 144 return False 145 if self.IsBallWarping(itemID) and itemID != self.ego: 146 return False 147 return True 148 149 def LookAtMaintainDistance(self, itemID): 150 lookAtBall = self._TrySetLookAtBall(itemID) 151 if lookAtBall: 152 radius = self.GetZoomDistance() 153 self._LookAtAnimate(itemID, radius) 154 155 def IsBallWarping(self, itemID): 156 trackBall = GetBall(itemID) 157 return trackBall is None or trackBall.mode == destiny.DSTBALL_WARP 158 159 def DisableManualFov(self): 160 self.isManualFovEnabled = False 161 162 def _SetLookAtBall(self, itemID): 163 self.lookAtBall = GetBall(itemID) 164 if self.lookAtBall: 165 sm.StartService('stateSvc').SetState(self.lookAtBall.id, states.lookingAt, True) 166 CheckShowModelTurrets(self.lookAtBall) 167 self.Track(None, speed=TRACK_RESET_SPEED) 168 if not self.lookAtBall: 169 self.ResetAnchorPos() 170 return 171 self.UpdateMaxZoom() 172 self.ConstructAnchorBall() 173 if isinstance(self.lookAtBall, SpaceObject): 174 self.lookAtBall.RegisterForModelLoad(self.OnLookAtItemModelLoaded) 175 176 def UpdateMaxZoom(self): 177 ball = self.lookAtBall 178 nearClip = self.nearClip 179 if ball is not None and nearClip is not None: 180 self.SetMaxZoom(GetBallMaxZoom(ball, nearClip)) 181 182 def _LookAtAnimate(self, itemID, radius): 183 atPos1 = GetBallPosition(self.lookAtBall) 184 eyePos1 = self._GetNewLookAtEyePos(atPos1, itemID, radius) 185 duration = GetDurationByDistance(self.eyePosition, eyePos1, 0.5, 1.5) 186 self.speedOffsetter.Reset() 187 self.TransitTo(atPos1, eyePos1, duration=duration, smoothing=0.0) 188 189 def _GetNewLookAtEyePos(self, atPos1, itemID, radius): 190 typeID = self.lookAtBall.typeID 191 if typeID and evetypes.GetGroupID(typeID) == invconst.groupBillboard: 192 direction = self._GetBillboardLookAtDirection() 193 radius = self.lookAtBall.radius * 5 194 else: 195 direction = self.GetLookAtDirection() 196 eyePos1 = geo2.Vec3Add(atPos1, geo2.Vec3Scale(direction, radius)) 197 return eyePos1 198 199 def _GetBillboardLookAtDirection(self): 200 direction = GetSpeedDirection(self.lookAtBall) 201 if geo2.Vec3Dot(self.GetLookAtDirection(), direction) < 0: 202 direction = geo2.Vec3Scale(direction, -1) 203 return direction 204 205 def GetLookAtDistance(self, objRadius = None): 206 return GetInitialLookAtDistance(self.maxZoom, self.minZoom, objRadius) 207 208 def _UpdateAtOffset(self): 209 if not self.lookAtBall: 210 self._trackOffsetChaser.ResetValue() 211 return 212 atOffset = None 213 self.speedDir = GetSpeedDirection(self.lookAtBall) 214 self._UpdateTrackOffset() 215 trackOffset = self._trackOffsetChaser.GetValue() 216 self.speedOffsetter._Update(self.lookAtBall, self.maxZoom, self.IsTracking()) 217 speedOffset = self.speedOffsetter.GetSpeedOffset() 218 self._AddToAtOffset(geo2.Vec3Add(trackOffset, speedOffset)) 219 220 def _UpdateTrackOffset(self): 221 if self.IsTracking() and IsDynamicCameraMovementEnabled(): 222 trackOffset = self._GetTrackAtOffset() 223 self._trackOffsetChaser.SetTargetValue(trackOffset, self._trackSpeed * self._trackSpeedMultiplier) 224 else: 225 self._trackOffsetChaser.ResetValue(TRACK_RESET_SPEED * self._trackSpeedMultiplier) 226 227 def _GetTrackAtOffset(self): 228 trackOffset = geo2.Vec3Subtract(self.GetTrackPosition(self.trackBall), self._atPosition) 229 length = geo2.Vec3Length(trackOffset) 230 maxLen = 250000 231 if length > maxLen: 232 trackOffset = geo2.Vec3Scale(trackOffset, maxLen / length) 233 return trackOffset 234 235 def _GetTrackEyeOffset(self): 236 offsetProp = 1.0 - self.GetZoomProportion() ** self.kZoomPower 237 offsetDir = self._GetTrackEyeOffsetDirection() 238 offsetAmount = offsetProp * self.maxZoom 239 offset = geo2.Vec3Scale(offsetDir, offsetAmount) 240 return offset 241 242 def _GetTrackEyeOffsetDirection(self): 243 pitch = math.pi - self.GetPitch() 244 rotMat = geo2.MatrixRotationAxis(self.GetZAxis(), -pitch) 245 return geo2.Vec3Transform(self.GetYAxis(), rotMat) 246 247 def _UpdateEyeOffset(self): 248 if self.IsChasing(): 249 offset = (0, 0.5 * self.maxZoom, 0) 250 eyeOffset = self.GetChaseEyeOffset() 251 offset = geo2.Vec3Subtract(offset, eyeOffset) 252 self._eyeOffsetChaser.SetTargetValue(offset, 1.0) 253 elif self.IsTracking() and IsDynamicCameraMovementEnabled(): 254 offset = self._GetTrackEyeOffset() 255 self._eyeOffsetChaser.SetTargetValue(offset, self._trackSpeed * self._trackSpeedMultiplier) 256 else: 257 self._eyeOffsetChaser.ResetValue(self._trackSpeed * self._trackSpeedMultiplier) 258 self._AddToEyeOffset(self._eyeOffsetChaser.GetValue()) 259 260 def Update(self): 261 self._UpdateAnchorPosition() 262 BaseSpaceCamera.Update(self) 263 if not self.lookAtBall or not self.ego: 264 return 265 zoomProp = self.GetZoomProportion() 266 self._UpdateAtOffset() 267 self._UpdateEyeOffset() 268 newAtPos = self.GetTrackPosition(self.lookAtBall) 269 atDiff = geo2.Vec3Subtract(newAtPos, self._atPosition) 270 self.SetAtPosition(newAtPos) 271 if self.IsChasing(): 272 self.TrySetEyePosition(self.trackLerper.GetValue(self._eyePosition, self.GetChaseEyePosition())) 273 elif self.IsTracking(): 274 self.TrySetEyePosition(self.trackLerper.GetValue(self._eyePosition, self.GetTrackingEyePosition())) 275 else: 276 prop = self._GetEyePosDriftProporition() 277 eyeOffset = geo2.Vec3Scale(atDiff, prop) 278 self.TrySetEyePosition(geo2.Vec3Add(self._eyePosition, eyeOffset)) 279 if not self.IsInTransit(): 280 if self.GetItemID() == self.ego or self.IsTracking() or self.IsChasing(): 281 self.SetZoom(zoomProp) 282 self.EnforceMinZoom() 283 if not self.isManualFovEnabled and IsDynamicCameraMovementEnabled(): 284 self.SetFovTarget(self.GetDynamicFov()) 285 286 def _UpdateAnchorPosition(self): 287 if self.lookAtBall and self.lookAtBall.mode == destiny.DSTBALL_WARP: 288 self.ResetAnchorPos() 289 elif not self._anchorBall or geo2.Vec3Length(GetBallPosition(self._anchorBall)) > evecamera.LOOKATRANGE_MAX_NEW: 290 self.ConstructAnchorBall() 291 292 def GetTrackingEyePosition(self): 293 trackPos = self.GetTrackPosition(self.trackBall) 294 direction = geo2.Vec3Subtract(self._atPosition, trackPos) 295 if geo2.Vec3Length(direction) == 0.0: 296 direction = self.GetLookAtDirection() 297 direction = geo2.Vec3Normalize(direction) 298 offset = geo2.Vec3Scale(direction, self.GetZoomDistance()) 299 return geo2.Vec3Add(self._atPosition, offset) 300 301 def GetChaseEyePosition(self): 302 offset = geo2.Vec3Scale(self.speedDir, -self.GetZoomDistance()) 303 return geo2.Vec3Add(self._atPosition, offset) 304 305 def IsTracking(self): 306 return self.trackBall is not None and self.trackBall != self.lookAtBall 307 308 def GetChaseEyeOffset(self): 309 offsetAmount = geo2.Vec3Length(self.speedOffsetter.GetSpeedOffset()) 310 eyeOffset = geo2.Vec3Scale(self.speedDir, offsetAmount) 311 return eyeOffset 312 313 def Track(self, itemID = None, speed = None, duration = 1.5, **kwargs): 314 if not speed: 315 speed = TRACK_DEFAULT_SPEED if itemID else TRACK_RESET_SPEED 316 self.trackPendingItemIDSpeedDuration = None 317 if self.trackBall and self.trackBall.id == itemID: 318 return 319 if not self.trackBall and itemID is None: 320 return 321 self.StopUpdateThreads() 322 if itemID and self.trackBall is None: 323 self._TrackZoomOutIfTooClose() 324 self.trackBall = GetBall(itemID) 325 self._trackSpeed = speed 326 self._RampUpTrackSpeed(duration) 327 self.trackLerper.Reset(duration) 328 self.StopHandleTargetKilledThread() 329 sm.ScatterEvent('OnCameraTrack', itemID) 330 331 def _TrackZoomOutIfTooClose(self): 332 if self.GetZoomProportion() < 0.45: 333 self.SetZoomTarget(0.45) 334 335 def _RampUpTrackSpeed(self, duration = 1.5): 336 self._trackSpeedMultiplier = 0.0 337 uicore.animations.MorphScalar(self, '_trackSpeedMultiplier', 0.0, 1.0, duration=duration) 338 339 def _GetEyePosDriftProporition(self): 340 if not IsDynamicCameraMovementEnabled(): 341 return 1.0 342 elif self.GetItemID() == self.ego: 343 return 0.999 344 else: 345 zoomProp = self.GetZoomProportion() 346 prop = 0.7 * (1.0 - zoomProp) 347 prop = max(0.5, prop) 348 if prop < 1.0: 349 prop += self.orbitFreezeProp * (1.0 - prop) 350 prop = min(prop, 1.0) 351 return prop 352 353 def IsChasing(self): 354 return self.lookAtBall == self.trackBall and self.speedDir and geo2.Vec3Length(self.speedDir) > 0.0 355 356 def GetTrackItemID(self): 357 if self.IsTracking(): 358 return self.trackBall.id 359 360 def ResetCamera(self, *args): 361 self.LookAt(self.ego, forceUpdate=True) 362 363 def ResetCameraPosition(self): 364 BaseSpaceCamera.ResetCameraPosition(self) 365 self._SetLookAtBall(self.ego) 366 367 def Orbit(self, dx = 0, dy = 0): 368 if self.IsTransitioningToOrFromTracking() and IsDynamicCameraMovementEnabled(): 369 return 370 BaseSpaceCamera.Orbit(self, dx, dy) 371 if self.IsTracking() or self.IsChasing(): 372 self.Track(None, speed=TRACK_RESET_SPEED) 373 374 def IsTransitioningToOrFromTracking(self): 375 return self._trackSpeedMultiplier < 0.4 376 377 def OnDeactivated(self): 378 BaseSpaceCamera.OnDeactivated(self) 379 self._zoomPropCache = self.GetZoomProportion() 380 self.lookAtBall = None 381 self._trackOffsetChaser.ResetValue() 382 self.speedOffsetter.Reset() 383 self.ResetAnchorPos() 384 self.DisableManualFov() 385 self._trackSpeed = 1.0 386 self._trackSpeedMultiplier = 1.0 387 self.ResetRotate() 388 self.StopHandleTargetKilledThread() 389 390 def GetItemID(self): 391 if self.lookAtBall: 392 return self.lookAtBall.id 393 394 def ClearCameraParent(self): 395 self._SetLookAtBall(self.ego) 396 397 def OnBallRemoved(self, ball): 398 if ball == self.lookAtBall: 399 if not self.isActive or ball.id == self.ego: 400 self._SetLookAtBall(None) 401 elif ball.id != self.ego and destructionEffectType.isExplosionOrOverride(ball.destructionEffectId): 402 if gfxsettings.Get(gfxsettings.UI_EXPLOSION_EFFECTS_ENABLED) and IsDynamicCameraMovementEnabled(): 403 sm.GetService('sceneManager').SetPrimaryCamera(evecamera.CAM_EXPLOSION, itemID=ball.id) 404 else: 405 self.LookAt(self.ego) 406 else: 407 self.LookAt(self.ego) 408 if ball == self.trackBall: 409 SpaceObjectExplosionManager.GetExplosionTimesWhenAvailable(ball.id, lambda t1, t2: self.StartHandleTargetKilledThread(ball.id, t1, t2)) 410 411 def StartHandleTargetKilledThread(self, ballID, globalExplosionStart, wreckSwitchTime): 412 self._handleTargetKilledThread = uthread.new(self._HandleTargetKilled, ballID, globalExplosionStart, wreckSwitchTime) 413 414 def _HandleTargetKilled(self, ballID, globalExplosionStart, wreckSwitchTime): 415 blue.synchro.SleepUntilSim(wreckSwitchTime + 5 * gametime.SEC) 416 self.Track(None, speed=TRACK_RESET_SPEED) 417 418 def OnBallparkSetState(self): 419 if self.isActive: 420 self._SetLookAtBall(self.ego) 421 else: 422 self._SetLookAtBall(None) 423 424 def OnCurrentShipWarping(self): 425 if self.GetLookAtItemID() is not None and self.GetLookAtItemID() != self.ego: 426 self.LookAt(self.ego) 427 428 def OnMouseDown(self, button): 429 if self.IsTracking() or self.IsChasing(): 430 return 431 if button == 0: 432 uicore.animations.MorphScalar(self, 'orbitFreezeProp', self.orbitFreezeProp, 1.0, duration=0.5, timeOffset=0.0) 433 434 def OnMouseUp(self, button): 435 if button == 0: 436 uicore.animations.MorphScalar(self, 'orbitFreezeProp', self.orbitFreezeProp, 0.0, duration=2.0, timeOffset=0.0) 437 438 def FovZoom(self, dz): 439 self.minFov = 0.3 440 self.maxFov = 1.3 441 BaseSpaceCamera.FovZoom(self, dz) 442 self.isManualFovEnabled = True 443 444 def OnStateChange(self, itemID, flag, flagState, *args): 445 if flagState and flag == states.selected and IsAutoTrackingEnabled(): 446 if not uicore.cmd.IsSomeCombatCommandLoaded(): 447 self.Track(itemID) 448 449 def OnDungeonCameraInterest(self, itemID, speed, duration): 450 if not (self.isActive and IsDynamicCameraMovementEnabled()): 451 return 452 ball = GetBall(itemID) 453 if ball: 454 self.Track(itemID, speed, duration) 455 else: 456 self.trackPendingItemIDSpeedDuration = (itemID, speed, duration) 457 458 def OnBallAdded(self, slimItem): 459 if self.trackPendingItemIDSpeedDuration and slimItem.itemID == self.trackPendingItemIDSpeedDuration[0]: 460 self.Track(*self.trackPendingItemIDSpeedDuration) 461 462 def GetZoomToPoint(self): 463 offset = BaseSpaceCamera.GetZoomToPoint(self) 464 speedOffset = self.speedOffsetter.GetSpeedOffset() 465 if speedOffset: 466 offset = geo2.Vec3AddD(offset, speedOffset) 467 return offset 468 469 def OnLookAtItemModelLoaded(self): 470 self.UpdateMaxZoom() 471 if self.GetZoomDistance() < self.maxZoom: 472 self.SetZoom(0.0)