paperDollLOD.py (9572B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\client\script\paperDoll\paperDollLOD.py 2 import blue 3 import trinity 4 import uthread 5 import weakref 6 import log 7 import locks 8 import time 9 from eve.common.script.paperDoll.paperDollConfiguration import PerformanceOptions 10 LoadingStubPath = 'res:/Graphics/Character/Global/LowLODs/Female/BasicFemale/BasicFemale.red' 11 12 class LodQueue(object): 13 instance = None 14 magicLOD = 99 15 16 class QueueEntry: 17 18 def __init__(self, avatarBluePythonWeakRef, dollWeakref, factoryWeakref, lodWanted): 19 self.avatar = avatarBluePythonWeakRef 20 self.doll = dollWeakref 21 self.factory = factoryWeakref 22 self.lodWanted = lodWanted 23 self.timeAddToQueue = time.time() 24 self.timeUpdateStarted = 0 25 26 def __init__(self): 27 self.queue = [] 28 self.inCallback = False 29 self.updateEvent = locks.Event(name='LodQueueEvent') 30 self.__freezeQueue = False 31 uthread.new(LodQueue.QueueMonitorThread, weakref.ref(self)) 32 self.queueSizeStat = blue.statistics.Find('paperDoll/queueSize') 33 if not self.queueSizeStat: 34 self.queueSizeStat = blue.CcpStatisticsEntry() 35 self.queueSizeStat.name = 'paperDoll/queueSize' 36 self.queueSizeStat.type = 1 37 self.queueSizeStat.resetPerFrame = False 38 self.queueSizeStat.description = 'The length of the LOD switching queue' 39 blue.statistics.Register(self.queueSizeStat) 40 self.queueActiveUpStat = blue.statistics.Find('paperDoll/queueActiveUp') 41 if not self.queueActiveUpStat: 42 self.queueActiveUpStat = blue.CcpStatisticsEntry() 43 self.queueActiveUpStat.name = 'paperDoll/queueActiveUp' 44 self.queueActiveUpStat.type = 1 45 self.queueActiveUpStat.resetPerFrame = False 46 self.queueActiveUpStat.description = 'Number of LOD switches to higher quality in progress' 47 blue.statistics.Register(self.queueActiveUpStat) 48 self.queueActiveDownStat = blue.statistics.Find('paperDoll/queueActiveDown') 49 if not self.queueActiveDownStat: 50 self.queueActiveDownStat = blue.CcpStatisticsEntry() 51 self.queueActiveDownStat.name = 'paperDoll/queueActiveDown' 52 self.queueActiveDownStat.type = 1 53 self.queueActiveDownStat.resetPerFrame = False 54 self.queueActiveDownStat.description = 'Number of LOD switches to lower quality in progress' 55 blue.statistics.Register(self.queueActiveDownStat) 56 57 def getFreezeQueue(self): 58 return self.__freezeQueue 59 60 def setFreezeQueue(self, freeze): 61 self.__freezeQueue = freeze 62 LodQueue.OnDollUpdateDoneStatic() 63 64 freezeQueue = property(getFreezeQueue, setFreezeQueue) 65 66 def __del__(self): 67 self.updateEvent.set() 68 69 @staticmethod 70 def OnDollUpdateDoneStatic(): 71 if LodQueue.instance is None: 72 return 73 LodQueue.instance.updateEvent.set() 74 75 @staticmethod 76 def QueueMonitorThread(weakSelf): 77 while weakSelf(): 78 weakSelf().updateEvent.wait() 79 wakeUpTime = time.time() 80 self = weakSelf() 81 if self is None: 82 break 83 self.updateEvent.clear() 84 busyUp, busyDown = self.UpdateQueue(wakeUpTime) 85 if not self.__freezeQueue: 86 maxBusyUp = PerformanceOptions.maxLodQueueActiveUp 87 maxBusyDown = PerformanceOptions.maxLodQueueActiveDown 88 scan = 0 89 max = len(self.queue) 90 while busyDown < maxBusyDown and busyUp < maxBusyUp and scan < max: 91 doll = self.queue[scan].doll() 92 if doll is not None and not doll.busyUpdating: 93 doll = self.queue[scan].doll() 94 goingUp = True 95 if doll is not None: 96 goingUp = self.queue[scan].lodWanted < doll.overrideLod 97 if self.ProcessRequest(self.queue[scan], allowUp=busyUp < maxBusyUp): 98 if goingUp: 99 busyUp = busyUp + 1 100 else: 101 busyDown = busyDown + 1 102 scan = scan + 1 103 104 self.queueActiveUpStat.Set(busyUp) 105 self.queueActiveDownStat.Set(busyDown) 106 107 def UpdateQueue(self, wakeUpTime): 108 i = 0 109 busyUp = 0 110 busyDown = 0 111 while i < len(self.queue): 112 doll = self.queue[i].doll() 113 factory = self.queue[i].factory() 114 avatar = self.queue[i].avatar.object 115 if doll is None: 116 self.queue.pop(i) 117 elif doll.busyUpdating: 118 if doll.previousLOD != LodQueue.magicLOD and doll.previousLOD <= self.queue[i].lodWanted: 119 busyDown = busyDown + 1 120 else: 121 busyUp = busyUp + 1 122 i = i + 1 123 elif doll.overrideLod == self.queue[i].lodWanted: 124 q = self.queue.pop(i) 125 if PerformanceOptions.logLodPerformance: 126 log.LogInfo('LOD switch to', q.lodWanted, 'took', wakeUpTime - q.timeUpdateStarted, 'secs; wait in queue', q.timeUpdateStarted - q.timeAddToQueue, 'secs') 127 else: 128 i = i + 1 129 130 self.queueSizeStat.Set(len(self.queue)) 131 return (busyUp, busyDown) 132 133 def AddToQueue(self, avatarBluePythonWeakRef, dollWeakref, factoryWeakref, lodWanted): 134 if type(avatarBluePythonWeakRef) != blue.BluePythonWeakRef: 135 avatarBluePythonWeakRef = blue.BluePythonWeakRef(avatarBluePythonWeakRef) 136 if type(dollWeakref) != weakref.ref: 137 dollWeakref = weakref.ref(dollWeakref) 138 if type(factoryWeakref) != weakref.ref: 139 factoryWeakref = weakref.ref(factoryWeakref) 140 for i in xrange(len(self.queue)): 141 q = self.queue[i] 142 if q.doll() == dollWeakref() and q.factory() == factoryWeakref() and q.avatar.object == avatarBluePythonWeakRef.object: 143 q.lodWanted = lodWanted 144 if q.doll().busyUpdating: 145 q.doll().Update(q.factory(), q.avatar.object) 146 break 147 else: 148 entry = self.QueueEntry(avatarBluePythonWeakRef, dollWeakref, factoryWeakref, lodWanted) 149 self.queue.append(entry) 150 151 self.updateEvent.set() 152 153 def ProcessRequest(self, queueEntry, allowUp): 154 doll = queueEntry.doll() 155 factory = queueEntry.factory() 156 avatar = queueEntry.avatar.object 157 if doll is None or factory is None or avatar is None: 158 return False 159 if queueEntry.lodWanted == doll.overrideLod: 160 return False 161 if queueEntry.lodWanted < doll.overrideLod and not allowUp: 162 return False 163 doll.overrideLod = queueEntry.lodWanted 164 doll.AddUpdateDoneListener(LodQueue.OnDollUpdateDoneStatic) 165 queueEntry.timeUpdateStarted = time.time() 166 doll.Update(factory, avatar) 167 return True 168 169 170 def SetupLODFromPaperdoll(avatar, doll, factory, animation, loadStub = True): 171 if doll is None or avatar is None: 172 return 173 stub = None 174 if loadStub: 175 if type(avatar) == trinity.Tr2IntSkinnedObject: 176 stub = blue.resMan.LoadObject(LoadingStubPath) 177 if hasattr(stub, 'visualModel'): 178 stub = stub.visualModel 179 180 class InPlaceBuilder: 181 182 def __init__(self, avatar, doll, factory, stub): 183 self.avatar = blue.BluePythonWeakRef(avatar) 184 self.doll = weakref.ref(doll) 185 self.factory = weakref.ref(factory) 186 doll.overrideLod = LodQueue.magicLOD 187 188 def MakeBuilder(lod): 189 lodBuilder = blue.BlueObjectBuilderPython() 190 lodBuilder.SetCreateMethod(lambda objectMarker, callingProxy: self.DoCreate(callingProxy, lod)) 191 lodBuilder.SetSelectedHandler(lambda objectMarker, callingProxy: self.OnSelected(callingProxy, lod)) 192 proxy = blue.BlueObjectProxy() 193 proxy.builder = lodBuilder 194 return proxy 195 196 avatar.highDetailModel = MakeBuilder(0) 197 avatar.mediumDetailModel = MakeBuilder(1) 198 avatar.lowDetailModel = MakeBuilder(2) 199 factory.AppendMeshesToVisualModel(avatar.visualModel, stub.meshes) 200 201 def DoCreate(self, callingProxy, lod): 202 if self.avatar.object is None: 203 return 204 return self.avatar.object.visualModel 205 206 def OnSelected(self, callingProxy, lod): 207 doll = self.doll() 208 factory = self.factory() 209 avatar = self.avatar.object 210 if doll is None or factory is None or avatar is None: 211 return 212 if doll.overrideLod != lod: 213 if LodQueue.instance is None: 214 doll.overrideLod = lod 215 doll.Update(factory, avatar) 216 else: 217 LodQueue.instance.AddToQueue(self.avatar, self.doll, self.factory, lod) 218 219 simpleBuilder = InPlaceBuilder(avatar, doll, factory, stub) 220 221 222 def AbortAllLod(avatar): 223 if avatar is None: 224 return 225 if avatar.highDetailModel is not None: 226 avatar.highDetailModel.object = None 227 if avatar.mediumDetailModel is not None: 228 avatar.mediumDetailModel.object = None 229 if avatar.lowDetailModel is not None: 230 avatar.lowDetailModel.object = None