示例#1
0
    class BlueNotifyWrapper(decometaclass.WrapBlueClass(blueClassName)):
        _alwaysEditableMembers = []

        def AddNotify(self, attrName, callback):
            """
            Calls the specified callback when the attribute specified is set
            """
            if not hasattr(self, '_notifyChangeList'):
                self._notifyEnabled = True
                self._notifyChangeListBoundFuncs = weakref.WeakValueDictionary(
                )
                self._notifyChangeListBoundObjects = weakref.WeakValueDictionary(
                )
                self._notifyChangeList = weakref.WeakValueDictionary()
            if getattr(callback, 'im_self'):
                self._notifyChangeListBoundFuncs[attrName] = callback.im_func
                self._notifyChangeListBoundObjects[attrName] = callback.im_self
            else:
                self._notifyChangeList[attrName] = callback

        def EnableNotify(self):
            self._notifyEnabled = True

        def DisableNotify(self):
            self._notifyEnabled = False

        def IsNotifyEnabled(self):
            return self._notifyEnabled

        def IsLocked(self):
            """
            Overridable lock
            """
            return False

        def __setattr__(self, key, value):
            if key in self.__members__ and key not in self._alwaysEditableMembers and self.IsLocked(
            ):
                return
            if hasattr(self, '_notifyChangeList') and self._notifyEnabled:
                callFunc = self._notifyChangeList.get(key, None)
                if callFunc:
                    callFunc(value)
                unboundFunc = self._notifyChangeListBoundFuncs.get(key, None)
                obj = self._notifyChangeListBoundObjects.get(key, None)
                if unboundFunc:
                    if obj:
                        unboundFunc(obj, value)
                    else:
                        del self._notifyChangeListBoundFuncs[key]
                elif obj:
                    del self._notifyChangeListBoundObjects[key]
            ourSetAttr = BlueNotifyWrapper.__setattr__
            del BlueNotifyWrapper.__setattr__
            setattr(self, key, value)
            BlueNotifyWrapper.__setattr__ = ourSetAttr
示例#2
0
class PythonCamera(decometaclass.WrapBlueClass('trinity.TriCameraPython')):
    def __init__(self):
        trinity.TriCameraPython.__init__(self)
        self.instancedBehaviors = {}
        self.SetCallbackObject(self)

    def GetBehavior(self, sName):
        pRes = None
        if sName in self.instancedBehaviors:
            pRes = self.instancedBehaviors[sName]
        if pRes == None and sName in __cameraBehaviors__:
            pRes = __cameraBehaviors__[sName]()
            self.instancedBehaviors[sName] = pRes
        return pRes

    def GetDefaultBehavior(self):
        return DefaultCamera

    def HasBehavior(self, sName):
        return sName in __cameraBehaviors__

    def GetHookPosition(self):
        if self.parent != None:
            if hasattr(self.parent, 'vCamearHook'):
                return (self.parent.vCamearHook.x, self.parent.vCamearHook.y,
                        self.parent.vCamearHook.z)
            if hasattr(self.parent, 'vLocation'):
                return (self.parent.vLocation.x, self.parent.vLocation.y,
                        self.parent.vLocation.z)
            if hasattr(self.parent, 'translation'):
                return (self.parent.translation.x, self.parent.translation.y,
                        self.parent.translation.z)
            if hasattr(self.parent, 'position'):
                return (self.parent.position.x, self.parent.position.y,
                        self.parent.position.z)
        return (0.0, 0.0, 0.0)

    def GetHookRotation(self):
        if self.parent != None:
            if hasattr(self.parent, 'qCamearRotation'):
                return (self.parent.qCamearRotation.x,
                        self.parent.qCamearRotation.y,
                        self.parent.qCamearRotation.z,
                        self.parent.qCamearRotation.w)
            if hasattr(self.parent, 'qRotation'):
                return (self.parent.qRotation.x, self.parent.qRotation.y,
                        self.parent.qRotation.z, self.parent.qRotation.w)
            if hasattr(self.parent, 'rotation'):
                return (self.parent.rotation.x, self.parent.rotation.y,
                        self.parent.rotation.z, self.parent.rotation.w)
        return (0.0, 0.0, 0.0, 0.0)
示例#3
0
class LabelTracker(decometaclass.WrapBlueClass('trinity.TriTransform')):
    __guid__ = 'xtriui.LabelTracker'
    __persistvars__ = ['sr']

    def __init__(self):
        self.sr = uiutil.Bunch()
        self.wr = util.WeakRefAttrObject()

    def Initialize(self, name, itemID):
        self.sr.itemID = itemID

    def SetTranslation(self, x = 0.0, y = 0.0, z = 0.0, factor = None):
        self.translation.SetXYZ(x, y, z)
        if factor:
            self.translation.Scale(factor)
示例#4
0
class DistrictBall(decometaclass.WrapBlueClass('destiny.ClientBall')):
    def __init__(self):
        self.model = trinity.EveRootTransform()
