tacticalCamera.py (14661B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\client\script\ui\camera\tacticalCamera.py 2 import geo2 3 from eve.client.script.parklife import states 4 from eve.client.script.ui.camera.baseSpaceCamera import BaseSpaceCamera 5 from eve.client.script.ui.camera.cameraUtil import GetDurationByDistance, GetBallPosition, GetBall, GetBallMaxZoom, IsBallWarping, CheckShowModelTurrets, VectorLerper, GetCameraInertiaMultiplier, IsAutoTrackingEnabled, PositionAnimatorDetached, PositionAnimatorAttached 6 import evecamera 7 from carbonui.uicore import uicore 8 DEFAULT_EYEDIST = 40000 9 FREE_ORBIT_DIST = 250 10 LOOKAT_DIST = 50000 11 12 class TacticalCamera(BaseSpaceCamera): 13 name = 'TacticalCamera' 14 __notifyevents__ = BaseSpaceCamera.__notifyevents__ + ['OnStateChange'] 15 cameraID = evecamera.CAM_TACTICAL 16 kOrbitSpeed = 5.0 17 default_fov = 1.0 18 default_atPosition = (0, 0, 0) 19 default_eyePosition = (-DEFAULT_EYEDIST, DEFAULT_EYEDIST, DEFAULT_EYEDIST) 20 maxFov = 1.0 21 minFov = 0.3 22 23 def __init__(self): 24 BaseSpaceCamera.__init__(self) 25 self.lastLookAtID = None 26 self.sceneCursor = (0, 0, 0) 27 self.positionAnimator = PositionAnimatorDetached(self) 28 self.trackBall = None 29 self.trackBallMorpher = VectorLerper() 30 31 def GetLookAtItemID(self): 32 if self.IsAttached(): 33 return self.GetItemID() 34 else: 35 return None 36 37 def IsAttached(self): 38 return self.positionAnimator.IsAttached() 39 40 def LookAt(self, itemID, allowSwitchCamera = True, **kwargs): 41 if not self.IsManualControlEnabled(): 42 return 43 if self.CheckObjectTooFar(itemID) and itemID != self.ego: 44 self.Track(itemID) 45 return 46 self.StopTracking() 47 if itemID == self.GetItemID(): 48 self.ResetFOV() 49 if itemID != self.ego: 50 self.LookAt(self.ego) 51 return 52 self.StopUpdateThreads() 53 self.ResetFOV() 54 ball = GetBall(itemID) 55 if not ball: 56 return 57 CheckShowModelTurrets(ball) 58 duration = self.AnimateLookAt(ball) 59 self._SetLookAtBall(ball, duration=duration) 60 if ball.id == self.ego and hasattr(ball, 'GetModel') and ball.GetModel() is None: 61 ball.RegisterForModelLoad(self.UpdateMaxZoom) 62 sm.ScatterEvent('OnCameraLookAt', itemID == self.ego, itemID) 63 64 def AnimateLookAt(self, ball): 65 eyePos1 = self.GetLookAtEyePos(ball) 66 duration = self.AnimLookAtTransit(ball, eyePos1) 67 return duration 68 69 def AnimLookAtTransit(self, ball, eyePos1): 70 ballPos = GetBallPosition(ball) 71 self.SetAppropriateAtPositionForRotation(ballPos) 72 duration = GetDurationByDistance(self.positionAnimator.GetAtPosition(), ballPos, minTime=0.3, maxTime=0.6) 73 self.TransitTo(ballPos, eyePos1, duration=duration, smoothing=0.0) 74 return duration 75 76 def GetLookAtEyePos(self, ball): 77 distance = self.GetLookAtDistance(ball) 78 lookVec = geo2.Vec3Scale(self.GetLookAtDirection(), distance) 79 eyePos1 = geo2.Vec3Add(GetBallPosition(ball), lookVec) 80 return eyePos1 81 82 def GetLookAtDistance(self, ball): 83 if self.IsAttached(): 84 distance = self.GetZoomDistance() 85 else: 86 distance = geo2.Vec3Distance(self.eyePosition, GetBallPosition(ball)) 87 maxZoom = GetBallMaxZoom(ball, self.nearClip) 88 distance = max(maxZoom, min(distance, self.minZoom)) 89 return distance 90 91 def _SetLookAtBall(self, ball, duration = 0.6): 92 if ball: 93 self.positionAnimator = PositionAnimatorAttached(self, ball, duration) 94 self.UpdateMaxZoom() 95 self.lastLookAtID = ball.id 96 sm.GetService('stateSvc').SetState(ball.id, states.lookingAt, True) 97 else: 98 self.positionAnimator = PositionAnimatorDetached(self) 99 100 def OnDeactivated(self): 101 BaseSpaceCamera.OnDeactivated(self) 102 self._SetLookAtBall(None) 103 self.StopTracking() 104 105 def UpdateMaxZoom(self): 106 ball = self.GetZoomToBall() 107 if ball: 108 maxZoom = GetBallMaxZoom(ball, self.nearClip) 109 if maxZoom < self.minZoom: 110 self.SetMaxZoom(maxZoom) 111 112 def GetZoomToBall(self): 113 if self.trackBall: 114 return self.trackBall 115 if self.positionAnimator.ball: 116 return self.positionAnimator.ball 117 118 def Pan(self, dx = None, dy = None, dz = None): 119 if not self.IsManualControlEnabled(): 120 return 121 if self.IsActiveOrTrackingShipWarping(): 122 return 123 self.StopTracking() 124 if self.IsAttached(): 125 self.Detach() 126 k = self.GetPanSpeed() 127 BaseSpaceCamera.Pan(self, k * dx, k * dy, k * dz) 128 129 def PanImmediate(self, dx, dy, dz): 130 if not self.IsManualControlEnabled(): 131 return 132 if self.IsActiveOrTrackingShipWarping(): 133 return 134 pan = geo2.Add(geo2.Add(geo2.Scale(self.GetXAxis(), dx), geo2.Scale(self.GetYAxis(), dy)), geo2.Scale(self.GetZAxis(), dz)) 135 self.eyePosition = geo2.Add(self._eyePosition, pan) 136 self.atPosition = geo2.Add(self._atPosition, pan) 137 138 def OrbitImmediate(self, yaw, pitch): 139 self.pitch = self.pitch + pitch 140 self.yaw = self.yaw + yaw 141 self.StopOrbitUpdate() 142 143 def StopTracking(self): 144 self.Track(None) 145 146 def IsTracking(self): 147 return self.trackBall is not None or not self.trackBallMorpher.IsDone() 148 149 def GetPanSpeed(self): 150 return 0.01 + 0.001 * self.GetDistanceToCursor() ** 0.9 151 152 def Detach(self): 153 if self.IsActiveOrTrackingShipWarping(): 154 return 155 self.StopUpdateThreads() 156 self.positionAnimator = PositionAnimatorDetached(self) 157 if self.lastLookAtID: 158 self.lastLookAtID = None 159 self.sceneCursor = self.atPosition 160 self.SetAtPosToFixedDistance() 161 sm.ScatterEvent('OnCameraLookAt', False, None) 162 163 def SetAtPosToFixedDistance(self): 164 self.SetAtPosition(geo2.Vec3AddD(self._eyePosition, geo2.Vec3Scale(self.GetLookAtDirectionWithOffset(), -100.0))) 165 166 def GetDistanceToCursor(self): 167 return geo2.Vec3Distance(self.eyePosition, self.sceneCursor) 168 169 def ResetCamera(self, *args): 170 self.LookAt(self.ego) 171 172 def OnActivated(self, lastCamera = None, itemID = None, duration = None, **kwargs): 173 if self.positionAnimator: 174 self.positionAnimator.Reset() 175 BaseSpaceCamera.OnActivated(self, **kwargs) 176 settings.char.ui.Set('spaceCameraID', evecamera.CAM_TACTICAL) 177 if lastCamera: 178 distance = max(self.maxZoom, min(geo2.Vec3Length(self.eyePosition), self.minZoom)) 179 if lastCamera.cameraID in (evecamera.CAM_SHIPORBIT, 180 evecamera.CAM_UNDOCK, 181 evecamera.CAM_ENTERSPACE, 182 evecamera.CAM_SHIPORBIT_ABYSSAL_SPACE, 183 evecamera.CAM_SHIPORBIT_HAZARD): 184 self._ResetEyeAndAtPosition(lastCamera.eyePosition, lastCamera.atPosition, distance) 185 elif lastCamera.cameraID == evecamera.CAM_JUMP and sm.GetService('subway').Enabled(): 186 duration = lastCamera.transitionDelay 187 direction = lastCamera.GetLookAtDirection() 188 d = self.eyePosition 189 self.Transit(lastCamera.atPosition, lastCamera.eyePosition, (0, 0, 0), geo2.Vec3Scale(direction, self.GetZoomDistanceByZoomProportion(lastCamera.GetZoom())), duration=duration, callback=lambda : self.AfterJumpCallback(d)) 190 else: 191 animate = lastCamera.cameraID not in (evecamera.CAM_SHIPPOV, evecamera.CAM_HANGAR) 192 self._ResetEyeAndAtPosition(self.eyePosition, self.atPosition, distance, animate) 193 targetBall = GetBall(lastCamera.GetItemID()) 194 if targetBall: 195 self._SetLookAtBall(targetBall) 196 if lastCamera.cameraID != evecamera.CAM_SHIPPOV: 197 self.fov = lastCamera.fov 198 self.ResetFOV() 199 else: 200 if not itemID: 201 itemID = self.ego 202 self._SetLookAtBall(GetBall(itemID)) 203 self.SetEyePosition(self.default_eyePosition) 204 205 def AfterJumpCallback(self, desiredEyePosition): 206 self.EnableManualControl() 207 desiredDistance = geo2.Vec3Length(desiredEyePosition) 208 desiredDirection = geo2.Vec3Normalize(desiredEyePosition) 209 desiredEyePosition = geo2.Vec3Scale(desiredDirection, max(self.maxZoom, min(self.minZoom, desiredDistance))) 210 self.Transit((0, 0, 0), self.eyePosition, (0, 0, 0), desiredEyePosition, duration=0.5) 211 212 def _GetNewDirection(self, direction): 213 y = geo2.Vec2Length((direction[0], direction[2])) 214 direction = (direction[0], y, direction[2]) 215 direction = geo2.Vec3Normalize(direction) 216 return direction 217 218 def _ResetEyeAndAtPosition(self, eyePos0, atPos0, distance = LOOKAT_DIST, animate = True, duration = None): 219 direction = self._GetNewDirection(geo2.Vec3Subtract(eyePos0, atPos0)) 220 eyePos1 = geo2.Vec3Add(atPos0, geo2.Vec3Scale(direction, distance)) 221 if animate: 222 if duration is None: 223 duration = GetDurationByDistance(eyePos0, eyePos1, 0.4, 0.6) 224 atPos1 = atPos0 225 diff = geo2.Vec3Scale(geo2.Vec3Direction(atPos0, eyePos0), distance / 5) 226 atPos0 = geo2.Vec3Add(atPos0, diff) 227 self.Transit(atPos0, eyePos0, atPos1, eyePos1, duration=duration, callback=self.EnableManualControl) 228 else: 229 self.SetAtPosition(atPos0) 230 self.SetEyePosition(eyePos1) 231 232 def Update(self): 233 BaseSpaceCamera.Update(self) 234 if not session.solarsystemid: 235 return 236 if self.IsActiveOrTrackingShipWarping() and not self.IsAttached(): 237 self.LookAt(self.ego) 238 if self.positionAnimator.GetItemID(): 239 self.positionAnimator.Update() 240 if self.IsTracking(): 241 atPos = self.GetTrackingAtPosition() 242 else: 243 atPos = self.positionAnimator.GetAtPosition() 244 self.SetAtPosition(atPos) 245 self.SetEyePosition(self.positionAnimator.GetEyePosition()) 246 if self.IsAttached(): 247 self._EnforceMaximumDistanceAttached() 248 else: 249 self._EnforceMaximumDistanceDetached() 250 251 def _EnforceMaximumDistanceAttached(self): 252 dist = geo2.Vec3Length(self.positionAnimator.GetAtPosition()) 253 if dist > evecamera.LOOKATRANGE_MAX_NEW and not self.IsInTransit(): 254 self.LookAt(self.ego) 255 256 def GetTrackingAtPosition(self): 257 if self.trackBall: 258 ballPos = GetBallPosition(self.trackBall) 259 else: 260 ballPos = self.positionAnimator.GetAtPosition() 261 if geo2.Vec3Length(ballPos) > evecamera.LOOKATRANGE_MAX_NEW: 262 direction = geo2.Vec3Normalize(geo2.Vec3Subtract(ballPos, self.eyePosition)) 263 ballPos = geo2.Vec3Add(self.eyePosition, geo2.Vec3Scale(direction, evecamera.LOOKATRANGE_MAX_NEW)) 264 return self.trackBallMorpher.GetValue(self.atPosition, ballPos) 265 266 def IsActiveOrTrackingShipWarping(self): 267 return IsBallWarping(self.GetItemID()) or IsBallWarping(self.ego) 268 269 def GetItemID(self): 270 return self.positionAnimator.GetItemID() 271 272 def _EnforceMaximumDistanceDetached(self): 273 dist = geo2.Vec3Length(self.eyePosition) 274 if dist > evecamera.LOOKATRANGE_MAX_NEW and not self.IsInTransit(): 275 direction = geo2.Vec3Normalize(self.eyePosition) 276 newEye = geo2.Vec3Scale(direction, evecamera.LOOKATRANGE_MAX_NEW) 277 diff = geo2.Vec3Subtract(self.eyePosition, newEye) 278 self.SetEyePosition(newEye) 279 self.SetAtPosition(geo2.Vec3Subtract(self._atPosition, diff)) 280 281 def OnCurrentShipWarping(self): 282 if self.isActive: 283 self.LookAt(self.ego) 284 285 def Track(self, itemID = None, **kwargs): 286 if itemID is None and not self.trackBall: 287 return 288 ball = GetBall(itemID) 289 if ball and ball not in (self.positionAnimator.ball, self.trackBall): 290 self._TrackItem(ball) 291 else: 292 self._TrackNothing() 293 self.UpdateMaxZoom() 294 sm.ScatterEvent('OnCameraTrack', itemID) 295 296 def _TrackNothing(self): 297 self.trackBallMorpher.Reset(0.5 / GetCameraInertiaMultiplier()) 298 self.trackBall = None 299 300 def _TrackItem(self, ball): 301 self.trackBallMorpher.Reset(3.0 / GetCameraInertiaMultiplier()) 302 ballPos = GetBallPosition(ball) 303 self.StopUpdateThreads() 304 self.SetAppropriateAtPositionForRotation(ballPos) 305 self.trackBall = ball 306 307 def SetAppropriateAtPositionForRotation(self, atPos): 308 distanceToNewAtPos = geo2.Vec3Distance(self.eyePosition, atPos) 309 distanceToNewAtPos = min(evecamera.LOOKATRANGE_MAX_NEW, distanceToNewAtPos) 310 lookVec = geo2.Vec3Scale(self.GetLookAtDirection(), distanceToNewAtPos) 311 newAtPos = geo2.Vec3Subtract(self.eyePosition, lookVec) 312 if newAtPos != self._eyePosition: 313 self.SetAtPosition(newAtPos) 314 315 def OnBallRemoved(self, ball): 316 if self.positionAnimator and ball == self.positionAnimator.ball: 317 self.Detach() 318 if ball == self.trackBall: 319 self.StopTracking() 320 321 def OnStateChange(self, itemID, flag, flagState, *args): 322 if not self.isActive: 323 return 324 if flagState and flag == states.selected and IsAutoTrackingEnabled(): 325 if not uicore.cmd.IsSomeCombatCommandLoaded(): 326 self.Track(itemID) 327 328 def Orbit(self, *args): 329 if self.IsTracking() and self.IsBeyondZoomDistance(): 330 self.StopTracking() 331 self.AnimLookAtTransit(self.positionAnimator.ball, self.eyePosition) 332 else: 333 BaseSpaceCamera.Orbit(self, *args) 334 335 def IsBeyondZoomDistance(self): 336 return self.GetZoomDistance() > self.minZoom 337 338 def Zoom(self, dz): 339 if self.IsTracking() and self.trackBall and self.CheckObjectTooFar(self.trackBall.id): 340 return 341 BaseSpaceCamera.Zoom(self, dz) 342 343 def GetAtPositionClosestToShip(self): 344 if self.IsAttached(): 345 return self.atPosition 346 distanceToShip = self.GetLookAtDistance(GetBall(self.ego)) 347 distFromLookAt = geo2.Vec3Scale(self.GetLookAtDirection(), distanceToShip) 348 closestAtPosition = geo2.Vector(self.eyePosition) - distFromLookAt 349 if closestAtPosition == self.eyePosition: 350 closestAtPosition = self.atPosition 351 return closestAtPosition