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

modularHangarBehaviours.py (49209B)


      1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\client\script\ui\view\hangarBehaviours\modularHangarBehaviours.py
      2 from __future__ import print_function
      3 from __future__ import absolute_import
      4 import blue
      5 import random as rnd
      6 import geo2
      7 import trinity
      8 import math
      9 import uthread
     10 import logging
     11 from . import modularHangarBehavioursConstants as hConst
     12 from cosmetics.common.ships.skins.static_data.skin_type import ShipSkinType
     13 from eve.common.script.sys.idCheckers import IsJunkLocation
     14 from inventorycommon import const
     15 from uthread2 import call_after_simtime_delay
     16 from fsdBuiltData.common.graphicIDs import GetGraphicFile
     17 from .baseHangarBehaviours import BaseHangarShipBehaviour, BaseHangarShipDroneBehaviour
     18 from .modularHangarBehavioursConstants import GetShipSizeClass, IsInLookUpTable
     19 import evecamera
     20 from evetypes import GetGroupID
     21 from gametime import GetSecondsUntilSimTime
     22 from appConst import factionAngelCartel, factionGuristasPirates
     23 logger = logging.getLogger(__name__)
     24 
     25 class Dock(object):
     26 
     27     def __init__(self, pos, rot):
     28         self.translation = pos
     29         self.rotation = rot
     30         self.isPlayer = False
     31         self.dockMultiEffect = None
     32         self.dockedShip = None
     33         self.isActive = False
     34         self.childObject = None
     35         self.dockedShipItemID = 0
     36         self.exitPoint = (0.0, 0.0, 0.0)
     37         self.hallwayPoint = (0.0, 0.0, 0.0)
     38         self.relativeMEExitPoint = (0.0, 0.0, 0.0)
     39         self.cameraExitPoint = (0.0, 0.0, 0.0)
     40 
     41     def Setup(self, pos, rot):
     42         self.translation = pos
     43         self.rotation = rot
     44 
     45     def shipDeparture(self):
     46         pass
     47 
     48     def shipDocking(self):
     49         pass
     50 
     51 
     52 class ModularHangarShipBehaviour(BaseHangarShipBehaviour):
     53 
     54     def __init__(self):
     55         super(ModularHangarShipBehaviour, self).__init__()
     56         self.smallDocks = []
     57         self.bigDocks = []
     58         self.playerDock = None
     59         self.playerShipItemID = 0
     60         self.playerShipTypeID = 0
     61         self.shipOffset = (0, 0, 0)
     62         self.endPos = (0, 0, 0)
     63         self.isInitialized = False
     64         self.hangarScene = None
     65         self.reflectionProbeThread = None
     66         self.flightPath = {'exit1': (0.0, 0.0, 0.0),
     67          'hallway1': (0.0, 0.0, 0.0),
     68          'hallway2': (0.0, 0.0, 0.0),
     69          'exit2': (0.0, 0.0, 0.0)}
     70         self.isEnlistmentDockingEnabled = False
     71 
     72     def SetEnlistmentDockingEnabled(self, enabled):
     73         self.isEnlistmentDockingEnabled = enabled
     74 
     75     def SetDockingEffectGraphicID(self, graphicID):
     76         self.dockingEffectGraphicID = graphicID
     77 
     78     def SetAnchorPoint(self, hangarModel, hangarScene):
     79         if hangarModel is None:
     80             self.log.error('ModularHangarShipBehaviour.SetAnchorPoint: Setting anchor point when hangarModel is None')
     81             return
     82         self.hangarScene = hangarScene
     83         self._CreateDocks(hangarModel, hangarScene)
     84 
     85     def CleanScene(self):
     86 
     87         def _cleanMultiEffect(multiEffect):
     88             if multiEffect is not None:
     89                 for param in multiEffect.parameters:
     90                     param.object = None
     91 
     92                 multiEffect.bindings.removeAt(-1)
     93 
     94         def _cleanChildObject(obj):
     95             if obj is not None:
     96                 obj.objects.removeAt(-1)
     97                 for ctrlr in obj.controllers:
     98                     ctrlr.Stop()
     99 
    100                 obj.controllers.removeAt(-1)
    101 
    102         for dock in self.smallDocks:
    103             dock.dockedShip = None
    104             _cleanChildObject(dock.childObject)
    105             dock.childObject = None
    106             _cleanMultiEffect(dock.dockMultiEffect)
    107             dock.dockMultiEffect = None
    108 
    109         for dock in self.bigDocks:
    110             dock.dockedShip = None
    111             _cleanChildObject(dock.childObject)
    112             dock.childObject = None
    113             _cleanMultiEffect(dock.dockMultiEffect)
    114             dock.dockMultiEffect = None
    115 
    116         self.GetCamera().ClearRefs()
    117         self.hangarScene = None
    118         self.playerDock = None
    119         self.smallDocks = None
    120         self.bigDocks = None
    121         self.flightPath = None
    122         self.isInitialized = False
    123         self.reflectionProbeThread = None
    124 
    125     def GetCamera(self):
    126         return sm.GetService('sceneManager').GetRegisteredCamera(evecamera.CAM_MODULARHANGAR)
    127 
    128     def _ReflectionProbePositionUpdateThread(self, probe):
    129         try:
    130             camera = self.GetCamera()
    131             while True:
    132                 if camera is None or probe is None:
    133                     break
    134                 probe.position = camera.GetZoomToPoint()
    135                 blue.synchro.Yield()
    136 
    137         finally:
    138             self.reflectionProbeThread = None
    139 
    140     def PlaceReflectionProbe(self, reflectionProbe):
    141         if reflectionProbe:
    142             reflectionProbe.lockPosition = True
    143             if not self.reflectionProbeThread:
    144                 self.reflectionProbeThread = uthread.new(self._ReflectionProbePositionUpdateThread, reflectionProbe)
    145 
    146     def _GetEnlistment(self):
    147         if not self.isEnlistmentDockingEnabled:
    148             return None
    149         else:
    150             enlistment, _, _ = sm.RemoteSvc('fwCharacterEnlistmentMgr').GetMyEnlistment()
    151             return enlistment or 0.0
    152 
    153     def _CreateDocks(self, hangarModel, hangarScene):
    154         enlistment = self._GetEnlistment()
    155         smallDockLocators, bigDockLocators = [], []
    156         if enlistment is None:
    157             smallDockLocators = self.GetLocatorsFromSet(hangarModel, hConst.LOCATORSET_SMALL_DOCK_SHIPS)
    158             bigDockLocators = self.GetLocatorsFromSet(hangarModel, hConst.LOCATORSET_MEDIUM_DOCK_SHIPS)
    159         if enlistment is not None:
    160             smallDockLocators = self.GetLocatorsFromSet(hangarModel, hConst.LOCATORSET_SMALL_DEATHLESS_DOCK)
    161             bigDockLocators = self.GetLocatorsFromSet(hangarModel, hConst.LOCATORSET_MEDIUM_DEATHLESS_DOCK)
    162             if self.isEnlistmentDockingEnabled and enlistment == factionAngelCartel:
    163                 smallDockLocators += self.GetLocatorsFromSet(hangarModel, hConst.LOCATORSET_SMALL_ANGEL_DOCK)
    164                 bigDockLocators += self.GetLocatorsFromSet(hangarModel, hConst.LOCATORSET_MEDIUM_ANGEL_DOCK)
    165             elif self.isEnlistmentDockingEnabled and enlistment == factionGuristasPirates:
    166                 smallDockLocators += self.GetLocatorsFromSet(hangarModel, hConst.LOCATORSET_SMALL_GURISTAS_DOCK)
    167                 bigDockLocators += self.GetLocatorsFromSet(hangarModel, hConst.LOCATORSET_MEDIUM_GURISTAS_DOCK)
    168         hallwayLocatorSetName = hConst.LOCATORSET_HALLWAY_POINTS
    169         if not smallDockLocators or not bigDockLocators:
    170             self.log.error('ModularHangarShipBehaviour.SetAnchorPoint: not all required LocatorSets are defined.')
    171             return
    172         smallDockObjects = []
    173         smallDockObjectPosTuples = []
    174         bigDockObjects = []
    175         bigDockObjectPosTuples = []
    176         layoutContainers = [ container for container in hangarModel.effectChildren if container.name == 'layouts' ]
    177         try:
    178             i = 0
    179             for layoutContainer in layoutContainers:
    180                 containerName = hConst.LOCATORSET_SMALL_DOCK_SHIPS
    181                 for container in (cont for cont in layoutContainer.objects if cont.name == containerName or cont.name == containerName + '_potato'):
    182                     smallDockObjects.append(container)
    183                     pos = container.objects.FindByName('Hull').translation
    184                     smallDockObjectPosTuples.append((pos[0],
    185                      pos[1],
    186                      pos[2],
    187                      i))
    188                     i = i + 1
    189 
    190             i = 0
    191             for layoutContainer in layoutContainers:
    192                 for container in (cont for cont in layoutContainer.objects if cont.name == hConst.LOCATORSET_MEDIUM_DOCK_SHIPS):
    193                     bigDockObjects.append(container)
    194                     pos = container.objects.FindByName('Hull').translation
    195                     bigDockObjectPosTuples.append((pos[0],
    196                      pos[1],
    197                      pos[2],
    198                      i))
    199                     i = i + 1
    200 
    201         except AttributeError:
    202             self.log.error("modularHangarShipBehaviour._CreateDocks: can't find child objects")
    203             return
    204 
    205         def SetExitPoint(dock, shipPos, platformRotation):
    206             exitIndex = hangarModel.GetCloseLocatorIndex(shipPos, exitPointSetName)
    207             exitPos = hangarModel.GetLocatorPositionFromSet(exitIndex, True, exitPointSetName)
    208             relativePos = geo2.Subtract(exitPos, shipPos)
    209             relativePosRotated = geo2.QuaternionTransformVector(geo2.QuaternionInverse(platformRotation), relativePos)
    210             dock.relativeMEExitPoint = (relativePosRotated[0],
    211              relativePosRotated[1],
    212              relativePosRotated[2],
    213              0.0)
    214             return exitPos
    215 
    216         def GetClosestDockObject(isSmall, location):
    217             target = -1
    218             bestDist = 420
    219             bestDist = bestDist * bestDist
    220             dock = None
    221             if isSmall:
    222                 for dockObj in smallDockObjectPosTuples:
    223                     x, y, z, index = dockObj
    224                     dist = geo2.Vec3DistanceSq(location, (x, y, z))
    225                     if dist < bestDist:
    226                         target = index
    227                         bestDist = dist
    228 
    229                 if target != -1:
    230                     dock = smallDockObjects[target]
    231             else:
    232                 for dockObj in bigDockObjectPosTuples:
    233                     x, y, z, index = dockObj
    234                     dist = geo2.Vec3DistanceSq(location, (x, y, z))
    235                     if dist < bestDist:
    236                         target = index
    237                         bestDist = dist
    238 
    239                 if target != -1:
    240                     dock = bigDockObjects[target]
    241             if target is -1:
    242                 return
    243             return dock
    244 
    245         def CreateDocks(locators, setToAddTo, isSmall):
    246             for locator in locators:
    247                 pos = locator[0]
    248                 rot = locator[1]
    249                 potentialChildObject = GetClosestDockObject(isSmall, pos)
    250                 if potentialChildObject is None:
    251                     continue
    252                 dock = Dock(pos, rot)
    253                 dock.exitPoint = SetExitPoint(dock, pos, rot)
    254                 cameraExitLocatorIndex = hangarModel.GetCloseLocatorIndex(pos, cameraExitPointSetName)
    255                 dock.cameraExitPoint = hangarModel.GetLocatorPositionFromSet(cameraExitLocatorIndex, True, cameraExitPointSetName)
    256                 dock.childObject = potentialChildObject
    257                 hallwayLocatorIndex = hangarModel.GetCloseLocatorIndex(dock.cameraExitPoint, hallwayLocatorSetName)
    258                 dock.hallwayPoint = hangarModel.GetLocatorPositionFromSet(hallwayLocatorIndex, True, hallwayLocatorSetName)
    259                 setToAddTo.append(dock)
    260 
    261         exitPointSetName = hConst.LOCATORSET_SMALL_DOCK_EXITS
    262         cameraExitPointSetName = hConst.LOCATORSET_SMALL_DOCK_CAMERA_EXITS
    263         CreateDocks(smallDockLocators, self.smallDocks, True)
    264         exitPointSetName = hConst.LOCATORSET_MEDIUM_DOCK_EXITS
    265         cameraExitPointSetName = hConst.LOCATORSET_MEDIUM_DOCK_CAMERA_EXITS
    266         CreateDocks(bigDockLocators, self.bigDocks, False)
    267 
    268     def IsInitialized(self):
    269         return self.isInitialized
    270 
    271     def _GetPlayerDock(self):
    272         return self.playerDock
    273 
    274     def GetAllDockedShips(self):
    275         ships = []
    276         for each in self.smallDocks:
    277             if each.dockedShip is not None:
    278                 ships.append(each.dockedShip)
    279 
    280         for each in self.bigDocks:
    281             if each.dockedShip is not None:
    282                 ships.append(each.dockedShip)
    283 
    284         return ships
    285 
    286     def OnItemChangeProcessed(self, item, itemInfo):
    287         if item.itemID is None or item.typeID is None:
    288             return
    289         isT3cItem = False
    290         if item.groupID in const.subsystemSlotGroupIDs or item.groupID == const.groupStrategicCruiser:
    291             isT3cItem = True
    292         if item.flagID == const.flagHangar and item.quantity < 0:
    293             if IsJunkLocation(item.locationID):
    294                 self._RemoveShipIfItsInTheScene(item.itemID, item.typeID)
    295             elif const.categoryTrading in itemInfo and not isT3cItem:
    296                 self._SpawnANewShipIfThereIsRoom(item.itemID, item.typeID)
    297         elif item.flagID == const.flagJunkyardTrashed:
    298             self._RemoveShipIfItsInTheScene(item.itemID, item.typeID)
    299 
    300     def _ConfigureShipTransform(self, ship, offset, dock):
    301         platformRotation = trinity.Tr2CurveConstant()
    302         platformRotation.value = dock.rotation
    303         shipTranslation = trinity.Tr2CurveCombiner()
    304         platformTranslation = trinity.Tr2TranslationAdapter()
    305         platformTranslation.value = geo2.Add(offset, dock.translation)
    306         multiEffectTranslation = trinity.Tr2TranslationAdapter()
    307         multiEffectTranslation.rotationOffset = dock.rotation
    308         shipTranslation.curves.append(platformTranslation)
    309         shipTranslation.curves.append(multiEffectTranslation)
    310         displayOffset = ship.locatorSets.FindByName(hConst.LOCATORSET_DISPLAY_OFFSET)
    311         if displayOffset is not None and len(displayOffset.locators) == 1:
    312             displayOffsetCurve = trinity.Tr2TranslationAdapter()
    313             displayOffsetCurve.value = displayOffset.locators[0][0]
    314             displayOffsetCurve.rotationOffset = dock.rotation
    315             shipTranslation.curves.append(displayOffsetCurve)
    316         ship.translationCurve = shipTranslation
    317         ship.rotationCurve = platformRotation
    318         ship.modelRotationCurve = trinity.Tr2RotationAdapter()
    319         ship.modelTranslationCurve = trinity.Tr2TranslationAdapter()
    320 
    321     def _SpawnANewShipIfThereIsRoom(self, itemID, typeID):
    322         groupID = GetGroupID(typeID)
    323         if not IsInLookUpTable(groupID):
    324             return
    325         sizeClass = GetShipSizeClass(groupID)
    326         newDock = None
    327         if sizeClass > 2:
    328             return
    329         if sizeClass < 2:
    330             emptyDocks = [ dock for dock in self.smallDocks if not dock.isActive ]
    331             if len(emptyDocks) > 0:
    332                 newDock = rnd.choice(emptyDocks)
    333         else:
    334             emptyDocks = [ dock for dock in self.bigDocks if not dock.isActive ]
    335             if len(emptyDocks) > 0:
    336                 newDock = rnd.choice(emptyDocks)
    337         if newDock is None:
    338             return
    339         model = self.LoadShipModel(itemID, typeID, playerShip=False)
    340         if model is None:
    341             return
    342         newDock.dockedShipItemID = itemID
    343         self._ReplaceShipInDock(model, newDock, makeActiveShip=False)
    344         self._WaitForShipBoundingBox(model)
    345         shipOffset = geo2.QuaternionTransformVector(newDock.rotation, self.GetShipOffset(model, typeID))
    346         self._ConfigureShipTransform(model, shipOffset, newDock)
    347         newDock.dockedShip = model
    348         newDock.isActive = True
    349         if model.boosters is not None:
    350             model.boosters.display = True
    351         if newDock.dockMultiEffect is not None:
    352             newDock.dockMultiEffect.SetParameter('docking_ship', model)
    353             newDock.dockMultiEffect.SetControllerVariable('materializeDelay', 0.75)
    354             newDock.dockMultiEffect.SetControllerVariable('docked', 1.0)
    355             newDock.dockMultiEffect.StartControllers()
    356         self.hangarScene.objects.append(model)
    357 
    358     def _RemoveShipIfItsInTheScene(self, itemID, typeID):
    359         if self.playerShipItemID == itemID:
    360             return False
    361         groupID = GetGroupID(typeID)
    362         sizeClass = GetShipSizeClass(groupID)
    363         if sizeClass < 2:
    364             dock = next((dock for dock in self.smallDocks if dock.dockedShipItemID == itemID), None)
    365         else:
    366             dock = next((dock for dock in self.bigDocks if dock.dockedShipItemID == itemID), None)
    367         if dock is None:
    368             return False
    369 
    370         def cleanUp(hangarScene, ship, multiEffect):
    371             if hangarScene is None:
    372                 return
    373             if ship is not None and ship in hangarScene.objects:
    374                 hangarScene.objects.remove(ship)
    375             if multiEffect is not None and multiEffect in hangarScene.objects:
    376                 for param in multiEffect.parameters:
    377                     param.object = None
    378 
    379                 multiEffect.bindings.removeAt(-1)
    380                 hangarScene.objects.remove(multiEffect)
    381 
    382         oldME = dock.dockMultiEffect
    383         oldME.SetControllerVariable('materialize', 0.0)
    384         oldME.SetControllerVariable('docked', 0.0)
    385         dock.childObject.SetControllerVariable('isDocked', 0.0)
    386         oldShip = oldME.parameters.FindByName('docking_ship').object
    387         dock.dockMultiEffect = None
    388         dock.childObject.SetControllerVariable('isDocked', 0.0)
    389         dock.childObject.SetControllerVariable('docked', 0.0)
    390         dock.dockedShip = None
    391         dock.isActive = False
    392         dock.dockedShipItemID = 0
    393         call_after_simtime_delay(cleanUp, 15.0, self.hangarScene, oldShip, oldME)
    394 
    395     def _FindPLayerShipInADock(self, sizeClass):
    396         if sizeClass < 2:
    397             dock = next((dock for dock in self.smallDocks if dock.dockedShipItemID == self.playerShipItemID), None)
    398         else:
    399             dock = next((dock for dock in self.bigDocks if dock.dockedShipItemID == self.playerShipItemID), None)
    400         return dock
    401 
    402     def _WaitForShipBoundingBox(self, model):
    403         if model is None:
    404             return
    405         try:
    406             counter = 0
    407             maxYields = 25
    408             while counter < maxYields:
    409                 modelBB = model.GetLocalBoundingBox()
    410                 if modelBB[0][0] != 0.0 and modelBB[0][2] != 0.0:
    411                     return
    412                 counter = counter + 1
    413                 blue.synchro.Yield()
    414 
    415         except IndexError:
    416             self.log.error('modularHangarShipBehaviour.populateDocksWithInventoryShips: bounding box missconfigured')
    417 
    418     def PrepareFSB(self, vfxMultiEffect):
    419         self.playerDock.dockMultiEffect.SetParameter('docking_ship', None)
    420         p = self.playerDock.cameraExitPoint
    421         self.SetFlightPath(p, p, p, p, p)
    422         self.GetCamera().SkipFlight()
    423         vfxMultiEffect.SetParameter('activeDock', self.playerDock.childObject)
    424         self.playerDock.childObject.SetControllerVariable('isActivePlayerDock', 0.0)
    425         self.playerDock.childObject.SetControllerVariable('isDocked', 1.0)
    426         self.playerDock.childObject.StartControllers()
    427         vfxMultiEffect.StartControllers()
    428         for ship in (obj for obj in self.hangarScene.objects if type(obj) == trinity.EveShip2):
    429             ship.SetControllerVariable('lightRigOn', 0.0)
    430 
    431     def FinishFSB(self):
    432         self.playerDock.dockMultiEffect.SetParameter('docking_ship', self.playerDock.dockedShip)
    433         self.playerDock.dockMultiEffect.SetControllerVariable('materialize', 1.0)
    434         self.playerDock.dockMultiEffect.SetControllerVariable('_previousState', 1.0)
    435         self.playerDock.dockMultiEffect.SetControllerVariable('materializeDelay', 0.0)
    436         self.playerDock.dockMultiEffect.StartControllers()
    437         self.GetCamera().zoomFactor = 0.2
    438         self.GetCamera().zoomTarget = 0.2
    439         for ship in (obj for obj in self.hangarScene.objects if type(obj) == trinity.EveShip2):
    440             ship.SetControllerVariable('lightRigOn', 1.0)
    441 
    442     def GetActiveDock(self):
    443         if self.playerDock is not None:
    444             return self.playerDock.childObject
    445 
    446     def PlaceShip(self, itemID, typeID, skipDockingAnimation = False):
    447         groupID = GetGroupID(typeID)
    448         sizeClass = GetShipSizeClass(groupID)
    449         firstDocking = self.playerDock is None
    450         foundDock = self._FindPLayerShipInADock(sizeClass)
    451         if foundDock is None:
    452             if firstDocking:
    453                 if sizeClass < 2:
    454                     dock = next((dock for dock in self.smallDocks if dock.isPlayer), None)
    455                     unusedDock = next((dock for dock in self.bigDocks if dock.isPlayer), None)
    456                     if unusedDock is not None:
    457                         unusedDock.isPlayer = False
    458                         unusedDock.isActive = unusedDock.dockedShipItemID is not 0
    459                 else:
    460                     dock = next((dock for dock in self.bigDocks if dock.isPlayer), None)
    461                     unusedDock = next((dock for dock in self.smallDocks if dock.isPlayer), None)
    462                     if unusedDock is not None:
    463                         unusedDock.isPlayer = False
    464                         unusedDock.isActive = unusedDock.dockedShipItemID is not 0
    465                 if dock is None:
    466                     if sizeClass < 2:
    467                         if self.smallDocks:
    468                             dock = rnd.choice(self.smallDocks)
    469                         elif self.bigDocks:
    470                             dock = rnd.choice(self.bigDocks)
    471                     elif self.bigDocks:
    472                         dock = rnd.choice(self.bigDocks)
    473                     elif self.smallDocks:
    474                         dock = rnd.choice(self.smallDocks)
    475                 if dock is None:
    476                     return
    477                 dock.dockedShipItemID = self.playerShipItemID
    478                 model = self.LoadShipModel(itemID, typeID, True)
    479                 self.playerDock = dock
    480                 self._ReplaceShipInDock(model, dock)
    481                 if dock.dockMultiEffect is not None:
    482                     dock.dockMultiEffect.SetParameter('docking_ship', model)
    483                     dock.dockMultiEffect.SetParameter('docking_dock', dock.childObject)
    484                     dock.dockMultiEffect.SetControllerVariable('materialize', 1.0)
    485                     dock.dockMultiEffect.SetControllerVariable('_previousState', 1.0)
    486                     dock.dockMultiEffect.SetControllerVariable('materializeDelay', 0.0)
    487                     dock.dockMultiEffect.SetControllerVariable('docked', 1.0 if skipDockingAnimation else 0.0)
    488                     dock.dockMultiEffect.StartControllers()
    489                     if skipDockingAnimation:
    490                         dock.childObject.SetControllerVariable('isActivePlayerDock', 0.0)
    491                         dock.childObject.SetControllerVariable('isDocked', 1.0)
    492                         dock.childObject.StartControllers()
    493                         call_after_simtime_delay(dock.childObject.SetControllerVariable, 1.0, 'isActivePlayerDock', 1.0)
    494             else:
    495                 try:
    496                     if sizeClass < 2:
    497                         emptyDocks = [ dock for dock in self.smallDocks if not dock.isActive ]
    498                         if len(emptyDocks) > 0:
    499                             newDock = rnd.choice(emptyDocks)
    500                         else:
    501                             nonPlayerDocks = [ dock for dock in self.smallDocks if not dock.isPlayer ]
    502                             if nonPlayerDocks:
    503                                 newDock = rnd.choice(nonPlayerDocks)
    504                             else:
    505                                 raise IndexError('No available docks')
    506                     else:
    507                         emptyDocks = [ dock for dock in self.bigDocks if not dock.isActive ]
    508                         if len(emptyDocks) > 0:
    509                             newDock = rnd.choice(emptyDocks)
    510                         else:
    511                             nonPlayerDocks = [ dock for dock in self.bigDocks if not dock.isPlayer ]
    512                             if nonPlayerDocks:
    513                                 newDock = rnd.choice(nonPlayerDocks)
    514                             else:
    515                                 raise IndexError('No available docks')
    516                 except IndexError:
    517                     if sizeClass < 2:
    518                         if self.smallDocks:
    519                             newDock = rnd.choice(self.smallDocks)
    520                         elif self.bigDocks:
    521                             newDock = rnd.choice(self.bigDocks)
    522                         else:
    523                             return
    524                     elif self.bigDocks:
    525                         newDock = rnd.choice(self.bigDocks)
    526                     elif self.smallDocks:
    527                         newDock = rnd.choice(self.smallDocks)
    528                     else:
    529                         return
    530 
    531                 self.playerDock.isPlayer = False
    532                 newDock.isPlayer = True
    533                 newDock.dockedShipItemID = itemID
    534                 oldDock = self.playerDock
    535                 if oldDock.childObject is not None:
    536                     oldDock.childObject.SetControllerVariable('isActivePlayerDock', 0.0)
    537                 model = self.LoadShipModel(itemID, typeID, True)
    538                 oldShip = newDock.dockedShip
    539                 oldME = newDock.dockMultiEffect
    540                 self._WaitForShipBoundingBox(model)
    541                 self.playerDock = self._ReplaceShipInDock(model, newDock, skipMaterialization=skipDockingAnimation)
    542                 shipOffset = geo2.QuaternionTransformVector(newDock.rotation, self.GetShipOffset(model, typeID))
    543                 if not skipDockingAnimation:
    544                     self.SetFlightPath(oldDock.cameraExitPoint, oldDock.hallwayPoint, newDock.hallwayPoint, newDock.cameraExitPoint, geo2.Vec3Add(newDock.translation, shipOffset))
    545                 dist = geo2.Vec3DistanceSq(oldDock.cameraExitPoint, newDock.cameraExitPoint)
    546                 if not self.GetCamera().IsPointWithinViewAngle(newDock.translation, 75) and dist > 1000000 or skipDockingAnimation:
    547                     if oldShip is not None and oldShip in self.hangarScene.objects:
    548                         self.hangarScene.objects.remove(oldShip)
    549                     if oldME is not None and oldME in self.hangarScene.objects:
    550                         self.hangarScene.objects.remove(oldME)
    551                     newDock.dockMultiEffect.SetParameter('docking_ship', model)
    552                     newDock.dockMultiEffect.SetParameter('docking_dock', newDock.childObject)
    553                     newDock.dockMultiEffect.SetControllerVariable('materialize', 1.0)
    554                     newDock.dockMultiEffect.SetControllerVariable('_previousState', 1.0)
    555                     newDock.dockMultiEffect.SetControllerVariable('materializeDelay', 0.0)
    556                     newDock.childObject.SetControllerVariable('isDocked', 1.0 if skipDockingAnimation else 0.0)
    557                     newDock.childObject.StartControllers()
    558                     newDock.dockMultiEffect.SetControllerVariable('docked', 1.0 if skipDockingAnimation else 0.0)
    559                     newDock.dockMultiEffect.StartControllers()
    560         else:
    561             if foundDock == self.playerDock:
    562                 if itemID == self.playerDock.dockedShipItemID:
    563                     if skipDockingAnimation:
    564                         docker = self.playerDock.dockMultiEffect
    565                         docker.SetControllerVariable('docked', 1.0 if skipDockingAnimation else 0.0)
    566                         docker.StartControllers()
    567                         self.playerDock.childObject.SetControllerVariable('isActivePlayerDock', 0.0)
    568                         self.playerDock.childObject.SetControllerVariable('isDocked', 1.0)
    569                         self.playerDock.childObject.StartControllers()
    570                         call_after_simtime_delay(self.playerDock.childObject.SetControllerVariable, 1.0, 'isActivePlayerDock', 1.0)
    571                     return self.playerDock.dockedShip
    572                 model = self.LoadShipModel(itemID, typeID, True)
    573                 self._ReplaceShipInDock(model, self.playerDock)
    574                 self._WaitForShipBoundingBox(model)
    575                 self.shipOffset = geo2.QuaternionTransformVector(self.playerDock.rotation, self.GetShipOffset(model, typeID))
    576                 self._ConfigureShipTransform(model, self.shipOffset, self.playerDock)
    577                 self.playerDock.dockedShip = model
    578                 self.GetCamera().SetIsChangingSkin()
    579                 self.GetCamera().SetShip(model, typeID, changingShip=False)
    580                 self.GetCamera().SetCurrentShipSizeClass(sizeClass)
    581                 self._AddDetailsToShipModel(itemID, typeID, model, playerShip=True)
    582                 self.hangarScene.objects.append(model)
    583                 if self.playerDock.dockMultiEffect is not None:
    584                     self.playerDock.dockMultiEffect.SetParameter('docking_ship', model)
    585                     self.playerDock.dockMultiEffect.SetParameter('docking_dock', self.playerDock.childObject)
    586                     self.playerDock.dockMultiEffect.StartControllers()
    587                 return model
    588             if firstDocking:
    589                 smalldock = next((dock for dock in self.smallDocks if dock.isPlayer), None)
    590                 smalldock.isPlayer = False
    591                 smalldock.isActive = False
    592                 bigdock = next((dock for dock in self.bigDocks if dock.isPlayer), None)
    593                 bigdock.isPlayer = False
    594                 bigdock.isActive = False
    595                 if foundDock.childObject is not None:
    596                     foundDock.childObject.SetControllerVariable('isActivePlayerDock', 1.0)
    597                 if foundDock.dockedShip is not None:
    598                     foundDock.dockedShip.SetControllerVariable('isActivePlayerDock', 1.0)
    599                 self.playerDock = foundDock
    600                 foundDock.isActive = True
    601                 foundDock.isPlayer = True
    602                 while foundDock.dockedShip is None:
    603                     blue.synchro.Yield()
    604 
    605                 foundDock.dockMultiEffect.SetControllerVariable('_previousState', 1.0)
    606                 foundDock.dockMultiEffect.SetControllerVariable('docked', 1.0 if skipDockingAnimation else 0.0)
    607                 self.GetCamera().SetShip(foundDock.dockedShip, typeID)
    608                 self.GetCamera().SetCurrentShipSizeClass(sizeClass)
    609                 foundDock.dockMultiEffect.StartControllers()
    610                 sm.ScatterEvent('OnHangarGoingToShip', foundDock.dockedShip)
    611                 self._AddDetailsToShipModel(itemID, typeID, foundDock.dockedShip, playerShip=True)
    612                 if skipDockingAnimation:
    613                     foundDock.childObject.SetControllerVariable('isActivePlayerDock', 0.0)
    614                     foundDock.childObject.SetControllerVariable('isDocked', 1.0)
    615                     call_after_simtime_delay(foundDock.childObject.SetControllerVariable, 1.0, 'isActivePlayerDock', 1.0)
    616                 return foundDock.dockedShip
    617             if self.playerDock.childObject is not None:
    618                 self.playerDock.childObject.SetControllerVariable('isActivePlayerDock', 0.0)
    619             if self.playerDock.dockedShip is not None:
    620                 self.playerDock.dockedShip.SetControllerVariable('isActivePlayerDock', 0.0)
    621             if foundDock.childObject is not None:
    622                 foundDock.childObject.SetControllerVariable('isActivePlayerDock', 1.0)
    623             if foundDock.dockedShip is not None:
    624                 foundDock.dockedShip.SetControllerVariable('isActivePlayerDock', 1.0)
    625             self.playerDock.isPlayer = False
    626             foundDock.isPlayer = True
    627             self.GetCamera().SetShip(foundDock.dockedShip, typeID)
    628             self.GetCamera().SetCurrentShipSizeClass(sizeClass)
    629             shipOffset = geo2.QuaternionTransformVector(foundDock.rotation, self.GetShipOffset(foundDock.dockedShip, typeID))
    630             self.SetFlightPath(self.playerDock.cameraExitPoint, self.playerDock.hallwayPoint, foundDock.hallwayPoint, foundDock.cameraExitPoint, geo2.Vec3Add(foundDock.translation, shipOffset))
    631             self.playerDock = foundDock
    632             self._AddDetailsToShipModel(itemID, typeID, foundDock.dockedShip, playerShip=True)
    633             sm.ScatterEvent('OnHangarGoingToShip', foundDock.dockedShip)
    634             return foundDock.dockedShip
    635         if self.playerDock is None or model is None:
    636             self.log.error('ModularHangarShipBehaviour.PlaceShip: Dock missconfigured')
    637             return
    638         self.playerDock.isActive = True
    639         self._WaitForShipBoundingBox(model)
    640         self.shipOffset = geo2.QuaternionTransformVector(self.playerDock.rotation, self.GetShipOffset(model, typeID))
    641         self._ConfigureShipTransform(model, self.shipOffset, self.playerDock)
    642         self.playerDock.dockedShip = model
    643         self.GetCamera().SetShip(model, typeID)
    644         self.GetCamera().SetCurrentShipSizeClass(sizeClass)
    645         if model.boosters is not None:
    646             model.boosters.display = True
    647         self._AddDetailsToShipModel(itemID, typeID, model, playerShip=True)
    648         if self.playerDock.dockMultiEffect is not None:
    649             self.playerDock.dockMultiEffect.SetParameter('docking_ship', model)
    650             self.playerDock.dockMultiEffect.SetParameter('docking_dock', self.playerDock.childObject)
    651             self.playerDock.dockMultiEffect.StartControllers()
    652         sm.ScatterEvent('OnHangarGoingToShip', model)
    653         self.hangarScene.objects.append(model)
    654         return model
    655 
    656     def GetShipOffset(self, model, typeID):
    657         if model is None:
    658             return (0.0, 0.0, 0.0)
    659         localBB = model.GetLocalBoundingBox()
    660         height = abs(localBB[0][0])
    661         width = abs(localBB[0][2])
    662         groupID = GetGroupID(typeID)
    663         sizeClass = GetShipSizeClass(groupID)
    664         if sizeClass < 2:
    665             shipOffset = hConst.SMALL_PLATFORM_SHIP_PLACEMENT_OFFSET
    666             return (0.0, shipOffset[2] + shipOffset[3] * height, shipOffset[0] + shipOffset[1] * width)
    667         shipOffset = hConst.MEDIUM_PLATFORM_SHIP_PLACEMENT_OFFSET
    668         return (0.0, shipOffset[2] + shipOffset[3] * height, shipOffset[0] + shipOffset[1] * width)
    669 
    670     def GetShipCenter(self, model, typeID):
    671         translation = model.translationCurve.currentValue if model.translationCurve is not None else None
    672         modelTranslation = model.translationCurve.currentValue if model.translationCurve is not None else None
    673         return geo2.Vec3Add(translation or (0.0, 0.0, 0.0), modelTranslation or (0.0, 0.0, 0.0))
    674 
    675     def GetAnimEndPosition(self):
    676         return (0.0, 0.0, 0.0)
    677 
    678     def GetAnimStartPosition(self):
    679         return (0.0, 0.0, 0.0)
    680 
    681     def _GetSizeClass(self, ship):
    682         assignedGroup = GetShipSizeClass(ship.groupID)
    683         if assignedGroup is None:
    684             return 1
    685         return assignedGroup
    686 
    687     def _GetDockingMultieffect(self):
    688         return blue.resMan.LoadObject(GetGraphicFile(self.dockingEffectGraphicID))
    689 
    690     def populateDocksWithInventoryShips(self, ships, scene, hangar):
    691         rnd.shuffle(ships)
    692         bigShips = []
    693         smallShips = []
    694         capitalShips = []
    695         for ship in ships:
    696             sizeClass = self._GetSizeClass(ship)
    697             if sizeClass < 2:
    698                 smallShips.append(ship)
    699             elif sizeClass < 3:
    700                 bigShips.append(ship)
    701             else:
    702                 capitalShips.append(ship)
    703 
    704         if self.smallDocks:
    705             smallDock = rnd.choice(self.smallDocks)
    706             smallDock.isPlayer = True
    707             smallDock.isActive = True
    708         if self.bigDocks:
    709             bigDock = rnd.choice(self.bigDocks)
    710             bigDock.isPlayer = True
    711             bigDock.isActive = True
    712 
    713         def _placeShipInDock(ship, dock):
    714             multiEffect = self._GetDockingMultieffect()
    715             if multiEffect is None:
    716                 return self.log.error('modularHangarShipBehaviour.populateDocksWithInventoryShips: MultiEffect broken')
    717             multiEffect.SetParameter('docking_dock', dock.childObject)
    718             try:
    719                 curveSet = multiEffect.curveSets.FindByName('docking_cs')
    720                 exitPoint = curveSet.curves.FindByName('exit_point')
    721                 exitPoint.value = dock.relativeMEExitPoint
    722             except AttributeError:
    723                 self.log.error('modularHangarShipBehaviour.populateDocksWithInventoryShips: MultiEffect Attributes broken')
    724 
    725             dock.dockMultiEffect = multiEffect
    726             scene.objects.append(multiEffect)
    727             model = self.LoadShipModel(ship.itemID, ship.typeID, False)
    728             self._WaitForShipBoundingBox(model)
    729             shipOffset = geo2.QuaternionTransformVector(dock.rotation, self.GetShipOffset(model, ship.typeID))
    730             self._ConfigureShipTransform(model, shipOffset, dock)
    731             scene.objects.append(model)
    732             dock.dockedShip = model
    733             dock.dockMultiEffect.SetParameter('docking_ship', model)
    734             dock.dockMultiEffect.SetControllerVariable('_previousState', 1.0)
    735             dock.dockMultiEffect.SetControllerVariable('docked', 1.0)
    736             dock.childObject.SetControllerVariable('isDocked', 1.0)
    737             dock.childObject.StartControllers()
    738             if ship.itemID != self.playerShipItemID:
    739                 dock.dockMultiEffect.StartControllers()
    740             dock.dockMultiEffect.name = dock.dockMultiEffect.name + '_' + model.name
    741 
    742         for ship in smallShips:
    743             if sum((d.isActive is False for d in self.smallDocks)) == 0:
    744                 break
    745             if ship.itemID == self.playerShipItemID:
    746                 for smallDock in self.smallDocks:
    747                     if smallDock.isPlayer:
    748                         dock = smallDock
    749 
    750             else:
    751                 dock = rnd.choice([ dock for dock in self.smallDocks if not dock.isActive ])
    752             dock.isActive = True
    753             dock.dockedShipItemID = ship.itemID
    754             if dock.isPlayer:
    755                 _placeShipInDock(ship, dock)
    756             else:
    757                 uthread.new(_placeShipInDock, ship, dock)
    758 
    759         for ship in bigShips:
    760             if sum((d.isActive is False for d in self.bigDocks)) == 0:
    761                 break
    762             if ship.itemID == self.playerShipItemID:
    763                 for bigDock in self.bigDocks:
    764                     if bigDock.isPlayer:
    765                         dock = bigDock
    766 
    767             else:
    768                 dock = rnd.choice([ dock for dock in self.bigDocks if not dock.isActive ])
    769             dock.isActive = True
    770             dock.dockedShipItemID = ship.itemID
    771             if dock.isPlayer:
    772                 _placeShipInDock(ship, dock)
    773             else:
    774                 uthread.new(_placeShipInDock, ship, dock)
    775 
    776         def _LoadAndPlaceCapitalShip(ship):
    777             positionLocators = self.GetLocatorsFromSet(hangar, hConst.LOCATORSET_CAPITAL_SHIP)
    778             if len(positionLocators) != 1:
    779                 self.log.info('ModularHangarShipBehaviour.populateDocksWithInventoryShips: capital locator missing')
    780                 return
    781             model = self.LoadShipModel(ship.itemID, ship.typeID, False)
    782             if model is None:
    783                 return
    784             self._WaitForShipBoundingBox(model)
    785             position = positionLocators[0][0]
    786             rotation = positionLocators[0][1]
    787             shipTranslation = trinity.Tr2TranslationAdapter()
    788             shipBBOffset = self.GetShipOffset(model, ship.typeID)
    789             shipTranslation.value = geo2.Vec3Add(position, shipBBOffset)
    790             shipRotation = trinity.Tr2CurveConstant()
    791             shipRotation.value = rotation
    792             model.translationCurve = shipTranslation
    793             model.rotationCurve = shipRotation
    794             scene.objects.append(model)
    795 
    796         if len(capitalShips) > 0:
    797             ship = rnd.choice(capitalShips)
    798             uthread.new(_LoadAndPlaceCapitalShip, ship)
    799         self.isInitialized = True
    800 
    801     def SetFlightPath(self, exit1, hallway1, hallway2, exit2, dockPos):
    802         self.flightPath['exit1'] = exit1
    803         self.flightPath['exit2'] = exit2
    804         self.flightPath['hallway1'] = hallway1
    805         self.flightPath['hallway2'] = hallway2
    806         self.GetCamera().SetFlightValueMap(exit1, hallway1, hallway2, exit2, dockPos)
    807 
    808     def UpdateStructureState(self, hangarViewState, hangarModel):
    809         try:
    810             if hangarViewState.upkeepState is not None:
    811                 hangarModel.SetControllerVariable('upkeepState', hangarViewState.upkeepState - 1 or 0)
    812             if hangarViewState.operatingState is not None:
    813                 if hangarViewState.operatingState == 102:
    814                     operatingState = 0
    815                 else:
    816                     operatingState = hangarViewState.operatingState - 109
    817                 hangarModel.SetControllerVariable('operatingState', operatingState)
    818             hangarModel.SetControllerVariable('hangarShieldDamage', hangarViewState.damageState[0] or 1.0)
    819             hangarModel.SetControllerVariable('hangarArmorDamage', hangarViewState.damageState[1] or 1.0)
    820             hangarModel.SetControllerVariable('hangarHullDamage', hangarViewState.damageState[2] or 1.0)
    821             if hangarViewState.timerProgress is not None and type(hangarViewState.timerProgress) == float:
    822                 timerProgress = 1 + math.floor(hangarViewState.timerProgress * 15) or 0
    823                 hangarModel.SetControllerVariable('timerProgress', timerProgress)
    824             hangarModel.SetControllerVariable('isRepairing', float(hangarViewState.timerIsProgressing) or 0)
    825             hangarModel.SetControllerVariable('isDamaged', float(hangarViewState.timerIsPaused) or 0)
    826             timeRemainingSec = GetSecondsUntilSimTime(hangarViewState.timerEndAt or 0)
    827             hangarModel.SetControllerVariable('remainingTime', timeRemainingSec or 0)
    828         except TypeError:
    829             self.log.error('modularHangarBehaviours.UpdateStructureState hangarViewState attribute error')
    830 
    831     def UpdateUndockStatus(self, isUndocking):
    832         dock = self._GetPlayerDock()
    833         if dock is not None and dock.dockMultiEffect is not None:
    834             dock.dockMultiEffect.SetControllerVariable('docked', 1.0 - isUndocking)
    835 
    836     def _ReplaceShipInDock(self, model, dock, skipCleanup = False, makeActiveShip = True, skipMaterialization = False):
    837 
    838         def cleanUp(hangarScene, ship, multiEffect):
    839             for param in multiEffect.parameters:
    840                 param.object = None
    841 
    842             multiEffect.bindings.removeAt(-1)
    843             if ship is not None and ship in hangarScene.objects:
    844                 hangarScene.objects.remove(ship)
    845             if multiEffect is not None and multiEffect in hangarScene.objects:
    846                 hangarScene.objects.remove(multiEffect)
    847 
    848         if self.playerDock is None:
    849             return
    850         multiEffect = self._GetDockingMultieffect()
    851         multiEffect.name = multiEffect.name + '_' + model.name
    852         if dock.dockMultiEffect is None:
    853             if multiEffect is None:
    854                 return self.log.error('modularHangarShipBehaviour._ReplaceShipInDock: MultiEffect broken')
    855             multiEffect.SetParameter('docking_dock', dock.childObject)
    856             curveSet = multiEffect.curveSets.FindByName('docking_cs')
    857             exitPoint = curveSet.curves.FindByName('exit_point')
    858             exitPoint.value = dock.relativeMEExitPoint
    859         else:
    860             newExit = multiEffect.curveSets.FindByName('docking_cs').curves.FindByName('exit_point')
    861             oldExit = dock.dockMultiEffect.curveSets.FindByName('docking_cs').curves.FindByName('exit_point')
    862             newExit.value = oldExit.value
    863             oldME = dock.dockMultiEffect
    864             multiEffect.SetParameter('docking_dock', dock.childObject)
    865             oldME.SetControllerVariable('materialize', 0.0)
    866             if skipMaterialization:
    867                 oldME.SetControllerVariable('_previousState', 0.0)
    868                 oldME.StartControllers()
    869             oldShip = oldME.parameters.FindByName('docking_ship').object
    870             if not skipCleanup:
    871                 call_after_simtime_delay(cleanUp, 15.0, self.hangarScene, oldShip, oldME)
    872         dock.dockMultiEffect = multiEffect
    873         self.hangarScene.objects.append(multiEffect)
    874         multiEffect.SetControllerVariable('materialize', 1.0)
    875         multiEffect.SetControllerVariable('_previousState', 1.0 if skipMaterialization else 0.0)
    876         multiEffect.SetControllerVariable('docked', 1.0)
    877         multiEffect.SetControllerVariable('materializeDelay', 2.75)
    878         if dock.childObject is not None and makeActiveShip:
    879             call_after_simtime_delay(dock.childObject.SetControllerVariable, 0.1, 'isActivePlayerDock', 1.0)
    880         return dock
    881 
    882     def AnimateShipEntry(self, newModel, typeID, scene = None, duration = 5.0):
    883         pass
    884 
    885     def UpdateActiveShipIDs(self, typeID, itemID):
    886         self.playerShipItemID = itemID
    887         self.playerShipTypeID = typeID
    888 
    889     def OnShipCosmeticsChanged(self, ship_id, cosmetics_types):
    890         if self.smallDocks:
    891             for each in (dock for dock in self.smallDocks):
    892                 if each.dockedShip is not None:
    893                     enabledCosmetics = sm.GetService('cosmeticsSvc').get_enabled_ship_cosmetics(each.dockedShipItemID, forceRefresh=False)
    894                     uthread.new(self.cosmeticsLoader.SetCosmeticsOnShip, each.dockedShip, enabledCosmetics)
    895 
    896         if self.bigDocks:
    897             for each in (dock for dock in self.bigDocks):
    898                 if each.dockedShip is not None:
    899                     enabledCosmetics = sm.GetService('cosmeticsSvc').get_enabled_ship_cosmetics(each.dockedShipItemID, forceRefresh=False)
    900                     uthread.new(self.cosmeticsLoader.SetCosmeticsOnShip, each.dockedShip, enabledCosmetics)
    901 
    902     def OnSessionChanged(self, _isremote, _session, change):
    903         if 'corpid' or 'allianceid' in change:
    904             enabledCosmetics = sm.GetService('cosmeticsSvc').get_enabled_ship_cosmetics(session.shipid)
    905             self.OnShipCosmeticsChanged(session.shipid, enabledCosmetics)
    906 
    907     def _AddDetailsToShipModel(self, itemID, typeID, model, playerShip = False, skipSetupAnimation = False):
    908         try:
    909             if model is None:
    910                 return
    911             if playerShip:
    912                 self.SetShipDamage(itemID, model)
    913                 self.FitTurrets(itemID, typeID, model)
    914                 self.SetShipKillCounter(itemID, model)
    915                 self.SetShipDirtLevel(itemID, model)
    916             if not skipSetupAnimation:
    917                 self.SetupShipAnimation(model, typeID, itemID)
    918             enabledCosmetics = sm.GetService('cosmeticsSvc').get_enabled_ship_cosmetics(itemID, forceRefresh=True)
    919             if enabledCosmetics is not None:
    920                 uthread.new(self.cosmeticsLoader.SetCosmeticsOnShip, model, enabledCosmetics)
    921         except RuntimeError:
    922             self.log.error('modularHangarBehaviours._AddDetailsToShipModel failed to get dogmaItem')
    923 
    924     def LoadShipModel(self, itemID, typeID, playerShip = False, skipSetupAnimation = False):
    925         model = self._LoadSOFShipModel(itemID, typeID)
    926         if model is not None:
    927             model.name = str(itemID)
    928         if playerShip:
    929             self.playerShipItemID = itemID
    930             self.playerShipTypeID = typeID
    931         if hasattr(model, 'boosters') and model.boosters is not None:
    932             model.boosters.display = True
    933         self._AddDetailsToShipModel(itemID, typeID, model, playerShip=playerShip, skipSetupAnimation=skipSetupAnimation)
    934         self.SetInHangarVariables(model)
    935         return model
    936 
    937     def OnShipsRepaired(self, itemIDs):
    938         for each in (dock for dock in self.smallDocks if dock.dockedShipItemID in itemIDs):
    939             each.dockMultiEffect.SetControllerVariable('isRepairing', 1.0)
    940 
    941         for each in (dock for dock in self.bigDocks if dock.dockedShipItemID in itemIDs):
    942             each.dockMultiEffect.SetControllerVariable('isRepairing', 1.0)
    943 
    944     def ProcessSkinChange(self, newModel):
    945         if self.playerDock is not None and self.playerDock.dockMultiEffect is not None:
    946             self.playerDock.dockedShip = newModel
    947         else:
    948             return
    949         if newModel.boosters is not None:
    950             newModel.boosters.display = True
    951         self.GetCamera().SetIsChangingSkin()
    952         self.GetCamera().SetShip(newModel, self.playerShipTypeID, changingShip=False)
    953         self._AddDetailsToShipModel(self.playerShipItemID, self.playerShipTypeID, newModel, playerShip=True)
    954         self.playerDock.dockMultiEffect.SetParameter('docking_ship', newModel)
    955         self.playerDock.dockMultiEffect.SetControllerVariable('materialize', 1.0)
    956         self.playerDock.dockMultiEffect.SetControllerVariable('materializeDelay', 0.0)
    957         self.playerDock.dockMultiEffect.SetControllerVariable('_previousState', 1.0)
    958         self.playerDock.dockMultiEffect.SetControllerVariable('skinChange', 1.0)
    959         self.playerDock.dockMultiEffect.SetControllerVariable('docked', 1.0)
    960         newModel.StartControllers()
    961         for curveSet in self.playerDock.dockMultiEffect.curveSets:
    962             curveSet.Play()
    963 
    964         for controller in self.playerDock.dockMultiEffect.controllers:
    965             controller.Start()
    966 
    967         skin_state = sm.GetService('cosmeticsSvc').GetAppliedSkinStateForCurrentSession(self.playerShipItemID)
    968         if skin_state is not None and skin_state.skin_type == ShipSkinType.FIRST_PARTY_SKIN:
    969             self._activeSkinID = sm.GetService('cosmeticsSvc').GetFirstPartySkinObjectForCurrentSession(skin_state.skin_data.skin_id)
    970 
    971     def ProcessCamera(self, camera, newModel, typeID):
    972         print('process camera called with newModel typeID: ', typeID)
    973 
    974     def _shipRequiresBigDock(self, ship):
    975         pass
    976 
    977 
    978 class ModularHangarDroneBehaviour(BaseHangarShipDroneBehaviour):
    979 
    980     def SetRepairDroneCount(self, boundingRadius):
    981         count = int(math.ceil(boundingRadius / 60.0))
    982         if self.repairDroneBehaviourGroup:
    983             self.repairDroneBehaviourGroup.SetCount(count)