slimDogmaItem.py (23177B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\packages\dogma\items\slimDogmaItem.py 2 import itertools 3 import weakref 4 from dogma.dogmaLogging import * 5 import blue 6 import evetypes 7 from eveexceptions.exceptionEater import ExceptionEater 8 import dogma.const as const 9 from dogma.effects.environment import Environment 10 from dogma.attributes.itemAttributeFactory import NewItemAttributeFactory 11 from utillib import KeyVal, keydefaultdict 12 from collections import defaultdict 13 from ccpProfile import TimedFunction 14 RESISTANCEMATRIX = {const.attributeShieldCharge: [1, 15 1, 16 1, 17 1], 18 const.attributeArmorDamage: [1, 19 1, 20 1, 21 1], 22 const.attributeDamage: [1, 23 1, 24 1, 25 1]} 26 27 class SlimDogmaItem(object): 28 29 @TimedFunction('SlimDogmaItem::__init__') 30 def __init__(self, dogmaLocation, invItem, clientIDFunc, attributes = None): 31 self._owner = None 32 self.dogmaLocation = dogmaLocation 33 self.dogmaLocation.dogmaItems[invItem.itemID] = self 34 self.invItem = invItem 35 self.itemID = invItem.itemID 36 self.typeID = invItem.typeID 37 self.groupID = invItem.groupID 38 self.categoryID = invItem.categoryID 39 self.reqSkills = dogmaLocation.dogmaStaticMgr.GetRequiredSkills(invItem.typeID) 40 self.contentsChangedCallbacks = set() 41 self.FindClientID = clientIDFunc 42 attributeFactory = NewItemAttributeFactory(self, self.dogmaLocation, attributes) 43 self.attributes = keydefaultdict(attributeFactory.GetAttributeInstance) 44 self.activeEffects = {} 45 self._SetupLocationLinks() 46 self._SetupLocationMods() 47 self._SetupOwnerLinks() 48 self._SetupOwnerMods() 49 locationItem = self.location 50 if locationItem: 51 for callBack in locationItem.contentsChangedCallbacks: 52 with ExceptionEater('Contents callback excepted'): 53 callBack(self) 54 55 def __str__(self): 56 return '<%s::%s::%s>' % (self.__class__.__name__, self.itemID, self.typeID) 57 58 def __repr__(self): 59 return '<%s::%s::%s>' % (self.__class__.__name__, self.itemID, self.typeID) 60 61 @property 62 def owner(self): 63 try: 64 if self._owner: 65 return self._owner 66 return None 67 except ReferenceError: 68 return None 69 70 @owner.setter 71 def owner(self, value): 72 self._owner = value 73 74 def _SetupLocationLinks(self): 75 self.subItems = self.__ClaimSubItems() 76 for theSubItem in self.subItems: 77 self.dogmaLocation.LogInfo('Patching-up location link for item {} to location {}'.format(theSubItem, self)) 78 theSubItem.location = self 79 80 try: 81 locationItem = self.dogmaLocation.dogmaItems[self.invItem.locationID] 82 locationItem.subItems.add(self) 83 self.location = locationItem 84 except KeyError: 85 self.location = None 86 if self.invItem.locationID is not None: 87 self.__MarkMissingLocation() 88 89 def _SetupOwnerLinks(self): 90 self.ownedItems = self.__ClaimOwnedItems() 91 for theOwnedItem in self.ownedItems: 92 self.dogmaLocation.LogInfo('Patching-up owner link for item {} to location {}'.format(theOwnedItem, self)) 93 theOwnedItem.owner = weakref.proxy(self) 94 95 self.ownedItemsAtCreation = self.ownedItems.copy() 96 try: 97 ownerItem = self.dogmaLocation.dogmaItems[self.invItem.ownerID] 98 ownerItem.ownedItems.add(self) 99 self.owner = weakref.proxy(ownerItem) 100 except KeyError: 101 self.owner = None 102 if self.invItem.ownerID is not None: 103 self.__MarkMissingOwner() 104 105 def __ClaimSubItems(self): 106 if self.itemID not in self.dogmaLocation.itemsMissingLocation: 107 return set() 108 return self.dogmaLocation.itemsMissingLocation.pop(self.itemID) 109 110 def __ClaimOwnedItems(self): 111 if self.itemID not in self.dogmaLocation.itemsMissingOwner: 112 return set() 113 return self.dogmaLocation.itemsMissingOwner.pop(self.itemID) 114 115 def __MarkMissingLocation(self): 116 locationID = self.invItem.locationID 117 if locationID == self.dogmaLocation.locationID: 118 return 119 self.dogmaLocation.itemsMissingLocation[locationID].add(self) 120 121 def __MarkMissingOwner(self): 122 ownerID = self.invItem.ownerID 123 if ownerID < 2: 124 return 125 self.dogmaLocation.itemsMissingOwner[ownerID].add(self) 126 127 def __UnmarkMissingLocation(self, locationID): 128 if locationID == self.dogmaLocation.locationID: 129 return 130 self.dogmaLocation.itemsMissingLocation[locationID].discard(self) 131 if not self.dogmaLocation.itemsMissingLocation[locationID]: 132 del self.dogmaLocation.itemsMissingLocation[locationID] 133 134 def __UnmarkMissingOwner(self, ownerID): 135 self.dogmaLocation.itemsMissingOwner[ownerID].discard(self) 136 if not self.dogmaLocation.itemsMissingOwner[ownerID]: 137 del self.dogmaLocation.itemsMissingOwner[ownerID] 138 139 def _SetupLocationMods(self): 140 self.locationMods = defaultdict(set) 141 self.locationGroupMods = defaultdict(lambda : defaultdict(set)) 142 self.locationReqSkillMods = defaultdict(lambda : defaultdict(set)) 143 144 def _SetupOwnerMods(self): 145 self.ownerReqSkillMods = defaultdict(lambda : defaultdict(set)) 146 147 def _PickUpInitialModifiersFromLocationTo(fromSelf, toAttrib): 148 attribID = toAttrib.attribID 149 dogmaItem = toAttrib.item 150 groupID = dogmaItem.groupID 151 if attribID in fromSelf.locationMods: 152 myLocMods = fromSelf.locationMods[attribID] 153 fromSelf._ApplyModsToAttrib(myLocMods, toAttrib, debugContext='PickUp LocMods') 154 if groupID in fromSelf.locationGroupMods and attribID in fromSelf.locationGroupMods[groupID]: 155 myLocGroupMods = fromSelf.locationGroupMods[groupID][attribID] 156 fromSelf._ApplyModsToAttrib(myLocGroupMods, toAttrib, debugContext='PickUp LogGroupMods') 157 for skillID in dogmaItem.reqSkills: 158 if skillID in fromSelf.locationReqSkillMods and attribID in fromSelf.locationReqSkillMods[skillID]: 159 myLocReqSkillMods = fromSelf.locationReqSkillMods[skillID][attribID] 160 fromSelf._ApplyModsToAttrib(myLocReqSkillMods, toAttrib, debugContext='PickUp LocReqSkillMods') 161 162 def _PickUpInitialModifiersFromOwnerTo(fromSelf, toAttrib): 163 attribID = toAttrib.attribID 164 dogmaItem = toAttrib.item 165 for skillID in dogmaItem.reqSkills: 166 if skillID in fromSelf.ownerReqSkillMods and attribID in fromSelf.ownerReqSkillMods[skillID]: 167 myOwnerReqSkillMods = fromSelf.ownerReqSkillMods[skillID][attribID] 168 fromSelf._ApplyModsToAttrib(myOwnerReqSkillMods, toAttrib, debugContext='PickUp OwnerReqSkillMods') 169 170 def _ApplyModsToAttrib(self, modSeq, toAttrib, callOnAttributeChanged = False, debugContext = '<no debug context>'): 171 if not modSeq: 172 return 173 itemsToPurge = None 174 for modifier in modSeq: 175 operation, fromAttrib = modifier 176 if fromAttrib.IsAnOrphan(): 177 if itemsToPurge is None: 178 itemsToPurge = set() 179 itemsToPurge.add(modifier) 180 else: 181 fromAttrib.AddModifierTo(operation, toAttrib) 182 if callOnAttributeChanged: 183 self.dogmaLocation.OnAttributeChanged(toAttrib.attribID, self.itemID) 184 185 if itemsToPurge: 186 self.dogmaLocation.LogError('SlimDogmaItem::_ApplyModsToAttrib PURGING ORPHANS (attempting self-repair)! \nmodSeq = {}, \nitemsToPurge = {}, \ntoAttrib = {} \n, debugContext = {}'.format(modSeq, itemsToPurge, toAttrib, debugContext)) 187 modSeq.difference_update(itemsToPurge) 188 189 def CanAttributeBeModified(self): 190 return True 191 192 def IsOwnerModifiable(self): 193 return False 194 195 def GetOwnedItemsToModify(self): 196 LogTraceback('GetOwnedItemsToModify called on non-owner item %s of type %s' % (self.itemID, self.__class__)) 197 return [] 198 199 @property 200 def locationID(self): 201 return self.invItem.locationID 202 203 @property 204 def ownerID(self): 205 return self.invItem.ownerID 206 207 def GetPilot(self): 208 return None 209 210 def GetLocation(self): 211 return self.location 212 213 def GetValue(self, attributeID): 214 return self.attributes[attributeID].GetValue() 215 216 def GetResistanceMatrix(self): 217 return RESISTANCEMATRIX 218 219 def Unload(self): 220 if self.owner: 221 self.dogmaLocation.LogInfo('SlimDogmaItem removing self from ownedItems of owner:', self.owner) 222 try: 223 self.owner.ownedItems.remove(self) 224 except KeyError: 225 LogTraceback("Tried to remove self from ownedItems but wasn't there") 226 227 else: 228 self.__UnmarkMissingOwner(self.invItem.ownerID) 229 if self.location: 230 self.dogmaLocation.LogInfo('SlimDogmaItem removing self from subItems of location:', self.location) 231 try: 232 self.location.subItems.remove(self) 233 except KeyError: 234 pass 235 236 else: 237 self.__UnmarkMissingLocation(self.invItem.locationID) 238 self.dogmaLocation.PersistItem2(self.itemID) 239 240 def RemoveModifierSet(self, modifiers): 241 for attribID, modSet in modifiers.iteritems(): 242 if attribID in self.attributes: 243 toAttrib = self.attributes[attribID] 244 for operation, fromAttrib in modSet: 245 fromAttrib.RemoveOutgoingModifier(operation, toAttrib) 246 toAttrib.RemoveIncomingModifier(operation, fromAttrib) 247 248 def AddModifierSet(self, modifiers): 249 for attribID, modSet in modifiers.iteritems(): 250 if attribID in self.attributes: 251 toAttrib = self.attributes[attribID] 252 for operation, fromAttrib in modSet: 253 fromAttrib.AddOutgoingModifier(operation, toAttrib) 254 toAttrib.AddIncomingModifier(operation, fromAttrib) 255 self.dogmaLocation.OnAttributeChanged(attribID, self.itemID) 256 257 def HandleLocationChange(self, oldLocationID): 258 if self.location is None: 259 self.__UnmarkMissingLocation(oldLocationID) 260 else: 261 try: 262 oldLocationItem = self.dogmaLocation.dogmaItems[oldLocationID] 263 except KeyError: 264 pass 265 else: 266 self.RemoveModifierSet(oldLocationItem.locationMods) 267 try: 268 locationGroupMods = oldLocationItem.locationGroupMods[self.groupID] 269 except KeyError: 270 pass 271 else: 272 self.RemoveModifierSet(locationGroupMods) 273 274 for skillID in self.reqSkills: 275 try: 276 locationReqSkillMods = oldLocationItem.locationReqSkillMods[skillID] 277 except KeyError: 278 pass 279 else: 280 self.RemoveModifierSet(locationReqSkillMods) 281 282 if self in oldLocationItem.subItems: 283 oldLocationItem.subItems.remove(self) 284 285 newLocationID = self.invItem.locationID 286 try: 287 locationItem = self.dogmaLocation.dogmaItems[newLocationID] 288 self.location = locationItem 289 except KeyError: 290 self.location = None 291 if newLocationID is not None: 292 self.__MarkMissingLocation() 293 else: 294 if self not in locationItem.subItems: 295 locationItem.subItems.add(self) 296 self.AddModifierSet(locationItem.locationMods) 297 try: 298 locationGroupMods = locationItem.locationGroupMods[self.groupID] 299 except KeyError: 300 pass 301 else: 302 self.AddModifierSet(locationGroupMods) 303 304 for skillID in self.reqSkills: 305 try: 306 locationReqSkillMods = locationItem.locationReqSkillMods[skillID] 307 except KeyError: 308 pass 309 else: 310 self.AddModifierSet(locationReqSkillMods) 311 312 def HandlePilotChange(self, pilotID): 313 if not pilotID: 314 oldPilotItem = self.dogmaLocation.dogmaItems[self.GetPilot()] 315 for skillID in self.reqSkills: 316 try: 317 ownerReqSkillMods = oldPilotItem.ownerReqSkillMods[skillID] 318 except KeyError: 319 pass 320 else: 321 self.RemoveModifierSet(ownerReqSkillMods) 322 323 else: 324 newPilotItem = self.dogmaLocation.dogmaItems[pilotID] 325 for skillID in self.reqSkills: 326 try: 327 ownerReqSkillMods = newPilotItem.ownerReqSkillMods[skillID] 328 except KeyError: 329 pass 330 else: 331 self.RemoveModifierSet(ownerReqSkillMods) 332 333 def HandleOwnerChange(self, oldOwnerID): 334 if self.owner is None: 335 self.__UnmarkMissingOwner(oldOwnerID) 336 oldOwner = self.dogmaLocation.dogmaItems.get(oldOwnerID, None) 337 if oldOwner is not None: 338 oldOwner.ownedItems.discard(self) 339 for skillID in self.reqSkills: 340 try: 341 ownerReqSkillMods = oldOwner.ownerReqSkillMods[skillID] 342 except KeyError: 343 pass 344 else: 345 self.RemoveModifierSet(ownerReqSkillMods) 346 347 newOwnerID = self.invItem.ownerID 348 try: 349 ownerItem = self.dogmaLocation.dogmaItems[newOwnerID] 350 except KeyError: 351 self.owner = None 352 if newOwnerID is not None: 353 self.dogmaLocation.itemsMissingOwner[newOwnerID].add(self) 354 else: 355 ownerItem.ownedItems.add(self) 356 self.owner = weakref.proxy(ownerItem) 357 for skillID in self.reqSkills: 358 try: 359 ownerReqSkillMods = ownerItem.ownerReqSkillMods[skillID] 360 except KeyError: 361 pass 362 else: 363 if self.IsOwnerModifiable(): 364 self.AddModifierSet(ownerReqSkillMods) 365 366 self.dogmaLocation.HandleDogmaLocationEffectsOnItem(self) 367 368 @WrappedMethod 369 def FlushAllModifiers(self): 370 for attrib in self.attributes.itervalues(): 371 attrib.RemoveAllModifiers() 372 373 def SerializeForPropagation(self): 374 return _SlimDogmaItemPacker(self).PackItem() 375 376 def UnpackPropagationData(self, propData, charID, shipID): 377 _SlimDogmaItemUnpacker(self, self.dogmaLocation, propData, charID, shipID).UnpackItem() 378 379 380 class _SlimDogmaItemPacker(object): 381 382 def __init__(self, dogmaItem): 383 self.dogmaItem = dogmaItem 384 385 @TimedFunction('DogmaLocation::PackItem') 386 def PackItem(self): 387 packedItem = KeyVal() 388 self.PackAttributes(packedItem) 389 self.PackModifiers(packedItem) 390 self.PackModifierGroups(packedItem) 391 self.PackEffects(packedItem) 392 return packedItem 393 394 def PackAttributes(self, packedItem): 395 attributeValues = [] 396 for attribID, attrib in self.dogmaItem.attributes.iteritems(): 397 persistData = attrib.GetPersistData() 398 if persistData is not None: 399 attributeValues.append((attribID, persistData)) 400 401 packedItem.attributeValues = attributeValues 402 403 def PackModifiers(self, packedItem): 404 outgoingModifiers = defaultdict(list) 405 for attribID, attribute in self.dogmaItem.attributes.iteritems(): 406 for operator, destAttrib in attribute.GetOutgoingModifiers(): 407 if destAttrib is not None: 408 if destAttrib.attribID is None: 409 LogTraceback('Packing modifiers with attribID None on %s which is definitely going to break while unpacking' % destAttrib) 410 else: 411 outgoingModifiers[attribID].append((operator, destAttrib.item.itemID, destAttrib.attribID)) 412 413 sanitized = {} 414 sanitized.update(outgoingModifiers) 415 packedItem.outgoingModifiers = sanitized 416 417 def _SerializeModifierSet(self, modSet): 418 modList = [] 419 for attribID, opSet in modSet.iteritems(): 420 for operation, fromAttrib in opSet: 421 if hasattr(fromAttrib, 'noPropagation'): 422 continue 423 try: 424 modList.append((attribID, 425 operation, 426 fromAttrib.item.itemID, 427 fromAttrib.attribID)) 428 except: 429 LogWarn("_SerializeModifierSet: Couldn't serialize fromAttrib {}".format(fromAttrib)) 430 431 return modList 432 433 def PackModifierGroups(self, packedItem): 434 packedItem.locationMods = self._SerializeModifierSet(self.dogmaItem.locationMods) 435 packedItem.locationGroupMods = {groupID:self._SerializeModifierSet(modSet) for groupID, modSet in self.dogmaItem.locationGroupMods.iteritems()} 436 packedItem.locationReqSkillMods = {skillID:self._SerializeModifierSet(modSet) for skillID, modSet in self.dogmaItem.locationReqSkillMods.iteritems()} 437 packedItem.ownerReqSkillMods = {skillID:self._SerializeModifierSet(modSet) for skillID, modSet in self.dogmaItem.ownerReqSkillMods.iteritems()} 438 439 def PackEffects(self, packedItem): 440 packedItem.effectIDs = self.dogmaItem.activeEffects.keys() 441 442 443 class _SlimDogmaItemUnpacker(object): 444 445 def __init__(self, dogmaItem, dogmaLM, propData, charID, shipID): 446 self.dogmaItem = dogmaItem 447 self.dogmaLM = dogmaLM 448 self.propData = propData 449 self.charID = charID 450 self.shipID = shipID 451 452 def UnpackItem(self): 453 self.UnpackAttributes() 454 self.UnpackModifiers() 455 self.UnpackModifierSets() 456 self.UnpackEffects() 457 458 @TimedFunction('DogmaLocation::UnpackProp::Attribs') 459 def UnpackAttributes(self): 460 for attribID, newBaseValue in self.propData.attributeValues: 461 self.dogmaItem.attributes[attribID].ApplyPersistData(newBaseValue) 462 463 @TimedFunction('DogmaLocation::UnpackProp::Modifiers') 464 def UnpackModifiers(self): 465 for attribID, modList in self.propData.outgoingModifiers.iteritems(): 466 attrib = self.dogmaItem.attributes[attribID] 467 for operator, destItemID, destAttribID in modList: 468 destItem = self.dogmaLM.dogmaItems.get(destItemID) 469 if destItem is None: 470 continue 471 destAttrib = destItem.attributes[destAttribID] 472 attrib.AddModifierTo(operator, destAttrib) 473 474 def _UnpackModifierSet(self, modSet, packedData): 475 for attribID, operation, fromItemID, fromAttribID in packedData: 476 fromItem = self.dogmaLM.dogmaItems.get(fromItemID) 477 if fromItem is None: 478 continue 479 fromAttrib = fromItem.attributes[fromAttribID] 480 modSet[attribID].add((operation, fromAttrib)) 481 482 @TimedFunction('DogmaLocation::UnpackProp::ModSets') 483 def UnpackModifierSets(self): 484 self._UnpackModifierSet(self.dogmaItem.locationMods, self.propData.locationMods) 485 for groupID, packedModSet in self.propData.locationGroupMods.iteritems(): 486 self._UnpackModifierSet(self.dogmaItem.locationGroupMods[groupID], packedModSet) 487 488 for skillID, packedModSet in self.propData.locationReqSkillMods.iteritems(): 489 self._UnpackModifierSet(self.dogmaItem.locationReqSkillMods[skillID], packedModSet) 490 491 for skillID, packedModSet in self.propData.ownerReqSkillMods.iteritems(): 492 self._UnpackModifierSet(self.dogmaItem.ownerReqSkillMods[skillID], packedModSet) 493 494 ownerReqSkillMods = self.dogmaItem.ownerReqSkillMods 495 if ownerReqSkillMods: 496 for ownedItem in self.dogmaItem.ownedItemsAtCreation: 497 modsToSetup = [ ownerReqSkillMods[skillID] for skillID in ownedItem.reqSkills if skillID in ownerReqSkillMods ] 498 for mods in modsToSetup: 499 for attribID, modSet in mods.iteritems(): 500 if attribID in ownedItem.attributes: 501 toAttrib = ownedItem.attributes[attribID] 502 for operator, fromAttrib in modSet: 503 fromAttrib.AddOutgoingModifier(operator, toAttrib) 504 toAttrib.AddIncomingModifier(operator, fromAttrib) 505 506 def _MakeEnvironment(self, effectID, otherID): 507 return Environment(self.dogmaItem.itemID, self.charID, self.shipID, None, otherID, effectID, self.dogmaLM, None, None) 508 509 @TimedFunction('DogmaLocation::UnpackProp::Effects') 510 def UnpackEffects(self): 511 dogmaItem = self.dogmaItem 512 now = blue.os.GetSimTime() 513 otherID = None 514 if evetypes.GetIsGroupFittableNonSingletonByGroup(dogmaItem.groupID): 515 otherID = self.dogmaLM.GetSlotOther(self.shipID, dogmaItem.flagID) 516 onlineEffect = None 517 for possibleOnlineEffectID in self.dogmaLM.onlineEffects: 518 if possibleOnlineEffectID in self.propData.effectIDs: 519 onlineEnv = self._MakeEnvironment(possibleOnlineEffectID, otherID) 520 onlineEffect = [now, 521 -1, 522 onlineEnv, 523 0] 524 dogmaItem.activeEffects[possibleOnlineEffectID] = onlineEffect 525 self.propData.effectIDs.remove(possibleOnlineEffectID) 526 527 IsEffectPythonOverridden = self.dogmaLM.effectCompiler.IsEffectPythonOverridden 528 staticEffects = self.dogmaLM.dogmaStaticMgr.effects 529 passiveEffectEnvironment = None 530 for effectID in self.propData.effectIDs: 531 effectCategory = staticEffects[effectID].effectCategory 532 if effectCategory == const.dgmEffPassive: 533 if IsEffectPythonOverridden(effectID): 534 dogmaItem.activeEffects[effectID] = [now, 535 -1, 536 self._MakeEnvironment(effectID, otherID), 537 0] 538 else: 539 if passiveEffectEnvironment is None: 540 passiveEffectEnvironment = self._MakeEnvironment(effectID, otherID) 541 dogmaItem.activeEffects[effectID] = [now, 542 -1, 543 passiveEffectEnvironment, 544 0] 545 elif effectCategory == const.dgmEffOnline: 546 dogmaItem.activeEffects[effectID] = onlineEffect[:] 547 else: 548 dogmaItem.activeEffects[effectID] = [now, 549 -1, 550 self._MakeEnvironment(effectID, otherID), 551 0]