NovaBryan/EVE_Dump
Log | Files | 📦 下载最新源码 (.zip) | Refs | README

ship.py (21015B)


      1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\client\script\environment\spaceObject\ship.py
      2 from eveexceptions.exceptionEater import ExceptionEater
      3 from inventorycommon.util import IsModularShip
      4 from inventorycommon.const import categoryFighter, flagFighterBay, flagFighterTube0, flagFighterTube1, flagFighterTube2, flagFighterTube3, flagFighterTube4
      5 import blue
      6 import uthread2
      7 import uthread
      8 import evetypes
      9 import eve.common.lib.appConst as const
     10 from eve.client.script.environment.model.turretSet import TurretSet
     11 from eve.client.script.environment.spaceObject.spaceObject import SpaceObject
     12 from eve.client.script.environment.spaceObject.cosmeticsManager import CosmeticsManager
     13 from eveSpaceObject import multiHullComponent
     14 from eveSpaceObject import spaceobjanimation
     15 import destiny
     16 import geo2
     17 import evegraphics.utils as gfxutils
     18 from evegraphics.CosmeticsLoader import CosmeticsLoader
     19 import evetypes
     20 from fsdBuiltData.common.graphicIDs import GetSofRaceName
     21 from eveaudio.const import ActingParty
     22 from eveaudio.turrets import setupTurretMovementAudio
     23 from cosmetics.client.ships.ship_skin_signals import on_skin_state_set
     24 from cosmetics.common.ships.skins.static_data.skin_type import ShipSkinType
     25 from mining.client import mining_signals
     26 import dogma.const as dogmaConst
     27 from eve.common.script.mgt.fighterConst import TUBE_STATE_EMPTY, TUBE_STATE_LANDING, TUBE_STATE_REFUELLING
     28 from logging import getLogger
     29 logger = getLogger(__name__)
     30 RACE_CONTROLLER_DICT = {'None': 0,
     31  'gallente': 1,
     32  'caldari': 2,
     33  'minmatar': 3,
     34  'amarr': 4}
     35 TUBE_CONTROLLER_PARAM_DICT = {flagFighterTube0: 'carrier_fighterbay_1_race',
     36  flagFighterTube1: 'carrier_fighterbay_2_race',
     37  flagFighterTube2: 'carrier_fighterbay_3_race',
     38  flagFighterTube3: 'carrier_fighterbay_4_race'}
     39 FIGHTER_COUNT_PARAM_DICT = {flagFighterTube0: 'carrier_fighterbay_1_numFighters',
     40  flagFighterTube1: 'carrier_fighterbay_2_numFighters',
     41  flagFighterTube2: 'carrier_fighterbay_3_numFighters',
     42  flagFighterTube3: 'carrier_fighterbay_4_numFighters'}
     43 FIGHTER_LAUNCHED_PARAM_DICT = {flagFighterTube0: 'carrier_fighterbay_1_launched',
     44  flagFighterTube1: 'carrier_fighterbay_2_launched',
     45  flagFighterTube2: 'carrier_fighterbay_3_launched',
     46  flagFighterTube3: 'carrier_fighterbay_4_launched'}
     47 
     48 class Ship(SpaceObject):
     49     __notifyevents__ = ['OnAllianceLogoReady',
     50      'OnCorpLogoReady',
     51      'OnFighterAddedToController',
     52      'OnFighterRemovedFromController',
     53      'OnFighterTubeContentUpdate',
     54      'OnFighterTubeContentEmpty',
     55      'OnGodmaShipEffect']
     56 
     57     def __init__(self):
     58         SpaceObject.__init__(self)
     59         self.cosmeticsLoader = CosmeticsLoader((CosmeticsLoader.ALLIANCE, CosmeticsLoader.CORP))
     60         sm.RegisterNotify(self)
     61         self.cosmeticsItems = []
     62         on_skin_state_set.connect(self._on_skin_state_set)
     63         self.cosmeticsManager = CosmeticsManager()
     64         self.activeTargetID = None
     65         self.fitted = False
     66         self.cachedShip = None
     67         self.fittingThread = None
     68         self.turrets = []
     69         self.modules = {}
     70         self.stanceID = None
     71         self.lastStanceID = None
     72         self._multiHullComponent = multiHullComponent.MultiHullComponent(self.id) if self.IsModularShip() else None
     73         self.damageOverTimeTaken = 0.0
     74         self.visualDamageThread = None
     75         self.isReceivingMiningEvents = False
     76         self.isHarvesting = False
     77         self.activeHarvestingModules = set()
     78         if self._multiHullComponent is not None:
     79             self._multiHullComponent.SetSubsystemModules(self.typeData.get('slimItem').modules)
     80 
     81     def _UpdateFighterTubeVisuals(self, tubeFlagID, fighterTypeID = None, squadronSize = None):
     82         if not self.model:
     83             return
     84         if tubeFlagID in TUBE_CONTROLLER_PARAM_DICT and fighterTypeID is not None:
     85             gid = evetypes.GetGraphicID(fighterTypeID)
     86             raceName = GetSofRaceName(gid)
     87             self.model.SetControllerVariable(TUBE_CONTROLLER_PARAM_DICT[tubeFlagID], RACE_CONTROLLER_DICT.get(raceName, 0))
     88         if tubeFlagID in FIGHTER_COUNT_PARAM_DICT and squadronSize is not None:
     89             self.model.SetControllerVariable(FIGHTER_COUNT_PARAM_DICT[tubeFlagID], squadronSize)
     90 
     91     def _UpdateFighterTubeVisualsFromState(self, tubeFlagID):
     92         fightersSvc = sm.GetService('fighters')
     93         shipFighterState = getattr(fightersSvc, 'shipFighterState', None)
     94         if shipFighterState is None:
     95             return
     96         inSpace = shipFighterState.GetFightersInSpace(tubeFlagID)
     97         if inSpace is not None:
     98             _, fighterTypeID, _, squadronSize = inSpace
     99             self._UpdateFighterTubeVisuals(tubeFlagID, fighterTypeID=fighterTypeID, squadronSize=squadronSize)
    100             if tubeFlagID in FIGHTER_LAUNCHED_PARAM_DICT and self.model:
    101                 self.model.SetControllerVariable(FIGHTER_LAUNCHED_PARAM_DICT[tubeFlagID], 1.0)
    102             return
    103         inTube = shipFighterState.GetFightersInTube(tubeFlagID)
    104         if inTube is not None:
    105             _, fighterTypeID, _, squadronSize = inTube
    106             self._UpdateFighterTubeVisuals(tubeFlagID, fighterTypeID=fighterTypeID, squadronSize=squadronSize)
    107             if tubeFlagID in FIGHTER_LAUNCHED_PARAM_DICT and self.model:
    108                 self.model.SetControllerVariable(FIGHTER_LAUNCHED_PARAM_DICT[tubeFlagID], 0.0)
    109             return
    110         tubeStatus = shipFighterState.GetTubeStatus(tubeFlagID)
    111         if tubeStatus and tubeStatus.statusID in (TUBE_STATE_LANDING, TUBE_STATE_REFUELLING):
    112             return
    113         self._UpdateFighterTubeVisuals(tubeFlagID, squadronSize=0)
    114         if tubeFlagID in TUBE_CONTROLLER_PARAM_DICT and self.model:
    115             self.model.SetControllerVariable(TUBE_CONTROLLER_PARAM_DICT[tubeFlagID], 0)
    116         if tubeFlagID in FIGHTER_LAUNCHED_PARAM_DICT and self.model:
    117             self.model.SetControllerVariable(FIGHTER_LAUNCHED_PARAM_DICT[tubeFlagID], 0.0)
    118 
    119     def OnFighterAddedToController(self, fighterID, fighterTypeID, tubeFlagID, squadronSize, abilitySlotStates):
    120         if session.shipid != self.id:
    121             return
    122         self._UpdateFighterTubeVisualsFromState(tubeFlagID)
    123 
    124     def OnFighterRemovedFromController(self, fighterID, tubeFlagID):
    125         if session.shipid != self.id:
    126             return
    127         self._UpdateFighterTubeVisualsFromState(tubeFlagID)
    128 
    129     def OnFighterTubeContentUpdate(self, tubeFlagID, fighterID, fighterTypeID, squadronSize):
    130         if session.shipid != self.id:
    131             return
    132         self._UpdateFighterTubeVisualsFromState(tubeFlagID)
    133 
    134     def OnFighterTubeContentEmpty(self, tubeFlagID):
    135         if session.shipid != self.id:
    136             return
    137         self._UpdateFighterTubeVisualsFromState(tubeFlagID)
    138 
    139     def OnGodmaShipEffect(self, itemID, effectID, t, start, active, environment, startTime, duration, repeat, error, actualStopTime = None):
    140         if itemID not in self.modules:
    141             return
    142         if effectID in (dogmaConst.effectMining, dogmaConst.effectMiningLaser, dogmaConst.effectMiningClouds):
    143             if active:
    144                 self.activeHarvestingModules.add(itemID)
    145             else:
    146                 self.activeHarvestingModules.discard(itemID)
    147             self._UpdateHarvestingState()
    148 
    149     def _CheckHarvestingState(self):
    150         return len(self.activeHarvestingModules) > 0
    151 
    152     def _UpdateHarvestingState(self):
    153         self.isHarvesting = self._CheckHarvestingState()
    154         if self.isHarvesting and self.model:
    155             self.model.SetControllerVariable('isHarvesting', 1.0)
    156         else:
    157             self.model.SetControllerVariable('isHarvesting', 0.0)
    158 
    159     def _on_skin_state_set(self, ship_instance_id, skin_state):
    160         if ship_instance_id != self.id:
    161             return
    162         logger.info('SKIN STATES - space object %s received on_skin_state_set with %s' % (ship_instance_id, skin_state))
    163         if skin_state is not None:
    164             skin_type = skin_state.skin_type
    165             if skin_type == ShipSkinType.FIRST_PARTY_SKIN:
    166                 skinID = skin_state.skin_data.skin_id
    167                 self.skinMaterialSetID = sm.GetService('cosmeticsSvc').GetFirstPartySkinMaterialSetID(skinID)
    168                 self._ApplySkin(skinMaterialSetID=self.skinMaterialSetID)
    169             elif skin_type == ShipSkinType.NO_SKIN:
    170                 self.skinMaterialSetID = None
    171                 self._ApplySkin(skinMaterialSetID=self.skinMaterialSetID)
    172             elif skin_type == ShipSkinType.THIRD_PARTY_SKIN:
    173                 self.skinMaterialSetID = None
    174                 self._ApplySkin(skinMaterialSetID=self.skinMaterialSetID)
    175             else:
    176                 logger.error('Failed to apply SKIN to ship: SKIN type %s is not supported', skin_type)
    177 
    178     def _ApplySkin(self, skinMaterialSetID):
    179         self._skinChangeTasklets.append(uthread2.StartTasklet(self.ChangeSkin))
    180 
    181     def IsModularShip(self):
    182         return IsModularShip(self.GetTypeID())
    183 
    184     def _BuildSOFDNAFromTypeID(self):
    185         multiHullTypeIDList = None if self._multiHullComponent is None else self._multiHullComponent.GetTypeIDList()
    186         return gfxutils.BuildSOFDNAFromTypeID(typeID=self.GetTypeID(), materialSetID=self.skinMaterialSetID, multiHullTypeIDList=multiHullTypeIDList)
    187 
    188     def LoadModel(self, fileName = None, loadedModel = None, notify = True, addToScene = True, canYield = True):
    189         SpaceObject.LoadModel(self, fileName, loadedModel, notify, addToScene)
    190         self.UpdateCosmeticsItems()
    191         self.Display(1, canYield=False)
    192 
    193     def OnSubSystemChanged(self, newSlim):
    194         self.typeData['slimItem'] = newSlim
    195         if self._multiHullComponent is not None:
    196             self._multiHullComponent.SetSubsystemModules(self.typeData.get('slimItem').modules)
    197             self.UnfitHardpoints()
    198             self.RemoveAndClearModel(self.model)
    199             self.LoadModel(canYield=False)
    200             self.FitHardpoints(self.model)
    201 
    202     def GetStanceIDFromSlimItem(self, slimItem):
    203         if slimItem.shipStance is None:
    204             return
    205         _, _, stanceID = slimItem.shipStance
    206         return stanceID
    207 
    208     def OnAllianceLogoReady(self, allianceID, _size):
    209         if self.cosmeticsLoader.HasID(allianceID):
    210             uthread.new(self.cosmeticsLoader.Update, self.model, self.cosmeticsItems)
    211 
    212     def OnCorpLogoReady(self, corpID, _size):
    213         if self.cosmeticsLoader.HasID(corpID):
    214             uthread.new(self.cosmeticsLoader.Update, self.model, self.cosmeticsItems)
    215 
    216     def GetCosmeticsFromSlimItem(self, slimItem):
    217         if slimItem.cosmeticsItems is None:
    218             return
    219         items = slimItem.cosmeticsItems
    220         return items
    221 
    222     def UpdateCosmeticsItems(self):
    223         uthread.new(self.cosmeticsLoader.Load, self.model, self.typeData['slimItem'])
    224 
    225     def OnDamageState(self, damageState):
    226         self._OnDamageState(damageState)
    227 
    228     def GracefulEffectPropagatorRemover(self, sleepTime):
    229         self.model.SetControllerVariable('gracefullyRemove', 1.0)
    230         blue.synchro.SleepSim(sleepTime)
    231         if not self.visualDamageThread:
    232             self.model.SetControllerVariable('gracefullyRemove', 0.0)
    233             self.model.SetControllerVariable('explosive_damageAmount', self.damageOverTimeTaken)
    234             return
    235         fxSequencer = sm.GetService('FxSequencer')
    236         fxSequencer.OnSpecialFX(self.id, None, None, self.id, None, 'effects.VisualDamageSystemShipEffect', 1, 0, None, graphicInfo={})
    237 
    238     def UpdateDamageOverTime(self):
    239         currentDamageOverTimeTaken = getattr(self.typeData['slimItem'], 'dotHpPercentageApplied', 0.0)
    240         if currentDamageOverTimeTaken > 0.0:
    241             self.damageOverTimeTaken = currentDamageOverTimeTaken / 4.0
    242             self.visualDamageThread = None
    243             fxSequencer = sm.GetService('FxSequencer')
    244             fxSequencer.OnSpecialFX(self.id, None, None, self.id, None, 'effects.VisualDamageSystemShipEffect', 1, 1, None, graphicInfo={})
    245             self.model.SetControllerVariable('gracefullyRemove', 0.0)
    246             self.model.SetControllerVariable('explosive_damageAmount', self.damageOverTimeTaken)
    247             if self.model:
    248                 self.model.SetControllerVariable('boundingSphereRadius', self.model.boundingSphereRadius)
    249         elif self.damageOverTimeTaken > 0.0 and self.visualDamageThread is None:
    250             self.visualDamageThread = uthread.new(self.GracefulEffectPropagatorRemover, 18000)
    251 
    252     def OnSlimItemUpdated(self, slimItem):
    253         SpaceObject.OnSlimItemUpdated(self, slimItem)
    254         with ExceptionEater('ship::OnSlimItemUpdated failed'):
    255             self.typeData['slimItem'] = slimItem
    256             stanceID = self.GetStanceIDFromSlimItem(self.typeData['slimItem'])
    257             if stanceID != self.stanceID:
    258                 self.lastStanceID = self.stanceID
    259                 self.stanceID = stanceID
    260                 spaceobjanimation.SetShipAnimationStance(self.model, stanceID)
    261             if hasattr(self.typeData['slimItem'], 'cosmeticsItems'):
    262                 self.cosmeticsItems = self.GetCosmeticsFromSlimItem(slimItem)
    263                 self.UpdateCosmeticsItems()
    264             if hasattr(self.typeData['slimItem'], 'dotHpPercentageApplied'):
    265                 self.UpdateDamageOverTime()
    266 
    267     def AddChildEffect(self, effect):
    268         if self.model:
    269             self.model.effectChildren.append(effect)
    270 
    271     def RemoveChildEffect(self, effect):
    272         if not self.model:
    273             return
    274         if effect in self.model.effectChildren:
    275             effect.mute = True
    276             self.model.effectChildren.fremove(effect)
    277 
    278     def _SetInitialState(self, model = None):
    279         if model is None:
    280             model = self.model
    281         stanceID = self.GetStanceIDFromSlimItem(self.typeData['slimItem'])
    282         if stanceID is not None:
    283             self.stanceID = stanceID
    284             spaceobjanimation.SetShipAnimationStance(model, self.stanceID)
    285         if self.mode == destiny.DSTBALL_WARP:
    286             self.SetControllerVariable('IsWarping', True)
    287             try:
    288                 model.boosters.warpIntensity = 1
    289             except AttributeError:
    290                 pass
    291 
    292             if session.shipid != self.id:
    293                 self.sm.GetService('FxSequencer').OnSpecialFX(self.id, None, None, None, None, 'effects.WarpIn', 0, 1, 0)
    294         if session.shipid == self.id:
    295             self.SetControllerVariable(ActingParty.__name__, ActingParty.firstParty.value)
    296             for tubeFlagID in TUBE_CONTROLLER_PARAM_DICT:
    297                 self._UpdateFighterTubeVisualsFromState(tubeFlagID)
    298 
    299             self._UpdateHarvestingState()
    300 
    301     def Assemble(self):
    302         self.AssembleModel(self.model)
    303 
    304     def AssembleModel(self, model):
    305         if model is None:
    306             return
    307         self.UnSync(model)
    308         if self.id == session.shipid:
    309             self.CheckAmbientAudio()
    310         self.FitHardpoints(model)
    311         self._SetInitialState(model)
    312         self._UpdateImpacts(model)
    313 
    314     def Release(self):
    315         if self.released:
    316             return
    317         if self.model is None:
    318             return
    319         self.modules = {}
    320         self.activeHarvestingModules.clear()
    321         self.isHarvesting = False
    322         if self.isReceivingMiningEvents:
    323             mining_signals.on_ore_mined.disconnect(self.HandleMiningEvent)
    324         SpaceObject.Release(self, 'Ship')
    325         audsvc = self.sm.GetServiceIfRunning('audio')
    326         if audsvc.lastLookedAt == self:
    327             audsvc.lastLookedAt = None
    328 
    329     def LookAtMe(self):
    330         if not self.model:
    331             return
    332         if not self.fitted:
    333             self.FitHardpoints()
    334         self.CheckAmbientAudio()
    335 
    336     def CheckAmbientAudio(self):
    337         audsvc = self.sm.GetServiceIfRunning('audio')
    338         if audsvc.active:
    339             lookedAt = audsvc.lastLookedAt
    340             if lookedAt is None:
    341                 self.SetupAmbientAudio()
    342                 audsvc.lastLookedAt = self
    343             elif lookedAt is not self:
    344                 lookedAt.PlayGeneralAudioEvent('shipsounds_stop')
    345                 self.SetupAmbientAudio()
    346                 audsvc.lastLookedAt = self
    347             else:
    348                 return
    349 
    350     def FitBoosters(self, alwaysOn = False, enableTrails = True, isNPC = False):
    351         if self.typeID is None:
    352             return
    353         raceName = self.typeData.get('sofRaceName', None)
    354         if raceName is None:
    355             self.logger.error('SpaceObject type %s has invaldi raceID (not set!)', self.typeID)
    356             raceName = 'generic'
    357         if self.model is None:
    358             self.logger.warning('No model to fit boosters')
    359             return
    360         if not hasattr(self.model, 'boosters'):
    361             self.logger.warning('Model has no attribute boosters')
    362             return
    363         if self.model.boosters:
    364             self.model.boosters.maxVel = self.maxVelocity
    365             self.model.boosters.alwaysOn = alwaysOn
    366             if not enableTrails:
    367                 self.model.boosters.trails = None
    368             dogmaAttr = const.attributeMaxVelocity
    369             if isNPC:
    370                 dogmaAttr = const.attributeEntityCruiseSpeed
    371             velocity = self.sm.GetService('godma').GetTypeAttribute(self.typeID, dogmaAttr)
    372             if velocity is None:
    373                 velocity = 1.0
    374             self.model.maxSpeed = velocity
    375 
    376     def EnterWarp(self):
    377         for t in self.turrets:
    378             t.EnterWarp()
    379 
    380         self.SetControllerVariable('IsWarping', True)
    381         try:
    382             self.model.boosters.warpIntensity = 1
    383         except AttributeError:
    384             pass
    385 
    386     def ExitWarp(self):
    387         for t in self.turrets:
    388             t.ExitWarp()
    389 
    390         self.SetControllerVariable('IsWarping', False)
    391         try:
    392             self.model.boosters.warpIntensity = 0
    393         except AttributeError:
    394             pass
    395 
    396     def UnfitHardpoints(self):
    397         if not self.fitted:
    398             return
    399         newModules = {}
    400         for key, val in self.modules.iteritems():
    401             if val not in self.turrets:
    402                 newModules[key] = val
    403 
    404         self.modules = newModules
    405         del self.turrets[:]
    406         self.fitted = False
    407 
    408     def FitHardpoints(self, model = None, blocking = False):
    409         if model is None:
    410             model = self.model
    411         if getattr(self.fittingThread, 'alive', False):
    412             self.fitted = False
    413             self.fittingThread.kill()
    414         if blocking:
    415             self._FitHardpoints(model)
    416         else:
    417             self.fittingThread = uthread2.StartTasklet(self._FitHardpoints, model)
    418 
    419     def _FitHardpoints(self, model = None):
    420         if self.fitted:
    421             return
    422         if model is None:
    423             model = self.model
    424         if model is None:
    425             self.logger.warning('FitHardpoints - No model')
    426             return
    427         self.fitted = True
    428         newTurretSetDict = TurretSet.FitTurrets(self.id, model, self.typeData.get('sofFactionName', None))
    429         self.turrets = []
    430         for key, val in newTurretSetDict.iteritems():
    431             self.modules[key] = val
    432             self.turrets.append(val)
    433             moduleGroupID = evetypes.GetGroupID(val.turretTypeID)
    434             if not self.isReceivingMiningEvents and moduleGroupID in const.miningModuleGroups:
    435                 self.isReceivingMiningEvents = True
    436                 mining_signals.on_ore_mined.connect(self.HandleMiningEvent)
    437 
    438         if model and hasattr(model, 'locators') and hasattr(model, 'GetLocalBoundingBox'):
    439             setupTurretMovementAudio([ x.GetTurretSet() for x in self.turrets ], model.locators, model.GetLocalBoundingBox())
    440 
    441     def HandleMiningEvent(self, asteroid_id, module_item_id, type_id, yield_quantity, crit_quantity, wasted_quantity):
    442         if module_item_id in self.modules:
    443             if crit_quantity > 0:
    444                 if self.modules[module_item_id] is not None:
    445                     self.modules[module_item_id].SetControllerVariable('miningCrit', 1.0)
    446 
    447     def ApplyTorqueAtDamageLocator(self, damageLocatorID, impactVelocity, impactObjectMass):
    448         if not self.model:
    449             return
    450         damageLocatorPosition = self.model.GetDamageLocator(damageLocatorID)
    451         bsCenter = geo2.Vector(*self.model.GetBoundingSphereCenter())
    452         damageLocatorPosition -= bsCenter
    453         q = self.GetQuaternionAt(blue.os.GetSimTime())
    454         damageLocatorPosition = geo2.QuaternionTransformVector((q.x,
    455          q.y,
    456          q.z,
    457          q.w), damageLocatorPosition)
    458         self.ApplyTorqueAtPosition(damageLocatorPosition, impactVelocity, impactObjectMass)
    459 
    460     def ApplyTorqueAtPosition(self, position, impactVelocity, impactObjectMass):
    461         if not self.model:
    462             return
    463         impactForce = geo2.Vec3Scale(impactVelocity, impactObjectMass)
    464         self.ApplyImpulsiveForceAtPosition(impactForce, geo2.Vector(*position))
    465 
    466     def ChangingSkin(self, nextModel):
    467         self._FitHardpoints(self.nextModel)
    468 
    469     def PostChangingSkin(self):
    470         self.FitBoosters()
    471         if self.stanceID is not None:
    472             spaceobjanimation.SetShipAnimationStance(self.model, self.stanceID)
    473         self.UpdateCosmeticsItems()