invCache.py (60339B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\client\script\environment\invCache.py 2 from future.utils import raise_ 3 import copy 4 import sys 5 import traceback 6 from functools import wraps 7 import blue 8 import dogma.data 9 import evetypes 10 import localization 11 import log 12 import stackless 13 import telemetry 14 import uthread 15 from caching.memoize import Memoize 16 from carbon.common.script.net.moniker import Moniker 17 from carbon.common.script.sys.crowset import CRowset 18 from carbon.common.script.sys.row import Row 19 from carbon.common.script.sys.service import Service 20 from carbon.common.script.sys.serviceConst import ROLE_ADMIN 21 from carbon.common.script.util.format import FmtDate 22 from carbonui import uiconst 23 from eve.client.script.ui.inflight.shipHud import ActiveShipController 24 from eve.client.script.ui.util import utilWindows 25 from eve.common.lib import appConst as const 26 from eve.common.script.net import eveMoniker 27 from eve.common.script.sys import eveCfg, idCheckers 28 from eve.common.script.util import inventoryFlagsCommon 29 from eveexceptions import UserError 30 from inventorycommon.const import flagFrigateEscapeBay 31 from inventorycommon.util import GetItemVolume, IsFittingFlag, IsFittable 32 from inventoryrestrictions import can_be_unfitted, ItemCannotBeUnfitted 33 from player_messaging.client.ui_message import prompt_player_fsd_dialog 34 from resourcewars.common.const import RW_CORPORATIONS 35 CAPACITY_ATTRIBUTES = (const.attributeCapacity, 36 const.attributeDroneCapacity, 37 const.attributeShipMaintenanceBayCapacity, 38 const.attributeFleetHangarCapacity) 39 SPECIAL_CONTAINER_IDS = [const.containerWallet, 40 const.containerStationCharacters, 41 const.containerGlobal, 42 const.containerSolarSystem, 43 const.containerRecycler, 44 const.containerCharacter] 45 PRIVATE_SHIP_FLAGS = [const.flagCargo] 46 PRIVATE_STRUCTURE_FLAGS = [const.flagHangar] 47 PRIVATE_STATION_FLAGS = [const.flagHangar, const.flagShipHangar] 48 PRIVATE_STATION_CONTAINERS = [const.containerHangar] 49 50 class UnavailableInventoryLocation(Exception): 51 52 def __init__(self, locationName): 53 super(UnavailableInventoryLocation, self).__init__(self) 54 self.message = 'Failed to retrieve items; character is not located in a %s' % locationName 55 56 def __str__(self): 57 return self.message 58 59 60 def RaiseIfInventoryLocationUnavailable(sessionCheck, locationName): 61 62 def RaiseIfInventoryLocationUnavailableDecorator(f): 63 64 @wraps(f) 65 def wrapped(*args, **kwargs): 66 if not sessionCheck(): 67 raise UnavailableInventoryLocation(locationName) 68 try: 69 return f(*args, **kwargs) 70 except Exception: 71 raise UnavailableInventoryLocation(locationName) 72 73 return wrapped 74 75 return RaiseIfInventoryLocationUnavailableDecorator 76 77 78 class invCache(Service): 79 __guid__ = 'svc.invCache' 80 __exportedcalls__ = {'GetInventory': [], 81 'GetInventoryFromId': [], 82 'GetInventoryMgr': [], 83 'GetItemHeader': [], 84 'IsItemLocked': [], 85 'TryLockItem': [], 86 'UnlockItem': [], 87 'GetStationIDOfItem': [], 88 'IsInventoryPrimedAndListed': [], 89 'InvalidateLocationCache': [], 90 'AcceptPossibleRemovalTax': []} 91 __dependencies__ = [] 92 __notifyevents__ = ['ProcessSessionChange', 93 'OnSessionChanged', 94 'OnItemsChanged', 95 'OnItemChange', 96 'OnCapacityChange', 97 'OnPasswordChanged', 98 'DoBallRemove', 99 'OnDogmaAttributeChanged', 100 'ProcessActiveShipChanged', 101 'DoBallsRemove', 102 'OnSessionReset', 103 'OnInvalidateCacheForLocations'] 104 105 def __init__(self): 106 super(invCache, self).__init__() 107 self.Initialize() 108 109 def Initialize(self): 110 self.__invmgr = None 111 self.__invlocID = 0 112 self.__stationinvmgr = None 113 self.__stationID = 0 114 self.__itemhdr = None 115 self.inventories = {} 116 self.containerGlobal = None 117 self.lockedItems = {} 118 self.lockedItemsSemaphore = uthread.Semaphore() 119 self.trace = 0 120 self.locks = {} 121 122 def Run(self, ms = None): 123 sm.FavourMe(self.OnItemChange) 124 sm.FavourMe(self.ProcessSessionChange) 125 sm.FavourMe(self.OnCapacityChange) 126 self.LogInfo('invCache lock tracing:', ['OFF', 'ON'][self.trace]) 127 128 def Stop(self, memStream = None): 129 self.InvalidateCache() 130 131 @telemetry.ZONE_METHOD 132 def DoBallsRemove(self, pythonBalls, isRelease): 133 for ball, slimItem, terminal in pythonBalls: 134 self.DoBallRemove(ball, slimItem, terminal) 135 136 def DoBallRemove(self, ball, slimItem, terminal): 137 if ball is None: 138 return 139 if (ball.id, None) in self.inventories: 140 del self.inventories[ball.id, None] 141 142 def ProcessSessionChange(self, isRemote, session, change): 143 try: 144 if not session.charid: 145 return self.InvalidateCache() 146 if 'corprole' in change and session.stationid: 147 self.LogInfo('ProcessSessionChange corprole in station') 148 office = sm.GetService('officeManager').GetCorpOfficeAtLocation() 149 if office is not None: 150 key = (office.officeID, None) 151 if key in self.inventories: 152 self.LogInfo('Removing inventory for corp hangar') 153 del self.inventories[key] 154 if 'shipid' in change and session.solarsystemid is not None: 155 key = (change['shipid'][0], None) 156 if key in self.inventories: 157 del self.inventories[key] 158 return 159 if not self._ShouldInvalidateCache(change): 160 return 161 self.InvalidateCache() 162 finally: 163 sm.services['godma'].ProcessSessionChange(isRemote, session, change) 164 165 def _ShouldInvalidateCache(self, change): 166 return 'stationid' in change or 'structureid' in change or 'solarsystemid' in change 167 168 def OnSessionChanged(self, isRemote, sess, change): 169 if ROLE_ADMIN & session.role == ROLE_ADMIN: 170 self.trace = 1 171 else: 172 self.trace = 0 173 if 'corprole' in change and (session.stationid or session.structureid): 174 self.LogInfo('OnSessionChanged corprole in station') 175 self.InvalidateCorpCache() 176 177 def OnSessionReset(self): 178 self.InvalidateCache() 179 self.Initialize() 180 181 def OnPasswordChanged(self, which, containerItem): 182 self.RemoveInventoryContainer(containerItem) 183 184 def __getattr__(self, key): 185 if key == 'inventorymgr': 186 while session.IsMutating() and not session.IsChanging(): 187 self.LogInfo('Sleeping while waiting for a session change or mutation to complete') 188 blue.pyos.synchro.SleepSim(250) 189 190 if self.__invmgr is None or self.__invlocID != session.locationid: 191 self.__invlocID = session.locationid 192 self.__invmgr = eveMoniker.GetInventoryMgr() 193 return self.__invmgr 194 if key == 'stationInventoryMgr': 195 while session.IsMutating() and not session.IsChanging(): 196 self.LogInfo('Sleeping while waiting for a session change or mutation to complete') 197 blue.pyos.synchro.SleepSim(250) 198 199 if self.__stationinvmgr is None or self.__stationID != session.stationid: 200 if session.stationid is None: 201 raise RuntimeError('CharacterNotAtStation') 202 self.__stationID = session.stationid 203 self.__stationinvmgr = eveMoniker.GetStationInventoryMgr(session.stationid) 204 return self.__stationinvmgr 205 if key in self.__dict__: 206 return self.__dict__[key] 207 raise_(AttributeError, key) 208 209 def OnItemsChanged(self, items, change, location): 210 self.LogInfo('server says do change ', change, ' for ', len(items), ' items:', items) 211 self.ValidateLocationCacheForItems(items) 212 for i, item in enumerate(items): 213 sm.ScatterEvent('OnItemChange', item, change, location) 214 blue.pyos.BeNice() 215 216 sm.ScatterEvent('OnMultipleItemChange', items, change) 217 218 def OnItemChange(self, item, change, location): 219 if const.ixQuantity in change: 220 log.LogTraceback('invCache processing a ixQuantity change') 221 if change[const.ixQuantity] < 0 or item.quantity < 0: 222 raise RuntimeError('OnItemChange in invCache: negative qty', item, change) 223 try: 224 lockKey = item.itemID 225 uthread.Lock(self, lockKey) 226 try: 227 self.LockedItemChange(item, change) 228 oldItem = blue.DBRow(item) 229 for k, v in change.iteritems(): 230 if k in (const.ixStackSize, const.ixSingleton): 231 k = const.ixQuantity 232 oldItem[k] = v 233 234 keyIs, keyWas = (None, None) 235 if session.stationid: 236 if item.locationID == session.stationid: 237 if item.ownerID == session.charid or item.ownerID == session.corpid: 238 keyIs = (const.containerHangar, None) 239 if item.flagID == const.flagCorpDeliveries: 240 keyIs = (const.containerCorpMarket, item.ownerID) 241 if item.flagID == const.flagCapsuleerDeliveries: 242 keyIs = (const.containerCapsuleerDeliveries, item.ownerID) 243 elif keyIs is None: 244 keyIs = (const.containerHangar, item.ownerID) 245 if oldItem.locationID == session.stationid: 246 if oldItem.ownerID == session.charid or oldItem.ownerID == session.corpid: 247 keyWas = (const.containerHangar, None) 248 if oldItem.flagID == const.flagCorpDeliveries: 249 keyWas = (const.containerCorpMarket, oldItem.ownerID) 250 if oldItem.flagID == const.flagCapsuleerDeliveries: 251 keyWas = (const.containerCapsuleerDeliveries, oldItem.ownerID) 252 elif keyWas is None: 253 keyWas = (const.containerHangar, oldItem.ownerID) 254 if keyIs is None: 255 keyIs = (item.locationID, None) 256 if keyWas is None: 257 keyWas = (oldItem.locationID, None) 258 if keyWas and keyWas in self.inventories: 259 inv = self.inventories[keyWas] 260 inv.OnItemChange(item, change, location) 261 if keyIs != keyWas or const.ixFlag in change: 262 if keyIs and keyIs in self.inventories: 263 inv = self.inventories[keyIs] 264 inv.OnItemChange(item, change, location) 265 if idCheckers.IsJunkLocation(item.locationID) or const.ixOwnerID in change or (const.ixQuantity in change or const.ixStackSize in change) and item.stacksize == 0: 266 if idCheckers.IsJunkLocation(item.locationID): 267 self.LogInfo('REMOVING:', item.itemID, 'item is in junk location') 268 elif const.ixOwnerID in change: 269 self.LogInfo('REMOVING:', item.itemID, ' ownership changed') 270 elif const.ixStackSize in change and item.stacksize == 0: 271 self.LogInfo('REMOVING:', item.itemID, ' new stacksize is 0') 272 if const.ixLocationID in change: 273 if self.containerGlobal: 274 self.containerGlobal.TrashItem(change[const.ixLocationID], item.itemID, item.locationID) 275 if (item.itemID, None) in self.inventories: 276 if oldItem.ownerID == session.charid != item.ownerID: 277 del self.inventories[item.itemID, None] 278 else: 279 self.inventories[item.itemID, None].item = item 280 finally: 281 sm.services['godma'].OnItemChange(item, change, location) 282 sm.services['inv'].OnItemChange(item, change, location) 283 sm.ScatterEvent('OnItemChanged', item, change, location) 284 285 finally: 286 uthread.UnLock(self, lockKey) 287 288 def LockedItemChange(self, item, change): 289 self.UnlockItem(item.itemID) 290 291 def TryLockItem(self, itemID, userErrorName = '', userErrorDict = {}, raiseIfLocked = 0): 292 try: 293 self.lockedItemsSemaphore.acquire() 294 self.LogInfo('TryLockItem', itemID) 295 bIsLocked, xlockTime, xuserErrorName, xuserErrorDict, co_name, co_filename, co_lineno, thread = self.IsItemLocked_NoLock(itemID) 296 if bIsLocked: 297 lockTime, userErrorName, userErrorDict = xlockTime, xuserErrorName, xuserErrorDict 298 else: 299 co_name = None 300 co_filname = None 301 co_lineno = None 302 if self.trace: 303 frames = traceback.extract_stack(limit=2) 304 frame = frames[1] 305 if frame[0].endswith('service.py'): 306 frame = frames[0] 307 co_name = frame[2] 308 co_filname = frame[0] 309 co_lineno = frame[1] 310 self.LogInfo('TryLockItem called by ', co_name, ' ', co_filename, '(', co_lineno, ')') 311 now = blue.os.GetWallclockTime() 312 self.lockedItems[itemID] = (now, 313 userErrorName, 314 userErrorDict, 315 co_name, 316 co_filname, 317 co_lineno, 318 stackless.getcurrent()) 319 self.LogInfo('Locked Item', itemID) 320 sm.ScatterEvent('OnItemLocked', itemID) 321 return 1 322 finally: 323 self.lockedItemsSemaphore.release() 324 325 if bIsLocked and raiseIfLocked: 326 self.RaiseLockError(itemID, lockTime, userErrorName, userErrorDict, co_name, co_filename, co_lineno) 327 return bIsLocked 328 329 def RaiseLockError(self, itemID, lockTime, userErrorName, userErrorDict, co_name, co_filename, co_lineno): 330 if len(userErrorName) == 0: 331 userErrorName = 'ItemIsLocked' 332 userErrorDict = {'reason': localization.GetByLabel('UI/Generic/NoReasonWasSpecified'), 333 'lockTime': FmtDate(lockTime)} 334 if userErrorDict == type({}): 335 userErrorDict['lockTime'] = lockTime 336 if not self.trace: 337 raise UserError(userErrorName, userErrorDict) 338 message = cfg.GetMessage(userErrorName, userErrorDict) 339 msgDict = {} 340 if co_name is None: 341 co_name = localization.GetByLabel('UI/Generic/Unknown') 342 if co_filename is None: 343 co_filename = localization.GetByLabel('UI/Generic/Unknown') 344 if co_lineno is None: 345 co_lineno = localization.GetByLabel('UI/Generic/Unknown') 346 msgDict['title'] = message.title 347 msgDict['text'] = message.text 348 msgDict['itemID'] = itemID 349 msgDict['co_name'] = co_name 350 msgDict['co_filename'] = co_filename 351 msgDict['co_lineno'] = co_lineno 352 msgDict['lockTime'] = lockTime 353 raise UserError('AdminReportItemLocked', msgDict) 354 355 def UnlockItem(self, itemID): 356 try: 357 self.lockedItemsSemaphore.acquire() 358 self.UnlockItem_NoLock(itemID) 359 finally: 360 self.lockedItemsSemaphore.release() 361 362 def UnlockItem_NoLock(self, itemID): 363 self.LogInfo('UnlockItem_NoLock', itemID) 364 if itemID in self.lockedItems: 365 del self.lockedItems[itemID] 366 self.LogInfo('Unlocked Item:', itemID) 367 sm.ScatterEvent('OnItemUnlocked', itemID) 368 else: 369 self.LogInfo('UnlockItem_NoLock irrelevant item:', itemID) 370 371 def IsItemLocked(self, itemID, raiseIfLocked = 0): 372 try: 373 self.lockedItemsSemaphore.acquire() 374 bIsLocked, lockTime, userErrorName, userErrorDict, co_name, co_filename, co_lineno, thread = self.IsItemLocked_NoLock(itemID) 375 finally: 376 self.lockedItemsSemaphore.release() 377 378 if bIsLocked and raiseIfLocked: 379 self.RaiseLockError(itemID, lockTime, userErrorName, userErrorDict, co_name, co_filename, co_lineno) 380 return bIsLocked 381 382 def IsItemLocked_NoLock(self, itemID): 383 if itemID not in self.lockedItems: 384 return (0, 385 0, 386 '', 387 {}, 388 None, 389 None, 390 None, 391 None) 392 lockTime, userErrorName, userErrorDict, co_name, co_filename, co_lineno, thread = self.lockedItems[itemID] 393 return (1, 394 lockTime, 395 userErrorName, 396 userErrorDict, 397 co_name, 398 co_filename, 399 co_lineno, 400 thread) 401 402 def RemoveInventoryContainer(self, containerItem): 403 self.LogInfo('Removing', evetypes.GetName(containerItem.typeID), 'container', containerItem.itemID, 'from cache as ownership has changed.') 404 if (containerItem.itemID, None) not in self.inventories: 405 self.LogInfo('RemoveInventoryContainer container not found in inventories') 406 return 407 for itemID, item in self.inventories[containerItem.itemID, None].cachedItems.iteritems(): 408 if cfg.IsContainer(item): 409 self.RemoveInventoryContainer(item) 410 411 del self.inventories[containerItem.itemID, None] 412 413 def GetInventoryMgr(self): 414 return self.inventorymgr 415 416 def GetItemHeader(self, force = 0): 417 if self.__itemhdr is None or force: 418 self.__itemhdr = sm.RemoteSvc('invbroker').GetItemDescriptor() 419 self.LogInfo('invCache got remote itemhdr', self.__itemhdr) 420 return self.__itemhdr 421 422 def ValidateItemCanBeOpened(self, item): 423 if not cfg.IsCargoContainer(item): 424 return True 425 if self.__invmgr: 426 return self.__invmgr.ValidateItemCanBeOpened(item) 427 return True 428 429 def ValidateItemListCanBeOpened(self, items): 430 cargoContainerItems = [] 431 for item in items: 432 if cfg.IsCargoContainer(item): 433 cargoContainerItems.append(item) 434 435 if cargoContainerItems and self.__invmgr: 436 return self.__invmgr.ValidateItemListCanBeOpened(cargoContainerItems) 437 return [] 438 439 def GetItemsInCurrentShip(self, inventoryFlags): 440 items = set() 441 inventory = self.GetInventoryFromId(session.shipid) 442 for inventoryFlag in inventoryFlags: 443 for item in inventory.List(inventoryFlag): 444 items.add(item.itemID) 445 446 return items 447 448 def _GetShipsInHangarInventory(self, inventory): 449 items = set() 450 for item in inventory.List(const.flagHangar): 451 if idCheckers.IsShip(item.categoryID): 452 items.add(item.itemID) 453 454 return items 455 456 def _GetItemsInHangarInventory(self, inventory): 457 items = set() 458 for item in inventory.List(const.flagHangar): 459 if not idCheckers.IsShip(item.categoryID): 460 items.add(item.itemID) 461 462 return items 463 464 @RaiseIfInventoryLocationUnavailable(sessionCheck=lambda : bool(session.shipid), locationName='ship') 465 def GetItemsInCurrentShipCargo(self): 466 inventoryFlags = [const.flagCargo] 467 return self.GetItemsInCurrentShip(inventoryFlags) 468 469 @RaiseIfInventoryLocationUnavailable(sessionCheck=lambda : bool(session.stationid), locationName='station') 470 def GetItemsInCurrentStationShipHangar(self): 471 inventory = self.GetInventory(const.containerHangar) 472 return self._GetShipsInHangarInventory(inventory) 473 474 @RaiseIfInventoryLocationUnavailable(sessionCheck=lambda : bool(session.stationid), locationName='station') 475 def GetItemsInCurrentStationItemHangar(self): 476 inventory = self.GetInventory(const.containerHangar) 477 return self._GetItemsInHangarInventory(inventory) 478 479 @RaiseIfInventoryLocationUnavailable(sessionCheck=lambda : bool(session.structureid), locationName='structure') 480 def GetItemsInCurrentStructureShipHangar(self): 481 inventory = self.GetInventoryFromId(session.structureid) 482 return self._GetShipsInHangarInventory(inventory) 483 484 @RaiseIfInventoryLocationUnavailable(sessionCheck=lambda : bool(session.structureid), locationName='structure') 485 def GetItemsInCurrentStructureItemHangar(self): 486 inventory = self.GetInventoryFromId(session.structureid) 487 return self._GetItemsInHangarInventory(inventory) 488 489 def GetInventory(self, containerid, param1 = None): 490 if containerid in (const.containerHangar, const.containerCorpMarket, const.containerCapsuleerDeliveries) and session.structureid: 491 containerid = const.containerStructure 492 key = (session.structureid, None) 493 else: 494 key = (containerid, param1) 495 if containerid in (const.containerHangar, const.containerCorpMarket, const.containerCapsuleerDeliveries): 496 if self.__stationID != 0 and self.__stationID != session.stationid: 497 self.InvalidateCache() 498 inventoryMgr = self.stationInventoryMgr 499 sessionCheckParams = {'stationid': self.__stationID} 500 else: 501 if self.__invlocID != session.locationid: 502 self.InvalidateCache() 503 inventoryMgr = self.inventorymgr 504 sessionCheckParams = {'locationid': self.__invlocID} 505 if containerid in SPECIAL_CONTAINER_IDS: 506 if containerid == const.containerGlobal: 507 if self.containerGlobal is None: 508 inv = Moniker('charMgr', (session.charid, containerid)) 509 self.containerGlobal = inv5MinCacheContainer(inv) 510 return self.containerGlobal 511 inv = self.inventorymgr.GetInventory(containerid, param1) 512 inv.SetSessionCheck({'locationid': self.__invlocID}) 513 return inv 514 if key not in self.inventories: 515 inv = inventoryMgr.GetInventory(containerid, param1) 516 inv.SetSessionCheck(sessionCheckParams) 517 self.inventories[key] = invCacheContainer(inv, key, self) 518 return self.inventories[key] 519 520 def GetInventoryFromId(self, itemid, passive = 0, locationID = None): 521 if itemid is None: 522 log.LogTraceback('Thou shalt not send None in as itemid to GetInventoryFromId') 523 raise IndexError 524 if locationID is None: 525 locationID = session.locationid 526 if locationID == session.locationid: 527 if locationID != self.__invlocID: 528 self.InvalidateCache() 529 inventoryMgr = self.inventorymgr 530 sessionCheckParams = {'locationid': self.__invlocID} 531 elif locationID == session.structureid: 532 if session.solarsystemid != self.__invlocID: 533 self.InvalidateCache() 534 inventoryMgr = self.inventorymgr 535 sessionCheckParams = {'locationid': self.__invlocID, 536 'structureid': session.structureid} 537 elif locationID == session.stationid: 538 if locationID != self.__stationID: 539 self.InvalidateCache() 540 inventoryMgr = self.stationInventoryMgr 541 sessionCheckParams = {'stationid': self.__stationID} 542 key = (itemid, None) 543 if key in self.inventories: 544 return self.inventories[key] 545 inv = inventoryMgr.GetInventoryFromId(itemid, passive) 546 inv.SetSessionCheck(sessionCheckParams) 547 self.inventories[key] = invCacheContainer(inv, key, self) 548 return self.inventories[key] 549 550 def IsInventoryPrimedAndListed(self, itemid): 551 key = (itemid, None) 552 inv = self.inventories.get(key, None) 553 if inv is not None and inv.listed: 554 return True 555 return False 556 557 def InvalidateCache(self): 558 self.__invmgr = None 559 self.__stationinvmgr = None 560 self.containerGlobal = None 561 for containerGuard in self.inventories.itervalues(): 562 containerGuard.moniker = None 563 564 self.inventories = {} 565 self.lockedItems = {} 566 lockKeys = self.locks.keys() 567 for lockKey in lockKeys: 568 uthread.UnLock(self, lockKey) 569 570 self.locks = {} 571 572 def ValidateLocationCacheForItems(self, items): 573 invalidItemIDs = self.ValidateItemListCanBeOpened(items) 574 for itemID in invalidItemIDs: 575 self.InvalidateLocationCache(itemID) 576 577 def InvalidateLocationCache(self, itemID): 578 key = itemID if isinstance(itemID, tuple) else (itemID, None) 579 try: 580 self.inventories[key].moniker = None 581 del self.inventories[key] 582 self.LogInfo('Invalidated location cache for ', key) 583 except KeyError: 584 pass 585 586 def InvalidateCorpCache(self): 587 keysToInvalidate = self.GetOfficeKeys() | self.GetCorpKeys() 588 for key in keysToInvalidate: 589 if key in self.inventories: 590 del self.inventories[key] 591 592 if keysToInvalidate: 593 self.LogInfo('Removed inventory for corp hangar') 594 595 def OnInvalidateCacheForLocations(self, locationIDs): 596 for locID in locationIDs: 597 self.InvalidateLocationCache(locID) 598 599 def GetOfficeKeys(self): 600 officeItemsKeys = set() 601 office = sm.GetService('officeManager').GetCorpOfficeAtLocation() 602 if office is None: 603 return officeItemsKeys 604 officeKey = (office.officeID, None) 605 officeItemsKeys.add(officeKey) 606 for key in self.inventories.keys(): 607 item = getattr(self.inventories[key], 'item', None) 608 if item: 609 locationID = getattr(item, 'locationID', None) 610 if locationID and locationID == office.officeID: 611 officeItemsKeys.add(key) 612 613 return officeItemsKeys 614 615 def GetCorpKeys(self): 616 corpItemsKeys = set() 617 for key in self.inventories.keys(): 618 item = getattr(self.inventories[key], 'item', None) 619 if item: 620 ownerID = getattr(item, 'ownerID', None) 621 if ownerID and ownerID == session.corpid: 622 corpItemsKeys.add(key) 623 624 return corpItemsKeys 625 626 def OnCapacityChange(self, moduleID): 627 key = (moduleID, None) 628 if key in self.inventories: 629 self.inventories[key].capacityByFlag = {} 630 self.inventories[key].capacityByLocation = None 631 632 def GetStationIDOfItem(self, item): 633 stationID = self.GetStationIDandOfficeIDOfItem(item)[0] 634 if stationID: 635 return stationID 636 if item.flagID in const.flagCorpSAGs: 637 if idCheckers.IsStation(item.locationID) or idCheckers.IsSolarSystem(item.locationID): 638 return None 639 if item.locationID in (session.locationid, session.structureid): 640 return item.locationID 641 invCache = sm.GetService('invCache') 642 if self.IsInventoryPrimedAndListed(item.locationID): 643 locationItem = invCache.GetInventoryFromId(item.locationID).GetItem() 644 while locationItem and locationItem.itemID not in (session.stationid, session.structureid) and locationItem.locationID > const.minStation: 645 if locationItem.typeID == const.typeAssetSafetyWrap: 646 return locationItem.locationID 647 locationItem = invCache.GetInventoryFromId(locationItem.locationID).GetItem() 648 649 def GetStationIDandOfficeIDOfItem(self, item): 650 if idCheckers.IsStation(item.locationID) or item.locationID == session.structureid: 651 return (item.locationID, None) 652 if item.flagID in const.flagCorpSAGs: 653 for office in sm.GetService('officeManager').GetMyCorporationsOffices(): 654 if item.locationID == office.officeID: 655 return (office.stationID, office.officeID) 656 657 if sm.GetService('structureDirectory').GetStructureInfo(item.locationID): 658 return (item.locationID, item.locationID) 659 return (None, None) 660 661 def FetchItem(self, itemID, fromLocationID): 662 if idCheckers.IsStation(fromLocationID): 663 inv = self.inventories.get((const.containerHangar, None), None) 664 else: 665 inv = self.inventories.get((fromLocationID, None), None) 666 if inv is None: 667 self.LogInfo('invCache::FetchItem - Could not find inventory', itemID, fromLocationID) 668 return 669 return inv.cachedItems.get(itemID, None) 670 671 def GetCachedItem(self, itemID): 672 for invCacheCont in self.inventories.values(): 673 if itemID in invCacheCont.cachedItems: 674 return invCacheCont.cachedItems[itemID] 675 676 def IsMyItemAtCurrentDockable(self, item): 677 currentDockable = session.stationid or session.structureid 678 if not currentDockable: 679 return False 680 if not item: 681 self.LogError('Failed to find if item is at current dockable: specified item is None') 682 return False 683 if item.ownerID != session.charid: 684 return False 685 isItemAtDockable = self._IsItemAtDockableBasedOnItemCache(item, currentDockable) 686 if isItemAtDockable is not None: 687 return isItemAtDockable 688 return self.GetInventoryMgr().IsMyItemAtDockableLocation(currentDockable, item) 689 690 def _IsItemAtDockableBasedOnItemCache(self, item, dockableID): 691 if item.locationID == dockableID: 692 return True 693 elif item.locationID < const.minStation: 694 return False 695 parentItem = self.GetCachedItem(item.locationID) 696 if not parentItem: 697 return None 698 else: 699 return self._IsItemAtDockableBasedOnItemCache(parentItem, dockableID) 700 701 def OnDogmaAttributeChanged(self, shipID, itemID, attributeID, value): 702 if attributeID in CAPACITY_ATTRIBUTES: 703 sm.ScatterEvent('OnCapacityChange', itemID) 704 705 def ProcessActiveShipChanged(self, shipID, oldShipID): 706 if shipID: 707 sm.ScatterEvent('OnCapacityChange', shipID) 708 key = (oldShipID, None) 709 if key in self.inventories: 710 del self.inventories[key] 711 712 def AcceptPossibleRemovalTax(self, items): 713 if not items: 714 return True 715 assetWrapItem = None 716 containerID = items[0].locationID 717 parentLocationItem = self.GetCachedItem(containerID) 718 while parentLocationItem is not None and assetWrapItem is None: 719 if parentLocationItem.typeID == const.typeAssetSafetyWrap: 720 assetWrapItem = parentLocationItem 721 parentLocationItem = self.GetCachedItem(parentLocationItem.locationID) 722 723 if assetWrapItem is None: 724 return True 725 assetInv = self.GetInventoryFromId(assetWrapItem.itemID) 726 iskToPay = assetInv.GetPriceForItems([ item.itemID for item in items ]) 727 if iskToPay == 0: 728 return True 729 response = prompt_player_fsd_dialog('CustomQuestion', {'header': localization.GetByLabel('UI/Common/Confirm'), 730 'question': localization.GetByLabel('UI/Inventory/AssetSafetyRecoveryConfirmation', tax=iskToPay)}, uiconst.YESNO) 731 if response == uiconst.ID_YES: 732 return True 733 return False 734 735 def StripFitting(self, itemID): 736 inventory = self.GetInventoryFromId(itemID) 737 fittedItems = ActiveShipController().GetModules() 738 fittedTypes = {item.typeID for item in fittedItems} 739 typesThatCannotBeUnfitted = {typeID for typeID in fittedTypes if not can_be_unfitted(typeID)} 740 if typesThatCannotBeUnfitted: 741 raise ItemCannotBeUnfitted(typesThatCannotBeUnfitted) 742 ret = inventory.StripFitting() 743 sm.ScatterEvent('OnFittingStripped', itemID) 744 return ret 745 746 747 class inv5MinCacheContainer(): 748 __update_on_reload__ = 1 749 750 def __init__(self, moniker): 751 self.moniker = moniker 752 self.listed = None 753 self.cachedItems = {} 754 self.listTime = None 755 self.listedAll = None 756 self.cachedItemsAll = {} 757 self.cachedStationItems = {} 758 self.cachedStations = (0, []) 759 self.crits = {} 760 self.deleteCacheThread = None 761 762 def __EnterCriticalSection(self, k, v = None): 763 if (k, v) not in self.crits: 764 self.crits[k, v] = uthread.CriticalSection((k, v)) 765 self.crits[k, v].acquire() 766 767 def __LeaveCriticalSection(self, k, v = None): 768 self.crits[k, v].release() 769 if (k, v) in self.crits and self.crits[k, v].IsCool(): 770 del self.crits[k, v] 771 772 def __str__(self): 773 try: 774 return 'Global inventory for %s:%d' % (cfg.eveowners.Get(session.charid).name, session.charid) 775 except Exception: 776 sys.exc_clear() 777 return 'inventory.Global instance - failed to __str__ self' 778 779 def ListStations(self): 780 self.__EnterCriticalSection('ListStations') 781 try: 782 now = blue.os.GetWallclockTime() 783 if self.cachedStations[0] + const.MIN * 5 < now: 784 self.cachedStations = (now, self.moniker.ListStations()) 785 return self.cachedStations[1] 786 finally: 787 self.__LeaveCriticalSection('ListStations') 788 789 def ListStationItems(self, stationID): 790 try: 791 self.__EnterCriticalSection('ListStationItems', stationID) 792 now = blue.os.GetWallclockTime() 793 if stationID in self.cachedStationItems: 794 if self.cachedStationItems[stationID][0] + const.MIN * 5 < now: 795 del self.cachedStationItems[stationID] 796 if stationID not in self.cachedStationItems: 797 self.cachedStationItems[stationID] = (now, self.moniker.ListStationItems(stationID)) 798 return self.cachedStationItems[stationID][1] 799 finally: 800 self.__LeaveCriticalSection('ListStationItems', stationID) 801 802 def InvalidateStationItemsCache(self, stationID): 803 if stationID in self.cachedStationItems: 804 del self.cachedStationItems[stationID] 805 806 def List(self): 807 now = blue.os.GetWallclockTime() 808 if self.listed is not None: 809 if self.listTime + const.MIN * 5 < now: 810 self.listed = None 811 self.cachedItems = {} 812 if self.listed is None: 813 self.listTime = now 814 if self.moniker is None: 815 return [] 816 realItems = self.moniker.List() 817 for realItem in realItems: 818 self.cachedItems[realItem.itemID] = realItem 819 820 self.listed = 1 821 return self.cachedItems.values() 822 823 def ListIncludingContainers(self): 824 if self.listedAll: 825 return self.cachedItemsAll.values() 826 realItems = self.moniker.ListIncludingContainers() 827 for realItem in realItems: 828 self.cachedItemsAll[realItem.itemID] = realItem 829 830 self.deleteCacheThread = uthread.new(self._DeleteCachedItemsAll) 831 self.deleteCacheThread.context = 'DeleteCahcedItemsAll' 832 self.listedAll = 1 833 return self.cachedItemsAll.values() 834 835 def GetAssetWorth(self): 836 self.moniker.Bind() 837 return self.moniker.GetAssetWorth() 838 839 def _DeleteCachedItemsAll(self): 840 blue.pyos.synchro.Sleep(const.MIN * 5 / 10000) 841 self.listedAll = 0 842 self.cachedItemsAll = {} 843 844 def TrashItem(self, stationID, itemID, locationID): 845 if stationID in self.cachedStationItems: 846 for item in self.cachedStationItems[stationID][1]: 847 if item.itemID == itemID: 848 item.locationID = locationID 849 break 850 851 852 class invCacheContainer(): 853 __update_on_reload__ = 1 854 855 def __init__(self, moniker, key, broker): 856 self.broker = broker 857 self.key = key 858 self.moniker = PasswordHandlerObjectWrapper(moniker) 859 self.cachedItems = {} 860 self.listed = set() 861 self._itemID = None 862 self._typeID = None 863 self._item = None 864 self.capacityByFlag = {} 865 self.capacityByLocation = None 866 containerIDs = (const.containerHangar, 867 const.containerWallet, 868 const.containerStationCharacters, 869 const.containerGlobal, 870 const.containerSolarSystem, 871 const.containerRecycler, 872 const.containerCharacter, 873 const.containerCorpMarket, 874 const.containerCapsuleerDeliveries) 875 if key[0] not in containerIDs: 876 self._itemID = key[0] 877 878 @property 879 def itemID(self): 880 if self._itemID is None: 881 try: 882 self._SetItemData() 883 except AttributeError as error: 884 raise_(RuntimeError, error, sys.exc_info()[2]) 885 886 return self._itemID 887 888 @property 889 def typeID(self): 890 if self._typeID is None: 891 try: 892 self._SetItemData() 893 except AttributeError as error: 894 raise_(RuntimeError, error, sys.exc_info()[2]) 895 896 return self._typeID 897 898 @property 899 def item(self): 900 if self._item is None: 901 try: 902 self._SetItemData() 903 except AttributeError as error: 904 raise_(RuntimeError, error, sys.exc_info()[2]) 905 906 return self._item 907 908 def _SetItemData(self): 909 if None in (self._itemID, self._typeID, self._item): 910 session.WaitUntilSafe() 911 if self._item is None and self.moniker is not None: 912 self._item = self.moniker.GetSelfInvItem() 913 self._itemID = self._item.itemID 914 self._typeID = self._item.typeID 915 916 def __str__(self): 917 try: 918 return 'invCacheContainer %d for %s' % (self.itemID, self.key) 919 except Exception: 920 sys.exc_clear() 921 return 'invCacheContainer instance - failed to __str__ self' 922 923 def LogInfo(self, *k, **v): 924 self.broker.LogInfo('invCacheContainer', self.key, ':', *k, **v) 925 926 def LogWarn(self, *k, **v): 927 self.broker.LogWarn('invCacheContainer', self.key, ':', *k, **v) 928 929 def LogError(self, *k, **v): 930 self.broker.LogError('invCacheContainer', self.key, ':', *k, **v) 931 932 def Add(self, itemID, sourceID, **kw): 933 activeShipID = eveCfg.GetActiveShip() 934 if itemID == activeShipID: 935 raise UserError('CanNotPlaceActiveShipInAnotherHangar') 936 dogmaLocation = sm.GetService('clientDogmaIM').GetDogmaLocation() 937 if self.itemID == activeShipID: 938 flagID = kw.get('flag', None) 939 if flagID is not None and IsFittingFlag(flagID) or flagID == const.flagAutoFit: 940 dogmaLocation.CheckCanFit(self.itemID, itemID, flagID, sourceID) 941 if 'qty' in kw and kw['qty'] == 0: 942 self.LogError('Trying to add a stack with 0 quantity to a container. Fix your code.') 943 return 944 if sm.GetService('lockedItems').IsItemIDLocked(itemID): 945 raise UserError('CrpItemIsLocked') 946 if itemID == self.itemID: 947 raise UserError('CannotPlaceItemInsideItself') 948 self.broker.TryLockItem(itemID, 'lockAddItemToContainer', {'containerType': self.typeID}, 1) 949 try: 950 if type(itemID) is tuple: 951 return dogmaLocation.UnloadAmmoToContainer(activeShipID, itemID, self.itemID, kw.get('qty')) 952 return self.moniker.Add(itemID, sourceID, **kw) 953 finally: 954 self.broker.UnlockItem(itemID) 955 956 def MultiAdd(self, itemIDs, sourceID, **kw): 957 activeShipID = eveCfg.GetActiveShip() 958 if activeShipID in itemIDs: 959 raise UserError('CanNotPlaceActiveShipInAnotherHangar') 960 dogmaLocation = sm.GetService('clientDogmaIM').GetDogmaLocation() 961 if self.itemID == activeShipID: 962 flagID = kw.get('flag', None) 963 if flagID is not None and IsFittingFlag(flagID) or flagID == const.flagAutoFit: 964 for itemID in itemIDs: 965 dogmaLocation.CheckCanFit(self.itemID, itemID, flagID, sourceID) 966 967 lockedItems = set() 968 charges = set() 969 for itemID in itemIDs: 970 if self.itemID is not None and itemID == self.itemID: 971 continue 972 if sm.GetService('lockedItems').IsItemIDLocked(itemID): 973 continue 974 if not self.broker.IsItemLocked(itemID): 975 if self.broker.TryLockItem(itemID): 976 lockedItems.add(itemID) 977 if type(itemID) is tuple: 978 charges.add(itemID) 979 dogmaLocation.UnloadAmmoToContainer(activeShipID, itemID, self.itemID) 980 981 if not len(lockedItems): 982 return 983 try: 984 nonCharges = lockedItems - charges 985 if len(nonCharges) > 0: 986 self.moniker.MultiAdd(list(nonCharges), sourceID, **kw) 987 finally: 988 for itemID in lockedItems: 989 self.broker.UnlockItem(itemID) 990 991 return True 992 993 def StackAll(self, *args, **kw): 994 if idCheckers.IsFakeItem(self.itemID): 995 self.LogInfo("StackAll called on a fake location. Why bother.. I won't do it") 996 return 997 itemIDsToLock = [] 998 types = set() 999 hasSomethingToStack = False 1000 for each in self.List(*args, **kw): 1001 if self.itemID is not None and each.itemID == self.itemID: 1002 continue 1003 if each.quantity < 0: 1004 continue 1005 if sm.GetService('lockedItems').IsItemLocked(each): 1006 continue 1007 if not hasSomethingToStack: 1008 if each.quantity != const.maxInt: 1009 if each.typeID in types: 1010 hasSomethingToStack = True 1011 types.add(each.typeID) 1012 if not self.broker.IsItemLocked(each.itemID): 1013 if self.broker.TryLockItem(each.itemID): 1014 itemIDsToLock.append(each.itemID) 1015 1016 if not len(itemIDsToLock): 1017 return 1018 try: 1019 if hasSomethingToStack: 1020 return self.moniker.StackAll(*args, **kw) 1021 finally: 1022 for itemID in itemIDsToLock: 1023 self.broker.UnlockItem(itemID) 1024 1025 def MultiMerge(self, ops, sourceContainerID): 1026 itemIDsToLock = [] 1027 for i, (sourceid, destid, qty) in enumerate(ops): 1028 if self.itemID is not None and sourceid == self.itemID: 1029 continue 1030 if sm.GetService('lockedItems').IsItemIDLocked(sourceid): 1031 continue 1032 if not self.broker.IsItemLocked(sourceid): 1033 if self.broker.TryLockItem(sourceid): 1034 itemIDsToLock.append(sourceid) 1035 1036 if not len(itemIDsToLock): 1037 return 1038 try: 1039 dogmaLocation = sm.GetService('clientDogmaIM').GetDogmaLocation() 1040 activeShipID = eveCfg.GetActiveShip() 1041 for sourceid, destid, qty in copy.copy(ops): 1042 if type(sourceid) is tuple: 1043 dogmaLocation.UnloadAmmoToContainer(activeShipID, sourceid, destid, qty) 1044 ops.remove((sourceid, destid, qty)) 1045 1046 self.LogInfo('MultiMerge - merging ops = ', len(ops)) 1047 if len(ops) > 0: 1048 self.moniker.MultiMerge(ops, sourceContainerID) 1049 finally: 1050 for itemID in itemIDsToLock: 1051 self.broker.UnlockItem(itemID) 1052 1053 def List(self, *args, **kw): 1054 flag = None 1055 if args is not None and len(args): 1056 flag = args[0] 1057 elif kw is not None and 'flag' in kw: 1058 flag = kw['flag'] 1059 if flag not in self.listed: 1060 realItems = self.moniker.List(flag=flag) 1061 for realItem in realItems: 1062 self.cachedItems[realItem.itemID] = realItem 1063 self.listed.add(realItem.flagID) 1064 1065 godmaSM = sm.GetService('godma').GetStateManager() 1066 if godmaSM.IsLocationLoaded(self.itemID): 1067 godmaItem = godmaSM.GetItem(self.itemID) 1068 if godmaItem is not None: 1069 for subloc in godmaItem.sublocations: 1070 self.cachedItems[subloc.itemID] = subloc.invItem 1071 1072 self.listed.add(flag) 1073 self.LogInfo('We now have listed', self.listed, 'in', self.key) 1074 res = CRowset(self.broker.GetItemHeader(), []) 1075 for itemID in self.cachedItems.iterkeys(): 1076 item = self.cachedItems[itemID] 1077 if flag is not None: 1078 if item.flagID != flag: 1079 continue 1080 if 'typeID' in kw and item.typeID != kw['typeID']: 1081 continue 1082 if len(item) != len(res.header): 1083 self.LogError('Invalid Item', item) 1084 continue 1085 res.append(item) 1086 1087 return res 1088 1089 def ListByFlags(self, flagIDs, **kw): 1090 res = CRowset(self.broker.GetItemHeader(), []) 1091 if not flagIDs: 1092 return res 1093 uncachedFlags = [ flagID for flagID in flagIDs if flagID not in self.listed ] 1094 if uncachedFlags: 1095 uncachedRealItems = self.moniker.ListByFlags(flags=uncachedFlags) 1096 for realItem in uncachedRealItems: 1097 self.cachedItems[realItem.itemID] = realItem 1098 self.listed.add(realItem.flagID) 1099 1100 godmaSM = sm.GetService('godma').GetStateManager() 1101 if godmaSM.IsLocationLoaded(self.itemID): 1102 godmaItem = godmaSM.GetItem(self.itemID) 1103 if godmaItem is not None: 1104 for subloc in godmaItem.sublocations: 1105 self.cachedItems[subloc.itemID] = subloc.invItem 1106 1107 for flagID in uncachedFlags: 1108 self.listed.add(flagID) 1109 1110 self.LogInfo('We now have listed', self.listed, 'in', self.key) 1111 for itemID in self.cachedItems.iterkeys(): 1112 item = self.cachedItems[itemID] 1113 if item.flagID not in flagIDs: 1114 continue 1115 if 'typeID' in kw and item.typeID != kw['typeID']: 1116 continue 1117 if len(item) != len(res.header): 1118 self.LogError('Invalid Item', item) 1119 continue 1120 res.append(item) 1121 1122 return res 1123 1124 def ListHangar(self): 1125 return self.List(const.flagHangar) 1126 1127 def ListCargo(self): 1128 return self.List(const.flagCargo) 1129 1130 def ListDroneBay(self): 1131 return self.List(const.flagDroneBay) 1132 1133 def ListHardware(self): 1134 return [ i for i in self.List() if const.flagSlotFirst <= i.flagID <= const.flagSlotLast ] 1135 1136 def ListHardwareModules(self): 1137 return [ i for i in self.List() if IsFittable(i.categoryID) and IsFittingFlag(i.flagID) ] 1138 1139 @staticmethod 1140 def IsFlagCapacityLocationWide(item): 1141 if item.groupID in (const.groupCorporateHangarArray, const.groupAssemblyArray, const.groupMobileLaboratory): 1142 return True 1143 return False 1144 1145 def GetCapacity(self, flag = None): 1146 if self.item.groupID in (const.groupStation,) or self.item.typeID in (const.typeOffice,): 1147 capacity = Row(['capacity', 'used'], [9000000000000000.0, 0.0]) 1148 return capacity 1149 if flag == flagFrigateEscapeBay: 1150 return self.GetFrigateEscapeBayCapacity(flag) 1151 if flag is None: 1152 flags = {i.flagID for i in self.List() if i.flagID is not None} 1153 if flags: 1154 capacity = Row(['capacity', 'used'], [0, 0.0]) 1155 for flag in flags: 1156 cap = self.GetCapacity(flag) 1157 if capacity.capacity == 0: 1158 capacity.capacity = cap.capacity 1159 capacity.used += cap.used 1160 1161 return capacity 1162 flag = flag or const.flagNone 1163 itemID = self.itemID 1164 if itemID is not None: 1165 godmaItem = sm.GetService('godma').GetItem(itemID) 1166 if godmaItem is not None and godmaItem.itemID in godmaItem.statemanager.invByID: 1167 if godmaItem.statemanager.invByID[godmaItem.itemID] != self: 1168 self.LogWarn('FIXUP: godma is using an old thrown away invCacheContainer') 1169 godmaItem.statemanager.invByID[godmaItem.itemID] = self 1170 capacity = godmaItem.GetCapacity(flag) 1171 return capacity 1172 capacityAttributeID = None 1173 if flag == const.flagDroneBay: 1174 capacityAttributeID = const.attributeDroneCapacity 1175 elif flag in inventoryFlagsCommon.inventoryFlagData and flag != const.flagCargo: 1176 capacityAttributeID = inventoryFlagsCommon.inventoryFlagData[flag]['attribute'] 1177 elif self.item.categoryID == const.categoryShip: 1178 if flag == const.flagShipHangar: 1179 capacityAttributeID = const.attributeShipMaintenanceBayCapacity 1180 elif flag == const.flagFleetHangar: 1181 capacityAttributeID = const.attributeFleetHangarCapacity 1182 elif flag == const.flagSecondaryStorage: 1183 capacityAttributeID = const.attributeCapacitySecondary 1184 elif self.item.groupID == const.groupSilo: 1185 capacityAttributeID = const.attributeCapacity 1186 typeID = self.typeID 1187 dogmaIM = sm.GetService('clientDogmaIM') 1188 if capacityAttributeID is not None: 1189 actualCapacity = dogmaIM.GetCapacityForItem(itemID, capacityAttributeID) 1190 if actualCapacity is None: 1191 attribs = [ x for x in dogma.data.get_type_attributes(typeID) if x.attributeID == capacityAttributeID ] 1192 if self.item.groupID == const.groupSilo and self.item.categoryID == const.categoryStarbase: 1193 actualCapacity = self.GetSiloCapacityByItemID(itemID) 1194 if actualCapacity is None and len(attribs): 1195 actualCapacity = attribs[0].value 1196 if actualCapacity is None: 1197 actualCapacity = dogma.data.get_attribute_default_value(capacityAttributeID) 1198 else: 1199 actualCapacity = None 1200 if flag == const.flagCargo: 1201 actualCapacity = dogmaIM.GetCapacityForItem(itemID, const.attributeCapacity) 1202 if actualCapacity is None: 1203 actualCapacity = evetypes.GetCapacity(typeID) 1204 used = 0.0 1205 isCustomsOffice = evetypes.GetGroupID(typeID) == const.groupPlanetaryCustomsOffices 1206 for each in self.List(flag): 1207 if isCustomsOffice and flag == const.flagHangar and each.ownerID != session.charid: 1208 continue 1209 if each.flagID == flag: 1210 used = used + GetItemVolume(each) 1211 1212 if typeID == const.typePlasticWrap: 1213 actualCapacity = used 1214 if self.item.groupID == const.groupNpcIndustrialCommand and self.item.ownerID in RW_CORPORATIONS: 1215 haulerCapacity = sm.GetService('rwService').get_hauler_capacity(itemID) 1216 if haulerCapacity is not None: 1217 actualCapacity = haulerCapacity 1218 capacity = Row(['capacity', 'used'], [actualCapacity, used]) 1219 self.capacityByLocation = capacity 1220 return capacity 1221 1222 def GetFrigateEscapeBayCapacity(self, flag): 1223 used = 0.0 1224 for each in self.List(flag): 1225 used = used + GetItemVolume(each) 1226 1227 if used: 1228 used = 1.0 1229 capacity = Row(['capacity', 'used'], [1.0, used]) 1230 return capacity 1231 1232 @Memoize(1) 1233 def GetSiloCapacityByItemID(self, itemID): 1234 return Moniker('posMgr', session.solarsystemid).GetSiloCapacityByItemID(itemID) 1235 1236 def GetItem(self, force = False): 1237 if force is True: 1238 self._itemID = self._typeID = self._item = None 1239 return self.item 1240 1241 def OnItemChange(self, item, change, location): 1242 self._ProcessItemChange(item, change) 1243 sm.ScatterEvent('OnItemChangeProcessed', item, change) 1244 1245 def _ProcessItemChange(self, item, change): 1246 oldItem = blue.DBRow(item) 1247 for k, v in change.iteritems(): 1248 if k in (const.ixStackSize, const.ixSingleton): 1249 k = const.ixQuantity 1250 oldItem[k] = v 1251 1252 location = self.key[0] 1253 owner = self.key[1] 1254 shouldCache = False 1255 if item.flagID in self.listed or item.ownerID == session.charid: 1256 shouldCache = True 1257 elif item.locationID == session.shipid: 1258 shouldCache = True 1259 elif item.ownerID == session.corpid: 1260 role = 0 1261 if item.flagID in const.corpHangarQueryRolesByFlag: 1262 role = const.corpHangarQueryRolesByFlag[item.flagID] 1263 elif self.item.groupID in const.containerGroupIDs: 1264 if not idCheckers.IsSystemOrNPC(item.locationID): 1265 try: 1266 containerItem = self.broker.GetInventoryFromId(item.locationID).GetItem() 1267 role = const.corpHangarQueryRolesByFlag[containerItem.flagID] 1268 except KeyError: 1269 pass 1270 1271 if session.corprole & role: 1272 shouldCache = True 1273 if location == const.containerHangar: 1274 if owner is not None and owner not in [item.ownerID, oldItem.ownerID]: 1275 return 1276 if not session.stationid: 1277 return 1278 if location == const.containerHangar and owner is not None and item.ownerID == owner and const.ixOwnerID in change: 1279 self.cachedItems[item.itemID] = item 1280 return 1281 if item.locationID != session.stationid or item.stacksize == 0 or item.ownerID != session.charid: 1282 if oldItem.flagID in self.capacityByFlag: 1283 del self.capacityByFlag[oldItem.flagID] 1284 elif self.item and self.IsFlagCapacityLocationWide(self.item): 1285 self.capacityByLocation = None 1286 if item.itemID in self.cachedItems: 1287 del self.cachedItems[item.itemID] 1288 return 1289 if item.ownerID == session.charid: 1290 if oldItem.flagID in self.capacityByFlag: 1291 del self.capacityByFlag[oldItem.flagID] 1292 elif self.item and self.IsFlagCapacityLocationWide(self.item): 1293 self.capacityByLocation = None 1294 self.cachedItems[item.itemID] = item 1295 elif location in (const.containerCorpMarket, const.containerCapsuleerDeliveries): 1296 if owner is not None and owner not in [item.ownerID, oldItem.ownerID]: 1297 return 1298 if not session.stationid: 1299 return 1300 if item.locationID != session.stationid or item.stacksize == 0 or item.ownerID != session.corpid: 1301 if oldItem.flagID in self.capacityByFlag: 1302 del self.capacityByFlag[oldItem.flagID] 1303 elif self.item and self.IsFlagCapacityLocationWide(self.item): 1304 self.capacityByLocation = None 1305 if item.itemID in self.cachedItems: 1306 del self.cachedItems[item.itemID] 1307 return 1308 if item.ownerID == session.corpid: 1309 if oldItem.flagID in self.capacityByFlag: 1310 del self.capacityByFlag[oldItem.flagID] 1311 elif self.item and self.IsFlagCapacityLocationWide(self.item): 1312 self.capacityByLocation = None 1313 if oldItem.locationID != session.stationid and item.locationID == session.stationid: 1314 if item.itemID in self.cachedItems: 1315 del self.cachedItems[item.itemID] 1316 self.cachedItems[item.itemID] = item 1317 else: 1318 if item.itemID in self.cachedItems: 1319 del self.cachedItems[item.itemID] 1320 self.cachedItems[item.itemID] = item 1321 elif item.locationID != location or item.stacksize == 0: 1322 if item.itemID in self.cachedItems: 1323 del self.cachedItems[item.itemID] 1324 if oldItem.flagID in self.capacityByFlag: 1325 del self.capacityByFlag[oldItem.flagID] 1326 elif self.item and self.IsFlagCapacityLocationWide(self.item): 1327 self.capacityByLocation = None 1328 elif oldItem.locationID != location and item.locationID == location: 1329 if item.itemID in self.cachedItems: 1330 del self.cachedItems[item.itemID] 1331 if shouldCache: 1332 self.cachedItems[item.itemID] = item 1333 if item.flagID in self.capacityByFlag: 1334 del self.capacityByFlag[item.flagID] 1335 elif self.item and self.IsFlagCapacityLocationWide(self.item): 1336 self.capacityByLocation = None 1337 else: 1338 if item.itemID in self.cachedItems: 1339 del self.cachedItems[item.itemID] 1340 if shouldCache: 1341 self.cachedItems[item.itemID] = item 1342 if item.flagID in self.capacityByFlag: 1343 del self.capacityByFlag[item.flagID] 1344 elif self.item and self.IsFlagCapacityLocationWide(self.item): 1345 self.capacityByLocation = None 1346 if const.ixFlag in change: 1347 if oldItem.flagID in self.capacityByFlag: 1348 del self.capacityByFlag[oldItem.flagID] 1349 elif self.item and self.IsFlagCapacityLocationWide(self.item): 1350 self.capacityByLocation = None 1351 1352 def __getattr__(self, method): 1353 if method in self.__dict__: 1354 return self.__dict__[method] 1355 if method.startswith('__'): 1356 raise AttributeError(method) 1357 if not hasattr(self.moniker, method): 1358 raise AttributeError(method) 1359 return FastInvCallWrapper(self.moniker, method) 1360 1361 1362 class PasswordHandlerCallWrapper(): 1363 1364 def __init__(self, object, method): 1365 self.__method__ = method 1366 self.__callable__ = object 1367 1368 def __call__(self, *args, **keywords): 1369 try: 1370 return getattr(self.__callable__, self.__method__)(*args, **keywords) 1371 except UserError as what: 1372 if what.args[0] == 'PasswordProtectedCacheInvalid': 1373 invCache = sm.GetService('invCache') 1374 invCache.InvalidateLocationCache(args[1]) 1375 raise UserError('SCGeneralPasswordRequired') 1376 else: 1377 if what.args[0] in ('SCGeneralPasswordRequired', 'SCConfigPasswordRequired') and self.__method__ != 'SetPassword': 1378 if what.args[0] == 'SCGeneralPasswordRequired': 1379 which = const.SCCPasswordTypeGeneral 1380 caption = localization.GetByLabel('UI/Inventory/ItemActions/AccessPasswordRequiredCaption') 1381 label = localization.GetByLabel('UI/Inventory/ItemActions/PleaseEnterAccessPassword') 1382 else: 1383 which = const.SCCPasswordTypeConfig 1384 caption = localization.GetByLabel('UI/Inventory/ItemActions/ConfigurationPasswordRequiredCaption') 1385 label = localization.GetByLabel('UI/Inventory/ItemActions/PleaseEnterConfigurationPassword') 1386 passw = utilWindows.NamePopup(caption=caption, label=label, setvalue='', maxLength=16, passwordChar='*') 1387 if passw is None: 1388 raise 1389 sys.exc_clear() 1390 self.__callable__.EnterPassword(which, passw) 1391 return self.__call__(*args, **keywords) 1392 raise 1393 finally: 1394 self.__dict__.clear() 1395 1396 1397 class PasswordHandlerObjectWrapper(): 1398 1399 def __init__(self, object): 1400 self.__object = object 1401 1402 def __getattr__(self, attributeName): 1403 if attributeName.startswith('__'): 1404 raise AttributeError(attributeName) 1405 if not hasattr(self.__object, attributeName): 1406 raise AttributeError(attributeName) 1407 return PasswordHandlerCallWrapper(self.__object, attributeName) 1408 1409 1410 class FastInvCallWrapper(): 1411 1412 def __init__(self, object, method): 1413 self.__method__ = method 1414 self.__callable__ = object 1415 1416 def __call__(self, *args, **keywords): 1417 try: 1418 return getattr(self.__callable__, self.__method__)(*args, **keywords) 1419 finally: 1420 self.__dict__.clear()