示例#5
0
#Embedded file name: e:\jenkins\workspace\client_SERENITY\branches\release\SERENITY\packages\destiny\__init__.py
import blue
from _destiny import *
import decometaclass
Ball = decometaclass.WrapBlueClass('destiny.Ball')
Ballpark = decometaclass.WrapBlueClass('destiny.Ballpark')
ClientBall = decometaclass.WrapBlueClass('destiny.ClientBall')
示例#6
0
class Tr2InteriorScene(decometaclass.WrapBlueClass('trinity.Tr2InteriorScene')
                       ):
    __guid__ = 'graphicWrappers.Tr2InteriorScene'

    @staticmethod
    def Wrap(triObject, resPath):
        Tr2InteriorScene(triObject)
        triObject.objects = {}
        triObject.systemParentName = {}
        triObject.systemNames = {}
        triObject.id = ''
        triObject.cellData = {}
        return triObject

    def SetID(self, id):
        self.id = id

    def _SortCells(self):
        listToSort = list(self.cells)
        listToSort.sort(lambda x, y: x.name < y.name)
        self.cells.removeAt(-1)
        self.cells.extend(listToSort)

    def _SortSystems(self, cell):
        listToSort = list(cell.systems)
        listToSort.sort(lambda x, y: x.systemID < y.systemID)
        cell.systems.removeAt(-1)
        cell.systems.extend(listToSort)
        for i, system in enumerate(cell.systems):
            system.SetSystemInCellIdx(i)

    def _GetCell(self, cellName):
        for cell in self.cells:
            if cell.name == cellName:
                return cell

        cell = trinity.Tr2InteriorCell()
        cell.name = cellName
        cell.shProbeResPath = INTERIOR_RES_PATH + str(
            self.id) + '_' + cellName + '.shp'
        cell.reflectionMapPath = INTERIOR_REFMAP_PATH + 'Cube_%s_%s.dds' % (
            self.id, cellName)
        self.cells.append(cell)
        self._SortCells()
        self._LoadUVData(cellName)
        return cell

    def _RemoveCellIfEmpty(self, cell):
        if cell in self.cells:
            if not cell.systems and not cell.probeVolumes:
                self.cells.remove(cell)

    def _RemoveSystemIfEmpty(self, system):
        cellName = self.systemParentName.get(system, None)
        if cellName:
            cell = self._GetCell(cellName)
            if not system.statics:
                cell.RemoveSystem(system)
                self._RemoveCellIfEmpty(cell)

    def _GetSystem(self, cell, systemName):
        systemNames = self.systemNames.get(cell.name, None)
        if systemNames is None:
            systemNames = []
            self.systemNames[cell.name] = systemNames
        if systemName not in systemNames:
            systemNames.append(systemName)
        systemNum = systemNames.index(systemName)
        while len(cell.systems) < systemNum + 1:
            newSystem = trinity.Tr2InteriorEnlightenSystem()
            newSystem.bounceScale = 1.0
            newSystem.systemID = hash(cell.name)
            newSystem.radSystemPath = INTERIOR_RES_PATH + str(
                self.id) + '_' + cell.name + '.rad'
            try:
                path = INTERIOR_RES_PATH + str(
                    self.id) + '_' + cell.name + '.yaml'
                rf = blue.ResFile()
                if rf.FileExists(path):
                    rf.Open(path)
                    yamlStr = rf.read()
                    rf.close()
                    data = yaml.load(yamlStr)
                    newSystem.irradianceScale = data['irradianceScale']
                    newSystem.bounceScale = data['bounceScale']
            except:
                pass

            cell.systems.append(newSystem)
            newSystem.SetSystemInCellIdx(cell.systems.index(newSystem))
            self._SortSystems(cell)
            self.systemParentName[newSystem] = cell.name

        return cell.systems[systemNum]

    def AddStatic(self,
                  staticObj,
                  cellName='DefaultCell',
                  systemName=0,
                  id=None):
        prepassConversion.AddPrepassAreasToStatic(staticObj)
        self.RemoveStatic(staticObj)
        cell = self._GetCell(cellName)
        system = self._GetSystem(cell, systemName)
        system.AddStatic(staticObj)
        self.objects[staticObj] = system
        if id is None:
            id = staticObj.objectID
        uvData = self.cellData.get(cellName, {}).get(id, None)
        if uvData:
            staticObj.SetInstanceData(*uvData)

    def RemoveStatic(self, staticObj):
        system = self.objects.get(staticObj, None)
        if system:
            system.RemoveStatic(staticObj)
            self.objects[staticObj] = None
            self._RemoveSystemIfEmpty(system)

    def AddLight(self, lightObj):
        self.RemoveLight(lightObj)
        self.AddLightSource(lightObj)
        try:
            import wx
            triPanel = wx.FindWindowByName('TrinityPanel')
            if triPanel:
                triPanel.PopulateLights()
                triPanel.PopulateLights()
        except:
            pass

    def RemoveLight(self, lightObj):
        if lightObj in self.lights:
            self.RemoveLightSource(lightObj)
            try:
                import wx
                triPanel = wx.FindWindowByName('TrinityPanel')
                if triPanel:
                    triPanel.PopulateLights()
                    triPanel.PopulateLights()
            except:
                pass

    def AddPhysicalPortal(self, portalObj):
        if portalObj in self.portals:
            self.RemovePhysicalPortal(portalObj)
        self.portals.append(portalObj)

    def RemovePhysicalPortal(self, portalObj):
        if portalObj in self.portals:
            self.portals.remove(portalObj)

    def AddOccluder(self, occluderObj, cellName=''):
        cell = self._GetCell(cellName)
        if occluderObj in cell.occluders:
            self.RemoveOccluder(occluderObj)
        cell.occluders.append(occluderObj)

    def RemoveOccluder(self, occluderObj):
        cell = self._GetCell(occluderObj.cellName)
        if occluderObj in cell.occluders:
            cell.occluders.remove(occluderObj)

    def AddProbeVolume(self, probeObj, cellName=''):
        cell = self._GetCell(cellName)
        if probeObj in cell.probeVolumes:
            self.RemoveProbeVolume(probeObj)
        cell.probeVolumes.append(probeObj)

    def RemoveProbeVolume(self, probeObj):
        cell = self._GetCell(probeObj.cellName)
        if probeObj in cell.probeVolumes:
            cell.probeVolumes.remove(probeObj)

    def AddAvatarToScene(self, avatar):
        self.AddDynamicToScene(avatar)

    def RemoveAvatarFromScene(self, avatar):
        self.RemoveDynamicFromScene(avatar)

    def AddDynamicToScene(self, obj):
        prepassConversion.AddPrepassAreasToDynamic(obj)
        if type(obj) is trinity.Tr2IntSkinnedObject:
            obj.visualModel.ResetAnimationBindings()
        self.AddDynamic(obj)
        return obj

    def RemoveDynamicFromScene(self, obj):
        if obj in self.dynamics:
            self.RemoveDynamic(obj)

    def AddCurveSetToScene(self, curveSet):
        self.curveSets.append(curveSet)

    def RemoveCurveSetFromScene(self, curveSet):
        self.curveSets.remove(curveSet)

    def Refresh(self):
        pass

    def BuildEnlightenScene(self):
        trinity.WaitForResourceLoads()
        import CCP_P4 as p4
        import os
        pathsToClear = []
        for cell in self.cells:
            p4.PrepareFileForSave(
                blue.paths.ResolvePathForWriting(cell.shProbeResPath))
            pathsToClear.append(cell.shProbeResPath)
            for system in cell.systems:
                p4.PrepareFileForSave(
                    blue.paths.ResolvePathForWriting(system.radSystemPath))
                pathsToClear.append(system.radSystemPath)

            cell.RebuildInternalData()
            lightVolumeRes = [
                int(v) + 1
                for v in geo2.Vec3Subtract(cell.maxBounds, cell.minBounds)
            ]
            cell.BuildLightVolume(*lightVolumeRes)
            uvResPath = 'res:/interiorCache/' + str(self.id) + '_' + str(
                cell.name) + '.uv'
            pathsToClear.append(uvResPath)
            uvFileName = blue.paths.ResolvePathForWriting(uvResPath)
            p4.PrepareFileForSave(uvFileName)

        import app.Interior.EnlightenBuildProgressDialog as progress
        dlg = progress.EnlightenBuildDialog()
        if dlg.BuildEnlighten(self):
            self.SaveEnlighten()
            revisionsDB = INTERIOR_RES_PATH + str(self.id) + '.revisions'
            revisionsDB = blue.paths.ResolvePathForWriting(revisionsDB)
            p4.PrepareFileForSave(revisionsDB)
            currentRevs = sm.GetService(
                'jessicaWorldSpaceClient').GetWorldSpace(
                    self.id).GetWorldSpaceSpawnRevisionsList()
            if not os.access(revisionsDB, os.F_OK):
                file = open(revisionsDB, 'w')
                yaml.dump(currentRevs, file)
                file.close()
            else:
                with open(revisionsDB, 'w') as DB:
                    yaml.dump(currentRevs, DB)
        p4.AddFilesToP4()
        for cell in self.cells:
            self._SaveUVData(cell, cell.name)

        for path in pathsToClear:
            blue.resMan.ClearCachedObject(path)

    def _SaveUVData(self, cell, cellName):
        import selectionTypes
        self.cellData[cellName] = {}
        cellData = self.cellData[cellName]
        for system in cell.systems:
            for static in system.statics:
                spawnID = cef.Spawn.GetByRecipeID(
                    selectionTypes.replaceObjects[static].recipeID).spawnID
                cellData[spawnID] = (static.uvLinearTransform,
                                     static.uvTranslation,
                                     static.instanceInSystemIdx)

        marshalData = blue.marshal.Save(cellData)
        import CCP_P4 as p4
        import os
        fileName = blue.paths.ResolvePathForWriting(INTERIOR_RES_PATH +
                                                    str(self.id) + '_' +
                                                    str(cellName) + '.uv')
        p4.PrepareFileForSave(fileName)
        if not os.path.exists(
                blue.paths.ResolvePathForWriting(INTERIOR_RES_PATH)):
            os.makedirs(blue.paths.ResolvePathForWriting(INTERIOR_RES_PATH))
        file = open(fileName, 'wb')
        file.write(marshalData)
        file.close()
        p4.AddFilesToP4()

    def _LoadUVData(self, cellName):
        file = blue.ResFile()
        filePath = INTERIOR_RES_PATH + str(
            self.id) + '_' + str(cellName) + '.uv'
        if file.FileExists(filePath):
            file.open(filePath)
            marshalData = file.read()
            file.close()
            self.cellData[cellName] = blue.marshal.Load(marshalData)
        else:
            self.cellData[cellName] = {}

    def RemoveSkyboxTexture(self):
        self.backgroundEffect = None
        self.backgroundCubemapPath = ''

    def SetSkyboxTexture(self, texturePath):
        self.backgroundEffect = trinity.Tr2Effect()
        texture = trinity.TriTextureCubeParameter()
        texture.name = 'EnvMap1'
        texture.resourcePath = texturePath
        self.backgroundEffect.resources.append(texture)
        self.backgroundEffect.effectFilePath = 'res:/Graphics/Effect/Managed/Interior/Static/EnvironmentCubemap.fx'
        self.backgroundCubemapPath = str(texturePath)

    def GetBoundingBox(self):
        minBB = (99999999.9, 99999999.9, 99999999.9)
        maxBB = (-99999999.9, -99999999.9, -99999999.9)
        for cell in self.cells:
            minBB = geo2.Vec3Minimize(minBB, cell.minBounds)
            maxBB = geo2.Vec3Maximize(maxBB, cell.maxBounds)

        return (minBB, maxBB)
