baseSpaceCamera.py (12131B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\client\script\ui\camera\baseSpaceCamera.py 2 import audio2 3 import blue 4 import evetypes 5 from carbon.common.script.util.mathCommon import GetAngleBetweenTwoVectors, IsWithinFrustum 6 from eve.client.script.parklife import states 7 from eve.client.script.ui.camera.baseCamera import Camera 8 from eve.client.script.ui.camera.cameraUtil import IsBobbingEnabled, GetCameraMaxLookAtRange, GetBallPosition, GetBall, IsAutoTrackingEnabled, FOV_MIN, FOV_MAX 9 from eve.client.script.ui.camera.util.cameraBobbingOffsetter import CameraBobbingOffsetter 10 from eve.common.lib import appConst 11 from evecamera.animation import AnimationController 12 from evecamera.shaker import ShakeController 13 from evecamera.utils import CreateBehaviorFromMagnitudeAndPosition, PanCameraAccelerated 14 import evegraphics.settings as gfxsettings 15 import geo2 16 import logging 17 import math 18 import random 19 import uthread 20 log = logging.getLogger(__name__) 21 MAX_NOISE = 160.0 22 23 class BaseSpaceCamera(Camera): 24 isBobbingCamera = False 25 name = 'BaseSpaceCamera' 26 minZoom = 700000 27 __notifyevents__ = Camera.__notifyevents__[:] + ['OnSpecialFX', 28 'DoBallsRemove', 29 'DoBallRemove', 30 'DoClientSideBallRemove'] 31 32 def __init__(self): 33 Camera.__init__(self) 34 self.noiseCurve = None 35 self.noiseScaleCurve = None 36 self.noiseScale = 0.0 37 self.noiseDampCurve = None 38 self.noiseDamp = 1.1 39 self._noiseX = 0.0 40 self._noiseY = 0.0 41 self._noiseOffset = None 42 self._anchorBall = None 43 self._anchorOffset = None 44 self.trackTarget = None 45 self.cachedCameraTranslation = None 46 self.shakeController = ShakeController(self) 47 self.animationController = AnimationController(self) 48 self.isManualControlEnabled = True 49 self.audioListener = None 50 self._startTime = 0 51 if self.isBobbingCamera: 52 self.bobbingOfsetter = CameraBobbingOffsetter() 53 else: 54 self.bobbingOfsetter = None 55 56 @property 57 def ego(self): 58 return session.structureid or session.shipid 59 60 def ShakeCamera(self, magnitude, position, key = None): 61 behavior = CreateBehaviorFromMagnitudeAndPosition(magnitude, position, self) 62 if behavior is None: 63 return 64 behavior.key = key 65 self.shakeController.DoCameraShake(behavior) 66 67 def StopShaking(self): 68 self.shakeController.ClearCurrentShake() 69 70 def Update(self): 71 Camera.Update(self) 72 if self.IsNoiseEnabled(): 73 self._UpdateCameraNoiseOffset() 74 if self.bobbingOfsetter: 75 self._UpdateBobbingOffset() 76 self.UpdateAnchorOffset() 77 78 def IsNoiseEnabled(self): 79 try: 80 return gfxsettings.Get(gfxsettings.UI_CAMERA_SHAKE_ENABLED) 81 except gfxsettings.UninitializedSettingsGroupError: 82 return False 83 84 def ResetCurveStartTime(self): 85 self._startTime = blue.os.GetSimTime() 86 87 def _UpdateCameraNoiseOffset(self): 88 if self._startTime == 0: 89 self._startTime = blue.os.GetSimTime() 90 localTime = blue.os.TimeAsDouble(blue.os.GetSimTime() - self._startTime) 91 if self.noiseScaleCurve: 92 self.noiseScale = self.noiseScaleCurve.UpdateScalar(localTime) 93 if self.noiseScale == 0: 94 return 95 if self.noiseDampCurve: 96 self.noiseDamp = self.noiseDampCurve.UpdateScalar(localTime) 97 dT = 1.0 / blue.os.fps 98 ran = random.random() - 0.5 99 self._noiseX = (self._noiseX + self.noiseDamp * ran) / (1.0 + self.noiseDamp * dT) 100 self._noiseX = max(-MAX_NOISE, min(self._noiseX, MAX_NOISE)) 101 ran = random.random() - 0.5 102 self._noiseY = (self._noiseY + self.noiseDamp * ran) / (1.0 + self.noiseDamp * dT) 103 self._noiseY = max(-MAX_NOISE, min(self._noiseY, MAX_NOISE)) 104 noiseScale = self.GetZoomDistance() / 100.0 * self.noiseScale 105 direction = self.GetLookAtDirection() 106 vecX = geo2.Vec3Cross(direction, self._upDirection) 107 vecY = geo2.Vec3Cross(direction, vecX) 108 vecX = geo2.Vec3Scale(vecX, self._noiseX * noiseScale) 109 vecY = geo2.Vec3Scale(vecY, self._noiseY * noiseScale) 110 noiseOffset = geo2.Vec3Add(vecX, vecY) 111 self._AddToAtOffset(noiseOffset) 112 113 def ClearCameraParent(self): 114 self.LookAt(self.ego) 115 self.ResetAnchorPos() 116 117 def Track(self, itemID, **kwargs): 118 pass 119 120 def OnAutoTrackingChanged(self): 121 if not self.isActive: 122 return 123 if IsAutoTrackingEnabled(): 124 itemID = sm.GetService('stateSvc').GetExclState(states.selected) 125 self.Track(itemID) 126 else: 127 self.Track(None) 128 129 def GetCameraParent(self): 130 return self.trackTarget 131 132 def DisableManualControl(self): 133 self.StopUpdateThreads() 134 self.isManualControlEnabled = False 135 136 def EnableManualControl(self): 137 self.isManualControlEnabled = True 138 139 def IsManualControlEnabled(self): 140 return self.isManualControlEnabled and not self.IsInTransit() 141 142 def Pan(self, *args): 143 if self.IsManualControlEnabled(): 144 Camera.Pan(self, *args) 145 146 def Zoom(self, dz): 147 if self.IsManualControlEnabled(): 148 Camera.Zoom(self, dz) 149 150 def Orbit(self, *args): 151 if self.IsManualControlEnabled(): 152 Camera.Orbit(self, *args) 153 154 def GetTrackPosition(self, ball): 155 if not ball: 156 ret = (0, 0, 0) 157 elif not ball.ballpark: 158 ret = self._atPosition 159 self.ResetCamera() 160 else: 161 ret = GetBallPosition(ball) 162 if self._anchorOffset: 163 ret = geo2.Vec3Subtract(ret, self._anchorOffset) 164 return ret 165 166 def _UpdateBobbingOffset(self): 167 if not IsBobbingEnabled(): 168 return 169 offset = self.bobbingOfsetter.UpdateOffset(self.atPosition, self.eyePosition) 170 self._AddToEyeAndAtOffset(offset) 171 172 def CheckObjectTooFar(self, itemID): 173 ball = GetBall(itemID) 174 if not ball: 175 return False 176 if getattr(ball, 'typeID', None) and self._IsBallTypeDisallowedForLookAt(ball.typeID): 177 return True 178 ballPos = GetBallPosition(ball) 179 return geo2.Vec3Length(ballPos) > GetCameraMaxLookAtRange() 180 181 def _IsBallTypeDisallowedForLookAt(self, typeID): 182 return evetypes.GetGroupID(typeID) in (appConst.groupPlanet, appConst.groupMoon) 183 184 def ConstructAnchorBall(self): 185 bp = sm.GetService('michelle').GetBallpark() 186 if not bp or not bp.ego: 187 return 188 pos = bp.GetCurrentEgoPos() 189 self._anchorBall = bp.AddClientSideBall(pos) 190 191 def ResetAnchorPos(self): 192 if self._anchorOffset: 193 self.eyePosition = geo2.Vec3Add(self.eyePosition, self._anchorOffset) 194 self.atPosition = geo2.Vec3Add(self.atPosition, self._anchorOffset) 195 self._anchorBall = None 196 self._anchorOffset = None 197 198 def UpdateAnchorOffset(self): 199 if self._anchorBall: 200 self._anchorOffset = GetBallPosition(self._anchorBall) 201 self._AddToEyeAndAtOffset(self._anchorOffset) 202 else: 203 self._anchorOffset = None 204 205 def OnSpecialFX(self, shipID, moduleID, moduleTypeID, targetID, otherTypeID, guid, isOffensive, start, active, duration = -1, repeat = None, startTime = None, timeFromStart = 0, graphicInfo = None): 206 if guid == 'effects.Warping': 207 if shipID in (self.ego, self.GetLookAtItemID()): 208 self.OnCurrentShipWarping() 209 210 def GetLookAtItemID(self): 211 return self.ego 212 213 def GetItemID(self): 214 return self.GetLookAtItemID() 215 216 def OnCurrentShipWarping(self): 217 pass 218 219 def OnActivated(self, **kwargs): 220 Camera.OnActivated(self, **kwargs) 221 uthread.new(self.AudioUpdateThread) 222 settings.char.Subscribe('ui', 'orbitCameraAutoTracking', self.OnAutoTrackingChanged) 223 if self.bobbingOfsetter: 224 self.bobbingOfsetter.OnActivated() 225 226 def OnDeactivated(self): 227 super(BaseSpaceCamera, self).OnDeactivated() 228 settings.char.Unsubscribe('ui', 'orbitCameraAutoTracking', self.OnAutoTrackingChanged) 229 230 def AudioUpdateThread(self): 231 self.audioListener = audio2.GetListener() 232 while self.isActive: 233 self.audioListener.SetPosition(self.GetLookAtDirection(), self.upDirection, self.eyePosition) 234 blue.synchro.Yield() 235 236 self.audioListener = None 237 238 def TranslateFromParentAccelerated(self, begin, end, durationSec, accelerationPower = 2.0): 239 self.animationController.Schedule(PanCameraAccelerated(begin, end, durationSec, accelerationPower)) 240 241 def IsLocked(self): 242 return False 243 244 def DoClientSideBallRemove(self, ball): 245 self.DoBallRemove(ball) 246 if ball == self._anchorBall: 247 self.ResetAnchorPos() 248 249 def DoBallsRemove(self, pythonBalls, isRelease): 250 for ball, _, _ in pythonBalls: 251 self.DoBallRemove(ball) 252 253 def DoBallRemove(self, ball, *args, **kwargs): 254 self.OnBallRemoved(ball) 255 256 def OnBallRemoved(self, ball): 257 pass 258 259 def GetDynamicFovByDistance(self, dist): 260 prop = max(0.0, min(dist / self.minZoom, 1.0)) 261 return FOV_MIN + prop ** 0.35 * (FOV_MAX - FOV_MIN) 262 263 def GetDynamicFov(self): 264 if self._atTransitOffset: 265 atPos = geo2.Vec3Subtract(self.atPosition, self._atTransitOffset) 266 else: 267 atPos = self.atPosition 268 dist = geo2.Vec3Distance(self.eyePosition, atPos) 269 return self.GetDynamicFovByDistance(dist) 270 271 def ResetFOV(self): 272 self.SetFovTarget(self.default_fov) 273 274 def GetItemPosition(self, itemID): 275 itemBall = GetBall(itemID) 276 if not itemBall: 277 raise RuntimeError('Failed to find position for item %s. Item is not in the current ballpark.' % itemID) 278 return GetBallPosition(itemBall) 279 280 def GetLookAtItemDirection(self, itemID): 281 itemPosition = self.GetItemPosition(itemID) 282 eyePosition = geo2.Vec3AddD(self._eyePosition, self._eyeOffset) if self._eyeOffset else self._eyePosition 283 return geo2.Vec3Direction(eyePosition, itemPosition) 284 285 def IsWithinViewAngle(self, itemID, angleInDegrees): 286 try: 287 cameraLookAtDirection = self.GetLookAtDirectionWithOffset() 288 itemLookAtDirection = self.GetLookAtItemDirection(itemID) 289 angleFromCameraToItem = GetAngleBetweenTwoVectors(cameraLookAtDirection, itemLookAtDirection) 290 angleToCheck = math.radians(angleInDegrees) 291 return angleFromCameraToItem <= angleToCheck 292 except Exception as exc: 293 log.exception('Error when checking if item %s is in %s degree view angle: %s', itemID, angleInDegrees, exc) 294 return False 295 296 def IsWithinViewFrustum(self, itemID): 297 try: 298 itemPosition = self.GetItemPosition(itemID) 299 return IsWithinFrustum(itemPosition, self.viewMatrix.transform, self.projectionMatrix.transform) 300 except Exception as exc: 301 log.exception('Error when checking whether item is within view frustum: %s', exc) 302 return False 303 304 def GetLookAtPointDirection(self, pointLocation): 305 eyePosition = geo2.Vec3AddD(self._eyePosition, self._eyeOffset) if self._eyeOffset else self._eyePosition 306 return geo2.Vec3Direction(eyePosition, pointLocation) 307 308 def IsPointWithinViewAngle(self, pointLocation, angleInDegrees): 309 try: 310 cameraLookAtDirection = self.GetLookAtDirectionWithOffset() 311 itemLookAtDirection = self.GetLookAtPointDirection(pointLocation) 312 angleFromCameraToPoint = GetAngleBetweenTwoVectors(cameraLookAtDirection, itemLookAtDirection) 313 angleToCheck = math.radians(angleInDegrees) 314 return angleFromCameraToPoint <= angleToCheck 315 except Exception as exc: 316 log.exception('Error when checking if point %s is in %s degree view angle: %s', pointLocation, angleInDegrees, exc) 317 return False