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

ExplosionManager.py (8285B)


      1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\client\script\environment\spaceObject\ExplosionManager.py
      2 from __future__ import print_function
      3 from collections import deque
      4 import blue
      5 import trinity
      6 import geo2
      7 import telemetry
      8 import uthread
      9 import random
     10 import carbon.common.script.util.logUtil as log
     11 from tacticalNavigation.ballparkFunctions import AddClientBall, RemoveClientBall
     12 SECOND = 10000000
     13 
     14 class Singleton(type):
     15 
     16     def __init__(cls, mcs, bases, dic):
     17         super(Singleton, cls).__init__(mcs, bases, dic)
     18         cls.instance = None
     19 
     20     def __call__(cls, *args, **kw):
     21         if cls.instance is None:
     22             cls.instance = super(Singleton, cls).__call__(*args, **kw)
     23         return cls.instance
     24 
     25 
     26 class PooledExplosion:
     27 
     28     def __init__(self, path):
     29         self.path = path
     30         self.refCount = 0
     31         self.timestamp = -1
     32         self.timeoutCountdown = 0
     33         self.total = 1
     34         self.active = 0
     35         self.maxActiveTick = 0
     36         self.inactive = 1
     37         self.maxRecentUsed = deque([1], 30)
     38         self.totalLoads = 1
     39         self.pool = [trinity.Load(self.path)]
     40         self.effectDuration = self.pool[0].duration
     41         if self.effectDuration == -1:
     42             self.effectDuration = 10
     43         self.effectDuration = self.effectDuration * SECOND
     44         self.boundingSphereRadius = self.pool[0].boundingSphereRadius
     45 
     46     def GetDuration(self):
     47         return self.effectDuration
     48 
     49     def AddRef(self, count):
     50         self.refCount += count
     51 
     52     def DecRef(self, count):
     53         self.refCount -= count
     54 
     55     def _AddActive(self, count):
     56         self.active += count
     57         self.maxActiveTick = max(self.maxActiveTick, self.active)
     58 
     59     def Pop(self):
     60         self._AddActive(1)
     61         if self.inactive > 0:
     62             self.inactive -= 1
     63             return self.pool.pop()
     64         self.total += 1
     65         self.totalLoads += 1
     66         return trinity.Load(self.path)
     67 
     68     def Push(self, explosion):
     69         self.pool.append(explosion)
     70         self._AddActive(-1)
     71         self.inactive += 1
     72 
     73     def PrunePool(self, timestamp):
     74         if self.refCount > 0:
     75             self.timestamp = -1
     76         self.maxRecentUsed.append(self.maxActiveTick)
     77         self.maxActiveTick = 0
     78         recentMax = max(self.maxRecentUsed)
     79         if recentMax < self.total:
     80             recentMax = min(self.total - recentMax, 4)
     81             self.total -= recentMax
     82             self.inactive -= recentMax
     83             del self.pool[:recentMax]
     84         if self.refCount <= 0:
     85             if self.timestamp < 0:
     86                 self.timestamp = timestamp
     87             if timestamp - self.timestamp > 15 * SECOND:
     88                 return True
     89         return False
     90 
     91 
     92 class ExplosionManager(object):
     93     __metaclass__ = Singleton
     94 
     95     def __init__(self, limit = 100):
     96         self.queue = []
     97         self.pooledExplosions = {}
     98         self.ageLimit = 20 * SECOND
     99         self.limit = limit
    100         self.running = True
    101         self.Start()
    102 
    103     def Run(self):
    104         while self.running:
    105             blue.synchro.SleepSim(1000)
    106             self._Prune()
    107 
    108     def Preload(self, path, count = 1):
    109         if path not in self.pooledExplosions:
    110             self.pooledExplosions[path] = PooledExplosion(path)
    111         self.pooledExplosions[path].AddRef(count)
    112 
    113     def Cancel(self, path, count = 1):
    114         if path not in self.pooledExplosions:
    115             log.LogWarn('ExplosionManager::Cancel ' + path + ' not loaded.')
    116             return
    117         self.pooledExplosions[path].DecRef(count)
    118 
    119     @telemetry.ZONE_METHOD
    120     def GetExplosion(self, path, scale = 1.0, preloaded = False, callback = None):
    121         if path not in self.pooledExplosions:
    122             if preloaded:
    123                 log.LogWarn('ExplosionManager::GetExplosion ' + path + ' not loaded.')
    124             self.Preload(path)
    125         elif not preloaded:
    126             self.pooledExplosions[path].AddRef(1)
    127         explosion = self.pooledExplosions[path].Pop()
    128         explosion.scaling = (scale, scale, scale)
    129         explosion.Start()
    130         self._Append(callback, explosion, self.pooledExplosions[path])
    131         return explosion
    132 
    133     def GetBoundingSphereRadius(self, path):
    134         if path not in self.pooledExplosions:
    135             log.LogWarn('ExplosionManager::GetBoundingSphereRadius ' + path + ' not loaded.')
    136             self.Preload(path, count=0)
    137         return self.pooledExplosions[path].boundingSphereRadius
    138 
    139     def _Append(self, callback, model, pool):
    140         delay = pool.GetDuration()
    141         if delay > self.ageLimit:
    142             delay = self.ageLimit
    143         stamp = blue.os.GetSimTime() + delay
    144         self.queue.append((stamp,
    145          callback,
    146          model,
    147          pool))
    148         if len(self.queue) > self.limit:
    149             self._Delete(self.queue.pop(0))
    150 
    151     def _Prune(self):
    152         if not len(self.queue) and not len(self.pooledExplosions):
    153             return
    154         now = blue.os.GetSimTime()
    155         if len(self.queue):
    156             self.queue.sort()
    157             while True:
    158                 blue.synchro.Yield()
    159                 now = blue.os.GetSimTime()
    160                 if not len(self.queue) or not self.running:
    161                     break
    162                 if self.queue[0][0] < now:
    163                     self._Delete(self.queue.pop(0))
    164                 else:
    165                     break
    166 
    167         delKeys = []
    168         for val in self.pooledExplosions.itervalues():
    169             if val.PrunePool(now):
    170                 delKeys.append(val.path)
    171 
    172         for key in delKeys:
    173             del self.pooledExplosions[key]
    174 
    175     def _Delete(self, item):
    176         if item is not None:
    177             stamp, callback, model, pool = item
    178             if model is None:
    179                 log.LogError('ExplosionManager::_Delete item has no model')
    180             if pool is None:
    181                 log.LogError('ExplosionManager::_Delete item has no pool')
    182             if callback is not None:
    183                 callback(model)
    184             model.Stop()
    185             pool.Push(model)
    186             pool.DecRef(1)
    187 
    188     def GetCount(self):
    189         return len(self.queue)
    190 
    191     def SetLimit(self, limit):
    192         self.limit = limit
    193 
    194     def Inspect(self):
    195         print(self.queue)
    196 
    197     def Start(self):
    198         self.running = True
    199         uthread.new(self.Run)
    200 
    201     def Stop(self):
    202         self.running = False
    203 
    204     @staticmethod
    205     def SetUpChildExplosion(explosionModel, explosionLocatorSets):
    206         explosionChildren = explosionModel.Find('trinity.EveChildExplosion', 2)
    207         if explosionLocatorSets is not None:
    208             transforms = []
    209             locators = [ (each[0], each[1]) for each in (explosionLocatorSets.locators if explosionLocatorSets else []) ]
    210             random.shuffle(locators)
    211             for position, direction in locators:
    212                 rotation = geo2.QuaternionRotationArc((0, 1, 0), direction)
    213                 transform = geo2.MatrixTransformation((0, 0, 0), (0, 0, 0, 1), (1, 1, 1), (0, 0, 0), rotation, position)
    214                 transforms.append(transform)
    215 
    216             for each in explosionChildren:
    217                 each.SetLocalExplosionTransforms(transforms)
    218 
    219         for each in explosionChildren:
    220             each.Play()
    221 
    222     @staticmethod
    223     def PlayClientSideExplosionBall(gfxResPath, worldPos, rotation, explosionLocatorSets = None):
    224         scene = sm.GetService('space').GetScene()
    225         clientBall = AddClientBall(worldPos)
    226         explosionModel = trinity.Load(gfxResPath)
    227         explosionModel.translationCurve = clientBall
    228         explosionModel.rotation = rotation
    229         ExplosionManager.SetUpChildExplosion(explosionModel, explosionLocatorSets)
    230         scene.objects.append(explosionModel)
    231         secTillBallRemove = 60.0
    232         if isinstance(explosionModel, trinity.EveEffectRoot2):
    233             for child in explosionModel.effectChildren:
    234                 secTillBallRemove = max(secTillBallRemove, child.globalDuration)
    235 
    236         uthread.new(ExplosionManager._DelayedBallRemove, clientBall, explosionModel, secTillBallRemove)
    237 
    238     @staticmethod
    239     def _DelayedBallRemove(clientBall, explosionModel, secTillBallRemove):
    240         blue.synchro.Sleep(secTillBallRemove * 1000)
    241         scene = sm.GetService('space').GetScene()
    242         scene.objects.fremove(explosionModel)
    243         RemoveClientBall(clientBall)