class SpaceObject(decometaclass.WrapBlueClass('destiny.ClientBall')):
    __persistdeco__ = 0
    __update_on_reload__ = 1
    _animationStates = None

    def __init__(self):
        self.explodeOnRemove = False
        self.exploded = False
        self.model = None
        self.animationSequencer = None
        self.released = False
        self.wreckID = None
        self._audioEntities = []
        self._audioEntity = None
        self.logger = logging.getLogger('spaceObject.' +
                                        self.__class__.__name__)
        self.modelLoadedEvent = locks.Event()
        self.explosionModel = None
        self.typeID = None
        self.typeData = {}
        self.explosionManager = ExplosionManager()

    @classmethod
    def GetDefaultAnimationName(cls):
        if cls._animationStates is None:
            return 'NormalLoop'
        states = blue.resMan.LoadObject(cls._animationStates)
        return states.defaultAnimation

    def Log(self, level, *args):
        try:
            self.logger.log(level, ' '.join(map(strx, args)))
        except TypeError:
            self.logger.log('[X]'.join(map(strx, args)).replace('\x00', '\\0'))

    def LogInfo(self, *args):
        self.Log(logging.DEBUG, '[', self.id, ']', *args)

    def LogWarn(self, *args):
        self.Log(logging.WARN, '[', self.id, ']', *args)

    def LogError(self, *args):
        self.Log(logging.ERROR, '[', self.id, ']', *args)

    def SetServices(self, spaceMgr, serviceMgr):
        self.spaceMgr = spaceMgr
        self.sm = serviceMgr
        self.spaceObjectFactory = serviceMgr.GetService(
            'sofService').spaceObjectFactory

    def Prepare(self):
        self.typeID = self.typeData.get('typeID', None)
        self.LoadModel()
        self.Assemble()

    def HasBlueInterface(self, obj, interfaceName):
        if hasattr(obj, 'TypeInfo'):
            return interfaceName in obj.TypeInfo()[1]
        return False

    def _GetComponentRegistry(self):
        return self.ballpark.componentRegistry

    def TriggerAnimation(self, state):
        if self.animationSequencer is None:
            return
        self.animationSequencer.GoToState(state)

    def GetCurrentAnimationState(self):
        if self.animationSequencer is None:
            return
        if self.animationSequencer.currentState is None:
            return
        return self.animationSequencer.currentState.name

    def GetModel(self):
        if not self.model:
            self.modelLoadedEvent.wait()
        return self.model

    def _LoadModelResource(self, fileName):
        self.LogInfo('LoadModel', fileName)
        model = None
        sofDNA = gfxutils.BuildSOFDNAFromTypeID(self.typeData['typeID'])
        if sofDNA is not None:
            model = self.spaceObjectFactory.BuildFromDNA(sofDNA)
        elif fileName is not None and len(fileName):
            model = blue.resMan.LoadObject(fileName)
        if model is None:
            self.LogError(
                'Error: Object type %s has invalid graphicFile, using graphicID: %s'
                % (self.typeData['typeID'], self.typeData['graphicID']))
        return model

    def LoadModel(self, fileName=None, loadedModel=None):
        if loadedModel:
            model = loadedModel
        else:
            if fileName is None:
                fileName = self.typeData.get('graphicFile')
            model = self._LoadModelResource(fileName)
        if self.released:
            return
        if not model:
            self.LogError('Could not load model for spaceobject. FileName:',
                          fileName, ' id:', self.id, ' typeID:',
                          getattr(self, 'typeID', '?'))
            return
        self.model = model
        if not hasattr(model, 'translationCurve'):
            self.LogError('LoadModel - Model in', fileName,
                          "doesn't have a translationCurve.")
        elif isinstance(self, blue.BlueWrapper):
            model.translationCurve = self
            model.rotationCurve = self
        model.name = '%d' % self.id
        if hasattr(model, 'useCurves'):
            model.useCurves = 1
        if self.model is not None and self.HasBlueInterface(
                self.model, 'IEveSpaceObject2'):
            scene = self.spaceMgr.GetScene()
            if scene is not None:
                scene.objects.append(self.model)
        else:
            raise RuntimeError('Invalid object loaded by spaceObject: %s' %
                               str(self.model))
        if self._animationStates is not None:
            self.animationSequencer = blue.resMan.LoadObject(
                self._animationStates)
            self.model.animationSequencer = self.animationSequencer
        self.sm.GetService('FxSequencer').NotifyModelLoaded(self.id)
        self.modelLoadedEvent.set()

    def Assemble(self):
        pass

    def SetStaticRotation(self):
        if self.model is None:
            return
        self.model.rotationCurve = None
        rot = self.typeData.get('dunRotation', None)
        if rot:
            yaw, pitch, roll = map(math.radians, rot)
            quat = geo2.QuaternionRotationSetYawPitchRoll(yaw, pitch, roll)
            if hasattr(self.model, 'rotation'):
                if type(self.model.rotation) == types.TupleType:
                    self.model.rotation = quat
                else:
                    self.model.rotation.SetYawPitchRoll(yaw, pitch, roll)
            else:
                self.model.rotationCurve = trinity.TriRotationCurve()
                self.model.rotationCurve.value = quat

    def _FindClosestBallDir(self, constgrp):
        bp = self.sm.StartService('michelle').GetBallpark()
        dist = 1e+100
        closestID = None
        for ballID, slimItem in bp.slimItems.iteritems():
            if slimItem.groupID == constgrp:
                test = bp.DistanceBetween(self.id, ballID)
                if test < dist:
                    dist = test
                    closestID = ballID

        if closestID is None:
            return (1.0, 0.0, 0.0)
        ball = bp.GetBall(closestID)
        direction = geo2.Vec3SubtractD((self.x, self.y, self.z),
                                       (ball.x, ball.y, ball.z))
        return direction

    def FindClosestMoonDir(self):
        return self._FindClosestBallDir(const.groupMoon)

    def FindClosestPlanetDir(self):
        """Locates the closet planet within reason and returns a direction to it"""
        return self._FindClosestBallDir(const.groupPlanet)

    def GetStaticDirection(self):
        """
            Override this method to define where an orbital object should
            align itself.
        
            I have ported the old ugly block of logic here to avoid having
            to perform trivial changes to a bunch of other objects.
        """
        return self.typeData.get('dunDirection', None)

    def SetStaticDirection(self):
        if self.model is None:
            return
        self.model.rotationCurve = None
        direction = self.GetStaticDirection()
        if direction is None:
            self.LogError(
                'Space object', self.id,
                'has no static direction defined - no rotation will be applied'
            )
            return
        self.AlignToDirection(direction)

    def AlignToDirection(self, direction):
        """Align the space object to a direction."""
        if not self.model:
            return
        zaxis = direction
        if geo2.Vec3LengthSqD(zaxis) > 0.0:
            zaxis = geo2.Vec3NormalizeD(zaxis)
            xaxis = geo2.Vec3CrossD(zaxis, (0, 1, 0))
            if geo2.Vec3LengthSqD(xaxis) == 0.0:
                zaxis = geo2.Vec3AddD(zaxis, mathCommon.RandomVector(0.0001))
                zaxis = geo2.Vec3NormalizeD(zaxis)
                xaxis = geo2.Vec3CrossD(zaxis, (0, 1, 0))
            xaxis = geo2.Vec3NormalizeD(xaxis)
            yaxis = geo2.Vec3CrossD(xaxis, zaxis)
        else:
            self.LogError('Space object', self.id, 'has invalid direction (',
                          direction, '). Unable to rotate it.')
            return
        mat = ((xaxis[0], xaxis[1], xaxis[2], 0.0), (yaxis[0], yaxis[1],
                                                     yaxis[2], 0.0),
               (-zaxis[0], -zaxis[1], -zaxis[2], 0.0), (0.0, 0.0, 0.0, 1.0))
        quat = geo2.QuaternionRotationMatrix(mat)
        if hasattr(self.model, 'modelRotationCurve'):
            if not self.model.modelRotationCurve:
                self.model.modelRotationCurve = trinity.TriRotationCurve(
                    0.0, 0.0, 0.0, 1.0)
            self.model.modelRotationCurve.value = quat
        else:
            self.model.rotationCurve = None

    def UnSync(self):
        if self.model is None:
            return
        startTime = long(random.random() * 123456.0 * 1234.0)
        scaling = 0.95 + random.random() * 0.1
        curves = timecurves.ReadCurves(self.model)
        timecurves.ResetTimeCurves(curves, startTime, scaling)

    def Display(self, display=1, canYield=True):
        if self.model is None:
            self.LogWarn('Display - No model')
            return
        if canYield:
            blue.synchro.Yield()
        if eve.session.shipid == self.id and display and self.IsCloaked():
            self.sm.StartService('FxSequencer').OnSpecialFX(
                self.id, None, None, None, None, 'effects.CloakNoAmim', 0, 1,
                0, 5, 0)
            return
        if self.model:
            self.model.display = display

    def IsCloaked(self):
        return self.isCloaked

    def OnDamageState(self, damageState):
        pass

    def GetDamageState(self):
        return self.spaceMgr.ballpark.GetDamageState(self.id)

    def DoFinalCleanup(self):
        """
        This is our last chance to clean up anything from this ball, called from Destiny
        as it removes it from the ballpark
        """
        if not self.sm.IsServiceRunning('FxSequencer'):
            return
        self.sm.GetService('FxSequencer').RemoveAllBallActivations(self.id)
        self.ClearExplosion()
        if not self.released:
            self.explodeOnRemove = False
            self.Release()

    def ClearExplosion(self, model=None):
        """
        Called by the explosion manager in case there are special references
        in the explosion that need cleaning up.
        """
        if hasattr(self, 'gfx') and self.gfx is not None:
            self.RemoveAndClearModel(self.gfx)
            self.gfx = None
        if self.explosionModel is not None:
            if getattr(self, 'explosionDisplayBinding', False):
                self.explosionDisplayBinding.destinationObject = None
                self.explosionDisplayBinding = None
            self.RemoveAndClearModel(self.explosionModel)
            self.explosionModel = None

    def Release(self, origin=None):
        uthread2.StartTasklet(self._Release, origin)

    def _Release(self, origin=None):
        self.LogInfo('Release')
        if self.released:
            return
        self.released = True
        if self.explodeOnRemove:
            delay = self.Explode()
            if delay:
                delay = min(delay, 5000)
                blue.synchro.SleepSim(delay)
        self.Display(display=0, canYield=False)
        scene = self.spaceMgr.GetScene()
        uthread2.StartTasklet(self.RemoveAndClearModel, self.model, scene)
        if self.animationSequencer is not None:
            self.model.animationSequencer = None
            self.animationSequencer = None
        self._audioEntities = []
        self._audioEntity = None
        self.model = None

    def RemoveAndClearModel(self, model, scene=None):
        """Remove the model from the scene and clear the transforms on it.
        
        :param model: The trinity model to clear.
        :param scene: The scene to remove the object from.
          If None, use the sceneManager to get the registered 
          default scene.
        """
        if model:
            self._Clearcurves(model)
        else:
            self.released = True
            return
        self.RemoveFromScene(model, scene)

    def _Clearcurves(self, model):
        """Clean up any references to the translation and rotation curves.
        
        :param model: The trinity model to clear.
        :param scene: The scene to remove the object from.
          If None, use the sceneManager to get the registered 
          default scene.
        """
        if hasattr(model, 'translationCurve'):
            model.translationCurve = None
            model.rotationCurve = None
        if hasattr(model, 'observers'):
            for ob in model.observers:
                ob.observer = None

    def RemoveFromScene(self, model, scene):
        """Remove the model from the objects list of the scene.
        
        :param model: The trinity model to clear.
        :param scene: The scene to remove the object from.
          If None, use the sceneManager to get the registered 
          default scene.
        """
        if scene is None:
            scene = self.spaceMgr.GetScene()
        if scene:
            scene.objects.fremove(model)

    def GetExplosionInfo(self):
        """
        This method builds an explosion path using the race.
        """
        raceName = self.typeData.get('sofRaceName', None)
        return eveSpaceObject.GetDeathExplosionInfo(self.model, self.radius,
                                                    raceName)

    def Explode(self,
                explosionURL=None,
                scaling=1.0,
                managed=False,
                delay=0.0):
        """
        Makes the spaceobject explode.
        Arguments:
            explosionURL is the path to the explosion asset
            scaling controls additionsl scaling of the explosion asset
            managed determines whether to use the explosionManager to manage the explosion
            delay is the delay with which to hide the exploding spaceobject during the explosion
        """
        self.LogInfo('Exploding')
        if self.exploded:
            return False
        self.sm.ScatterEvent('OnObjectExplode', self.GetModel())
        self.exploded = True
        delayedRemove = delay
        self.explodedTime = blue.os.GetTime()
        if gfxsettings.Get(gfxsettings.UI_EXPLOSION_EFFECTS_ENABLED):
            if managed:
                gfx = self.explosionManager.GetExplosion(
                    explosionURL, callback=self.ClearExplosion)
            else:
                if explosionURL is None:
                    self.LogError(
                        'explosionURL not set when calling Explode. Possibly wrongly authored content. typeID:',
                        self.typeID)
                    explosionURL, (delay, scaling) = self.GetExplosionInfo()
                explosionURL = explosionURL.replace('.blue', '.red').replace(
                    '/Effect/', '/Effect3/')
                gfx = trinity.Load(explosionURL)
                if not gfx:
                    self.LogError('Failed to load explosion: ', explosionURL,
                                  ' - using default')
                    gfx = trinity.Load(
                        'res:/Model/Effect3/Explosion/entityExplode_large.red')
                if gfx.__bluetype__ == 'trinity.EveEffectRoot':
                    msg = 'ExplosionManager circumvented, explosion not managed for %s. (Class:%s, Type:%s)'
                    self.LogWarn(
                        msg %
                        (explosionURL, self.__class__.__name__, self.typeID))
                    gfx.Start()
                elif gfx.__bluetype__ != 'trinity.EveRootTransform':
                    root = trinity.EveRootTransform()
                    root.children.append(gfx)
                    root.name = explosionURL
                    gfx = root
            gfx.translationCurve = self
            self.explosionModel = gfx
            scale = scaling
            gfx.scaling = (gfx.scaling[0] * scale, gfx.scaling[1] * scale,
                           gfx.scaling[2] * scale)
            scene = self.spaceMgr.GetScene()
            scene.objects.append(gfx)
        if self.wreckID is not None:
            wreckBall = self.sm.StartService('michelle').GetBall(self.wreckID)
            if wreckBall is not None:
                uthread2.StartTasklet(wreckBall.DisplayWreck, delayedRemove)
        return delayedRemove

    def GetEventNameFromSlimItem(self, defaultSoundUrl):
        slimItem = self.typeData.get('slimItem')
        eventName = spaceobjaudio.GetSoundUrl(slimItem, defaultSoundUrl)
        return eventName

    def SetupAmbientAudio(self, defaultSoundUrl=None):
        """
            Prepares any ambient audio effects authored on the graphics data.
        """
        audioUrl = self.GetEventNameFromSlimItem(defaultSoundUrl)
        if audioUrl is None:
            return
        audentity = self._GetGeneralAudioEntity()
        if audentity is not None:
            spaceobjaudio.PlayAmbientAudio(audentity, audioUrl)

    def SetupSharedAmbientAudio(self, defaultSoundUrl=None):
        """
            Prepares shared ambient audio effects authored on the graphics data.
        :param defaultSoundUrl: An audio event used if nothing is found in FSD
        """
        eventName = self.GetEventNameFromSlimItem(defaultSoundUrl)
        if eventName is None or self.model is None:
            return
        spaceobjaudio.SetupSharedEmitterForAudioEvent(self.model, eventName)

    def LookAtMe(self):
        pass

    def _GetGeneralAudioEntity(self, recreate=False):
        if self.model is None:
            self._audioEntity = None
            self.LogWarn('model is None, cannot play audio.')
        elif recreate or self._audioEntity is None:
            self._audioEntity = spaceobjaudio.SetupAudioEntity(self.model)
            self._audioEntities.append(self._audioEntity)
        return self._audioEntity

    def PlayGeneralAudioEvent(self, eventName):
        audentity = self._GetGeneralAudioEntity()
        if audentity is not None:
            spaceobjaudio.SendEvent(audentity, eventName)

    def GetNamedAudioEmitterFromObservers(self, emitterName):
        if getattr(self, 'model', None) is None:
            return
        for triObserver in self.model.observers:
            if triObserver.observer.name.lower() == emitterName:
                return triObserver.observer
