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

tryFit.py (11964B)


      1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\client\script\ui\shared\fittingScreen\tryFit.py
      2 from itertools import groupby
      3 import blue
      4 import evetypes
      5 import log
      6 from carbon.client.script.environment.AudioUtil import PlaySound
      7 from carbonui import uiconst
      8 from collections import defaultdict
      9 from dogma.ammoloadingUtils import GetModuleCapacityForAmmoType
     10 from eve.client.script.environment import invControllers as invCtrl
     11 from eve.client.script.ui.shared.fitting.fittingUtil import RigFittingCheck
     12 from eve.common.script.sys.idCheckers import IsStation, IsSolarSystem, flagCorpSAGs
     13 from inventorycommon.const import flagFrigateEscapeBay
     14 from inventorycommon.util import IsFittingModule, IsShipFittingFlag
     15 from player_messaging.client.ui_message import prompt_player_fsd_dialog
     16 from shipfitting.fittingStuff import GetSlotTypeForType
     17 from utillib import KeyVal
     18 FAKE_ITEM_GUID = ['listentry.GenericMarketItem',
     19  'listentry.Item',
     20  'uicls.GenericDraggableForTypeID',
     21  'listentry.QuickbarItem',
     22  'listentry.ContractItemSelect',
     23  'listentry.FittingModuleEntry',
     24  'listentry.KillItems']
     25 FAKE_ITEM_LOCATION_GUID = ['xtriui.ListSurroundingsBtn']
     26 
     27 class TryFitter(object):
     28 
     29     def __init__(self):
     30         self.ghostFittingSvc = sm.GetService('ghostFittingSvc')
     31 
     32     def TryFit(self, realInvItems, fakeInvItems, controller, shipID = None):
     33         if not shipID:
     34             shipID = session.shipid
     35             if not shipID:
     36                 return
     37         invItems = realInvItems + fakeInvItems
     38         dogmaLocation = controller.GetDogmaLocation()
     39         charges, drones, fakeFighters, newInvItems = self.GetInvItemsToFit(invItems, controller)
     40         if len(newInvItems) == 1:
     41             invItem = invItems[0]
     42             if self.IsShipOrStructure(invItem):
     43                 return GhostFitShip(invItem)
     44         if not controller.IsSimulated() and not realInvItems and fakeInvItems:
     45             self.ghostFittingSvc.LoadCurrentShip()
     46         if len(newInvItems) > 0:
     47             sourceID = getattr(newInvItems[0], 'locationID', None)
     48             self.FitModule(shipID, sourceID, newInvItems, controller)
     49         if drones:
     50             self.AddDrones(drones, shipID, controller)
     51         if fakeFighters:
     52             self.AddSimulatedFighters(fakeFighters, shipID, controller)
     53         if charges:
     54             self.TryFitCharges(dogmaLocation, shipID, controller, charges)
     55 
     56     def IsModuleSuitable(self, dogmaLocation, usedWith, module):
     57         if not IsShipFittingFlag(module.flagID):
     58             return False
     59         if module.typeID not in usedWith:
     60             return False
     61         if self.IsWeaponBankSlave(dogmaLocation, module):
     62             return False
     63         if self.IsCharge(module):
     64             return False
     65         return True
     66 
     67     def IsCharge(self, row):
     68         return row.categoryID == const.categoryCharge
     69 
     70     def IsWeaponBankSlave(self, dogmaLocation, row):
     71         return dogmaLocation.IsInWeaponBank(row.locationID, row.itemID) and dogmaLocation.IsModuleSlave(row.itemID, row.locationID)
     72 
     73     def IsShipOrStructure(self, invItem):
     74         categoryID = evetypes.GetCategoryID(invItem.typeID)
     75         if categoryID in (const.categoryShip, const.categoryStructure):
     76             return True
     77 
     78     def GetInvItemsToFit(self, invItems, controller):
     79         isSimulated = controller.IsSimulated()
     80         if isSimulated:
     81             useRigs = True
     82         else:
     83             useRigs = None
     84         charges = []
     85         drones = []
     86         fakeFighters = []
     87         newInvItems = []
     88         subSystemGroupIDs = set()
     89         for eachInvItem in invItems[:]:
     90             categoryID = evetypes.GetCategoryID(eachInvItem.typeID)
     91             if IsFittingModule(categoryID):
     92                 slotEffect = GetSlotTypeForType(eachInvItem.typeID)
     93                 if slotEffect == const.effectRigSlot:
     94                     if useRigs is None:
     95                         useRigs = RigFittingCheck(eachInvItem, controller.GetTypeID())
     96                     if useRigs:
     97                         newInvItems.append(eachInvItem)
     98                     continue
     99             if categoryID == const.categorySubSystem:
    100                 if eachInvItem.groupID not in subSystemGroupIDs:
    101                     subSystemGroupIDs.add(eachInvItem.groupID)
    102                     newInvItems.append(eachInvItem)
    103                 continue
    104             elif categoryID == const.categoryCharge:
    105                 charges.append(eachInvItem)
    106                 continue
    107             elif categoryID == const.categoryDrone:
    108                 drones.append(eachInvItem)
    109                 continue
    110             elif isSimulated and categoryID == const.categoryFighter:
    111                 fakeFighters.append(eachInvItem)
    112                 continue
    113             newInvItems.append(eachInvItem)
    114 
    115         return (charges,
    116          drones,
    117          fakeFighters,
    118          newInvItems)
    119 
    120     def FitModule(self, shipID, sourceID, invItems, controller):
    121         PlaySound(uiconst.SOUND_ADD_OR_USE)
    122         if controller.IsSimulated():
    123             sortedInvItems = sorted(invItems, key=lambda x: x.typeID)
    124             for each in sortedInvItems:
    125                 self.ghostFittingSvc.TryFitModuleToOneSlot(each.typeID, feedbackTimeOut=True, originalItemID=getattr(each, 'itemID', None))
    126 
    127         else:
    128             itemIDs = [ invItem.itemID for invItem in invItems ]
    129             shipInv = sm.GetService('invCache').GetInventoryFromId(shipID, locationID=session.stationid)
    130             shipInv.moniker.MultiAdd(itemIDs, sourceID, flag=const.flagAutoFit)
    131 
    132     def TryFitCharges(self, dogmaLocation, shipID, controller, charges):
    133         if controller.IsSimulated():
    134             return self.TryFitGhostCharges(charges)
    135         loadResults = None
    136         infoSvc = sm.GetService('info')
    137         sortKey = lambda charge: charge.typeID
    138         loadedModules = set()
    139         for chargeTypeID, chargeItems in groupby(sorted(charges, key=sortKey), sortKey):
    140             usedWith = infoSvc.GetUsedWithTypeIDs(chargeTypeID)
    141             if usedWith is None:
    142                 continue
    143             try:
    144                 dogmaLocation.CheckSkillRequirementsForType(None, chargeTypeID, 'FittingHasSkillPrerequisites')
    145             except UserError as e:
    146                 loadResults = e
    147                 continue
    148 
    149             chargeItems = list(chargeItems)
    150             availableRounds = sum((c.stacksize for c in chargeItems))
    151             isCrystalOrScript = evetypes.GetGroupID(chargeTypeID) in cfg.GetCrystalGroups()
    152             fittedItems = dogmaLocation.GetFittedItemsToShip().values()
    153             fittedItems = sorted(fittedItems, key=lambda x: getattr(x, 'flagID', None))
    154             suitableModules = set()
    155             for moduleItem in fittedItems:
    156                 if availableRounds <= 0:
    157                     break
    158                 if moduleItem.itemID in loadedModules:
    159                     continue
    160                 if not self.IsModuleSuitable(dogmaLocation, usedWith, moduleItem):
    161                     continue
    162                 if isCrystalOrScript:
    163                     if len([ i for i in fittedItems if i.flagID == moduleItem.flagID if i.itemID != moduleItem.itemID ]):
    164                         continue
    165                     availableRounds -= 1
    166                 else:
    167                     subLocation = dogmaLocation.GetSubLocation(shipID, moduleItem.flagID)
    168                     if subLocation is not None and subLocation[2] != chargeTypeID:
    169                         continue
    170                     neededRounds = GetModuleCapacityForAmmoType(moduleItem.typeID, chargeTypeID, dogmaLocation.dogmaStaticMgr)
    171                     if subLocation is not None:
    172                         neededRounds -= dogmaLocation.GetQuantity(subLocation)
    173                     if neededRounds <= 0:
    174                         continue
    175                     availableRounds -= neededRounds
    176                 suitableModules.add(moduleItem.itemID)
    177 
    178             if len(suitableModules):
    179                 try:
    180                     dogmaLocation.LoadAmmoToModules(shipID, suitableModules, [ c.itemID for c in chargeItems ], chargeItems[0].locationID)
    181                     loadResults = True
    182                     loadedModules.update(suitableModules)
    183                 except Exception as e:
    184                     loadResults = e
    185 
    186             blue.pyos.synchro.SleepSim(50)
    187 
    188         if isinstance(loadResults, UserError):
    189             raise loadResults
    190         elif not loadedModules:
    191             prompt_player_fsd_dialog('NoSuitableModules')
    192 
    193     def TryFitGhostCharges(self, charges):
    194         chargeTypeIDs = {x.typeID for x in charges}
    195         self.ghostFittingSvc.TryFitFakeAmmoToAllModulesFitted(chargeTypeIDs)
    196 
    197     def AddDrones(self, drones, shipID, controller):
    198         if controller.IsSimulated():
    199             qtyByTypeAndItemID = defaultdict(int)
    200             for eachDrone in drones:
    201                 qtyByTypeAndItemID[eachDrone.typeID, eachDrone.itemID] += 1
    202 
    203             self.ghostFittingSvc.TryFitDronesToDroneBay(qtyByTypeAndItemID)
    204         else:
    205             invCtrl.ShipDroneBay(shipID).AddItems(drones)
    206 
    207     def AddSimulatedFighters(self, fighters, shipID, controller):
    208         if not controller.IsSimulated():
    209             return
    210         qtyByTypeID = defaultdict(int)
    211         for eachFighter in fighters:
    212             qtyByTypeID[eachFighter.typeID] += getattr(eachFighter, 'stacksize', None) or 1
    213 
    214         self.ghostFittingSvc.TryFitFightersToTubeOrBay(qtyByTypeID)
    215 
    216 
    217 def GhostFitShip(invItem):
    218     shipTypeID = invItem.typeID
    219     fitData = []
    220     oringalItemIDByFlagAndTypeID = {}
    221     itemID = getattr(invItem, 'itemID', None)
    222     if itemID:
    223         dockableLocationID, solarSystemID, ownerID = _GetOwnerAndLocationID(invItem)
    224         if (dockableLocationID or solarSystemID) and ownerID in (session.charid, session.corpid):
    225             try:
    226                 fitData, oringalItemIDByFlagAndTypeID = sm.GetService('fittingSvc').FittingDictForRemoteShip(itemID, putModuleAmmoInCargo=True, dockableLocationID=dockableLocationID, solarSystemID=solarSystemID)
    227             except Exception as e:
    228                 if isinstance(e, UserError) and e.msg == 'InventoryStopSpamming':
    229                     raise
    230                 log.LogWarn('Tryfit - failed to get fitdata, e = ', e)
    231 
    232     fitting = KeyVal(shipTypeID=shipTypeID, fittingID=None, ownerID=None, fitData=fitData)
    233     sm.GetService('ghostFittingSvc').SimulateFitting(fitting, oringalItemIDByFlagAndTypeID)
    234 
    235 
    236 def _GetOwnerAndLocationID(invItem):
    237     dockableLocationID = getattr(invItem, 'locationID', None)
    238     solarSystemID = None
    239     ownerID = getattr(invItem, 'ownerID', None)
    240     item = getattr(invItem, 'item', invItem)
    241     if ownerID is None and item:
    242         ownerID = getattr(item, 'ownerID', None)
    243     if dockableLocationID is None and item:
    244         dockableLocationID = getattr(item, 'locationID', None)
    245     if item and item.flagID in (const.flagCargo, const.flagShipHangar, flagFrigateEscapeBay):
    246         parentShipInfo = GetParentShipInfo(item)
    247         if parentShipInfo:
    248             dockableLocationID, solarSystemID = parentShipInfo
    249     elif ownerID == session.corpid and item and item.flagID in flagCorpSAGs:
    250         for office in sm.GetService('officeManager').GetMyCorporationsOffices():
    251             if office.officeID == dockableLocationID:
    252                 dockableLocationID = office.stationID
    253                 break
    254 
    255     return (dockableLocationID, solarSystemID, ownerID)
    256 
    257 
    258 def GetParentShipInfo(item):
    259     parentShip = sm.GetService('invCache').GetInventoryFromId(item.locationID).GetItem()
    260     if not parentShip:
    261         return
    262     dockableLocationID = solarSystemID = None
    263     itemLocation = parentShip.locationID
    264     if IsStation(itemLocation):
    265         dockableLocationID = itemLocation
    266     elif IsSolarSystem(itemLocation):
    267         dockableLocationID = None
    268         solarSystemID = itemLocation
    269     elif sm.GetService('structureDirectory').GetStructureInfo(itemLocation) is not None:
    270         dockableLocationID = itemLocation
    271     return (dockableLocationID, solarSystemID)