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

hubController.py (27917B)


      1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\client\script\ui\shared\sov\sovHub\hubController.py
      2 import eveformat
      3 import evetypes
      4 import locks
      5 import uthread
      6 import uthread2
      7 from brennivin.itertoolsext import Bundle
      8 from carbon.common.script.util.format import FmtAmt
      9 from eve.client.script.ui import eveColor
     10 from eve.client.script.ui.shared.sov.sovHub.upgradeEntry import UpgradeTypeDragData
     11 from eve.client.script.ui.shared.sov.sovHub.upgradeEntryController import UpgradeEntryController
     12 from eve.common.script.sys import devIndexUtil
     13 from eve.common.script.sys.idCheckers import IsNPCCorporation
     14 from localization import GetByLabel
     15 from player_messaging.client.ui_message import prompt_player_fsd_dialog
     16 from signals import Signal
     17 from sovereignty.client.quasarCallWrapper import QuasarCallWrapper, DATA_NOT_AVAILABLE
     18 from sovereignty.client.sovHub.dataTypes import UpgradeData
     19 from sovereignty.upgrades.client.errors import SovUpgradeDataUnavailableError, SovUpgradeUninstallError, SovUpgradeInstallError
     20 from sovereignty.client.sovHub.hubUtil import GetPowerForUpgrades, GetWorkforceForUpgrades, GetConsumptionPerHour, GetStartupCost, GetHoursLeft, GetTimeLeftTextForTypeID, UpdateEffectiveStatesForUpgrades, GetHoursLeftProgress, GetPowerProductionForUpgrades, GetWorkforceProductionForUpgrades
     21 from sovereignty.workforce.client.workforceController import WorkforceController
     22 from stackless_response_router.exceptions import TimeoutException
     23 import inventorycommon.const as invConst
     24 import carbonui.const as uiconst
     25 import blue
     26 import sovereignty.upgrades.const as upgrades_const
     27 import logging
     28 logger = logging.getLogger(__name__)
     29 NO_ACL_SET = -99
     30 NOT_AVAILABLE = -999
     31 NOT_DEFINED = 'notDefined'
     32 
     33 class HubController(object):
     34     __notifyevents__ = ['OnHubUpgradesStateChanged', 'OnHubWorkforceConfigureChanged', 'OnHubWorkforceStateChanged']
     35 
     36     def __init__(self, itemID, solarSystemID):
     37         self._itemID = itemID
     38         self._solarSystemID = solarSystemID
     39         self._systemClaimTime = NOT_DEFINED
     40         self.sovHubSvc = sm.GetService('sovHubSvc')
     41         self.sovereigntyResourceSvc = sm.GetService('sovereigntyResourceSvc')
     42         self.quasarCallWrapper = QuasarCallWrapper(self.sovHubSvc, self.sovereigntyResourceSvc)
     43         self.workforceController = WorkforceController(self.itemID, self.quasarCallWrapper, self.solarSystemID)
     44         self.sovSvc = sm.GetService('sov')
     45         self.upgradeItemIDsPendingInstall = []
     46         fuelACL = self.sovSvc.GetSovHubFuelAccessGroup(self._solarSystemID)
     47         self._maxSystemPower, self._maxWorkforce = self.sovereigntyResourceSvc.GetMaxPowerAndWorkforce(solarSystemID)
     48         self._allowedTypeIDs = evetypes.GetTypeIDsByGroups(upgrades_const.UPGRADE_GROUP_IDS)
     49         self._accessGroupOptions = None
     50         self._availableHubResources = None
     51         self._simulatedInstalledUpgrades = None
     52         self._originalInstalledUpgradeData = None
     53         self._newUpgrades = {}
     54         self._currentFuelACL = fuelACL
     55         self._tempWorkforceMode = 1
     56         self._hubReagentsByTypeID = {}
     57         self.on_order_changed = Signal(signalName='order_changed')
     58         self.on_online_state_changed = Signal(signalName='on_online_state_changed')
     59         self.on_acl_changed = Signal(signalName='on_acl_changed')
     60         self.on_acl_setting_failed = Signal(signalName='on_acl_setting_failed')
     61         self.on_upgrades_changed = Signal(signalName='on_upgrades_changed')
     62         self.on_legend_moused_over = Signal(signalName='on_legend_moused_over')
     63         sm.RegisterNotify(self)
     64         uthread2.StartTasklet(self.PrimeSovHubInfo)
     65 
     66     def IsSameItemID(self, itemID):
     67         return self.itemID == itemID
     68 
     69     @property
     70     def itemID(self):
     71         return self._itemID
     72 
     73     @property
     74     def solarSystemID(self):
     75         return self._solarSystemID
     76 
     77     @property
     78     def fuelACL(self):
     79         return self._currentFuelACL
     80 
     81     @property
     82     def _availableLocalPower(self):
     83         self._PrimeAvailableResources()
     84         return self._availableHubResources.power_available
     85 
     86     @property
     87     def _availableSystemWorkforce(self):
     88         self._PrimeAvailableResources()
     89         return self._availableHubResources.workforce_available
     90 
     91     @property
     92     def _localHarvestWorkforce(self):
     93         self._PrimeAvailableResources()
     94         return self._availableHubResources.workforce_local_harvest
     95 
     96     def PrimeData(self):
     97         parallelCalls = [(self._PrimeInstalledUpgrades, ()),
     98          (self._PrimeAvailableResources, ()),
     99          (self._PrimeStaticDataForUpgrades, ()),
    100          (self._PrimeGetReagentsByTypeID, ())]
    101         installedError, _, failureStatus, _ = uthread.parallel(parallelCalls)
    102         if NOT_AVAILABLE in (installedError, failureStatus):
    103             raise SovUpgradeDataUnavailableError()
    104 
    105     def _PrimeInstalledUpgrades(self):
    106         if self.installedUpgradesSimulated is not None:
    107             return
    108         with locks.TempLock('HubController_Prime_upgrades%s' % self._itemID):
    109             if self.installedUpgradesSimulated is None:
    110                 installedUpgrades = self._GetInstalledUpgrades()
    111                 if installedUpgrades == NOT_AVAILABLE:
    112                     return NOT_AVAILABLE
    113                 self._simulatedInstalledUpgrades = [ UpgradeData.create_from_installed_upgrade_data(x, self.sovHubSvc) for x in installedUpgrades ]
    114                 self._originalInstalledUpgradeData = [ x.take_copy() for x in installedUpgrades ]
    115 
    116     def _GetInstalledUpgrades(self):
    117         installedUpgradesOriginal = self.quasarCallWrapper.GetInstalledUpgradesForHub(self._itemID)
    118         if installedUpgradesOriginal == DATA_NOT_AVAILABLE:
    119             return NOT_AVAILABLE
    120         return installedUpgradesOriginal
    121 
    122     def _PrimeAvailableResources(self):
    123         if self.AreResourcesSet():
    124             return
    125         with locks.TempLock('GetAvailableHubResources_%s' % self.itemID):
    126             if self.AreResourcesSet():
    127                 return
    128             availableSovHubResources = self.sovereigntyResourceSvc.GetAvailableHubResources(self.itemID)
    129             self._availableHubResources = availableSovHubResources
    130 
    131     def _PrimeStaticDataForUpgrades(self):
    132         failureStatus = self.quasarCallWrapper.PrimeStaticDataForUpgrades()
    133         return failureStatus
    134 
    135     def AreResourcesSet(self):
    136         return self._availableHubResources is not None
    137 
    138     def _PrimeGetReagentsByTypeID(self):
    139         reagentsByTypeID = self.sovHubSvc.GetReagentsByTypeID(self._itemID)
    140         self._hubReagentsByTypeID = {x:y.take_copy() for x, y in reagentsByTypeID.iteritems()}
    141 
    142     def GetInstalledUpgradesEntryControllers(self):
    143         dataList = []
    144         self.UpdateEffectiveStatesForSimulatedUpgrades()
    145         for i, installedUpgrade in enumerate(self.installedUpgradesSimulated):
    146             upgradeData = UpgradeEntryController(installedUpgrade, i, self, installedUpgrade.powerState)
    147             dataList.append(upgradeData)
    148 
    149         return dataList
    150 
    151     def GetNoInstalledUpgradesHint(self):
    152         if self.solarSystemID == session.solarsystemid:
    153             return GetByLabel('UI/Sovereignty/SovHub/Upgrades/DropUpgradesToAdd')
    154         else:
    155             return GetByLabel('UI/Sovereignty/SovHub/Upgrades/NoUpgradesInstalled')
    156 
    157     def VerifyStateIsCorrectOnFirstLoad(self):
    158         simulated = {x.typeID:x.powerState for x in self.installedUpgradesSimulated}
    159         original = {x.upgrade_type_id:x.power_state for x in self.originalInstalledUpgradeData}
    160         if simulated != original:
    161             prompt_player_fsd_dialog('CustomInfo', {'info': 'There seems to be a mismatch'})
    162 
    163     def GetDropError(self, data):
    164         isEntryInWnd = isinstance(data, UpgradeTypeDragData)
    165         if isEntryInWnd:
    166             return
    167         if data.__guid__ not in ('xtriui.InvItem', 'listentry.InvItem'):
    168             return GetByLabel('UI/Sovereignty/SovHub/Upgrades/SovHubUpgradeCannotBeAddedNotItem')
    169         dataTypeID = data.invtype
    170         if not self._IsTypeAllowed(dataTypeID):
    171             return GetByLabel('UI/Sovereignty/SovHub/Upgrades/SovHubUpgradeCannotBeAddedTypeNotValid')
    172         if not self._IsUpgradeAllowed(dataTypeID):
    173             return GetByLabel('UI/Sovereignty/SovHub/Upgrades/SovHubUpgradeCannotBeAddedAlreadyInstalled')
    174         if self._IsInMutuallyExclusiveGroup(dataTypeID):
    175             return GetByLabel('UI/Sovereignty/SovHub/Upgrades/UpgradeSlotFilled')
    176         if not self._IsEnoughPowerLeftInSystem(dataTypeID):
    177             return GetByLabel('UI/Sovereignty/SovHub/Upgrades/NotEnoughPower')
    178         if not isEntryInWnd and not self._IsInTransferRange():
    179             return GetByLabel('UI/Sovereignty/SovHub/Upgrades/SovHubUpgradeCannotBeAddedNotInRange')
    180         if not self._IsSovReqMet(dataTypeID):
    181             return GetByLabel('UI/Sovereignty/SovHub/Upgrades/SovHubUpgradeCannotBeAddedSovLevelTooLow')
    182         if data.rec.locationID != session.shipid:
    183             return GetByLabel('UI/Sovereignty/SovHub/Upgrades/SovHubUpgradeCannotBeAddedNotInShip')
    184 
    185     def _IsTypeAllowed(self, typeID):
    186         return typeID in self._allowedTypeIDs
    187 
    188     def _IsUpgradeAllowed(self, typeID):
    189         currentTypeIDs = [ x.typeID for x in self.installedUpgradesSimulated ]
    190         if typeID in currentTypeIDs:
    191             return False
    192         return True
    193 
    194     def _IsInTransferRange(self):
    195         bp = sm.GetService('michelle').GetBallpark()
    196         if bp is None:
    197             return False
    198         if session.shipid not in bp.balls:
    199             return False
    200         if self.itemID not in bp.balls:
    201             return False
    202         dist = bp.DistanceBetween(session.shipid, self.itemID)
    203         if dist is None:
    204             return False
    205         if dist > const.maxCargoContainerTransferDistance:
    206             return False
    207         return True
    208 
    209     def _IsEnoughPowerLeftInSystem(self, typeID):
    210         return True
    211 
    212     def _IsInMutuallyExclusiveGroup(self, typeID):
    213         upgradeStaticData = self.sovHubSvc.GetStaticDataForUpgrade(typeID)
    214         mutually_exclusive_group = upgradeStaticData.mutually_exclusive_group
    215         for upgrade in self.installedUpgradesSimulated:
    216             if upgrade.staticData.mutually_exclusive_group == mutually_exclusive_group:
    217                 return True
    218 
    219         return False
    220 
    221     def _IsSovReqMet(self, typeID):
    222         requiredSovereigntyLevel = int(sm.GetService('godma').GetTypeAttribute(typeID, const.attributeDevIndexSovereignty, 0))
    223         if requiredSovereigntyLevel:
    224             if self.systemClaimTime is None:
    225                 return False
    226             sovHeldFor = (blue.os.GetWallclockTime() - self.systemClaimTime) / const.DAY
    227             if devIndexUtil.GetTimeIndexLevelForDays(sovHeldFor) < requiredSovereigntyLevel:
    228                 return False
    229         return True
    230 
    231     @property
    232     def systemClaimTime(self):
    233         if self._systemClaimTime == NOT_DEFINED:
    234             iHubInfo = self.sovSvc.GetInfrastructureHubInfo(self.solarSystemID)
    235             if iHubInfo:
    236                 self._systemClaimTime = iHubInfo.claimTime
    237             else:
    238                 self._systemClaimTime = None
    239         return self._systemClaimTime
    240 
    241     def PrimeSovHubInfo(self):
    242         self.systemClaimTime
    243 
    244     def DoDropData(self, dragObj, entries, idx = -1):
    245         if not entries:
    246             return
    247         data = entries[0]
    248         if isinstance(data, UpgradeTypeDragData):
    249             self.DoMove(data, idx)
    250         elif data.__guid__ in ('xtriui.InvItem', 'listentry.InvItem'):
    251             dropError = self.GetDropError(data)
    252             if dropError:
    253                 prompt_player_fsd_dialog('CustomNotify', {'notify': dropError})
    254                 return
    255             dataTypeID = data.invtype
    256             rec = data.rec
    257             itemID = rec.itemID
    258             self._newUpgrades[rec.itemID] = rec
    259             upgradeData = self._GetUpgradeDataForUpgradeItem(dataTypeID, itemID)
    260             if idx < 0:
    261                 self.installedUpgradesSimulated.append(upgradeData)
    262             else:
    263                 self.installedUpgradesSimulated.insert(idx, upgradeData)
    264             self.on_order_changed()
    265             self.on_online_state_changed(dataTypeID)
    266         else:
    267             prompt_player_fsd_dialog('CustomNotify', {'notify': GetByLabel('UI/Sovereignty/SovHub/Upgrades/SovHubUpgradeCannotBeAddedNotItem')})
    268 
    269     def _GetUpgradeDataForUpgradeItem(self, typeID, itemID):
    270         staticData = self.sovHubSvc.GetStaticDataForUpgrade(typeID)
    271         return UpgradeData(typeID, True, staticData, itemID=itemID)
    272 
    273     def DoMove(self, data, newIdx):
    274         fromIdx = data.idx
    275         upgradeInfo = self.installedUpgradesSimulated.pop(fromIdx)
    276         if newIdx < 0:
    277             self.installedUpgradesSimulated.append(upgradeInfo)
    278         else:
    279             if fromIdx < newIdx:
    280                 newIdx -= 1
    281             self.installedUpgradesSimulated.insert(newIdx, upgradeInfo)
    282         self.on_order_changed()
    283         self.on_online_state_changed(upgradeInfo.typeID)
    284 
    285     def DeleteUpgrade(self, typeID, upgradeKey, itemID):
    286         if itemID:
    287             self._newUpgrades.pop(itemID, None)
    288         else:
    289             buttons = [Bundle(id=uiconst.ID_YES, label=GetByLabel('UI/Sovereignty/SovHub/HubWnd/ProceedBtn')), Bundle(id=uiconst.ID_CANCEL, label=GetByLabel('UI/Common/Buttons/Cancel'))]
    290             if prompt_player_fsd_dialog('ConfirmDestroyUpgrade', {}, buttons=buttons, suppress=uiconst.ID_YES) != uiconst.ID_YES:
    291                 return
    292             try:
    293                 self.sovHubSvc.UninstallUpgrade(upgradeKey)
    294             except (SovUpgradeUninstallError, TimeoutException):
    295                 logger.exception('Failed to delete upgrade')
    296                 prompt_player_fsd_dialog('CustomInfo', {'info': GetByLabel('UI/Sovereignty/SovHub/Upgrades/FailedToRemoveUpgrade')})
    297                 return
    298             except Exception as e:
    299                 prompt_player_fsd_dialog('CustomInfo', {'info': GetByLabel('UI/Sovereignty/SovHub/Upgrades/FailedToRemoveUpgrade')})
    300                 raise
    301 
    302         for upgrade in self.installedUpgradesSimulated:
    303             if upgrade.typeID == typeID:
    304                 self.installedUpgradesSimulated.remove(upgrade)
    305                 break
    306 
    307         self.on_order_changed()
    308         self.on_online_state_changed(typeID)
    309 
    310     def SetOnlineState(self, typeID, onlineState):
    311         if onlineState:
    312             newState = upgrades_const.POWER_STATE_ONLINE
    313         else:
    314             newState = upgrades_const.POWER_STATE_OFFLINE
    315         for upgrade in self.installedUpgradesSimulated:
    316             if upgrade.typeID == typeID:
    317                 upgrade.powerState = newState
    318                 break
    319 
    320         self.on_online_state_changed(typeID)
    321 
    322     def AreThereUnsavedChanges(self):
    323         if self.installedUpgradesSimulated is None or self.originalInstalledUpgradeData is None:
    324             return False
    325         simulatedConfig = [ (x.typeID, x.isConfiguredOnline) for x in self.installedUpgradesSimulated ]
    326         originalConfig = [ (x.upgrade_type_id, not x.is_power_offline) for x in self.originalInstalledUpgradeData ]
    327         if simulatedConfig != originalConfig:
    328             return True
    329         return False
    330 
    331     def SaveChanges(self, *args):
    332         data = {'currentUpgrades': self.installedUpgradesSimulated,
    333          'originalUpgrades': self.originalInstalledUpgradeData}
    334         buttons = [Bundle(id=uiconst.ID_YES, label=GetByLabel('UI/Sovereignty/SovHub/HubWnd/ProceedBtn')), Bundle(id=uiconst.ID_CANCEL, label=GetByLabel('UI/Common/Buttons/Cancel'))]
    335         if prompt_player_fsd_dialog('ConfirmSovHubUpgradeChanges', data, buttons=buttons, suppress=uiconst.ID_YES) != uiconst.ID_YES:
    336             return
    337         newUpgrades = self._newUpgrades.keys()
    338         installed = [ (upgrade.typeID, upgrade.isConfiguredOnline) for upgrade in self.installedUpgradesSimulated ]
    339         powerStatesBeforeSaving = [ (upgrade.typeID, upgrade.powerState) for upgrade in self.installedUpgradesSimulated ]
    340         try:
    341             result = self.sovHubSvc.SaveUpgradeConfiguration(self.itemID, newUpgrades, installed)
    342         except SovUpgradeInstallError as e:
    343             prompt_player_fsd_dialog('SovHubChangeNotSaved')
    344             raise
    345         except TimeoutException as e:
    346             prompt_player_fsd_dialog('SovHubChangeNotSavedTimeout')
    347             raise
    348 
    349         self._newUpgrades.clear()
    350         powerStatesAfterSaving = [ (x.upgrade_type_id, x.power_state) for x in result ]
    351         success = powerStatesBeforeSaving == powerStatesAfterSaving
    352         if success:
    353             prompt_player_fsd_dialog('CustomNotify', {'notify': GetByLabel('UI/Sovereignty/SovHub/HubWnd/ConfigurationSuccessfullySaved')})
    354         else:
    355             prompt_player_fsd_dialog('CustomInfo', {'info': GetByLabel('UI/Sovereignty/SovHub/HubWnd/ConfigurationSavedNotSame')})
    356             logger.exception('SovHubWnd: Unexpected state after save')
    357         self.on_order_changed()
    358 
    359     def SetFuelACL(self, fuelACL):
    360         try:
    361             self.sovSvc.SetSovHubFuelAccessGroup(self.solarSystemID, fuelACL)
    362         except UserError:
    363             self.on_acl_setting_failed()
    364             raise
    365 
    366         self._currentFuelACL = fuelACL
    367         self.on_acl_changed()
    368 
    369     @property
    370     def accessGroupOptions(self):
    371         if self._accessGroupOptions is None:
    372             from eve.client.script.ui.inflight.orbitalConfiguration import GetAccessGroupOptions
    373             self._accessGroupOptions = GetAccessGroupOptions()
    374             if self._currentFuelACL not in [ x[1] for x in self._accessGroupOptions ]:
    375                 self.AddGroup(self._currentFuelACL, False)
    376         return self._accessGroupOptions
    377 
    378     def AddGroup(self, newGroupID, raiseGroupNotFound = True):
    379         if newGroupID:
    380             try:
    381                 newGroup = sm.GetService('structureControllers').GetAccessGroupController().GetGroupInfoFromID(newGroupID, fetchToServer=True)
    382             except UserError as e:
    383                 if e.msg == 'GroupNotFound' and not raiseGroupNotFound:
    384                     return
    385                 raise
    386 
    387             groupDisplayName = cfg.eveowners.Get(newGroup.creatorID).name if IsNPCCorporation(newGroup.creatorID) else newGroup.name
    388             self._accessGroupOptions.append((groupDisplayName, newGroupID))
    389 
    390     def GetNumSimulatedUpgradesOnlineAndInstalled(self):
    391         self.UpdateEffectiveStatesForSimulatedUpgrades()
    392         return (len([ x for x in self.installedUpgradesSimulated if x.isPowerStateFunctional ]), len(self.installedUpgradesSimulated))
    393 
    394     def GetSimulatedPowerAllocated(self):
    395         fuelAmounts = self.GetRagentAmountByTypeID()
    396         return GetPowerForUpgrades(self, fuelAmounts)
    397 
    398     def GetSimulatedPowerProduction(self):
    399         fuelAmounts = self.GetRagentAmountByTypeID()
    400         return GetPowerProductionForUpgrades(self, fuelAmounts)
    401 
    402     def GetSimulatedPowerAllocatedText(self):
    403         return FmtAmt(self.GetSimulatedPowerAllocated())
    404 
    405     GetPowerAllocated = GetSimulatedPowerAllocated
    406     GetPowerAllocatedText = GetSimulatedPowerAllocatedText
    407 
    408     def GetSimulatedWorkforce(self):
    409         fuelAmounts = self.GetRagentAmountByTypeID()
    410         return GetWorkforceForUpgrades(self, fuelAmounts)
    411 
    412     def GetSimulatedWorkforceText(self):
    413         return FmtAmt(self.GetSimulatedWorkforce())
    414 
    415     GetWorkforce = GetSimulatedWorkforce
    416     GetWorkforceText = GetSimulatedWorkforceText
    417 
    418     def GetSimulatedWorkforceProduction(self):
    419         fuelAmounts = self.GetRagentAmountByTypeID()
    420         return GetWorkforceProductionForUpgrades(self, fuelAmounts)
    421 
    422     def GetReagentForTypeID(self, typeID):
    423         return self._hubReagentsByTypeID.get(typeID, None)
    424 
    425     def GetRagentAmountByTypeID(self):
    426         return {typeID:x.amount_now for typeID, x in self._hubReagentsByTypeID.iteritems()}
    427 
    428     def GetSimulatedReagentConsumptionForTypeID(self, reagentTypeID):
    429         fuelAmounts = self.GetRagentAmountByTypeID()
    430         return GetConsumptionPerHour(self, reagentTypeID, fuelAmounts=fuelAmounts)
    431 
    432     GetReagentConsumptionForTypeID = GetSimulatedReagentConsumptionForTypeID
    433 
    434     def GetSimulatedStartupCostForTypeID(self, reagentTypeID):
    435         fuelAmounts = self.GetRagentAmountByTypeID()
    436         return GetStartupCost(self, self.originalInstalledUpgradeData, reagentTypeID, fuelAmounts=fuelAmounts)
    437 
    438     GetStartupCostForTypeID = GetSimulatedStartupCostForTypeID
    439 
    440     def GetSimulatedTimeLeftForTypeID(self, reagentTypeID):
    441         fuelAmounts = self.GetRagentAmountByTypeID()
    442         if reagentTypeID not in fuelAmounts:
    443             return None
    444         return GetHoursLeft(self, self.originalInstalledUpgradeData, reagentTypeID, fuelAmounts)
    445 
    446     GetTimeLeftForTypeID = GetSimulatedTimeLeftForTypeID
    447 
    448     def GetSimulatedTimeLeftProgressForTypeID(self, reagentTypeID):
    449         hoursLeft = self.GetSimulatedTimeLeftForTypeID(reagentTypeID)
    450         return GetHoursLeftProgress(hoursLeft)
    451 
    452     GetTimeLeftProgressForTypeID = GetSimulatedTimeLeftProgressForTypeID
    453 
    454     def GetTimeLeftTextForTypeID(self, reagentTypeID):
    455         hoursLeft = self.GetSimulatedTimeLeftForTypeID(reagentTypeID)
    456         return GetTimeLeftTextForTypeID(hoursLeft)
    457 
    458     def GetSimulatedPowerOfAllInstalled(self):
    459         power = 0
    460         for upgrade in self.installedUpgradesSimulated:
    461             power += upgrade.staticData.power
    462 
    463         return power
    464 
    465     def GetOriginalPower(self):
    466         pass
    467 
    468     def GetOriginalWorkforce(self):
    469         pass
    470 
    471     def GetAvailableLocalPower(self):
    472         return self._availableLocalPower
    473 
    474     def GetTotalAvailablePower(self):
    475         return self.GetAvailableLocalPower() + self.GetSimulatedPowerProduction()
    476 
    477     def GetMaxSystemPower(self):
    478         return self._maxSystemPower
    479 
    480     def GetTotalMaxPower(self):
    481         return self._maxSystemPower + self.GetSimulatedPowerProduction()
    482 
    483     def GetMaxSystemWorkforce(self):
    484         return self._maxWorkforce
    485 
    486     def GetTotalMaxWorkforce(self):
    487         return self._maxWorkforce + self.GetSimulatedWorkforceProduction() + self.GetImportedValue()
    488 
    489     def GetTotalAvailablePowerText(self):
    490         return FmtAmt(self.GetTotalAvailablePower())
    491 
    492     def GetAvailableSystemWorkforce(self):
    493         return self._availableSystemWorkforce
    494 
    495     def GetTotalAvailableWorkforce(self):
    496         return self.GetAvailableSystemWorkforce() + self.GetSimulatedWorkforceProduction()
    497 
    498     def GetTotalAvailableWorkforceText(self):
    499         return FmtAmt(self.GetTotalAvailableWorkforce())
    500 
    501     def GetImportedValue(self):
    502         return self.workforceController.GetImportedWorkforceFromState()
    503 
    504     def GetImportedAndProducedValueTextAndHint(self):
    505         imported = self.GetImportedValue()
    506         produced = self.GetSimulatedPowerProduction()
    507         totalExtra = imported + produced
    508         hint = ''
    509         if not totalExtra:
    510             return ('', hint)
    511         if imported and produced:
    512             hint = GetByLabel('UI/Sovereignty/SovHub/HubWnd/ImportedAndProducedWorkforce', numImported=FmtAmt(imported), numProduced=FmtAmt(produced))
    513         elif imported:
    514             hint = GetByLabel('UI/Sovereignty/SovHub/HubWnd/ImportedWorkforce')
    515         elif produced:
    516             hint = GetByLabel('UI/Sovereignty/SovHub/HubWnd/ProducedWorkforce')
    517         return (eveformat.color('+%s' % FmtAmt(totalExtra), eveColor.SUCCESS_GREEN_HEX), hint)
    518 
    519     def GetExportedValue(self):
    520         return self.workforceController.GetExportedWorkforceFromState()
    521 
    522     def GetWorkforceAddition(self):
    523         return -self.GetImportedValue() or self.GetExportedValue()
    524 
    525     def GetPowerProductionValueTextAndHint(self):
    526         powerProduction = self.GetSimulatedPowerProduction()
    527         if not powerProduction:
    528             return ('', '')
    529         hint = GetByLabel('UI/Sovereignty/SovHub/HubWnd/ProducedPower')
    530         return (eveformat.color('+%s' % FmtAmt(powerProduction), eveColor.SUCCESS_GREEN_HEX), hint)
    531 
    532     def GetPowerLowStateUpgrades(self):
    533         power = 0
    534         self.UpdateEffectiveStatesForSimulatedUpgrades()
    535         for upgrade in self.installedUpgradesSimulated:
    536             if upgrade.isInRestrictedPowerState:
    537                 power += upgrade.staticData.power
    538 
    539         return power
    540 
    541     def GetWorkforceLowStateUpgrades(self):
    542         workforce = 0
    543         self.UpdateEffectiveStatesForSimulatedUpgrades()
    544         for upgrade in self.installedUpgradesSimulated:
    545             if upgrade.isInRestrictedPowerState:
    546                 workforce += upgrade.staticData.workforce
    547 
    548         return workforce
    549 
    550     def UpdateEffectiveStatesForSimulatedUpgrades(self):
    551         fuelAmounts = self.GetRagentAmountByTypeID()
    552         return UpdateEffectiveStatesForUpgrades(self, fuelAmounts)
    553 
    554     @property
    555     def originalInstalledUpgradeData(self):
    556         return self._originalInstalledUpgradeData
    557 
    558     @property
    559     def installedUpgradesSimulated(self):
    560         return self._simulatedInstalledUpgrades
    561 
    562     def GetAclName(self):
    563         if self._currentFuelACL is None:
    564             return GetByLabel('UI/Sovereignty/SovHub/HubWnd/SectionACLNotSet')
    565         for displayName, groupID in self.accessGroupOptions:
    566             if groupID == self._currentFuelACL:
    567                 return displayName
    568 
    569         try:
    570             newGroup = sm.GetService('structureControllers').GetAccessGroupController().GetGroupInfoFromID(self._currentFuelACL, fetchToServer=True)
    571         except UserError as e:
    572             if e.msg == 'GroupNotFound':
    573                 return GetByLabel('UI/Sovereignty/UnknownACL')
    574             raise
    575 
    576         if newGroup:
    577             if IsNPCCorporation(newGroup.creatorID):
    578                 return cfg.eveowners.Get(newGroup.creatorID).name
    579             return newGroup.name
    580 
    581     def GetHubName(self):
    582         systemName = cfg.evelocations.Get(self.solarSystemID).name
    583         caption = GetByLabel('UI/Sovereignty/SovHub/HubWnd/SovHubName', solarSystemName=systemName)
    584         return caption
    585 
    586     def CanEditACL(self):
    587         return session.corprole & const.corpRoleDirector
    588 
    589     def OnHubUpgradesStateChanged(self, hubID, installedUpgrades):
    590         if hubID != self.itemID:
    591             return
    592         prompt_player_fsd_dialog('CustomNotify', {'notify': GetByLabel('UI/Sovereignty/SovHub/Upgrades/UpgradesUpdated')})
    593         self._originalInstalledUpgradeData = [ x.take_copy() for x in installedUpgrades ]
    594         simulatedByTypeID = {x.typeID:x for x in self.installedUpgradesSimulated}
    595         for originalUpgrade in self._originalInstalledUpgradeData:
    596             simulatedUpgrade = simulatedByTypeID.pop(originalUpgrade.upgrade_type_id, None)
    597             if simulatedUpgrade:
    598                 simulatedUpgrade.UpdateOriginalUpgrade(originalUpgrade)
    599             else:
    600                 newSimulated = UpgradeData.create_from_installed_upgrade_data(originalUpgrade, self.sovHubSvc)
    601                 self._simulatedInstalledUpgrades.append(newSimulated)
    602 
    603         for simulatedUpgrade in simulatedByTypeID.itervalues():
    604             if simulatedUpgrade in self._simulatedInstalledUpgrades:
    605                 self._simulatedInstalledUpgrades.remove(simulatedUpgrade)
    606 
    607         self._availableHubResources = None
    608         self.workforceController.workforceState = None
    609         self._PrimeGetReagentsByTypeID()
    610         self.on_upgrades_changed()
    611 
    612     def OnHubWorkforceConfigureChanged(self, solarSystemID, sovHubID, oldConfig, newConfig):
    613         if solarSystemID != self.solarSystemID:
    614             return
    615         self._availableHubResources = None
    616         self.workforceController.UpdateWorkforceConfiguration(newConfig)
    617 
    618     def OnHubWorkforceStateChanged(self, solarSystemID, sovHubID, oldState, newState):
    619         if solarSystemID != self.solarSystemID:
    620             return
    621         self._availableHubResources = None
    622         self.workforceController.UpdateWorkforceState(newState)
    623 
    624     def Disconnect(self):
    625         self.on_order_changed.clear()
    626         self.on_online_state_changed.clear()
    627         self.on_acl_changed.clear()
    628         self.on_acl_setting_failed.clear()
    629         self.on_upgrades_changed.clear()
    630         sm.UnregisterNotify(self)