示例#8
0
class FakeBall(decometaclass.WrapBlueClass('destiny.ClientBall')):
    pass
示例#9
0
class SpaceObject(decometaclass.WrapBlueClass('destiny.ClientBall')):
    __persistdeco__ = 0
    __update_on_reload__ = 1

    def __init__(self):
        self.explodeOnRemove = False
        self.exploded = False
        self.unloaded = False
        self.model = None
        self.additionalModels = []
        self.animationSequencer = None
        self.animationStateObject = None
        self.released = False
        self.wreckID = None
        self._audioEntities = []
        self._audioEntity = None
        self.logger = logging.getLogger('spaceObject.' +
                                        self.__class__.__name__)
        self.logger = SpaceObjectLogAdapter(self.logger, so_id=self.id)
        self.modelLoadedEvent = locks.Event()
        self.modelLoadSignal = Signal()
        self.explosionModel = None
        self.typeID = None
        self.typeData = {}
        self.explosionManager = ExplosionManager()

    def GetPositionCurve(self):
        return self

    def GetTypeID(self):
        if self.typeID is None:
            self.typeID = self.typeData.get('typeID', None)
        return self.typeID

    def SetServices(self, spaceMgr, serviceMgr):
        self.spaceMgr = spaceMgr
        self.sm = serviceMgr
        self.spaceObjectFactory = serviceMgr.GetService(
            'sofService').spaceObjectFactory

    def Prepare(self):
        self.typeID = self.typeData.get('typeID', None)
        self.LoadModel()
        self.Assemble()

    def HasBlueInterface(self, obj, interfaceName):
        if hasattr(obj, 'TypeInfo'):
            return interfaceName in obj.TypeInfo()[1]
        return False

    def _GetComponentRegistry(self):
        return self.ballpark.componentRegistry

    def TriggerAnimation(self, state, **kwargs):
        if self.animationSequencer is None:
            return
        self.logger.debug(
            'SpaceObject: Trigger animation %s with parameters %s', state,
            kwargs)
        for parameterName, parameterValue in kwargs.iteritems():
            self.animationSequencer.SetStateParameter(state, parameterName,
                                                      parameterValue)

        self.animationSequencer.GoToState(state)
        if self.animationStateObject:
            self.RemoveAndClearModel(self.animationStateObject)
            self.animationStateObject = None
        if state in self.typeData['animationStateObjects']:
            dnaToLoad = self.typeData['animationStateObjects'][state]
            self.animationStateObject = self.spaceObjectFactory.BuildFromDNA(
                dnaToLoad)
            self._SetupModelAttributes(self.animationStateObject,
                                       '%d_%s' % (self.id, state))
            self.animationStateObject.rotationCurve = self.model.rotationCurve
            self._AddModelToScene(self.animationStateObject)

    def GetCurrentAnimationState(self, stateMachineName):
        if self.animationSequencer is None:
            return
        for stateMachine in self.animationSequencer.stateMachines:
            if stateMachine.name == stateMachineName:
                if stateMachine.currentState is None:
                    return
                else:
                    return stateMachine.currentState.name

    def GetModel(self):
        if not self.model:
            if blue.os.isOnMainTasklet:
                return None
            self.modelLoadedEvent.wait()
        return self.model

    def GetDNA(self):
        materialSetID = self.typeData.get('slimItem').skinMaterialSetID
        return gfxutils.BuildSOFDNAFromTypeID(self.typeData['typeID'],
                                              materialSetID=materialSetID)

    def _LoadModelResource(self, fileName=None):
        self.logger.debug('LoadModel: %s', fileName)
        model = None
        sofDNA = self.GetDNA()
        self.logger.debug("LoadModel fileName='%s' sofDNA='%s'", fileName,
                          sofDNA)
        if sofDNA is not None and fileName is None:
            model = self.spaceObjectFactory.BuildFromDNA(sofDNA)
        else:
            if fileName is None:
                fileName = self.typeData.get('graphicFile')
            if fileName is not None and len(fileName):
                model = blue.resMan.LoadObject(fileName)
        if model is None:
            self.logger.error(
                'Error: Object type %s has invalid graphicFile, using graphicID: %s',
                self.typeData['typeID'], self.typeData['graphicID'])
        return model

    def _SetupModelAndAddToScene(self, fileName=None, loadedModel=None):
        if loadedModel:
            model = loadedModel
        else:
            model = self._LoadModelResource(fileName)
        if self.released:
            return None
        if not model:
            self.logger.error(
                'Could not load model for spaceobject. FileName:%s typeID:%s',
                fileName, getattr(self, 'typeID', '?'))
            return None
        self._SetupModelAttributes(model, '%d' % self.id)
        self._AddModelToScene(model)
        return model

    def _SetupModelAttributes(self, model, objectName):
        model.translationCurve = self
        model.rotationCurve = self
        model.name = objectName
        if hasattr(model, 'useCurves'):
            model.useCurves = 1
        if model and hasattr(model, 'albedoColor'):
            model.albedoColor = eveSpaceObject.GetAlbedoColor(model)

    def _AddModelToScene(self, model):
        if model is not None:
            scene = self.spaceMgr.GetScene()
            if scene is not None:
                scene.objects.append(model)
            else:
                raise RuntimeError('Invalid object loaded by spaceObject: %s' %
                                   str(model))

    def LoadAdditionalModel(self, fileName=None):
        model = self._SetupModelAndAddToScene(fileName)
        if fileName is not None:
            self.additionalModels.append(model)
        return model

    def NotifyModelLoaded(self):
        if self.model is not None:
            self.logger.debug('SpaceObject - NotifyModelLoaded')
            self.modelLoadedEvent.set()
            self.modelLoadSignal()
            self.sm.GetService('FxSequencer').NotifyModelLoaded(self.id)
        else:
            self.logger.warning(
                'SpaceObject - NotifyModelLoaded called without a model present, no notification was done'
            )

    def RegisterForModelLoad(self, func):
        self.modelLoadSignal.connect(func)

    def LoadModel(self, fileName=None, loadedModel=None):
        self.model = self._SetupModelAndAddToScene(fileName, loadedModel)
        if self.model is None:
            return
        self.SetupAnimationInformation(self.model)
        self.NotifyModelLoaded()

    def SetupAnimationInformation(self, model):
        self._SetupAnimationStateMachines(model)
        self._SetupAnimationUpdater(model)

    def SetAnimationSequencer(self, model):
        if model is not None and hasattr(model, 'animationSequencer'):
            self.animationSequencer = model.animationSequencer
        else:
            self.animationSequencer = None

    def _SetupAnimationStateMachines(self, model):
        animationStates = self.typeData['animationStates']
        if len(animationStates) == 0:
            return
        spaceobjanimation.LoadAnimationStates(animationStates,
                                              cfg.graphicStates, model,
                                              trinity)
        self.SetAnimationSequencer(model)

    def _SetupAnimationUpdater(self, model):
        if not hasattr(
                model,
                'animationUpdater') or not self.typeData['animationStates']:
            return
        if self._audioEntity is None:
            self._audioEntity = self._GetGeneralAudioEntity(model=model)
        if model is not None and model.animationUpdater is not None:
            model.animationUpdater.eventListener = self._audioEntity

    def Assemble(self):
        pass

    def GetStaticRotation(self):
        rot = self.typeData.get('dunRotation', None)
        if rot:
            yaw, pitch, roll = map(math.radians, rot)
            return geo2.QuaternionRotationSetYawPitchRoll(yaw, pitch, roll)
        else:
            return (0.0, 0.0, 0.0, 1.0)

    def SetStaticRotation(self):
        if self.model is None:
            return
        self.model.rotationCurve = None
        rot = self.typeData.get('dunRotation', None)
        if rot:
            yaw, pitch, roll = map(math.radians, rot)
            quat = geo2.QuaternionRotationSetYawPitchRoll(yaw, pitch, roll)
            if hasattr(self.model, 'rotation'):
                if type(self.model.rotation) == types.TupleType:
                    self.model.rotation = quat
                else:
                    self.model.rotation.SetYawPitchRoll(yaw, pitch, roll)
            else:
                self.model.rotationCurve = trinity.TriRotationCurve()
                self.model.rotationCurve.value = quat
                if self.animationStateObject is not None:
                    self.animationStateObject.rotationCurve = self.model.rotationCurve

    def _FindClosestBallDir(self, constgrp):
        bp = self.sm.StartService('michelle').GetBallpark()
        dist = 1e+100
        closestID = None
        for ballID, slimItem in bp.slimItems.iteritems():
            if slimItem.groupID == constgrp:
                test = bp.DistanceBetween(self.id, ballID)
                if test < dist:
                    dist = test
                    closestID = ballID

        if closestID is None:
            return (1.0, 0.0, 0.0)
        ball = bp.GetBall(closestID)
        direction = geo2.Vec3SubtractD((self.x, self.y, self.z),
                                       (ball.x, ball.y, ball.z))
        return direction

    def FindClosestMoonDir(self):
        return self._FindClosestBallDir(const.groupMoon)

    def FindClosestPlanetDir(self):
        return self._FindClosestBallDir(const.groupPlanet)

    def GetStaticDirection(self):
        return self.typeData.get('dunDirection', None)

    def SetStaticDirection(self):
        if self.model is None:
            return
        self.model.rotationCurve = None
        direction = self.GetStaticDirection()
        if direction is None:
            self.logger.error(
                'No static direction defined - no rotation will be applied')
            return
        self.AlignToDirection(direction)

    def AlignToDirection(self, direction):
        if not self.model:
            return
        zaxis = direction
        if geo2.Vec3LengthSqD(zaxis) > 0.0:
            zaxis = geo2.Vec3NormalizeD(zaxis)
            xaxis = geo2.Vec3CrossD(zaxis, (0, 1, 0))
            if geo2.Vec3LengthSqD(xaxis) == 0.0:
                zaxis = geo2.Vec3AddD(zaxis, mathCommon.RandomVector(0.0001))
                zaxis = geo2.Vec3NormalizeD(zaxis)
                xaxis = geo2.Vec3CrossD(zaxis, (0, 1, 0))
            xaxis = geo2.Vec3NormalizeD(xaxis)
            yaxis = geo2.Vec3CrossD(xaxis, zaxis)
        else:
            self.logger.error('Invalid direction (%s). Unable to rotate it.',
                              direction)
            return
        mat = ((xaxis[0], xaxis[1], xaxis[2], 0.0), (yaxis[0], yaxis[1],
                                                     yaxis[2], 0.0),
               (-zaxis[0], -zaxis[1], -zaxis[2], 0.0), (0.0, 0.0, 0.0, 1.0))
        quat = geo2.QuaternionRotationMatrix(mat)
        if hasattr(self.model, 'modelRotationCurve'):
            if not self.model.modelRotationCurve:
                self.model.modelRotationCurve = trinity.TriRotationCurve(
                    0.0, 0.0, 0.0, 1.0)
            self.model.modelRotationCurve.value = quat
        else:
            self.model.rotationCurve = None

    def UnSync(self):
        if self.model is None:
            return
        startTime = long(random.random() * 123456.0 * 1234.0)
        scaling = 0.95 + random.random() * 0.1
        curves = timecurves.ReadCurves(self.model)
        timecurves.ResetTimeCurves(curves, startTime, scaling)

    def Display(self, display=1, canYield=True):
        if self.model is None:
            if display:
                self.logger.warning('Display - No model')
            return
        if canYield:
            blue.synchro.Yield()
        if eve.session.shipid == self.id and display and self.IsCloaked():
            self.sm.StartService('FxSequencer').OnSpecialFX(
                self.id, None, None, None, None, 'effects.CloakNoAmim', 0, 1,
                0, 5, 0)
            return
        if self.model:
            self.model.display = display

    def IsCloaked(self):
        return self.isCloaked

    def OnDamageState(self, damageState):
        pass

    def GetDamageState(self):
        bp = sm.GetService('michelle').GetBallpark()
        if bp is not None:
            return bp.GetDamageState(self.id)

    def _UpdateImpacts(self):
        states = self.GetDamageState()
        if states is not None and self.model is not None:
            damageState = [(d if d is not None else 0.0) for d in states]
            self.model.SetImpactDamageState(damageState[0], damageState[1],
                                            damageState[2], True)

    def DoFinalCleanup(self):
        if not self.sm.IsServiceRunning('FxSequencer'):
            return
        self.sm.GetService('FxSequencer').RemoveAllBallActivations(self.id)
        self.ClearExplosion()
        if not self.released:
            self.explodeOnRemove = False
            self.Release()
        elif self.HasModels():
            scene = self.spaceMgr.GetScene()
            self.ClearAndRemoveAllModels(scene)

    def ClearExplosion(self, model=None):
        if hasattr(self, 'gfx') and self.gfx is not None:
            self.RemoveAndClearModel(self.gfx)
            self.gfx = None
        if self.explosionModel is not None:
            if getattr(self, 'explosionDisplayBinding', False):
                self.explosionDisplayBinding.destinationObject = None
                self.explosionDisplayBinding = None
            self.RemoveAndClearModel(self.explosionModel)
            self.explosionModel = None

    def Release(self, origin=None):
        uthread2.StartTasklet(self._Release, origin)

    def _Release(self, origin=None):
        if self.released:
            return
        self.released = True
        if self.explodeOnRemove:
            delay = self.Explode()
            if delay:
                blue.synchro.SleepSim(delay)
        self.Display(display=0, canYield=False)
        for model in self.additionalModels:
            if model is not None:
                model.display = False

        if hasattr(self.model, 'animationSequencer'):
            self.model.animationSequencer = None
        self.animationSequencer = None
        if hasattr(self.model, 'animationUpdater'
                   ) and self.model.animationUpdater is not None:
            self.model.animationUpdater.eventListener = None
        self._audioEntities = []
        self._audioEntity = None
        scene = self.spaceMgr.GetScene()
        camera = sm.GetService('sceneManager').GetActiveSpaceCamera()
        lookingAt = camera.GetLookAtItemID()
        interestID = camera.GetTrackItemID()
        if self.explodeOnRemove and (self.id == lookingAt
                                     or interestID == self.id):
            self.RemoveAllModelsFromScene(scene)
        else:
            self.ClearAndRemoveAllModels(scene)

    def HasModels(self):
        return self.model is not None

    def ClearAndRemoveAllModels(self, scene):
        self.RemoveAndClearModel(self.model, scene)
        self.model = None
        for m in self.additionalModels:
            self.RemoveAndClearModel(m, scene)

        self.additionalModels = []
        if self.animationStateObject is not None:
            self.RemoveAndClearModel(self.animationStateObject, scene)
        self.animationStateObject = None

    def RemoveAllModelsFromScene(self, scene):
        if scene is None:
            return
        scene.objects.fremove(self.model)
        for m in self.additionalModels:
            scene.objects.fremove(m)

        if self.animationStateObject is not None:
            scene.objects.fremove(self.animationStateObject)

    def RemoveAndClearModel(self, model, scene=None):
        if model:
            self._Clearcurves(model)
        else:
            self.released = True
            return
        self.RemoveFromScene(model, scene)

    def _Clearcurves(self, model):
        if hasattr(model, 'translationCurve'):
            model.translationCurve = None
            model.rotationCurve = None
        if hasattr(model, 'observers'):
            for ob in model.observers:
                ob.observer = None

    def RemoveFromScene(self, model, scene):
        if scene is None:
            scene = self.spaceMgr.GetScene()
        if scene:
            scene.objects.fremove(model)

    def GetExplosionInfo(self):
        raceName = self.typeData.get('sofRaceName', None)
        return eveSpaceObject.GetDeathExplosionInfo(self.model, self.radius,
                                                    raceName)

    def GetExplosionLookAtDelay(self):
        return eveSpaceObject.GetDeathExplosionLookDelay(
            self.model, self.radius)

    def Explode(self,
                explosionURL=None,
                scaling=1.0,
                managed=False,
                delay=0.0):
        if self.exploded:
            return False
        self.sm.ScatterEvent('OnObjectExplode', self.GetModel())
        self.exploded = True
        delayedRemove = delay
        self.explodedTime = blue.os.GetTime()
        if gfxsettings.Get(gfxsettings.UI_EXPLOSION_EFFECTS_ENABLED):
            if SpaceObjectExplosionManager.USE_EXPLOSION_BUCKETS:
                explosionBucket = fsdExplosionBuckets.GetExplosionBucketByTypeID(
                    self.typeData['typeID'])
                if explosionBucket:
                    self.logger.debug('Exploding with explosion bucket')
                    scene = sm.GetService('space').GetScene()
                    wreckSwitchTime, _, __ = SpaceObjectExplosionManager.ExplodeBucketForBall(
                        self, scene)
                    return wreckSwitchTime
            if managed:
                gfx = self.explosionManager.GetExplosion(
                    explosionURL, callback=self.ClearExplosion)
            else:
                if explosionURL is None:
                    self.logger.error(
                        'explosionURL not set when calling Explode. Possibly wrongly authored content. typeID: %s',
                        self.typeID)
                    explosionURL, (delay, scaling) = self.GetExplosionInfo()
                explosionURL = explosionURL.replace('.blue', '.red').replace(
                    '/Effect/', '/Effect3/')
                gfx = trinity.Load(explosionURL)
                if not gfx:
                    self.logger.error(
                        'Failed to load explosion: %s - using default',
                        explosionURL)
                    gfx = trinity.Load(
                        'res:/Model/Effect3/Explosion/entityExplode_large.red')
                if isinstance(gfx, trinity.EveEffectRoot2):
                    msg = 'ExplosionManager circumvented, explosion not managed for %s. (Class:%s, Type:%s)'
                    self.logger.warning(msg, explosionURL,
                                        self.__class__.__name__, self.typeID)
                    gfx.Start()
                elif not isinstance(
                        gfx,
                    (trinity.EveRootTransform, trinity.EveEffectRoot2)):
                    root = trinity.EveRootTransform()
                    root.children.append(gfx)
                    root.name = explosionURL
                    gfx = root
            gfx.translationCurve = self
            self.explosionModel = gfx
            scale = scaling
            gfx.scaling = (gfx.scaling[0] * scale, gfx.scaling[1] * scale,
                           gfx.scaling[2] * scale)
            scene = self.spaceMgr.GetScene()
            if scene is not None:
                scene.objects.append(gfx)
        if self.wreckID is not None:
            wreckBall = self.sm.StartService('michelle').GetBall(self.wreckID)
            if wreckBall is not None:
                uthread2.StartTasklet(wreckBall.DisplayWreck, delayedRemove)
        return delayedRemove

    def PrepareForFiring(self):
        pass

    def GetEventNameFromSlimItem(self, defaultSoundUrl):
        slimItem = self.typeData.get('slimItem')
        eventName = spaceobjaudio.GetSoundUrl(slimItem, defaultSoundUrl)
        return eventName

    def SetupAmbientAudio(self, defaultSoundUrl=None):
        audioUrl = self.GetEventNameFromSlimItem(defaultSoundUrl)
        if audioUrl is None:
            return
        audentity = self._GetGeneralAudioEntity()
        if audentity is not None:
            spaceobjaudio.PlayAmbientAudio(audentity, audioUrl)

    def SetupSharedAmbientAudio(self, defaultSoundUrl=None):
        eventName = self.GetEventNameFromSlimItem(defaultSoundUrl)
        if eventName is None or self.model is None:
            return
        spaceobjaudio.SetupSharedEmitterForAudioEvent(self.model, eventName)

    def LookAtMe(self):
        pass

    def _GetGeneralAudioEntity(self, model=None, recreate=False):
        if model is None:
            model = self.model
        if model is None:
            self._audioEntity = None
            self.logger.warning('model is None, cannot play audio.')
        elif recreate or self._audioEntity is None:
            self._audioEntity = spaceobjaudio.SetupAudioEntity(model)
            self._audioEntities.append(self._audioEntity)
        return self._audioEntity

    def PlayGeneralAudioEvent(self, eventName):
        audentity = self._GetGeneralAudioEntity()
        if audentity is not None:
            spaceobjaudio.SendEvent(audentity, eventName)

    def GetNamedAudioEmitterFromObservers(self, emitterName):
        if getattr(self, 'model', None) is None:
            return
        for triObserver in self.model.observers:
            if triObserver.observer.name.lower() == emitterName:
                return triObserver.observer

    def PlaySound(self, event):
        if self.model is None:
            return
        if hasattr(self.model, 'observers'):
            for obs in self.model.observers:
                obs.observer.SendEvent(unicode(event))
                return

        self.logger.error(
            "Space Object: %s can't play sound. Sound observer not found.",
            self.typeData.get('typeName', None))
