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

attribute.py (15088B)


      1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\packages\dogma\attributes\attribute.py
      2 from __future__ import print_function
      3 import dogma
      4 import dogma.data as dogma_data
      5 import gametime
      6 from dogma.attributes import AttributeInterface
      7 import pytelemetry.zoning as zoning
      8 import itertools
      9 import dogma.const as const
     10 import weakref
     11 from dogma.dogmaLogging import GetCategoryNameFromID
     12 from dogma.dogmaLogging import GetGroupNameFromID
     13 from dogma.dogmaLogging import GetTypeNameFromID
     14 from dogma.dogmaLogging import LogError
     15 from dogma.dogmaLogging import LogException
     16 from dogma.dogmaLogging import WrappedMethod
     17 
     18 def Seq(sequenceOrNone):
     19     if sequenceOrNone is None:
     20         return []
     21     return sequenceOrNone
     22 
     23 
     24 class Attribute(AttributeInterface):
     25     __slots__ = ['category',
     26      'currentValue',
     27      'baseValue',
     28      'typeValue',
     29      'invItem',
     30      'incomingModifiers',
     31      '_outgoingModifiers',
     32      'capAttrib',
     33      'item',
     34      'dirty',
     35      'highIsGood',
     36      'dogmaLM',
     37      'attribID',
     38      '_onChangeCallbacks',
     39      'nonModifyingDependants',
     40      'clientSideValue',
     41      'floorAttrib']
     42 
     43     def __str__(self):
     44         return self.performantStr()
     45 
     46     def performantStr(self):
     47         try:
     48             itemID = self.item.itemID
     49             itemClass = self.item.__class__.__name__
     50             itemAddress = id(self.item)
     51         except ReferenceError:
     52             itemID = self.invItem.itemID
     53             itemClass = 'UNLOADED-ITEM'
     54             itemAddress = '[GONE]'
     55 
     56         attribID = self.attribID
     57         attributeClass = self.__class__.__name__
     58         invItemCategoryID = self.invItem.categoryID
     59         invItemGroupID = self.invItem.groupID
     60         invItemTypeID = self.invItem.typeID
     61         return "'{attribID}' ({attributeClass}) on '{invItemCategoryID} / {invItemTypeID}' ({itemClass} {itemID}) ".format(**locals())
     62 
     63     def friendlyStr(self):
     64         try:
     65             itemID = self.item.itemID
     66             itemClass = self.item.__class__.__name__
     67             itemAddress = id(self.item)
     68         except ReferenceError:
     69             itemID = self.invItem.itemID
     70             itemClass = 'UNLOADED-ITEM'
     71             itemAddress = '[GONE]'
     72 
     73         attribID = self.attribID
     74         attributeName = dogma_data.get_attribute_name(attribID)
     75         attributeClass = self.__class__.__name__
     76         invItemCategoryName = GetCategoryNameFromID(self.invItem.categoryID)
     77         invItemGroupName = GetGroupNameFromID(self.invItem.groupID)
     78         invItemTypeName = GetTypeNameFromID(self.invItem.typeID)
     79         numIncoming = self.CountIncomingModifiers()
     80         numOutgoing = self.CountOutgoingModifiers()
     81         return "'{attributeName}' ({attributeClass}) on '{invItemCategoryName} / {invItemTypeName}' ({itemClass} {itemID}) [i{numIncoming}:o{numOutgoing}] ".format(**locals())
     82 
     83     def printInvItemDetails(self, itemClass):
     84         print('START INV ITEM DETAILS:')
     85         print()
     86         try:
     87             i = self.invItem
     88             print('invItem:', i)
     89             print('type:', type(i))
     90             print('columns:', i.__columns__)
     91             print()
     92             for a in ['itemID',
     93              'typeID',
     94              'ownerID',
     95              'locationID',
     96              'flagID',
     97              'quantity',
     98              'groupID',
     99              'categoryID',
    100              'customInfo',
    101              'stacksize',
    102              'singleton']:
    103                 print(a, getattr(i, a))
    104 
    105             print()
    106             print('Underlying item:', self.item)
    107             print()
    108             print('class:', itemClass)
    109         except:
    110             print("*** OUCH. THAT DIDN'T WORK! ***")
    111 
    112         print()
    113         print('END INV ITEM DETAILS')
    114         print()
    115 
    116     def __init__(self, attribID, baseValue, dogmaItem, dogmaLM, staticAttr):
    117         self.attribID = attribID
    118         self.item = dogmaItem
    119         self.dogmaLM = dogmaLM
    120         self.invItem = dogmaItem.invItem
    121         if attribID is not None:
    122             self.typeValue = dogma_data.get_type_attribute_or_default(dogmaItem.invItem.typeID, attribID)
    123         else:
    124             self.typeValue = baseValue
    125         if baseValue is None:
    126             baseValue = self.typeValue
    127         self.baseValue = baseValue
    128         self.incomingModifiers = None
    129         self._outgoingModifiers = None
    130         self.nonModifyingDependants = None
    131         self._onChangeCallbacks = None
    132         self.highIsGood = staticAttr.highIsGood
    133         self.category = staticAttr.dataType
    134         self.currentValue = self.baseValue
    135         self.dirty = False
    136         if getattr(staticAttr, 'maxAttributeID', False):
    137             self.capAttrib = weakref.proxy(dogmaItem.attributes[staticAttr.maxAttributeID])
    138             self.capAttrib.AddNonModifyingDependant(self)
    139         else:
    140             self.capAttrib = None
    141         if getattr(staticAttr, 'minAttributeID', False):
    142             self.floorAttrib = weakref.proxy(dogmaItem.attributes[staticAttr.minAttributeID])
    143             self.floorAttrib.AddNonModifyingDependant(self)
    144         else:
    145             self.floorAttrib = None
    146         self._PickUpInitialModifiers(dogmaItem)
    147 
    148     def IsAnOrphan(self):
    149         try:
    150             testWhetherItemIsStillValid = self.item.invItem
    151             return False
    152         except ReferenceError:
    153             return True
    154 
    155     def _PickUpInitialModifiers(self, dogmaItem):
    156         location = dogmaItem.GetLocation()
    157         if location:
    158             location._PickUpInitialModifiersFromLocationTo(self)
    159         pilotID = dogmaItem.GetPilot()
    160         ownerItem = self.dogmaLM.dogmaItems.get(pilotID, None)
    161         if ownerItem and self.item.IsOwnerModifiable():
    162             ownerItem._PickUpInitialModifiersFromOwnerTo(self)
    163 
    164     def Update(self):
    165         prevValue = self.currentValue
    166         capVal = None
    167         floorVal = None
    168         if self.capAttrib:
    169             capVal = self.capAttrib.GetValue()
    170             self.baseValue = min(self.baseValue, capVal)
    171         if self.floorAttrib:
    172             floorVal = self.floorAttrib.GetValue()
    173             self.baseValue = max(self.baseValue, floorVal)
    174         val = self.baseValue
    175         val = self._ApplyModifierOperationsToVal(val)
    176         if capVal is not None:
    177             val = min(val, capVal)
    178         if floorVal is not None:
    179             val = max(val, floorVal)
    180         if self.category in (10, 11, 12):
    181             val = int(val)
    182         if self.attribID in (const.attributeCpuLoad,
    183          const.attributePowerLoad,
    184          const.attributePowerOutput,
    185          const.attributeCpuOutput,
    186          const.attributeCpu,
    187          const.attributePower):
    188             val = round(val, 2)
    189         self.currentValue = val
    190         self.dirty = False
    191         self._PerformCallbacksIfValueChanged(prevValue)
    192 
    193     def _ApplyModifierOperationsToVal(self, val):
    194         if self.incomingModifiers:
    195             for idx, mods in enumerate(self.incomingModifiers):
    196                 dogmaOperator = const.dgmOperators[const.dgmOperatorPrecedence[idx]]
    197                 for modAttrib in mods:
    198                     val = dogmaOperator(val, modAttrib.GetValue())
    199 
    200         return val
    201 
    202     def GetValue(self):
    203         if self.dirty:
    204             self.Update()
    205         return self.currentValue
    206 
    207     def MarkDirty(self, silent = False):
    208         self.dirty = True
    209         for op, nowDirtyAttrib in list(Seq(self._outgoingModifiers)):
    210             try:
    211                 nowDirtyAttrib().MarkDirty()
    212             except AttributeError:
    213                 continue
    214 
    215         for nowDirtyAttrib in Seq(self.nonModifyingDependants):
    216             try:
    217                 nowDirtyAttrib.MarkDirty()
    218             except AttributeError:
    219                 continue
    220 
    221         if silent:
    222             return
    223         ownerID = None
    224         if True:
    225             try:
    226                 ownerID = self.item.ownerID
    227             except AttributeError:
    228                 LogError('Attribute {} has no `ownerID` on its `item`, just: {}'.format(self, sorted(vars(self.item))))
    229 
    230         itemID = self.item.itemID
    231         if self.ShoulCallbackAttributeChange(itemID, ownerID):
    232             try:
    233                 oldValue = self.currentValue
    234                 newValue = self.GetValue()
    235                 self.dogmaLM.attributeChangeCallbacksByAttributeID[self.attribID](self.attribID, itemID, newValue, oldValue)
    236             except Exception:
    237                 LogException('Error broadcasting attribute change {}'.format(self.dogmaLM.attributeChangeCallbacksByAttributeID[self.attribID]))
    238 
    239         if dogma.IsClient():
    240             return
    241         if self.dogmaLM.ShouldMessageItemEvent(itemID):
    242             try:
    243                 if self.attribID is not None:
    244                     self.dogmaLM.msgMgr.AddAttribute(self)
    245             except Exception:
    246                 LogException('Error broadcasting attribute change')
    247 
    248     def ShoulCallbackAttributeChange(self, itemID, ownerID):
    249         if self.attribID not in self.dogmaLM.attributeChangeCallbacksByAttributeID:
    250             return False
    251         if not self.dogmaLM.ShouldMessageItemEvent(itemID, ownerID):
    252             return False
    253         return True
    254 
    255     def AddCallbackForChanges(self, func, params):
    256         if self._onChangeCallbacks is None:
    257             self._onChangeCallbacks = {}
    258         self._onChangeCallbacks[func] = params
    259 
    260     def RemoveCallbackForChanges(self, func):
    261         del self._onChangeCallbacks[func]
    262         if not self._onChangeCallbacks:
    263             self._onChangeCallbacks = None
    264 
    265     def _PerformCallbacksIfValueChanged(self, prevValue):
    266         if self._onChangeCallbacks is None:
    267             return
    268         if prevValue != self.currentValue:
    269             for func, params in self._onChangeCallbacks.iteritems():
    270                 func(self, prevValue, self.currentValue, *params)
    271 
    272     def ConstructMessage(self):
    273         try:
    274             if self.item.ownerID is None:
    275                 return
    276         except ReferenceError:
    277             return
    278 
    279         clientID = self.item.FindClientID('charid', [self.item.ownerID])
    280         if clientID is not None:
    281             newValue = self.GetValue()
    282             try:
    283                 oldValue = self.clientSideValue
    284                 if oldValue == newValue:
    285                     return
    286             except AttributeError:
    287                 oldValue = newValue
    288 
    289             self.clientSideValue = newValue
    290             if self.dogmaLM.ShouldMessageItemEvent(self.item.itemID):
    291                 simTime = gametime.GetSimTime()
    292                 return (clientID, (('OnModuleAttributeChange',
    293                    self.item.ownerID,
    294                    self.item.itemID,
    295                    self.attribID,
    296                    simTime,
    297                    newValue,
    298                    oldValue,
    299                    gametime.GetWallclockTime()), simTime))
    300         else:
    301             return
    302 
    303     def _makeEmptyIncomingModifiers(self):
    304         return tuple((set() for x in const.dgmOperatorPrecedence))
    305 
    306     def _initIncomingModifiers(self):
    307         self.incomingModifiers = self._makeEmptyIncomingModifiers()
    308 
    309     @WrappedMethod
    310     def AddIncomingModifier(self, op, attribute):
    311         if self.incomingModifiers is None:
    312             self._initIncomingModifiers()
    313         self.incomingModifiers[const.dgmOperatorIDtoIndex[op]].add(attribute)
    314         self.MarkDirty()
    315 
    316     @WrappedMethod
    317     def RemoveIncomingModifier(self, op, attribute):
    318         try:
    319             self.incomingModifiers[const.dgmOperatorIDtoIndex[op]].remove(attribute)
    320             self.MarkDirty()
    321         except (TypeError,
    322          IndexError,
    323          KeyError,
    324          ValueError):
    325             return
    326 
    327         if self.incomingModifiers is None:
    328             return
    329         if not any(self.incomingModifiers):
    330             self.incomingModifiers = None
    331 
    332     def GetIncomingModifiers(self):
    333         if self.incomingModifiers is None:
    334             return []
    335         result = []
    336         for opIdx, attribSet in enumerate(self.incomingModifiers):
    337             result.extend(((const.dgmOperatorPrecedence[opIdx], attrib) for attrib in attribSet))
    338 
    339         return result
    340 
    341     def CountIncomingModifiers(self):
    342         return len(self.GetIncomingModifiers())
    343 
    344     def AddNonModifyingDependant(self, attribute):
    345         if self.nonModifyingDependants is None:
    346             self.nonModifyingDependants = set()
    347         self.nonModifyingDependants.add(attribute)
    348         attribute.MarkDirty(silent=True)
    349 
    350     def _makeEmptyOutgoingModifiers(self):
    351         return set()
    352 
    353     def _initOutgoingModifiers(self):
    354         self._outgoingModifiers = self._makeEmptyOutgoingModifiers()
    355 
    356     @WrappedMethod
    357     def AddOutgoingModifier(self, op, attribute):
    358         if self._outgoingModifiers is None:
    359             self._initOutgoingModifiers()
    360         weak = weakref.ref(attribute)
    361         self._outgoingModifiers.add((op, weak))
    362 
    363     @WrappedMethod
    364     def RemoveOutgoingModifier(self, op, attribute):
    365         weak = weakref.ref(attribute)
    366         try:
    367             self._outgoingModifiers.remove((op, weak))
    368         except (AttributeError, KeyError, ValueError):
    369             return
    370 
    371         if not any(self._outgoingModifiers):
    372             self._outgoingModifiers = None
    373 
    374     def GetOutgoingModifiers(self):
    375         if self._outgoingModifiers is None:
    376             return []
    377         return [ (opIdx, attrib_weakref()) for opIdx, attrib_weakref in self._outgoingModifiers ]
    378 
    379     def CountOutgoingModifiers(self):
    380         return len(self.GetOutgoingModifiers())
    381 
    382     def RemoveAllModifiers(self):
    383         for operator, incomingAttrib in self.GetIncomingModifiers():
    384             incomingAttrib.RemoveOutgoingModifier(operator, self)
    385 
    386         for operator, outgoingAttrib in self.GetOutgoingModifiers():
    387             outgoingAttrib.RemoveIncomingModifier(operator, self)
    388 
    389         self._DiscardAllModifiers()
    390 
    391     def _DiscardAllModifiers(self):
    392         self.incomingModifiers = None
    393         self._outgoingModifiers = None
    394 
    395     def GetBaseValue(self):
    396         return self.baseValue
    397 
    398     def SetBaseValue(self, newBaseValue):
    399         if self.baseValue != newBaseValue:
    400             self.baseValue = newBaseValue
    401             self.MarkDirty()
    402 
    403     def ResetBaseValue(self):
    404         if self.baseValue != self.typeValue:
    405             self.baseValue = self.typeValue
    406             self.MarkDirty()
    407 
    408     def IncreaseBaseValue(self, addAmount):
    409         if not self.item.CanAttributeBeModified():
    410             return
    411         self.baseValue += addAmount
    412         self.MarkDirty()
    413 
    414     def DecreaseBaseValue(self, decAmount):
    415         if not self.item.CanAttributeBeModified():
    416             return
    417         self.baseValue -= decAmount
    418         self.MarkDirty()
    419 
    420     def GetModifyingItems(self):
    421         modifyingItems = set()
    422         if self.incomingModifiers is None:
    423             return modifyingItems
    424         for srcAttrib in itertools.chain(*self.incomingModifiers):
    425             if srcAttrib.item is not None:
    426                 modifyingItems.add(srcAttrib.item.itemID)
    427 
    428         return modifyingItems
    429 
    430     def GetPersistData(self):
    431         if self.baseValue != self.typeValue:
    432             return self.baseValue
    433         else:
    434             return None
    435 
    436     @zoning.ZONE_METHOD
    437     def ApplyPersistData(self, pData):
    438         self.SetBaseValue(pData)