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
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)
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)
class DistrictBall(decometaclass.WrapBlueClass('destiny.ClientBall')): def __init__(self): self.model = trinity.EveRootTransform()
#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')
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
class FakeBall(decometaclass.WrapBlueClass('destiny.ClientBall')): pass
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)
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)
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