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

planet.py (18293B)


      1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\client\script\environment\spaceObject\planet.py
      2 import random
      3 import datetime
      4 import math
      5 import blue
      6 import evetypes
      7 import trinity
      8 import uthread
      9 import pytelemetry.zoning as telemetry
     10 import eve.common.lib.appConst as appConst
     11 import carbon.common.lib.const as const
     12 from eve.client.script.environment.spaceObject.spaceObject import SpaceObject
     13 from eve.client.script.parklife.environmentSvc import GetEnvironmentService
     14 import inventorycommon.typeHelpers
     15 from eveuniverse.security import is_low_sec_or_higher_solar_system
     16 from fsdBuiltData.common.graphicIDs import GetGraphicFile
     17 import evegraphics.effects as gfxeffects
     18 from moonmining.const import MOON_CRATER_SLIMITEM_NAME
     19 from sovereignty.resource.shared.planetary_resources_cache import DataUnavailableError
     20 AURORA_PERIOD = (302400.0, 561600.0)
     21 AURORA_DURATION = (510.0, 930.0)
     22 
     23 def _FindAuroraCurveSet(model):
     24     for cs in model.Find('trinity.TriCurveSet'):
     25         if cs.name == 'PlayAurora':
     26             return cs
     27 
     28 
     29 def _StartAurora(model, rand, length, offset):
     30     cs = _FindAuroraCurveSet(model)
     31     if not cs:
     32         return
     33     seedCurve = cs.curves.FindByName('AuroraSeed')
     34     if seedCurve:
     35         seedCurve.value = (rand.random(),
     36          rand.random(),
     37          rand.random(),
     38          rand.random())
     39     cs.scale = 1.0 / length
     40     cs.PlayFrom(offset * cs.scale)
     41 
     42 
     43 def _AuroraTasklet(itemID, model):
     44     if not _FindAuroraCurveSet(model.object):
     45         return
     46     r = random.Random()
     47     r.seed(itemID)
     48     period = blue.os.TimeFromDouble(r.uniform(*AURORA_PERIOD))
     49     while model.object:
     50         t = blue.os.GetWallclockTime()
     51         phase = t % period
     52         r.seed(itemID + t / period)
     53         duration = blue.os.TimeFromDouble(r.uniform(*AURORA_DURATION))
     54         if phase < duration:
     55             _StartAurora(model.object, r, blue.os.TimeAsDouble(duration), blue.os.TimeAsDouble(phase))
     56         wait = blue.os.TimeAsDouble(period - phase)
     57         blue.synchro.Sleep(min(wait, 82800) * 1000)
     58 
     59 
     60 def GetTimeUntilNextAurora(itemID):
     61     r = random.Random()
     62     r.seed(itemID)
     63     period = blue.os.TimeFromDouble(r.uniform(*AURORA_PERIOD))
     64     t = blue.os.GetWallclockTime()
     65     phase = t % period
     66     r.seed(itemID + t / period)
     67     duration = blue.os.TimeFromDouble(r.uniform(*AURORA_DURATION))
     68     if phase < duration:
     69         return 0.0
     70     return blue.os.TimeAsDouble(period - phase)
     71 
     72 
     73 UNLOADED = 0
     74 TEXTURES_UNLOADED = 1
     75 LOADED = 2
     76 
     77 class Planet(SpaceObject):
     78     __notifyevents__ = ['OnSlimItemUpdated']
     79 
     80     def __init__(self):
     81         SpaceObject.__init__(self)
     82         self.isInflightPlanet = True
     83         self.attributes = None
     84         self.largeTextures = False
     85         self._crater = None
     86         self.itemID = None
     87         self.impactDirection = (0, 0, 0)
     88         self.impactStartTime = 0
     89         self.chunk = None
     90         self._auroraTasklet = None
     91         if not hasattr(self, 'typeData'):
     92             self.typeData = {}
     93         self.OnSlimItemUpdated(self.typeData.get('slimItem'))
     94         sm.RegisterNotify(self)
     95 
     96     def OnSlimItemUpdated(self, item):
     97         celestialEffect = getattr(item, 'celestialEffect', None)
     98         if celestialEffect is not None:
     99             effectGuid, graphicInfo = celestialEffect
    100             self.logger.debug('Planet.OnSlimItemUpdated found celestialEffect %s %s', effectGuid, graphicInfo)
    101             sm.ScatterEvent('OnSpecialFX', self.id, None, None, None, None, effectGuid, False, 1, True, graphicInfo=graphicInfo)
    102         if getattr(item, MOON_CRATER_SLIMITEM_NAME, None) is not None:
    103             self.impactDirection, self.impactStartTime, chunkID = getattr(item, MOON_CRATER_SLIMITEM_NAME)
    104             self.chunk = sm.GetService('michelle').GetBall(chunkID)
    105             if self.chunk is None or not hasattr(self.chunk, 'GetModel'):
    106                 return
    107             if self.chunk.GetModel() is None:
    108                 self.chunk.RegisterForModelLoad(self._SpawnImpactCraterFromSlimItemUpdate)
    109             else:
    110                 self._SpawnImpactCraterFromSlimItemUpdate()
    111 
    112     def Display(self, display = 1, canYield = True):
    113         pass
    114 
    115     def LoadModel(self, fileName = None, loadedModel = None, notify = True, addToScene = True):
    116         uthread.new(self.LoadPlanet)
    117 
    118     def _IsMoon(self):
    119         return evetypes.GetGroupID(self.typeID) == appConst.groupMoon
    120 
    121     def _ApplyPlanetRotation(self, model):
    122         if self._IsMoon():
    123             return
    124         rotationDirection = 1
    125         if self.id % 2:
    126             rotationDirection = -1
    127         r = random.Random()
    128         r.seed(self.id)
    129         rotationTime = r.random() * 2000 + 3000
    130         curve = trinity.Tr2CurveEulerRotation()
    131         curve.SetExtrapolation(trinity.Tr2CurveExtrapolation.CYCLE)
    132         curve.yaw.AddKey(0.0, math.radians(1.0), trinity.Tr2CurveInterpolation.LINEAR)
    133         curve.yaw.AddKey(rotationTime, math.radians(rotationDirection * 360.0), trinity.Tr2CurveInterpolation.LINEAR)
    134         tilt = r.random() * 60.0 - 30.0
    135         curve.pitch.AddKey(0.0, math.radians(1.0))
    136         curve.pitch.AddKey(6000.0, math.radians(tilt))
    137         curve.pitch.AddKey(12000.0, 0.0)
    138         model.rotationCurve = trinity.Tr2RotationAdapter()
    139         model.rotationCurve.curve = curve
    140 
    141     def _GetModelPath(self):
    142         graphicFile = self.typeData.get('graphicFile')
    143         if self.largeTextures:
    144             graphicFile = graphicFile.replace('.red', '_HI.red')
    145         return graphicFile
    146 
    147     @telemetry.ZONE_METHOD
    148     def LoadPlanet(self, itemID = None, forPhotoService = False, rotate = True, hiTextures = False, notifyLoaded = True):
    149         if itemID is None:
    150             itemID = self.id
    151         self.itemID = itemID
    152         fsdData = cfg.mapSolarSystemContentCache.celestials[self.itemID]
    153         if self.attributes is None:
    154             self.attributes = fsdData.planetAttributes
    155         if hasattr(fsdData, 'environmentTemplateID'):
    156             GetEnvironmentService().AddBallEnvironment(self, fsdData.environmentTemplateID)
    157         self.largeTextures = hiTextures
    158         self.isInflightPlanet = not forPhotoService
    159         self.model = trinity.Load(self._GetPresetPath())
    160         if self.model is None:
    161             self.logger.error('No planet was loaded! %s', self._GetPresetPath())
    162             return
    163         self._SetupPlanet(planet=self.model, itemID=itemID, rotate=rotate)
    164         self.model.StartControllers()
    165         if self.isInflightPlanet:
    166             scene = self.spaceMgr.GetScene()
    167             if scene is not None:
    168                 scene.planets.append(self.model)
    169         if notifyLoaded:
    170             self.NotifyModelLoaded()
    171 
    172     def GetTimeUntilNextAurora(self):
    173         return GetTimeUntilNextAurora(self.itemID)
    174 
    175     def ForceAuroraNow(self):
    176         if self._auroraTasklet:
    177             self._auroraTasklet.kill()
    178             self._auroraTasklet = None
    179         duration = random.uniform(*AURORA_DURATION)
    180         _StartAurora(self.model, random, duration, duration / 4.0)
    181 
    182     def _SetupTraffic(self, itemID):
    183         bp = getattr(self, 'ballpark', None)
    184         populationLevel = 1.0
    185         if bp is None or self.model is None:
    186             return
    187         solarSystemId = bp.solarsystemID
    188         if is_low_sec_or_higher_solar_system(solarSystemId):
    189             populationLevel = 10.0
    190         else:
    191             try:
    192                 colonyResourcesSvc = sm.GetService('sovereigntyResourceSvc')
    193                 workforce = colonyResourcesSvc.GetPlanetWorkforceProduction(itemID)
    194                 if workforce > 0 and workforce is not None:
    195                     workforceConfigurations = colonyResourcesSvc.GetAllPlanetWorkforceProduction()
    196                     max_workforce = max(workforceConfigurations.values())
    197                     if max_workforce > 0:
    198                         populationLevel = float(workforce) / float(max_workforce) * 10
    199                 elif itemID % 100 > 0:
    200                     populationLevel = itemID % 100 / 10
    201             except DataUnavailableError as e:
    202                 self.logger.warning('planet._SetupTraffic failed to get colony data')
    203 
    204         if self.model is not None and hasattr(self.model, 'SetControllerVariable'):
    205             self.model.SetControllerVariable('populationLevel', int(populationLevel))
    206 
    207     @telemetry.ZONE_METHOD
    208     def _SetupPlanet(self, planet, itemID, rotate):
    209         if rotate:
    210             self._ApplyPlanetRotation(planet)
    211         planet.translationCurve = self
    212         planet.scaling = (self.radius, self.radius, self.radius)
    213         planet.radius = self.radius
    214         planet.name = '%d' % itemID
    215         self.model.SetControllerVariable('radius', self.radius)
    216         if self.typeID == appConst.typePlanetOcean or self.typeID == appConst.typePlanetSandstorm or self.typeID == appConst.typePlanetEarthlike:
    217             uthread.new(self._SetupTraffic, itemID)
    218         gfx = inventorycommon.typeHelpers.GetGraphic(self.typeID)
    219         if hasattr(gfx, 'albedoColor') and gfx.albedoColor:
    220             planet.albedoColor = tuple(gfx.albedoColor)
    221         if hasattr(gfx, 'emissiveColor') and gfx.emissiveColor:
    222             planet.emissiveColor = tuple(gfx.emissiveColor)
    223         self._ModifyPlanetShader()
    224         self.SetEffectParameters()
    225         sm.GetService('audio').SetupPlanet3DAudio(planet, self.typeID)
    226         self._auroraTasklet = uthread.new(_AuroraTasklet, itemID, blue.BluePythonWeakRef(planet))
    227 
    228     def Release(self, origin = None):
    229         if self._auroraTasklet:
    230             self._auroraTasklet.kill()
    231             self._auroraTasklet = None
    232         scene = self.spaceMgr.GetScene()
    233         if scene:
    234             scene.planets.fremove(self.model)
    235         SpaceObject.Release(self, 'Planet')
    236 
    237     def RemoveFromScene(self, model, scene = None):
    238         pass
    239 
    240     @staticmethod
    241     def GetPlanetByID(itemID, typeID):
    242         planet = Planet()
    243         planet.logger.debug('GetPlanetByID called')
    244         planet.typeID = typeID
    245         planet.LoadPlanet(itemID, True, notifyLoaded=False)
    246         return planet
    247 
    248     def SetEffectParameters(self):
    249         planetParent = self._GetPlanetParent()
    250         if not planetParent:
    251             return
    252         for effect in planetParent.Find('trinity.Tr2Effect'):
    253             param1 = trinity.TriTextureParameter()
    254             param1.name = 'NormalHeight1'
    255             param1.resourcePath = GetGraphicFile(self._GetHeightMap1())
    256             effect.resources.append(param1)
    257             param2 = trinity.TriTextureParameter()
    258             param2.name = 'NormalHeight2'
    259             param2.resourcePath = GetGraphicFile(self._GetHeightMap2())
    260             effect.resources.append(param2)
    261             param3 = trinity.Tr2FloatParameter()
    262             param3.name = 'Random'
    263             param3.value = float(self.itemID % 100)
    264             effect.parameters.append(param3)
    265             ind = -1
    266             for r in range(0, len(effect.resources)):
    267                 resource = effect.resources[r]
    268                 if resource.name.lower() == 'heightmap':
    269                     ind = r
    270 
    271             if ind > 0:
    272                 effect.resources.removeAt(ind)
    273 
    274     def _GetAttribute(self, name):
    275         if self.attributes is None:
    276             raise RuntimeError('Planet was not loaded. Can not get population of an unloaded planet.')
    277         try:
    278             return getattr(self.attributes, name)
    279         except:
    280             self.logger.exception('Could not get attribute population. %s', str(self.attributes))
    281 
    282     def _GetPopulation(self):
    283         return self._GetAttribute('population')
    284 
    285     def _GetShaderPreset(self):
    286         return self._GetAttribute('shaderPreset')
    287 
    288     def _GetPresetPath(self):
    289         presetPath = self._GetModelPath() if self._GetShaderPreset() is None else GetGraphicFile(self._GetShaderPreset())
    290         return presetPath
    291 
    292     def _GetHeightMap1(self):
    293         return self._GetAttribute('heightMap1')
    294 
    295     def _GetHeightMap2(self):
    296         return self._GetAttribute('heightMap2')
    297 
    298     def _GetPlanetParent(self):
    299         return self.model.effectChildren.FindByName('Planet')
    300 
    301     def _GetPlanetShaderResources(self, paramName = ''):
    302         retList = []
    303         if not self.model:
    304             return retList
    305         planetParent = self.model
    306         if planetParent is not None:
    307             for param in planetParent.Find('trinity.TriTextureParameter'):
    308                 if paramName == param.name or paramName == '':
    309                     retList.append(param)
    310 
    311         return retList
    312 
    313     def _ModifyPlanetShaderParameter(self, paramName, x = None, y = None, z = None, w = None):
    314         if not self.model:
    315             return
    316         planetParent = self._GetPlanetParent()
    317         if not planetParent:
    318             return
    319         for effect in planetParent.Find('trinity.Tr2Effect'):
    320             for i, param in enumerate(effect.constParameters):
    321                 name, value = param
    322                 if name == paramName:
    323                     value = list(value)
    324                     if x is not None:
    325                         value[0] = x
    326                     if y is not None:
    327                         value[1] = y
    328                     if z is not None:
    329                         value[2] = z
    330                     if w is not None:
    331                         value[3] = w
    332                     effect.constParameters.removeAt(i)
    333                     effect.constParameters.append((name, tuple(value)))
    334                     effect.RebuildCachedData()
    335                     break
    336 
    337             for param in effect.parameters:
    338                 if param.name == paramName:
    339                     if isinstance(param, trinity.Tr2FloatParameter):
    340                         if x is not None:
    341                             param.value = x
    342                     else:
    343                         if x is not None:
    344                             param.x = x
    345                         if y is not None:
    346                             param.y = y
    347                         if z is not None:
    348                             param.z = z
    349                         if w is not None:
    350                             param.w = w
    351                     break
    352 
    353     def _ModifyPlanetShader(self):
    354         if self.typeID == appConst.typePlanetEarthlike or self.typeID == appConst.typePlanetSandstorm:
    355             self.RandomizeShaderClouds()
    356         if self.typeID is appConst.typePlanetOcean or self.typeID is appConst.typePlanetEarthlike:
    357             self.AdjustShaderPopulation()
    358 
    359     def AdjustShaderPopulation(self):
    360         if self._GetPopulation() == 0:
    361             for textureParamName in ['CityLight', 'CityDistributionTexture', 'CityDistributionMask']:
    362                 textureParamList = self._GetPlanetShaderResources(textureParamName)
    363                 for textureParam in textureParamList:
    364                     textureParam.resourcePath = ''
    365 
    366             self._ModifyPlanetShaderParameter('CoverageFactors', w=0.0)
    367 
    368     def RandomizeShaderClouds(self):
    369         now = datetime.datetime.now()
    370         r = random.Random()
    371         r.seed(now.year + now.month * 30 + now.day + self.itemID)
    372         val = r.randint(1, 5)
    373         useDense = val % 5 == 0
    374         if self.typeID == appConst.typePlanetEarthlike:
    375             if useDense:
    376                 cloudMapIDs = (3857, 3858, 3859, 3860)
    377                 cloudCapMapIDs = (3861, 3862, 3863, 3864)
    378             else:
    379                 cloudMapIDs = (3848, 3849, 3851, 3852)
    380                 cloudCapMapIDs = (3853, 3854, 3855, 3856)
    381         else:
    382             cloudMapIDs = (3956, 3957, 3958, 3959)
    383             cloudCapMapIDs = (3960, 3961, 3962, 3963)
    384         cloudMapIdx = r.randint(0, 3)
    385         cloudCapMapIdx = r.randint(0, 3)
    386         cloudCapTexResPath = GetGraphicFile(cloudCapMapIDs[cloudCapMapIdx])
    387         cloudTexResPath = GetGraphicFile(cloudMapIDs[cloudMapIdx])
    388         cloudCapParamList = self._GetPlanetShaderResources('CloudCapTexture')
    389         for cloudCapParam in cloudCapParamList:
    390             cloudCapParam.resourcePath = cloudCapTexResPath
    391 
    392         cloudParamList = self._GetPlanetShaderResources('CloudsTexture')
    393         for cloudParam in cloudParamList:
    394             cloudParam.resourcePath = cloudTexResPath
    395 
    396         cloudsBrightness = r.random() * 0.4 + 0.6
    397         cloudsTransparency = r.random() * 2.0 + 1.0
    398         self._ModifyPlanetShaderParameter('CloudsFactors', y=cloudsBrightness, z=cloudsTransparency)
    399 
    400     def SpawnImpactCrater(self, direction, size, timeFromStart):
    401         uthread.new(self._SpawnImpactCrater, direction, size, timeFromStart)
    402 
    403     def _SpawnImpactCrater(self, direction, size, timeFromStart):
    404         self.RemoveImpactCrater()
    405         radians = None
    406         if size is not None:
    407             size = max(0.0, min(1.0, 0.5 * size / self.radius))
    408             radians = math.asin(size) * 2
    409         pin = trinity.Load('res:/fisfx/structure/moonmining/moonmining_surfacecrater_01a.red')
    410         pin.centerNormal = direction
    411         if radians is not None:
    412             pin.pinRadius = radians
    413             pin.pinMaxRadius = radians
    414         self._crater = pin
    415         while self.GetModel() is None or len(self.GetModel().effectChildren) < 1:
    416             blue.synchro.Sleep(100)
    417 
    418         for curveSet in self._crater.curveSets:
    419             curveSet.PlayFrom(timeFromStart)
    420 
    421         self.GetModel().effectChildren.append(self._crater)
    422 
    423     def RemoveImpactCrater(self):
    424         model = self.GetModel()
    425         if model is not None and self._crater is not None:
    426             if self._crater in model.effectChildren:
    427                 model.effectChildren.remove(self._crater)
    428             self._crater = None
    429 
    430     def _SpawnImpactCraterFromSlimItemUpdate(self):
    431         currentSimTime = blue.os.GetSimTime()
    432         size = 2.0 * self.chunk.GetModel().boundingSphereRadius
    433         self.SpawnImpactCrater(self.impactDirection, size, float((currentSimTime - self.impactStartTime) / const.SEC))
    434 
    435     def _ApplyCraterEffectAttributes(self):
    436         if not self.model:
    437             return
    438         planetParent = self._GetPlanetParent()
    439         if not planetParent:
    440             return
    441         for effect in planetParent.Find('trinity.Tr2Effect'):
    442             gfxeffects.ApplyEffectOverride(self._crater.pinEffect, effect)
    443 
    444     def SetImpactIntensity(self, value):
    445         if self._crater is None:
    446             return
    447         effect = self._crater.pinEffect
    448         gfxeffects.SetParameterComponentValue(effect, 'IntensityParameters', value, componentIndex=0)