paperDollSpawnWrappers.py (14869B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\client\script\paperDoll\paperDollSpawnWrappers.py 2 import trinity 3 import uthread 4 import eve.common.script.paperDoll.paperDollDefinitions as pdDef 5 import eve.common.script.paperDoll.paperDollDataManagement as pdDm 6 import eve.client.script.paperDoll.commonClientFunctions as pdCcf 7 import eve.common.script.paperDoll.paperDollCommonFunctions as pdCf 8 import eve.client.script.paperDoll.paperDollImpl as pdImpl 9 import eve.client.script.paperDoll.paperDollLOD as pdLod 10 import eve.client.script.paperDoll.paperDollPortrait as pdPor 11 import blue 12 import telemetry 13 import yaml 14 import log 15 16 class PaperDollManager(object): 17 __metaclass__ = telemetry.ZONE_PER_METHOD 18 19 def __init__(self, factory, keyFunc = None): 20 self.factory = factory 21 self.keyFunc = keyFunc 22 self.__pdc = {} 23 24 def __del__(self): 25 self.ClearDolls() 26 27 def __iter__(self): 28 for pdc in self.__pdc.itervalues(): 29 yield pdc 30 31 def Count(self): 32 return len(self.__pdc) 33 34 def GetPaperDollCharacterByDoll(self, doll): 35 for pdc in iter(self): 36 if pdImpl.Doll.InstanceEquals(pdc.doll, doll): 37 return pdc 38 39 def GetPaperDollCharacterByAvatar(self, avatar): 40 for pdc in iter(self): 41 if pdc.avatar == avatar: 42 return pdc 43 44 def GetPaperDollCharacterByKey(self, key): 45 return self.__pdc.get(key) 46 47 def RemovePaperDollCharacter(self, pdc): 48 key = self.__GetKey(pdc) 49 if key in self.__pdc: 50 del self.__pdc[key] 51 52 def ClearDolls(self): 53 self.__pdc.clear() 54 55 def __GetKey(self, pdc): 56 doll = pdc.GetDoll() 57 if self.keyFunc: 58 return self.keyFunc(doll) 59 else: 60 return doll.instanceID 61 62 def SpawnPaperDollCharacterFromDNA(self, scene, dollName, dollDNA, position = None, rotation = None, lodEnabled = False, compressionSettings = None, gender = pdDef.GENDER.FEMALE, textureResolution = None, updateDoll = True, spawnAtLOD = 0): 63 pdc = PaperDollCharacter(self.factory) 64 pdc.LoadDollFromDNA(dollDNA, dollName=dollName, lodEnabled=lodEnabled, compressionSettings=compressionSettings) 65 if textureResolution: 66 pdc.doll.SetTextureSize(textureResolution) 67 if lodEnabled: 68 pdc.SpawnLOD(scene, point=position, rotation=rotation, gender=gender) 69 else: 70 pdc.Spawn(scene, point=position, rotation=rotation, gender=gender, updateDoll=updateDoll, lod=spawnAtLOD) 71 self.__pdc[self.__GetKey(pdc)] = pdc 72 sm.ScatterEvent('OnDollCreated', self.__GetKey(pdc)) 73 return pdc 74 75 def SpawnRandomDoll(self, scene, **kwargs): 76 pdc = PaperDollCharacter(self.factory) 77 pdc.MakeRandomDoll() 78 autoLod = kwargs.get('autoLOD') 79 if autoLod: 80 pdc.SpawnLOD(scene, **kwargs) 81 else: 82 pdc.Spawn(scene, **kwargs) 83 self.__pdc[self.__GetKey(pdc)] = pdc 84 sm.ScatterEvent('OnDollCreated', self.__GetKey(pdc)) 85 return pdc 86 87 def SpawnDoll(self, scene, **kwargs): 88 doll = kwargs.get('doll') 89 autoLod = kwargs.get('autoLOD') 90 pdc = PaperDollCharacter(self.factory, doll=doll) 91 if autoLod: 92 pdc.SpawnLOD(scene, **kwargs) 93 else: 94 pdc.Spawn(scene, **kwargs) 95 self.__pdc[self.__GetKey(pdc)] = pdc 96 sm.ScatterEvent('OnDollCreated', self.__GetKey(pdc)) 97 return pdc 98 99 def SpawnDollFromRes(self, scene, resPath, **kwargs): 100 pdc = PaperDollCharacter(self.factory) 101 pdc.LoadFromRes(resPath) 102 pdc.Spawn(scene, **kwargs) 103 self.__pdc[self.__GetKey(pdc)] = pdc 104 sm.ScatterEvent('OnDollCreated', self.__GetKey(pdc)) 105 return pdc 106 107 def GetAllDolls(self): 108 dolls = [] 109 for dc in self.__pdc.itervalues(): 110 dollInfo = {} 111 dollInfo['name'] = dc.doll.name 112 dollInfo['translation'] = dc.avatar.translation 113 dollInfo['rotation'] = dc.avatar.rotation 114 dollInfo['dna'] = dc.GetDNA() 115 dollInfo['doll'] = dc 116 dolls.append(dollInfo) 117 118 return dolls 119 120 def RestoreDollsFromDnaToScene(self, dolls, scene): 121 for dc in dolls: 122 self.SpawnPaperDollCharacterFromDNA(scene, dc['name'], dc['dna'], position=dc['translation'], rotation=dc['rotation']) 123 124 def WaitForAllDolls(self): 125 for dc in self.__pdc.itervalues(): 126 dc.WaitForUpdate() 127 128 129 class PaperDollCharacter(object): 130 __metaclass__ = telemetry.ZONE_PER_METHOD 131 __DEFAULT_NAME = 'Spawned Character' 132 133 def setscene(self, scene): 134 self.__scene = blue.BluePythonWeakRef(scene) 135 136 scene = property(fget=lambda self: self.__scene.object, fset=lambda self, x: self.setscene(x)) 137 138 def __init__(self, factory, doll = None, avatar = None, visualModel = None): 139 self.factory = factory 140 self.doll = None 141 self.factory.WaitUntilLoaded() 142 self.doll = doll 143 self.avatar = avatar 144 self.visualModel = visualModel 145 if not visualModel and hasattr(avatar, 'visualModel'): 146 self.visualModel = avatar.visualModel 147 self.__scene = blue.BluePythonWeakRef(None) 148 self.autoLod = False 149 self.disableDel = False 150 trinity.device.RegisterResource(self) 151 152 def __del__(self): 153 if self.disableDel: 154 return 155 del self.doll 156 del self.visualModel 157 if self.scene: 158 self.factory.RemoveAvatarFromScene(self.avatar, self.scene) 159 if self.avatar: 160 self.avatar.visualModel = None 161 if self.autoLod: 162 pdLod.AbortAllLod(self.avatar) 163 del self.avatar 164 165 def OnInvalidate(self, dev): 166 pass 167 168 def OnCreate(self, dev): 169 if self.doll and self.avatar: 170 self.doll.KillUpdate() 171 self.doll.mapBundle.ReCreate() 172 for modifier in self.doll.buildDataManager.GetModifiersAsList(): 173 modifier.IsDirty |= modifier.decalData is not None or modifier.IsMeshDirty() 174 175 self.doll.decalBaker = None 176 uthread.new(self.doll.Update, self.factory, self.avatar) 177 178 def ExportCharacter(self, resPath): 179 180 def fun(): 181 path = resPath 182 183 def GetMapResourcePath(map): 184 return path + '/' + pdDef.MAPNAMES[map] + '.dds' 185 186 for map in pdDef.MAPS: 187 texture = self.doll.mapBundle[map] 188 texture.SaveAsync(GetMapResourcePath(map)) 189 texture.WaitForSave() 190 191 meshGeometryResPaths = {} 192 for modifier in self.doll.buildDataManager.GetSortedModifiers(): 193 meshGeometryResPaths.update(modifier.meshGeometryResPaths) 194 195 for mesh in self.avatar.visualModel.meshes: 196 mesh.geometryResPath = meshGeometryResPaths.get(mesh.name, '') 197 for fx in pdCcf.GetEffectsFromMesh(mesh): 198 fx.StartUpdate() 199 try: 200 for resource in fx.resources: 201 if resource.name in pdDef.MAPNAMES: 202 resource.resourcePath = GetMapResourcePath(pdDef.MAPNAMES.index(resource.name)) 203 204 finally: 205 fx.EndUpdate() 206 207 trinity.Save(self.avatar, path + '/unique.red') 208 morphTargets = {} 209 for modifier in self.doll.buildDataManager.GetSortedModifiers(): 210 if modifier.categorie in pdDef.BLENDSHAPE_CATEGORIES: 211 morphTargets[modifier.name] = modifier.weight 212 213 bsFilePath = blue.paths.ResolvePath(path + '/blendshapes.yaml') 214 f = file(bsFilePath, 'w') 215 yaml.dump(morphTargets, f) 216 f.close() 217 animOffsets = {} 218 for bone in self.doll.boneOffsets: 219 trans = self.doll.boneOffsets[bone]['translation'] 220 animOffsets[bone] = trans 221 222 aoFilePath = blue.paths.ResolvePath(path + '/animationOffsets.yaml') 223 f = file(aoFilePath, 'w') 224 yaml.dump(animOffsets, f) 225 f.close() 226 227 uthread.new(fun) 228 229 @staticmethod 230 def ImportCharacter(factory, scene, resPath, **kwargs): 231 blocking = kwargs.get('blocking') 232 callBack = kwargs.get('callBack') 233 rotation = kwargs.get('rotation') 234 position = kwargs.get('point') 235 pdc = PaperDollCharacter(factory) 236 pdc.scene = scene 237 pdc.avatar = trinity.Load(resPath + '/unique.red') 238 if pdc.avatar is None: 239 log.LogInfo('Import failed on ' + resPath + '/unique.red') 240 return 241 pdc.visualModel = pdc.avatar.visualModel 242 slash = resPath.rfind('/') 243 pdc.avatar.name = str(resPath[slash + 1:] + ' (import)') 244 if position: 245 pdc.avatar.translation = position 246 if rotation: 247 pdc.avatar.rotation = rotation 248 rf = blue.ResFile() 249 bsPath = resPath + '/blendshapes.yaml' 250 meshes = None 251 morphTargets = pdDm.LoadYamlFileNicely(bsPath) 252 if morphTargets: 253 meshes = pdc.visualModel.meshes 254 255 def fun(): 256 if meshes: 257 factory.ApplyMorphTargetsToMeshes(meshes, morphTargets) 258 if trinity.GetShaderModel() == 'SM_2_0_LO': 259 pdPor.PortraitTools.RebindDXT5ShadersForSM2(meshes) 260 if callBack: 261 callBack() 262 263 if blocking: 264 fun() 265 else: 266 uthread.worker('paperDoll::PaperDollCharacter::ImportCharacter', fun) 267 scene.AddDynamic(pdc.avatar) 268 pdc.avatar.explicitMinBounds = (-5, -5, -5) 269 pdc.avatar.explicitMaxBounds = (5, 5, 5) 270 pdc.avatar.useExplicitBounds = True 271 return pdc 272 273 def GetDoll(self): 274 return self.doll 275 276 def GetAvatar(self): 277 return self.avatar 278 279 def MakeRandomDoll(self): 280 self.doll = pdCcf.CreateRandomDoll(self.doll.name if self.doll else PaperDollCharacter.__DEFAULT_NAME, self.factory) 281 if self.avatar: 282 self.doll.Update(self.factory, self.avatar) 283 284 def MakeDollNude(self): 285 self.doll.buildDataManager = pdDm.BuildDataManager() 286 if self.avatar: 287 self.doll.Update(self.factory, self.avatar) 288 289 def LoadFromRes(self, resPath): 290 self.doll = pdImpl.Doll(PaperDollCharacter.__DEFAULT_NAME) 291 while not self.factory.IsLoaded: 292 pdCf.Yield() 293 294 self.doll.Load(resPath, self.factory) 295 if self.avatar: 296 self.doll.Update(self.factory, self.avatar) 297 298 def LoadDollFromDNA(self, dollDNA, dollName = None, lodEnabled = True, compressionSettings = None): 299 name = dollName if dollName is not None else PaperDollCharacter.__DEFAULT_NAME 300 self.doll = pdImpl.Doll(name) 301 self.doll.LoadDNA(dollDNA, self.factory) 302 if compressionSettings: 303 self.doll.compressionSettings = compressionSettings 304 if self.avatar: 305 gender = pdDef.GENDER.MALE if self.doll.gender else pdDef.GENDER.FEMALE 306 networkToLoad = const.FEMALE_MORPHEME_PATH if gender == pdDef.GENDER.FEMALE else const.MALE_MORPHEME_PATH 307 if lodEnabled: 308 uthread.worker('^PaperDollCharacter::LoadFromDNA', pdLod.SetupLODFromPaperdoll, self.avatar, self.doll, self.factory, networkToLoad) 309 else: 310 uthread.worker('^PaperDollCharacter::LoadFromDNA', self.doll.Update, self.factory, self.avatar) 311 312 def GetDNA(self): 313 return self.doll.GetDNA() 314 315 def __PrepareAvatar(self, scene, point = None, rotation = None, name = None): 316 if scene is None: 317 raise ValueError('None type passed as scene to paperDoll::__PrepareAvatar!') 318 oldAnimation = None 319 sceneTypesDifferent = getattr(self.scene, '__typename__', None) != getattr(scene, '__typename__', None) 320 if self.avatar: 321 oldAnimation = self.avatar.animationUpdater 322 if self.scene: 323 self.factory.RemoveAvatarFromScene(self.avatar, self.scene) 324 if sceneTypesDifferent: 325 pdLod.AbortAllLod(self.avatar) 326 del self.avatar 327 if type(scene) in (trinity.Tr2InteriorScene, trinity.WodBakingScene) and type(self.scene) is not type(scene): 328 self.avatar = trinity.Tr2IntSkinnedObject() 329 if name: 330 self.avatar.name = name 331 self.doll.avatarType = 'interior' 332 self.factory.AddAvatarToScene(self.avatar, scene) 333 if point: 334 self.avatar.translation = point 335 if rotation: 336 self.avatar.rotation = rotation 337 if oldAnimation is not None: 338 self.avatar.animationUpdater = oldAnimation 339 if getattr(self.avatar.animationUpdater, 'network', None): 340 if self.doll.gender == pdDef.GENDER.MALE and self.avatar.animationUpdater.network.GetAnimationSetCount() > 1: 341 self.avatar.animationUpdater.network.SetAnimationSetIndex(1) 342 else: 343 self.avatar.animationUpdater.network.SetAnimationSetIndex(0) 344 345 def SpawnLOD(self, scene, **kwargs): 346 self.Spawn(scene, spawnLod=True, **kwargs) 347 348 def Spawn(self, scene, **kwargs): 349 gender = pdDef.GENDER.FEMALE 350 if 'gender' in kwargs: 351 gender = kwargs['gender'] 352 if self.doll is None: 353 self.doll = pdImpl.Doll(PaperDollCharacter.__DEFAULT_NAME, gender=gender) 354 else: 355 gender = self.doll.gender 356 spawnLod = kwargs.get('spawnLod', False) 357 if 'lod' in kwargs and not spawnLod: 358 self.doll.overrideLod = kwargs['lod'] 359 if self.visualModel is None: 360 self.visualModel = self.factory.CreateVisualModel(gender=gender) 361 self.__PrepareAvatar(scene, point=kwargs.get('point'), rotation=kwargs.get('rotation'), name=kwargs.get('name', None)) 362 self.scene = scene 363 self.avatar.visualModel = self.visualModel 364 if spawnLod: 365 networkToLoad = const.FEMALE_MORPHEME_PATH if gender == pdDef.GENDER.FEMALE else const.MALE_MORPHEME_PATH 366 pdLod.SetupLODFromPaperdoll(self.avatar, self.doll, self.factory, networkToLoad) 367 elif kwargs.get('updateDoll', True): 368 self.doll.Update(self.factory, self.avatar) 369 370 def MoveToScene(self, scene, point = None): 371 if scene and self.doll: 372 self.Spawn(scene, point=point, updateDoll=False) 373 374 def Update(self, channel = None): 375 return self.doll.Update(self.factory, self.avatar, channel=channel) 376 377 def UpdateClothSimulationStatus(self): 378 self.doll.buildDataManager.SetAllAsDirty(clearMeshes=True) 379 self.Update() 380 381 def WaitForUpdate(self): 382 while self.doll.busyUpdating: 383 pdCf.Yield()