class PythonCamera(decometaclass.WrapBlueClass('trinity.TriCameraPython')):
    def __init__(self):
        trinity.TriCameraPython.__init__(self)
        self.instancedBehaviors = {}
        self.SetCallbackObject(self)

    def GetBehavior(self, sName):
        """
        This will return a instance of a behavior, if we have never seen this behavior
        but it is registered, then create a isntance and return it and save the instance for future use.
        This will only create behaviors that are needed, when they are needed.
        """
        pRes = None
        if sName in self.instancedBehaviors:
            pRes = self.instancedBehaviors[sName]
        if pRes == None and sName in __cameraBehaviors__:
            pRes = __cameraBehaviors__[sName]()
            self.instancedBehaviors[sName] = pRes
        return pRes

    def GetDefaultBehavior(self):
        """
        return the name of the default camera
        """
        return DefaultCamera

    def HasBehavior(self, sName):
        """
        does the camera know about this behavior?
        """
        return sName in __cameraBehaviors__

    def GetHookPosition(self):
        """
        What is the position of the camera hook
        """
        if self.parent != None:
            if hasattr(self.parent, 'vCamearHook'):
                return (self.parent.vCamearHook.x, self.parent.vCamearHook.y,
                        self.parent.vCamearHook.z)
            if hasattr(self.parent, 'vLocation'):
                return (self.parent.vLocation.x, self.parent.vLocation.y,
                        self.parent.vLocation.z)
            if hasattr(self.parent, 'translation'):
                return (self.parent.translation.x, self.parent.translation.y,
                        self.parent.translation.z)
            if hasattr(self.parent, 'position'):
                return (self.parent.position.x, self.parent.position.y,
                        self.parent.position.z)
        return (0.0, 0.0, 0.0)

    def GetHookRotation(self):
        """
        What is the rotaiton of the camera hook?
        """
        if self.parent != None:
            if hasattr(self.parent, 'qCamearRotation'):
                return (self.parent.qCamearRotation.x,
                        self.parent.qCamearRotation.y,
                        self.parent.qCamearRotation.z,
                        self.parent.qCamearRotation.w)
            if hasattr(self.parent, 'qRotation'):
                return (self.parent.qRotation.x, self.parent.qRotation.y,
                        self.parent.qRotation.z, self.parent.qRotation.w)
            if hasattr(self.parent, 'rotation'):
                return (self.parent.rotation.x, self.parent.rotation.y,
                        self.parent.rotation.z, self.parent.rotation.w)
        return (0.0, 0.0, 0.0, 0.0)
示例#11
0
class Tr2InteriorScene(decometaclass.WrapBlueClass('trinity.Tr2InteriorScene')
                       ):
    __guid__ = 'graphicWrappers.Tr2InteriorScene'

    @staticmethod
    def Wrap(triObject, resPath):
        Tr2InteriorScene(triObject)
        triObject.objects = {}
        triObject.id = ''
        triObject.cellData = {}
        return triObject

    def SetID(self, id):
        self.id = id

    def _GetCell(self, cellName):
        for cell in self.cells:
            if cell.name == cellName:
                return cell

        cell = trinity.Tr2InteriorCell()
        cell.name = cellName
        cell.shProbeResPath = INTERIOR_RES_PATH + str(
            self.id) + '_' + cellName + '.shp'
        cell.reflectionMapPath = INTERIOR_REFMAP_PATH + 'Cube_%s_%s.dds' % (
            self.id, cellName)
        cell.irradianceTexturePath = '%s%s_%s_rad.dds' % (INTERIOR_RES_PATH,
                                                          self.id, cell.name)
        cell.directionalIrradianceTexturePath = '%s%s_%s_dir_rad.dds' % (
            INTERIOR_RES_PATH, self.id, cell.name)
        self.cells.append(cell)
        self._LoadUVData(cellName)
        return cell

    def _RemoveCellIfEmpty(self, cell):
        if cell in self.cells:
            self.cells.remove(cell)

    def AddStatic(self,
                  staticObj,
                  cellName='DefaultCell',
                  systemName=0,
                  id=None):
        if staticObj in self.objects:
            return
        cell = self._GetCell(cellName)
        cell.AddStatic(staticObj)
        self.objects[staticObj] = cell
        if id is None:
            id = staticObj.objectID
        uvData = self.cellData.get(cellName, {}).get(id, None)
        if uvData:
            staticObj.SetInstanceData(*uvData)

    def RemoveStatic(self, staticObj):
        cell = self.objects.get(staticObj, None)
        if cell:
            cell.RemoveStatic(staticObj)
            self.objects[staticObj] = None
            self._RemoveCellIfEmpty(cell)

    def AddLight(self, lightObj):
        if lightObj in self.lights:
            return
        self.AddLightSource(lightObj)

    def RemoveLight(self, lightObj):
        if lightObj in self.lights:
            self.RemoveLightSource(lightObj)

    def AddAvatarToScene(self, avatar):
        self.AddDynamicToScene(avatar)

    def RemoveAvatarFromScene(self, avatar):
        self.RemoveDynamicFromScene(avatar)

    def AddDynamicToScene(self, obj):
        if type(obj) is trinity.Tr2IntSkinnedObject:
            obj.visualModel.ResetAnimationBindings()
        self.AddDynamic(obj)
        return obj

    def RemoveDynamicFromScene(self, obj):
        if obj in self.dynamics:
            self.RemoveDynamic(obj)

    def AddCurveSetToScene(self, curveSet):
        self.curveSets.append(curveSet)

    def RemoveCurveSetFromScene(self, curveSet):
        self.curveSets.remove(curveSet)

    def Refresh(self):
        pass

    def _LoadUVData(self, cellName):
        filePath = INTERIOR_RES_PATH + str(
            self.id) + '_' + str(cellName) + '.uv'
        if blue.paths.exists(filePath):
            file = blue.ResFile()
            file.open(filePath)
            marshalData = file.read()
            file.close()
            self.cellData[cellName] = blue.marshal.Load(marshalData)
        else:
            self.cellData[cellName] = {}

    def RemoveSkyboxTexture(self):
        self.backgroundEffect = None
        self.backgroundCubemapPath = ''

    def SetSkyboxTexture(self, texturePath):
        self.backgroundEffect = trinity.Tr2Effect()
        texture = trinity.TriTextureParameter()
        texture.name = 'EnvMap1'
        texture.resourcePath = texturePath
        self.backgroundEffect.resources.append(texture)
        self.backgroundEffect.effectFilePath = 'res:/Graphics/Effect/Managed/Interior/Static/EnvironmentCubemap.fx'
        self.backgroundCubemapPath = str(texturePath)

    def GetBoundingBox(self):
        minBB = (99999999.9, 99999999.9, 99999999.9)
        maxBB = (-99999999.9, -99999999.9, -99999999.9)
        for cell in self.cells:
            minBB = geo2.Vec3Minimize(minBB, cell.minBounds)
            maxBB = geo2.Vec3Maximize(maxBB, cell.maxBounds)

        return (minBB, maxBB)
示例#12
0
class SpaceObject(decometaclass.WrapBlueClass('destiny.ClientBall')):
    __guid__ = 'spaceObject.SpaceObject'
    __persistdeco__ = 0
    __update_on_reload__ = 1

    def __init__(self):
        self.explodeOnRemove = False
        self.exploded = False
        self.model = None
        self.released = False
        self.forceLOD = False
        self.wreckID = None
        self.audioEntities = []
        self.generalAudioEntity = None
        self.boosterAudioEvent = ''
        self.audioPumpStarted = False
        self.logChannel = log.GetChannel(self.__guid__)
        self.modelLoadedEvent = locks.Event()
        self.explosionModel = None
        self.typeID = None
        self.raceID = None
        self.explosionManager = util.ExplosionManager()

    def Log(self, channelID, *args, **keywords):
        if self.logChannel.IsOpen(channelID):
            try:
                self.logChannel.Log(' '.join(map(strx, args)), channelID,
                                    keywords.get('backtrace', 1))
            except TypeError:
                self.logChannel.Log(
                    '[X]'.join(map(strx, args)).replace('\x00', '\\0'),
                    channelID, keywords.get('backtrace', 1))
                sys.exc_clear()

    def LogInfo(self, *args, **keywords):
        self.Log(1, '[', self.id, ']', *args, **keywords)

    def LogWarn(self, *args, **keywords):
        self.Log(2, '[', self.id, ']', *args, **keywords)

    def LogError(self, *args, **keywords):
        self.Log(4, '[', self.id, ']', *args, **keywords)

    def Prepare(self, spaceMgr):
        self.spaceMgr = spaceMgr
        self.LoadModel()
        self.Assemble()

    def HasBlueInterface(self, object, interfaceName):
        if hasattr(object, 'TypeInfo'):
            return interfaceName in object.TypeInfo()[1]
        return False

    def GetModel(self):
        if not self.model:
            self.modelLoadedEvent.wait()
        return self.model

    def LoadModel(self, fileName=None, loadedModel=None):
        shipType = cfg.invtypes.Get(self.typeID)
        if shipType is not None:
            g = cfg.graphics.GetIfExists(shipType.graphicID)
            self.raceID = getattr(g, 'gfxRaceID', None)
        if fileName is None and loadedModel is None:
            if self.typeID is None:
                return
            if shipType.graphicID is not None:
                if shipType.Graphic():
                    fileName = shipType.GraphicFile()
                    if not (fileName.lower().endswith('.red')
                            or fileName.lower().endswith('.blue')):
                        filename_and_turret_type = split(fileName, ' ')
                        fileName = filename_and_turret_type[0]
        self.LogInfo('LoadModel', fileName)
        if fileName is None and loadedModel is None:
            self.LogError(
                'Error: Object type %s has invalid graphicFile, using graphicID: %s'
                % (self.typeID, cfg.invtypes.Get(self.typeID).graphicID))
            return
        model = None
        if fileName is not None and len(fileName) and loadedModel is None:
            try:
                model = blue.resMan.LoadObject(fileName)
            except:
                model = None
                sys.exc_clear()

        else:
            model = loadedModel
        if not model:
            log.LogError('Could not load model for spaceobject. FileName:',
                         fileName, ' id:', self.id, ' typeID:',
                         getattr(self, 'typeID', '?'))
            log.LogError('Type is:', cfg.invtypes.Get(self.typeID).typeName)
            return
        self.model = model
        if not hasattr(model, 'translationCurve'):
            self.LogError('LoadModel - Model in', fileName,
                          "doesn't have a translationCurve.")
        else:
            model.translationCurve = self
            model.rotationCurve = self
        model.name = '%d' % self.id
        if hasattr(model, 'useCurves'):
            model.useCurves = 1
        if self.model is not None and self.HasBlueInterface(
                self.model, 'IEveSpaceObject2'):
            scene = sm.StartService('sceneManager').GetRegisteredScene(
                'default')
            if scene is not None:
                scene.objects.append(self.model)
        else:
            raise RuntimeError('Invalid object loaded by spaceObject: %s' %
                               str(self.model))
        sm.StartService('FxSequencer').NotifyModelLoaded(self.id)
        self.modelLoadedEvent.set()

    def Assemble(self):
        pass

    def SetDefaultLOD(self):
        if self.model is None:
            return
        if self.model.__typename__ == 'TriLODGroup':
            if settings.user.ui.Get('lod', 1) == 0 and not self.forceLOD:
                self.model.lodBy = trinity.TRILB_NONE
                self.model.activeLevel = 0
            else:
                self.model.lodBy = trinity.TRITB_CAMERA_DISTANCE_FOV_HEIGHT
                self.SetLODGroupRadius()
                for i in range(8):
                    setattr(self.model, 'treshold' + str(i), 0.0)

                childrenCnt = len(self.model.children)
                if childrenCnt == 4:
                    self.model.treshold0 = 0.025
                    self.model.treshold1 = 0.025
                    self.model.treshold2 = 0.013
                elif childrenCnt == 3:
                    self.model.treshold0 = 0.08
                    self.model.treshold1 = 0.009
                else:
                    self.model.treshold0 = 0.025

    def SetStaticRotation(self):
        if self.model is None:
            return
        self.model.rotationCurve = None
        slimItem = sm.StartService('michelle').GetItem(self.id)
        if slimItem:
            rot = getattr(slimItem, 'dunRotation', None)
            if rot is not None:
                yaw, pitch, roll = rot
                quat = geo2.QuaternionRotationSetYawPitchRoll(
                    yaw * DEG2RAD, pitch * DEG2RAD, roll * DEG2RAD)
                if hasattr(self.model, 'rotation'):
                    if type(self.model.rotation) == types.TupleType:
                        self.model.rotation = quat
                    else:
                        self.model.rotation.SetYawPitchRoll(
                            yaw * DEG2RAD, pitch * DEG2RAD, roll * DEG2RAD)
                else:
                    self.model.rotationCurve = trinity.TriRotationCurve()
                    self.model.rotationCurve.value = quat

    def FindClosestMoonDir(self):
        bp = sm.StartService('michelle').GetBallpark()
        dist = 1e+100
        closestMoonID = None
        for ballID, slimItem in bp.slimItems.iteritems():
            if slimItem.groupID == const.groupMoon:
                test = bp.DistanceBetween(self.id, ballID)
                if test < dist:
                    dist = test
                    closestMoonID = ballID

        if closestMoonID is None:
            return Vector3([1.0, 0.0, 0.0])
        moon = bp.GetBall(closestMoonID)
        direction = Vector3(
            [self.x - moon.x, self.y - moon.y, self.z - moon.z])
        return direction

    def FindClosestPlanetDir(self):
        bp = sm.StartService('michelle').GetBallpark()
        dist = 1e+100
        closestPlanetID = None
        for ballID, slimItem in bp.slimItems.iteritems():
            if slimItem.groupID == const.groupPlanet:
                test = bp.DistanceBetween(self.id, ballID)
                if test < dist:
                    dist = test
                    closestPlanetID = ballID

        if closestPlanetID is None:
            return Vector3([1.0, 0.0, 0.0])
        planet = bp.GetBall(closestPlanetID)
        direction = Vector3(
            [self.x - planet.x, self.y - planet.y, self.z - planet.z])
        return direction

    def GetStaticDirection(self):
        slimItem = sm.StartService('michelle').GetItem(self.id)
        if slimItem is None:
            return
        if slimItem.groupID == const.groupMoonMining:
            direction = self.FindClosestMoonDir()
        else:
            direction = getattr(slimItem, 'dunDirection', None)
        return direction

    def SetStaticDirection(self):
        if self.model is None:
            return
        self.model.rotationCurve = None
        direction = self.GetStaticDirection()
        if direction is None:
            self.LogError(
                'Space object', self.id,
                'has no static direction defined - no rotation will be applied'
            )
            return
        self.AlignToDirection(direction)

    def AlignToDirection(self, direction):
        zaxis = Vector3(direction)
        if zaxis.Length2() > 0.0:
            Up = Vector3([0.0, 1.0, 0.0])
            zaxis.Normalize()
            xaxis = zaxis ^ Up
            if xaxis.Length2() == 0.0:
                zaxis += Vector3().Randomize(0.0001)
                zaxis.Normalize()
                xaxis = zaxis ^ Up
            xaxis.Normalize()
            yaxis = xaxis ^ zaxis
        else:
            self.LogError('Space object', self.id,
                          'has zero dunDirection. I cannot rotate it.')
            return
        mat = ((xaxis[0], xaxis[1], xaxis[2], 0.0), (yaxis[0], yaxis[1],
                                                     yaxis[2], 0.0),
               (-zaxis[0], -zaxis[1], -zaxis[2], 0.0), (0.0, 0.0, 0.0, 1.0))
        quat = geo2.QuaternionRotationMatrix(mat)
        if self.model and self.HasBlueInterface(
                self.model, 'IEveSpaceObject2') and hasattr(
                    self.model, 'modelRotationCurve'):
            if not self.model.modelRotationCurve:
                self.model.modelRotationCurve = trinity.TriRotationCurve(
                    0.0, 0.0, 0.0, 1.0)
            self.model.modelRotationCurve.value = quat
        else:
            self.model.rotationCurve = None

    def UnSync(self):
        if self.model is None:
            return
        startTime = long(random.random() * 123456.0 * 1234.0)
        scaling = 0.95 + random.random() * 0.1
        curves = timecurves.ReadCurves(self.model)
        timecurves.ResetTimeCurves(curves, startTime, scaling)

    def SetMiniballExplosions(self, gfx):
        if gfx is None:
            return
        if not self.HasBlueInterface(gfx, 'IEveSpaceObject2'):
            self.LogWarn(self.id,
                         'SetMiniBallExplosions called for old content!')
            return
        miniExplosions = [
            x for x in gfx.Find('trinity.EveTransform')
            if x.name == 'SmallExplosion'
        ]
        if len(self.miniBalls) > 0:
            for explosionTransform in miniExplosions:
                miniball = random.choice(self.miniBalls)
                explosionTransform.translation = (miniball.x, miniball.y,
                                                  miniball.z)

    def Display(self, display=1, canYield=True):
        if self.model is None:
            self.LogWarn('Display - No model')
            return
        if canYield:
            blue.synchro.Yield()
        if display and self.IsCloaked():
            if eve.session.shipid == self.id:
                sm.StartService('FxSequencer').OnSpecialFX(
                    self.id, None, None, None, None, None,
                    'effects.CloakNoAmim', 0, 1, 0, 5, 0)
            return
        if self.model:
            self.model.display = display

    def IsCloaked(self):
        return self.isCloaked

    def OnDamageState(self, damageState):
        pass

    def GetDamageState(self):
        return self.spaceMgr.ballpark.GetDamageState(self.id)

    def DoFinalCleanup(self):
        if not sm.IsServiceRunning('FxSequencer'):
            return
        sm.GetService('FxSequencer').RemoveAllBallActivations(self.id)
        self.ClearExplosion()
        if not self.released:
            self.explodeOnRemove = False
            self.Release()

    def ClearExplosion(self, model=None):
        if hasattr(self, 'gfx') and self.gfx is not None:
            self.RemoveAndClearModel(self.gfx)
            self.gfx = None
        if self.explosionModel is not None:
            if getattr(self, 'explosionDisplayBinding', False):
                self.explosionDisplayBinding.destinationObject = None
                self.explosionDisplayBinding = None
            self.RemoveAndClearModel(self.explosionModel)
            self.explosionModel = None

    def Release(self, origin=None):
        uthread.new(self._Release, origin)

    def _Release(self, origin=None):
        self.LogInfo('Release')
        if self.released:
            return
        self.released = True
        if self.explodeOnRemove:
            delay = self.Explode()
            if delay:
                delay = min(delay, 2000)
                blue.synchro.SleepSim(delay)
        self.Display(display=0, canYield=False)
        uthread.new(self.RemoveAndClearModel, self.model)
        self.audioEntities = []
        self.generalAudioEntity = None
        self.model = None
        self.spaceMgr = None

    def RemoveAndClearModel(self, model, scene=None):
        if model:
            if hasattr(model, 'translationCurve'):
                model.translationCurve = None
                model.rotationCurve = None
            if hasattr(model, 'observers'):
                for ob in model.observers:
                    ob.observer = None

        else:
            self.released = True
            return
        if scene is None:
            scene = sm.StartService('sceneManager').GetRegisteredScene(
                'default')
        if scene:
            scene.objects.fremove(model)

    def GetExplosionInfo(self, basePath=None):
        EXPLOSION_PATH = basePath or 'res:/fisfx/deathexplosion/death'
        RACEID_TO_NAME_MAP = {
            gfxRaceAmarr: 'amarr',
            gfxRaceCaldari: 'caldari',
            gfxRaceGallente: 'gallente',
            gfxRaceMinmatar: 'minmatar',
            gfxRaceJove: 'jove',
            gfxRaceAngel: 'angel',
            gfxRaceSleeper: 'sleeper',
            gfxRaceORE: 'ore',
            gfxRaceConcord: 'roguedrone',
            gfxRaceRogueDrone: 'roguedrone',
            gfxRaceSansha: 'sansha',
            gfxRaceSOCT: 'roguedrone',
            gfxRaceTalocan: 'roguedrone',
            gfxRaceGeneric: 'roguedrone'
        }
        name = RACEID_TO_NAME_MAP.get(self.raceID, 'roguedrone')
        size = '_m_'
        radius = getattr(self.model, 'boundingSphereRadius', self.radius)
        delay = 0
        scale = 1.0
        if radius < 20.0:
            size = '_d_'
            scale = radius / 20.0
        elif radius < 100.0:
            size = '_s_'
            delay = 100
            scale = radius / 100.0
        elif radius < 400.0:
            size = '_m_'
            delay = 250
            scale = radius / 400.0
        elif radius < 1500.0:
            size = '_l_'
            delay = 500
            scale = radius / 700.0
        elif radius < 6000.0:
            size = '_h_'
            delay = 1000
            scale = radius / 6000.0
        else:
            size = '_t_'
            delay = 2000
        path = EXPLOSION_PATH + size + name + '.red'
        info = (delay, scale)
        return (path, info)

    def Explode(self,
                explosionURL=None,
                scaling=1.0,
                managed=False,
                delay=0.0):
        self.LogInfo('Exploding')
        if self.exploded:
            return False
        sm.ScatterEvent('OnObjectExplode', self.GetModel())
        self.exploded = True
        delayedRemove = delay
        if settings.user.ui.Get('explosionEffectsEnabled', 1):
            gfx = None
            if managed:
                gfx = self.explosionManager.GetExplosion(
                    explosionURL, callback=self.ClearExplosion)
            else:
                if explosionURL is None:
                    self.LogError(
                        'explosionURL not set when calling Explode. Possibly wrongly authored content. typeID:',
                        self.typeID)
                    explosionURL, (delay, scaling) = self.GetExplosionInfo()
                explosionURL = explosionURL.replace('.blue', '.red').replace(
                    '/Effect/', '/Effect3/')
                gfx = trinity.Load(explosionURL)
                if not gfx:
                    self.LogError('Failed to load explosion: ', explosionURL,
                                  ' - using default')
                    gfx = trinity.Load(
                        'res:/Model/Effect/Explosion/entityExplode_large.red')
                if gfx.__bluetype__ == 'trinity.EveEffectRoot':
                    self.LogWarn(
                        'EveEffectRoot explosion not managed for %s. ExplosionManager circumvented.'
                        % explosionURL)
                    gfx.Start()
                elif gfx.__bluetype__ != 'trinity.EveRootTransform':
                    root = trinity.EveRootTransform()
                    root.children.append(gfx)
                    root.name = explosionURL
                    gfx = root
            gfx.translationCurve = self
            self.explosionModel = gfx
            scale = scaling
            gfx.scaling = (gfx.scaling[0] * scale, gfx.scaling[1] * scale,
                           gfx.scaling[2] * scale)
            scene = sm.StartService('sceneManager').GetRegisteredScene(
                'default')
            scene.objects.append(gfx)
        if self.wreckID is not None:
            wreckBall = sm.StartService('michelle').GetBall(self.wreckID)
            if wreckBall is not None:
                uthread.pool('Wreck::DisplayWreck', wreckBall.DisplayWreck,
                             500)
        return delayedRemove

    def SetLODGroupRadius(self):
        r = self.FindSimpleBoundingRadius(self.model.children[0])
        self.model.boundingSphereRadius = r
        self.boundingSphereRadius = r

    def FindSimpleBoundingRadius(self, transform):
        if hasattr(transform, 'object') and hasattr(
                transform.object,
                'vertexRes') and transform.object.vertexRes is not None:
            minbox = transform.object.vertexRes.meshBoxMin.CopyTo()
            maxbox = transform.object.vertexRes.meshBoxMax.CopyTo()
            minbox.TransformCoord(transform.localTransform)
            maxbox.TransformCoord(transform.localTransform)
            spear = maxbox - minbox
            r = spear.Length() * 0.5
            if r * 10.0 < self.radius:
                r = self.radius
            return r
        return self.radius

    def FindHierarchicalBoundingBox(self,
                                    transform,
                                    printout,
                                    parentMat=trinity.TriMatrix(),
                                    indent='',
                                    minx=1e+100,
                                    maxx=-1e+100,
                                    miny=1e+100,
                                    maxy=-1e+100,
                                    minz=1e+100,
                                    maxz=-1e+100,
                                    parentScale=trinity.TriVector(
                                        1.0, 1.0, 1.0)):
        transform.Update(blue.os.GetSimTime())
        if hasattr(transform, 'translation') and transform.__typename__ in (
                'TriTransform', 'TriSplTransform', 'TriLODGroup'):
            if transform.__typename__ == 'TriTransform':
                if transform.transformBase != trinity.TRITB_OBJECT:
                    return (minx, maxx, miny, maxy, minz, maxz)
            if hasattr(transform, 'object') and hasattr(
                    transform.object,
                    'vertexRes') and transform.object.vertexRes is not None:
                damin = transform.object.vertexRes.meshBoxMin.CopyTo()
                damax = transform.object.vertexRes.meshBoxMax.CopyTo()
                damin.TransformCoord(transform.localTransform)
                damax.TransformCoord(transform.localTransform)
                damin.TransformCoord(parentMat)
                damax.TransformCoord(parentMat)
                minx = min(minx, min(damin.x, damax.x))
                maxx = max(maxx, max(damin.x, damax.x))
                miny = min(miny, min(damin.y, damax.y))
                maxy = max(maxy, max(damin.y, damax.y))
                minz = min(minz, min(damin.z, damax.z))
                maxz = max(maxz, max(damin.z, damax.z))
            newmat = transform.localTransform.CopyTo()
            newmat.Multiply(parentMat)
            for child in transform.children:
                indent = indent + '  '
                minx, maxx, miny, maxy, minz, maxz = self.FindHierarchicalBoundingBox(
                    child, printout, newmat, indent, minx, maxx, miny, maxy,
                    minz, maxz, parentScale)

        return (minx, maxx, miny, maxy, minz, maxz)

    def FitBoosters(self, alwaysOn=False, enableTrails=True):
        if self.typeID is None:
            return
        if self.raceID is None:
            self.LogError(
                'SpaceObject type %s has invaldi raceID (not set!) ' %
                self.typeID)
            self.raceID = gfxRaceGeneric
        boosterResPath = BOOSTER_GFX_SND_RESPATHS[self.raceID][0]
        boosterSoundName = BOOSTER_GFX_SND_RESPATHS[self.raceID][1]
        boosterFxObj = trinity.Load(boosterResPath)
        if boosterFxObj is None:
            return
        if self.model is None:
            log.LogWarn(
                'No model to fit boosters to on spaceobject with id = ' +
                str(self.id))
            return
        if not hasattr(self.model, 'boosters'):
            log.LogWarn(
                'Model has no attribute boosters on spaceobject with id = ' +
                str(self.id))
            return
        self.model.boosters = boosterFxObj
        self.model.boosters.maxVel = self.maxVelocity
        self.model.RebuildBoosterSet()
        self.model.boosters.alwaysOn = alwaysOn
        if not enableTrails:
            self.model.boosters.trails = None
        boosterAudioLocators = filter(
            lambda node: node.name.startswith('locator_audio_booster'),
            self.model.locators)
        tmpEntity = None
        tmpParameter = None
        for audLocator in boosterAudioLocators:
            tlpo = trinity.TriObserverLocal()
            transform = audLocator.transform
            tlpo.front = (-transform[2][0], -transform[2][1], -transform[2][2])
            tlpo.position = (transform[3][0], transform[3][1], transform[3][2])
            if tmpEntity is None:
                tmpEntity = audio2.AudEmitter('ship_' + str(self.id) +
                                              '_booster')
                tmpParameter = audio2.AudParameter()
                tmpParameter.name = u'ship_speed'
                tmpEntity.parameters.append(tmpParameter)
                self.shipSpeedParameter = tmpParameter
            tlpo.observer = tmpEntity
            self.audioEntities.append(tmpEntity)
            self.model.observers.append(tlpo)

        boosterSize = 'f'
        if self.radius > 99:
            boosterSize = 'c'
            if self.radius > 309:
                boosterSize = 'bs'
                if self.radius > 1500:
                    boosterSize = 'dr'
                    if self.radius > 5000:
                        boosterSize = 't'
        self.boosterAudioEvent = '_'.join(
            [boosterSoundName, boosterSize, 'play'])
        if tmpEntity is not None:
            self.model.audioSpeedParameter = self.shipSpeedParameter
            baseVelocity = 1
            if util.IsNPC(self.id):
                baseVelocity = sm.StartService('godma').GetTypeAttribte(
                    self.typeID, const.attributeEntityCruiseSpeed)
            else:
                baseVelocity = sm.StartService('godma').GetTypeAttribute(
                    self.typeID, const.attributeMaxVelocity)
            if baseVelocity is None:
                baseVelocity = 1.0
            self.model.maxSpeed = baseVelocity
            tmpEntity.SendEvent(unicode(self.boosterAudioEvent))

    def SetupAmbientAudio(self, defaultSoundUrl=None):
        slimItem = sm.StartService('michelle').GetBallpark().GetInvItem(
            self.id)
        audioSvc = sm.GetService('audio')
        validResource = True
        soundUrl = None
        soundUrl = audioSvc.GetSoundUrlForType(slimItem)
        if soundUrl is not None:
            validResource = soundUrl.startswith('wise:/')
        if soundUrl is None or len(soundUrl) <= 0 or not validResource:
            if not validResource:
                self.LogWarn(
                    self.id,
                    'Specified sound resource is not a Wwise resource, either default sound or no sound will be played! (url = %s)'
                    % soundUrl)
            if defaultSoundUrl is None:
                return
            soundUrl = defaultSoundUrl
        self.PlayGeneralAudioEvent(unicode(soundUrl))

    def LookAtMe(self):
        pass

    def GetGeneralAudioEntity(self):
        if self.generalAudioEntity is None:
            if self.model is not None and hasattr(self.model, 'observers'):
                triObserver = trinity.TriObserverLocal()
                self.generalAudioEntity = audio2.AudEmitter('spaceObject_' +
                                                            str(self.id) +
                                                            '_general')
                triObserver.observer = self.generalAudioEntity
                self.audioEntities.append(self.generalAudioEntity)
                self.model.observers.append(triObserver)
            else:
                self.LogWarn(
                    self.id,
                    'unable to construct generalized audio entity - model has no observers property'
                )
        return self.generalAudioEntity

    def PlayGeneralAudioEvent(self, eventName):
        audEntity = self.GetGeneralAudioEntity()
        if audEntity is None:
            return
        if eventName.startswith('wise:/'):
            eventName = eventName[6:]
        self.LogInfo(self.id, 'playing audio event', eventName,
                     'on generalized emitter')
        audEntity.SendEvent(unicode(eventName))
class FakeBall(decometaclass.WrapBlueClass('destiny.ClientBall')):
    """
    FakeBall is a class to wrap client balls just so we have a __dict__ on destiny balls
    """
    pass