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

clientPlanet.py (40167B)


      1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\client\script\environment\planet\clientPlanet.py
      2 import sys
      3 import blue
      4 import bluepy
      5 import geo2
      6 import utillib
      7 import uthread
      8 import evetypes
      9 from carbon.common.script.util.format import FmtTimeInterval
     10 from carbonui import uiconst
     11 from eve.client.script.environment.planet.clientColony import ClientColony
     12 from eve.client.script.ui.util import uix
     13 from eve.common.lib import appConst as const
     14 from eve.common.lib.PlanetResources import builder
     15 from eve.common.script.net import eveMoniker
     16 from eve.common.script.planet import commandStream
     17 from eve.common.script.planet.basePlanet import BasePlanet
     18 from eve.common.script.planet.colonyData import ColonyData
     19 from eve.common.script.sys.idCheckers import IsKnownSpaceSystem
     20 from eve.common.script.util import planetCommon
     21 from eveexceptions import UserError
     22 from localization import GetByLabel
     23 from menucheckers import SessionChecker
     24 from player_messaging.client.ui_message import prompt_player_fsd_dialog
     25 CP_COMMANDPINREMOVED = -1
     26 CP_NOCHANGE = 0
     27 CP_COMMANDPINADDED = 1
     28 
     29 class ClientPlanet(BasePlanet):
     30     __name__ = 'ClientPlanet'
     31 
     32     def Init(self):
     33         BasePlanet.Init(self)
     34         self.ticking = False
     35         self.tickThread = None
     36         self.remoteHandler = eveMoniker.GetPlanet(self.planetID)
     37         self.PreparePlanet()
     38         self.changes = commandStream.CommandStream()
     39         self.commandPinChange = CP_NOCHANGE
     40         self.backupData = None
     41         self.enteredEditModeTime = None
     42         self.isInEditMode = False
     43 
     44     def GetPlanetTypeID(self):
     45         if self.planetTypeID is None:
     46             planetData = sm.GetService('mapsvc').GetPlanetInfo(self.planetID)
     47             self.planetTypeID = planetData.typeID
     48         return self.planetTypeID
     49 
     50     def GetNewColony(self, ownerID):
     51         return ClientColony(self, ownerID)
     52 
     53     def GetCommandCenterForCharacter(self, characterID):
     54         colony = self.GetColony(characterID)
     55         if colony is None or colony.colonyData is None:
     56             return
     57         return colony.colonyData.commandPin
     58 
     59     def _PrimeColony(self, ownerID, serializedColony):
     60         if ownerID not in self.colonies:
     61             self.colonies[ownerID] = colony = self.GetNewColony(ownerID)
     62         else:
     63             colony = self.GetColony(ownerID)
     64         freshColonyData = ColonyData(session.charid, None)
     65         colony.SetColonyData(freshColonyData)
     66         freshColonyData.SetLevel(serializedColony.level)
     67         for pin in serializedColony.pins:
     68             freshColonyData.RestorePinFromRow(pin)
     69 
     70         for linkData in serializedColony.links:
     71             freshColonyData.RestoreLinkFromRow(linkData)
     72 
     73         for route in serializedColony.routes:
     74             freshColonyData.RestoreRouteFromRow(route)
     75 
     76         colony.currentSimTime = serializedColony.currentSimTime
     77         colony.PrimeSimulation(serializedColony.currentSimTime)
     78         self.colonies[ownerID] = colony
     79         self.colony = colony
     80         return colony
     81 
     82     @bluepy.TimedFunction('ClientPlanet::PreparePlanet')
     83     def PreparePlanet(self):
     84         planetInfo = self.remoteHandler.GetPlanetInfo()
     85         self.solarSystemID = planetInfo.solarSystemID
     86         self.planetTypeID = planetInfo.planetTypeID
     87         self.radius = planetInfo.radius
     88         self.colony = None
     89         self.celestialIndex = planetInfo.celestialIndex
     90         if hasattr(planetInfo, 'currentSimTime') or hasattr(planetInfo, 'pins'):
     91             colony = self._PrimeColony(session.charid, planetInfo)
     92             self.colony = colony
     93             self.colony.RunSimulation(beNice=True)
     94             self.StartTicking()
     95 
     96     def IsInEditMode(self):
     97         if self.isInEditMode:
     98             return True
     99         if self.commandPinChange != CP_NOCHANGE:
    100             return True
    101         if self.changes.GetStreamLength() > 0:
    102             return True
    103         return False
    104 
    105     def GetEditModeData(self):
    106         return self.backupData
    107 
    108     def ValidateMakeChanges(self):
    109         if self.commandPinChange == CP_COMMANDPINREMOVED:
    110             raise UserError('CannotModifyAbandonedColony')
    111 
    112     def _EnterEditMode(self):
    113         if not self.colony:
    114             colony = self.GetColony(session.charid)
    115             if colony is None:
    116                 self.LogInfo('No colony found, creating a blank one')
    117                 colony = self.GetNewColony(session.charid)
    118                 colony.SetColonyData(ColonyData(session.charid, None))
    119                 self.colonies[session.charid] = colony
    120                 self.colony = colony
    121             else:
    122                 self.colony = colony
    123         if not self.isInEditMode:
    124             self.backupData = self.colony.colonyData.GetCopy()
    125             self.backupData.SetEventHandler(self)
    126             self.enteredEditModeTime = blue.os.GetWallclockTime()
    127             self.StopTicking()
    128             self.isInEditMode = True
    129             sm.GetService('planetUI').EnteredEditMode(self.planetID)
    130 
    131     def _ExitEditMode(self):
    132         self.changes.Reset()
    133         self.commandPinChange = CP_NOCHANGE
    134         self.backupData = None
    135         if self.colony is not None:
    136             self.colony.ResetPinCreationCost()
    137             if self.colony.colonyData is not None:
    138                 for pin in self.colony.colonyData.pins.itervalues():
    139                     if getattr(pin, 'inEditMode', False):
    140                         pin.inEditMode = False
    141 
    142         self.enteredEditModeTime = None
    143         self.isInEditMode = False
    144         self.StartTicking()
    145         sm.GetService('planetUI').ExitedEditMode(self.planetID)
    146 
    147     def RevertChanges(self):
    148         if self.backupData is not None:
    149             colony = self.GetColony(session.charid)
    150             if colony is not None:
    151                 colony.SetColonyData(self.backupData)
    152             else:
    153                 self.LogWarn('RevertChanges - Reverting changes without reapplying old data; colony not found')
    154             self.backupData = None
    155         self._ExitEditMode()
    156 
    157     def SubmitChanges(self):
    158         planetSvc = sm.GetService('planetSvc')
    159         try:
    160             planetSvc.SetSubmittingInProgressForPlanet(self.planetID)
    161             return self._SubmitChanges()
    162         finally:
    163             planetSvc.RemoveSubmittingInProgressForPlanet(self.planetID)
    164 
    165     def _SubmitChanges(self):
    166         simulationEndTime = None
    167         if self.commandPinChange == CP_COMMANDPINREMOVED:
    168             self.remoteHandler.UserAbandonPlanet()
    169             newColonyData = ColonyData(session.charid, None)
    170             self.colonies[session.charid].SetColonyData(newColonyData)
    171         else:
    172             serializedChanges = self.changes.Serialize()
    173             try:
    174                 updatedColony = self.remoteHandler.UserUpdateNetwork(serializedChanges)
    175             except Exception:
    176                 self.changes.LogCommandStream(self)
    177                 raise
    178 
    179             self._PrimeColony(session.charid, updatedColony)
    180         if self.commandPinChange != CP_NOCHANGE:
    181             sm.GetService('planetSvc').ScatterOnPlanetCommandCenterDeployedOrRemoved(self.planetID)
    182         if self.commandPinChange == CP_COMMANDPINADDED:
    183             sm.GetService('neocom').Blink('planets', GetByLabel('UI/Neocom/Blink/NewPlanetaryColony'))
    184         self._ExitEditMode()
    185         sm.ScatterEvent('OnPlanetChangesSubmitted', self.planetID)
    186 
    187     def CreateCommandPin(self, charID, typeID, latitude, longitude):
    188         if charID in self.colonies:
    189             colony = self.GetColony(charID)
    190             if colony is not None and colony.colonyData is not None and colony.colonyData.commandPin is not None:
    191                 raise UserError('CannotBuildMultipleCommandPins')
    192         if session.shipid is None or SessionChecker(session, sm).IsPilotControllingStructure():
    193             raise UserError('CannotBuildCommandPinWithoutShip')
    194         shipInv = sm.GetService('invCache').GetInventoryFromId(session.shipid)
    195         commandCenterID = None
    196         invList = shipInv.List(const.flagSpecializedCommandCenterHold)
    197         invList.extend(shipInv.List(const.flagColonyResourcesHold))
    198         invList.extend(shipInv.List(const.flagCargo))
    199         for item in invList:
    200             if item.typeID == typeID:
    201                 commandCenterID = item.itemID
    202                 break
    203 
    204         if commandCenterID is None:
    205             raise UserError('CannotBuildCommandPin')
    206         colony = self.GetNewColony(charID)
    207         self.colonies[charID] = colony
    208         self.colony = colony
    209         colony.SetColonyData(ColonyData(charID, None))
    210         colony.ValidateCreatePin(charID, typeID, latitude, longitude)
    211         wasInEditMode = self.IsInEditMode()
    212         self._EnterEditMode()
    213         colony.colonyData.PrimePin(commandCenterID, typeID, charID, latitude, longitude)
    214         self.changes.AddCommand(commandStream.COMMAND_CREATEPIN, pinID=commandCenterID, typeID=typeID, latitude=latitude, longitude=longitude)
    215         self.commandPinChange = CP_COMMANDPINADDED
    216         sm.ScatterEvent('OnPlanetPinPlaced', commandCenterID)
    217         sm.ScatterEvent('OnEditModeBuiltOrDestroyed', self.planetID)
    218         pin = colony.GetPin(commandCenterID)
    219         pin.inEditMode = True
    220         level = evetypes.GetMetaLevel(typeID)
    221         colony.colonyData.SetLevel(level)
    222         return pin
    223 
    224     def CreatePin(self, typeID, latitude, longitude):
    225         self.ValidateMakeChanges()
    226         charID = session.charid
    227         if evetypes.GetGroupID(typeID) == const.groupCommandPins:
    228             return self.CreateCommandPin(charID, typeID, latitude, longitude)
    229         colony = self.GetColony(charID)
    230         if colony is None:
    231             raise UserError('CannotManagePlanetWithoutCommandCenter')
    232         colony.ValidateCreatePin(charID, typeID, latitude, longitude)
    233         pinID = colony.GetTemporaryPinID()
    234         wasInEditMode = self.IsInEditMode()
    235         self._EnterEditMode()
    236         colony.colonyData.PrimePin(pinID, typeID, charID, latitude, longitude)
    237         pin = colony.GetPin(pinID)
    238         pin.inEditMode = True
    239         self.changes.AddCommand(commandStream.COMMAND_CREATEPIN, pinID=pinID, typeID=typeID, latitude=latitude, longitude=longitude)
    240         sm.ScatterEvent('OnPlanetPinPlaced', pinID)
    241         sm.ScatterEvent('OnEditModeBuiltOrDestroyed', self.planetID)
    242         return pin
    243 
    244     def RemovePin(self, pinID):
    245         self.ValidateMakeChanges()
    246         charID = session.charid
    247         colony = self.GetColony(charID)
    248         if colony is None:
    249             raise UserError('CannotManagePlanetWithoutCommandCenter')
    250         pin = colony.GetPin(pinID)
    251         if pin is None:
    252             raise UserError('PinDoesNotExist')
    253         colony.ValidateRemovePin(charID, pinID)
    254         self._EnterEditMode()
    255         for endPointID in colony.colonyData.GetLinksForPin(pinID):
    256             self.RemoveLink(pinID, endPointID)
    257 
    258         colony.colonyData.RemovePin(charID, pinID)
    259         if pin.IsCommandCenter():
    260             if self.commandPinChange == CP_COMMANDPINADDED:
    261                 self.commandPinChange = CP_NOCHANGE
    262             else:
    263                 self.commandPinChange = CP_COMMANDPINREMOVED
    264             for subPinID in colony.colonyData.pins.keys():
    265                 colony.colonyData.RemovePin(charID, subPinID)
    266 
    267             self.changes.Reset()
    268         else:
    269             if colony.IsTemporaryID(pinID):
    270                 colony.RemoveCreationCost(pin.typeID)
    271             self.changes.AddCommand(commandStream.COMMAND_REMOVEPIN, pinID=pinID)
    272         sm.ScatterEvent('OnEditModeBuiltOrDestroyed', self.planetID)
    273 
    274     def InstallSchematic(self, pinID, schematicID):
    275         self.ValidateMakeChanges()
    276         charID = session.charid
    277         colony = self.GetColony(charID)
    278         if colony is None:
    279             raise UserError('CannotManagePlanetWithoutCommandCenter')
    280         colony.ValidateInstallSchematic(charID, pinID, schematicID)
    281         self._EnterEditMode()
    282         colony.InstallSchematicForPin(charID, pinID, schematicID)
    283         pin = colony.GetPin(pinID)
    284         pin.inEditMode = True
    285         self.changes.AddCommand(commandStream.COMMAND_SETSCHEMATIC, pinID=pinID, schematicID=schematicID)
    286         sm.ScatterEvent('OnRefreshPins', [pinID])
    287 
    288     def CreateLink(self, pin1ID, pin2ID, typeID):
    289         self.ValidateMakeChanges()
    290         if pin1ID > pin2ID:
    291             pin1ID, pin2ID = pin2ID, pin1ID
    292         charID = session.charid
    293         colony = self.GetColony(charID)
    294         if colony is None:
    295             raise UserError('CannotManagePlanetWithoutCommandCenter')
    296         colony.ValidateCreateLink(charID, pin1ID, pin2ID, typeID)
    297         self._EnterEditMode()
    298         link = colony.colonyData.PrimeLink(typeID, pin1ID, pin2ID)
    299         link.editModeLink = True
    300         self.changes.AddCommand(commandStream.COMMAND_CREATELINK, endpoint1=pin1ID, endpoint2=pin2ID, level=0)
    301         sm.ScatterEvent('OnEditModeBuiltOrDestroyed', self.planetID)
    302 
    303     def RemoveLink(self, pin1ID, pin2ID):
    304         self.ValidateMakeChanges()
    305         if pin1ID > pin2ID:
    306             pin1ID, pin2ID = pin2ID, pin1ID
    307         charID = session.charid
    308         colony = self.GetColony(charID)
    309         if colony is None:
    310             raise UserError('CannotManagePlanetWithoutCommandCenter')
    311         colony.ValidateRemoveLink(charID, pin1ID, pin2ID)
    312         self._EnterEditMode()
    313         link = self.colony.GetLink(pin1ID, pin2ID)
    314         for routeID in link.routesTransiting[:]:
    315             self.RemoveRoute(routeID)
    316 
    317         colony.colonyData.RemoveLink(pin1ID, pin2ID)
    318         self.changes.AddCommand(commandStream.COMMAND_REMOVELINK, endpoint1=pin1ID, endpoint2=pin2ID)
    319         sm.ScatterEvent('OnEditModeBuiltOrDestroyed', self.planetID)
    320 
    321     def SetLinkLevel(self, pin1ID, pin2ID, newLevel):
    322         self.ValidateMakeChanges()
    323         charID = session.charid
    324         colony = self.GetColony(charID)
    325         if colony is None:
    326             raise UserError('CannotManagePlanetWithoutCommandCenter')
    327         colony.ValidateSetLinkLevel(charID, pin1ID, pin2ID, newLevel)
    328         self._EnterEditMode()
    329         colony.colonyData.SetLinkLevel(pin1ID, pin2ID, newLevel)
    330         link = self.colony.GetLink(pin1ID, pin2ID)
    331         link.editModeLink = True
    332         self.changes.AddCommand(commandStream.COMMAND_SETLINKLEVEL, endpoint1=pin1ID, endpoint2=pin2ID, level=newLevel)
    333         sm.ScatterEvent('OnEditModeBuiltOrDestroyed', self.planetID)
    334 
    335     def CreateRoute(self, path, typeID, quantity):
    336         self.ValidateMakeChanges()
    337         charID = session.charid
    338         colony = self.GetColony(charID)
    339         if colony is None:
    340             raise UserError('CannotManagePlanetWithoutCommandCenter')
    341         colony.ValidateCreateRoute(charID, path, typeID, quantity)
    342         routeID = colony.GetTemporaryRouteID()
    343         self._EnterEditMode()
    344         colony.colonyData.PrimeRoute(routeID, path, typeID, quantity)
    345         self.changes.AddCommand(commandStream.COMMAND_CREATEROUTE, routeID=routeID, path=path, typeID=typeID, quantity=quantity)
    346         sm.ScatterEvent('OnEditModeBuiltOrDestroyed', self.planetID)
    347 
    348     def RemoveRoute(self, routeID):
    349         self.ValidateMakeChanges()
    350         charID = session.charid
    351         colony = self.GetColony(charID)
    352         if colony is None:
    353             raise UserError('CannotManagePlanetWithoutCommandCenter')
    354         colony.ValidateRemoveRoute(charID, routeID)
    355         self._EnterEditMode()
    356         colony.colonyData.RemoveRoute(routeID)
    357         self.changes.AddCommand(commandStream.COMMAND_REMOVEROUTE, routeID=routeID)
    358         sm.ScatterEvent('OnEditModeBuiltOrDestroyed', self.planetID)
    359 
    360     def UpgradeCommandCenter(self, pinID, level):
    361         self.ValidateMakeChanges()
    362         charID = session.charid
    363         colony = self.GetColony(charID)
    364         colony.ValidateCommandCenterUpgrade(level)
    365         self._EnterEditMode()
    366         colony.colonyData.SetLevel(level)
    367         self.changes.AddCommand(commandStream.COMMAND_UPGRADECOMMANDCENTER, pinID=pinID, level=level)
    368         sm.ScatterEvent('OnEditModeBuiltOrDestroyed', self.planetID)
    369 
    370     def GetLocalDistributionReport(self, surfacePoint):
    371         return self.remoteHandler.GMGetLocalDistributionReport(self.planetID, (surfacePoint.theta, surfacePoint.phi))
    372 
    373     def GetCostOfCurrentEdits(self):
    374         colony = self.GetColony(session.charid)
    375         if not colony:
    376             return 0.0
    377         return colony.cumulativePinCreationCost + colony.cumulativeUpgradeCost
    378 
    379     def LaunchCommodities(self, commandPinID, commoditiesToLaunch):
    380         if self.IsInEditMode():
    381             raise UserError('CannotLaunchInEditMode')
    382         if len(commoditiesToLaunch) < 1:
    383             raise UserError('PleaseSelectCommoditiesToLaunch')
    384         colony = self.GetColony(session.charid)
    385         if colony is None:
    386             raise UserError('CannotLaunchWithoutColony')
    387         commandPin = colony.GetPin(commandPinID)
    388         if not commandPin or not commandPin.IsCommandCenter():
    389             raise UserError('CanOnlyLaunchFromCommandCenters')
    390         nextLaunchTime = commandPin.GetNextLaunchTime()
    391         if nextLaunchTime is not None and nextLaunchTime > blue.os.GetWallclockTime():
    392             raise UserError('CannotLaunchCommandPinNotReady')
    393         if not commandPin.CanLaunch(commoditiesToLaunch):
    394             raise UserError('CannotLaunchCommoditiesNotFound')
    395         oldData = colony.colonyData.GetCopy()
    396         try:
    397             lastLaunchTime = self.remoteHandler.UserLaunchCommodities(commandPinID, commoditiesToLaunch)
    398             commandPin.lastLaunchTime = lastLaunchTime
    399             colony.RunSimulation(runSimUntil=lastLaunchTime)
    400             for typeID, qty in commoditiesToLaunch.iteritems():
    401                 commandPin.RemoveCommodity(typeID, qty)
    402 
    403         except:
    404             colony.SetColonyData(oldData)
    405             sm.ChainEvent('ProcessColonyDataSet', self.planetID)
    406             raise
    407 
    408         sm.ScatterEvent('OnRefreshPins', [commandPin.id])
    409         if not self.ticking:
    410             self.StartTicking()
    411 
    412     def OpenTransferWindow(self, path):
    413         from eve.client.script.ui.shared.planet.expeditedTransferUI import ExpeditedTransferManagementWindow
    414         ExpeditedTransferManagementWindow.CloseIfOpen()
    415         ExpeditedTransferManagementWindow.Open(planet=self, path=path)
    416 
    417     def TransferCommodities(self, path, commodities):
    418         if self.IsInEditMode():
    419             raise UserError('CannotTransferInEditMode')
    420         colony = self.GetColony(session.charid)
    421         if colony is None:
    422             raise UserError('CannotManagePlanetWithoutCommandCenter')
    423         if len(path) < 2:
    424             raise UserError('CreateRouteTooShort')
    425         if len(commodities) < 1:
    426             raise UserError('CreateRouteWithoutCommodities')
    427         runTime = blue.os.GetWallclockTime()
    428         minBandwidth = colony.ValidateExpeditedTransfer(session.charid, path, commodities, runTime)
    429         oldData = colony.colonyData.GetCopy()
    430         try:
    431             simTime, sourceRunTime = self.remoteHandler.UserTransferCommodities(path, commodities)
    432             colony.RunSimulation(runSimUntil=simTime)
    433             colony.ExecuteExpeditedTransfer(path[0], path[-1], commodities, minBandwidth, runTime)
    434             sourcePin = colony.GetPin(path[0])
    435             sourcePin.lastRunTime = sourceRunTime
    436         except:
    437             colony.SetColonyData(oldData)
    438             sm.ChainEvent('ProcessColonyDataSet', self.planetID)
    439             raise
    440 
    441         sm.ScatterEvent('OnRefreshPins', [path[0], path[-1]])
    442         self.StartTicking(forceRestart=True)
    443 
    444     def AddExtractorHead(self, pinID, headID, latitude, longitude):
    445         self.ValidateMakeChanges()
    446         charID = session.charid
    447         colony = self.GetColony(charID)
    448         if colony is None:
    449             raise UserError('CannotManagePlanetWithoutCommandCenter')
    450         if headID is None:
    451             headID = self.GetPin(pinID).GetNextAvailableHeadID()
    452         colony.ValidateAddExtractorHead(pinID, headID)
    453         self._EnterEditMode()
    454         colony.colonyData.AddExtractorHead(pinID, headID, latitude, longitude)
    455         self.changes.AddCommand(commandStream.COMMAND_ADDEXTRACTORHEAD, pinID=pinID, headID=headID, latitude=latitude, longitude=longitude)
    456         try:
    457             self.MoveExtractorHead(pinID, headID, latitude, longitude)
    458         except:
    459             self.RemoveExtractorHead(pinID, headID)
    460             raise
    461 
    462         sm.ScatterEvent('OnEditModeBuiltOrDestroyed', self.planetID)
    463         return headID
    464 
    465     def RemoveExtractorHead(self, pinID, headID):
    466         self.ValidateMakeChanges()
    467         charID = session.charid
    468         colony = self.GetColony(charID)
    469         if colony is None:
    470             raise UserError('CannotManagePlanetWithoutCommandCenter')
    471         colony.ValidateRemoveExtractorHead(pinID, headID)
    472         self._EnterEditMode()
    473         colony.colonyData.RemoveExtractorHead(pinID, headID)
    474         self.changes.AddCommand(commandStream.COMMAND_KILLEXTRACTORHEAD, pinID=pinID, headID=headID)
    475         sm.ScatterEvent('OnEditModeBuiltOrDestroyed', self.planetID)
    476 
    477     def MoveExtractorHead(self, pinID, headID, latitude, longitude):
    478         self.ValidateMakeChanges()
    479         charID = session.charid
    480         colony = self.GetColony(charID)
    481         if colony is None:
    482             raise UserError('CannotManagePlanetWithoutCommandCenter')
    483         colony.ValidateMoveExtractorHead(pinID, headID, latitude, longitude)
    484         self._EnterEditMode()
    485         colony.colonyData.MoveExtractorHead(pinID, headID, latitude, longitude)
    486         self.changes.AddCommand(commandStream.COMMAND_MOVEEXTRACTORHEAD, pinID=pinID, headID=headID, latitude=latitude, longitude=longitude)
    487         sm.ScatterEvent('OnEditModeBuiltOrDestroyed', self.planetID)
    488 
    489     def SetExtractorHeadRadius(self, pinID, radius):
    490         pin = self.GetPin(pinID)
    491         pin.SetExtractorHeadRadius(radius)
    492 
    493     def InstallProgram(self, pinID, typeID, headRadius):
    494         self.ValidateMakeChanges()
    495         charID = session.charid
    496         colony = self.GetColony(charID)
    497         if colony is None:
    498             raise UserError('CannotManagePlanetWithoutCommandCenter')
    499         pin = self.GetPin(pinID)
    500         if len(pin.heads) < 1:
    501             typeID = None
    502         colony.ValidateInstallProgram(pinID, typeID, headRadius)
    503         if typeID is not None:
    504             qtyToDistribute, cycleTime, numCycles = self.remoteHandler.GetProgramResultInfo(pinID, typeID, pin.heads, headRadius)
    505         else:
    506             qtyToDistribute, cycleTime, numCycles = (0, 0, 0)
    507         qtyToRoute = pin.GetMaxOutput(qtyToDistribute, cycleTime)
    508         self._EnterEditMode()
    509         routes = colony.colonyData.GetSourceRoutesForPin(pinID)
    510         if typeID is None:
    511             colony.colonyData.InstallProgram(pinID, typeID, headRadius, maxValue=qtyToDistribute, numCycles=numCycles)
    512             pin.inEditMode = True
    513             self.changes.AddCommand(commandStream.COMMAND_INSTALLPROGRAM, pinID=pinID, typeID=typeID, headRadius=headRadius)
    514         else:
    515             storageRouteQty = {}
    516             processRouteQty = {}
    517             pathsByID = {}
    518             formerQtyToStorage = 0
    519             for route in routes:
    520                 if route is None:
    521                     self.LogWarn('Unable to find route for recreation:', route.routeID)
    522                     continue
    523                 if typeID != route.GetType():
    524                     self.RemoveRoute(route.routeID)
    525                     continue
    526                 destPin = colony.GetPin(route.GetDestinationPinID())
    527                 if not destPin or not destPin.IsStorage() and not destPin.IsConsumer():
    528                     continue
    529                 pathsByID[route.routeID] = route.path
    530                 if destPin.IsStorage():
    531                     dictToUse = storageRouteQty
    532                     formerQtyToStorage += route.GetQuantity()
    533                 else:
    534                     dictToUse = processRouteQty
    535                 if route.routeID not in dictToUse:
    536                     dictToUse[route.routeID] = 0
    537                 dictToUse[route.routeID] += route.GetQuantity()
    538                 self.RemoveRoute(route.routeID)
    539 
    540             colony.colonyData.InstallProgram(pinID, typeID, headRadius, maxValue=qtyToDistribute, cycleTime=cycleTime, numCycles=numCycles)
    541             pin.inEditMode = True
    542             self.changes.AddCommand(commandStream.COMMAND_INSTALLPROGRAM, pinID=pinID, typeID=typeID, headRadius=headRadius)
    543             if len(processRouteQty) + len(storageRouteQty) > 0:
    544                 for routeID, formerQty in processRouteQty.iteritems():
    545                     amtToRoute = formerQty
    546                     if qtyToRoute <= 0:
    547                         break
    548                     elif qtyToRoute < formerQty:
    549                         amtToRoute = qtyToRoute
    550                     path = pathsByID[routeID]
    551                     try:
    552                         self.CreateRoute(path, typeID, amtToRoute)
    553                         qtyToRoute -= amtToRoute
    554                     except UserError as e:
    555                         self.LogInfo('Encountered problem when trying to reroute', amtToRoute, 'units of', typeID, 'along path', path, ':', e.msg)
    556                         sys.exc_clear()
    557 
    558                 storageTotalLeft = qtyToRoute
    559                 if formerQtyToStorage > 0:
    560                     qtyRemainder = 0.0
    561                     for routeID, formerQty in storageRouteQty.iteritems():
    562                         if qtyToRoute <= 0:
    563                             break
    564                         floatAmtToRoute = float(formerQty) / formerQtyToStorage * storageTotalLeft
    565                         amtToRoute = int(round(floatAmtToRoute))
    566                         qtyRemainder += floatAmtToRoute - amtToRoute
    567                         amtToRoute += int(round(qtyRemainder))
    568                         path = pathsByID[routeID]
    569                         amtToRoute = self.FindRoutableQuantityOfResource(colony, path, typeID, amtToRoute, pin.GetCycleTime())
    570                         qtyRemainder -= round(qtyRemainder)
    571                         try:
    572                             self.CreateRoute(path, typeID, amtToRoute)
    573                             qtyToRoute -= amtToRoute
    574                         except UserError as e:
    575                             self.LogInfo('Encountered problem when trying to reroute', amtToRoute, 'units of', typeID, 'along path', path, ':', e.msg)
    576                             sys.exc_clear()
    577 
    578     def CancelInstallProgram(self, pinID, pinData):
    579         if not self.isInEditMode:
    580             return None
    581         if not self.changes.stream:
    582             self.RevertChanges()
    583             return None
    584         pin = self.GetPin(pinID)
    585         return pin
    586 
    587     def FindRoutableQuantityOfResource(self, colony, path, typeID, quantity, cycleTime):
    588         minimumBandwidth = None
    589         prevPinID = None
    590         for pinID in path:
    591             if prevPinID is None:
    592                 prevPinID = pinID
    593                 continue
    594             link = colony.colonyData.GetLink(prevPinID, pinID)
    595             availableBandwidth = link.GetTotalBandwidth() - link.GetBandwidthUsage()
    596             if minimumBandwidth is None or availableBandwidth < minimumBandwidth:
    597                 minimumBandwidth = availableBandwidth
    598             prevPinID = pinID
    599 
    600         baseVolume = evetypes.GetVolume(typeID)
    601         requiredBandwidth = planetCommon.GetBandwidth(baseVolume * quantity, cycleTime)
    602         if requiredBandwidth > minimumBandwidth:
    603             quantity = int(minimumBandwidth * float(cycleTime) / (const.HOUR * baseVolume))
    604         return quantity
    605 
    606     def OnSchematicInstalled(self, charID, pinID, schematicID):
    607         colony = self.GetColony(charID)
    608         pin = colony.GetPin(pinID)
    609         obsoleteRoutes = colony.colonyData.GetObsoleteRoutesForPin(pin)
    610         for routeID in obsoleteRoutes:
    611             self.RemoveRoute(routeID)
    612 
    613     def GMInstallProgram(self, pinID):
    614         colony = self.GetColonyByPinID(pinID)
    615         if colony is None:
    616             raise RuntimeError('Unable to find colony for pinID')
    617         pin = colony.GetPin(pinID)
    618         resourceInfo = self.remoteHandler.GetPlanetResourceInfo()
    619         typeOptions = [ (evetypes.GetName(typeID), typeID) for typeID in resourceInfo.keys() ]
    620         format = [{'type': 'combo',
    621           'key': 'typeID',
    622           'label': 'Type',
    623           'options': typeOptions,
    624           'frame': 0,
    625           'labelwidth': 80},
    626          {'type': 'edit',
    627           'key': 'qtyPerCycle',
    628           'label': 'Output per cycle',
    629           'setvalue': '100',
    630           'frame': 0,
    631           'labelwidth': 140,
    632           'required': True},
    633          {'type': 'btline'},
    634          {'type': 'edit',
    635           'key': 'cycleTime',
    636           'label': 'Cycle time (seconds)',
    637           'setvalue': '60',
    638           'frame': 0,
    639           'labelwidth': 140,
    640           'required': True},
    641          {'type': 'edit',
    642           'key': 'lifetime',
    643           'label': 'Lifetime (hours)',
    644           'setvalue': '24',
    645           'frame': 0,
    646           'labelwidth': 140,
    647           'required': True}]
    648         icon = 'ui_35_64_11'
    649         retval = uix.HybridWnd(format=format, caption='Deposit designer: %s' % planetCommon.GetGenericPinName(pin.typeID, pin.id), windowID='installProgramGM', modal=1, buttons=uiconst.OKCANCEL, minW=300, minH=132, icon=icon)
    650         if retval is None:
    651             return
    652         typeID, qtyPerCycle, cycleTime, lifetimeHours = (retval['typeID'],
    653          retval['qtyPerCycle'],
    654          retval['cycleTime'],
    655          retval['lifetime'])
    656         typeID = int(typeID)
    657         qtyPerCycle = int(qtyPerCycle)
    658         cycleTime = long(cycleTime) * const.SEC
    659         lifetimeHours = int(lifetimeHours)
    660         headRadius = 1.0
    661         if typeID not in resourceInfo or qtyPerCycle < 0 or cycleTime < 10 * const.SEC or lifetimeHours < 1 or headRadius <= 0.0:
    662             return
    663         self.remoteHandler.GMForceInstallProgram(pinID, typeID, cycleTime, lifetimeHours, qtyPerCycle, headRadius)
    664 
    665     def GMConvertCommandCenter(self, pinID):
    666         self.remoteHandler.GMConvertCommandCenter(pinID)
    667 
    668     def GMAddCommodity(self, pinID, typeID):
    669         quantity = uix.QtyPopup(None, 1, 100).get('qty', None)
    670         if not quantity:
    671             return
    672         self.remoteHandler.GMAddCommodity(pinID, typeID, quantity)
    673 
    674     def GMVerifySimulation(self):
    675         self.LogNotice('VerifySimulation -- starting')
    676         simulationDuration, remoteColonyData = self.remoteHandler.GMGetSynchedServerState(session.charid)
    677         simEndTime = remoteColonyData.currentSimTime
    678         colony = self.GetColony(session.charid)
    679         startTime = blue.os.GetWallclockTimeNow()
    680         colony.RunSimulation(runSimUntil=simEndTime)
    681         clientSimulationRuntime = blue.os.GetWallclockTimeNow() - startTime
    682         pins = remoteColonyData.pins
    683         self.LogNotice('simulation ran for', clientSimulationRuntime, 'on client, ', simulationDuration, 'on server')
    684         for pin in pins:
    685             clientPin = colony.GetPin(pin.id)
    686             if clientPin is None:
    687                 self.LogError(pin.id, 'exists on server but not on client')
    688                 continue
    689             for key, value in pin.__dict__.iteritems():
    690                 if not hasattr(clientPin, key):
    691                     self.LogError(pin.id, 'on client does not have attribute ', key)
    692                     continue
    693                 clientValue = getattr(clientPin, key)
    694                 if clientValue != value:
    695                     self.LogError(pin.id, 'does not agree on a value for', key, 'Client says ', clientValue, 'but server', value)
    696 
    697         self.LogNotice('VerifySimulation -- finished')
    698 
    699     def GetPlanetRadius(self):
    700         return self.radius
    701 
    702     def GetTypeAttribute(self, typeID, attributeID):
    703         return sm.GetService('godma').GetTypeAttribute2(typeID, attributeID)
    704 
    705     def GetResourceData(self, resourceTypeID):
    706         if not hasattr(self, 'resources'):
    707             self.LogInfo('GetResourceData: creating resource collection')
    708             self.resources = {}
    709         if resourceTypeID not in self.resources:
    710             self.LogInfo('GetResourceData: creating new resource entry for resource', resourceTypeID)
    711             entry = self.CreateResourceEntry()
    712             self.resources[resourceTypeID] = entry
    713         else:
    714             entry = self.resources[resourceTypeID]
    715         inRange = True
    716         info = self.CreateResourceInfo(resourceTypeID, entry)
    717         if getattr(info, 'skillMissing', False):
    718             inRange = False
    719             prompt_player_fsd_dialog('PISkillRequiredToSurveyPlanetResources', {'skill': evetypes.GetName(const.typeRemoteSensing)})
    720         elif getattr(info, 'unreachableSystem', False):
    721             inRange = False
    722             prompt_player_fsd_dialog('PIUnableToScanWorholeSystemRemotely')
    723         elif hasattr(info, 'requiredSkill'):
    724             inRange = False
    725             prompt_player_fsd_dialog('PISkillLevelToLowForRemoteSensing', {'level': info.requiredSkill})
    726         elif hasattr(info, 'systemOutOfRange'):
    727             inRange = False
    728             prompt_player_fsd_dialog('PISkillLevelToLowForRemoteSensingDistance', {'systemDistance': info.systemDistance,
    729              'maxScanDistance': info.maxScanDistance})
    730         elif info.newBand > entry.numBands or blue.os.GetWallclockTime() > entry.updateTime:
    731             self.LogInfo('GetResourceData: refreshing data: newBand', info.newBand, 'currentBand', entry.numBands, 'updateTime', entry.updateTime)
    732             shData = self.remoteHandler.GetResourceData(info)
    733             if shData.data is not None:
    734                 entry.sh = builder.CreateSHFromBuffer(shData.data, shData.numBands)
    735                 entry.updateTime = blue.os.GetWallclockTime() + planetCommon.RESOURCE_CACHE_TIMEOUT
    736                 entry.proximity = shData.proximity
    737                 entry.numBands = shData.numBands
    738                 self.LogInfo('GetResourceData: creating SH for ', resourceTypeID, 'upto band', shData.numBands)
    739             else:
    740                 self.LogInfo('GetResourceData: no new data received')
    741         else:
    742             self.LogInfo('GetResourceData: no need to refresh data')
    743         return (inRange, self.resources[resourceTypeID].sh)
    744 
    745     def GetResourceHarmonic(self, typeID):
    746         inRange, sh = self.GetResourceData(typeID)
    747         return sh
    748 
    749     def CreateResourceInfo(self, resourceTypeID, entry):
    750         info = utillib.KeyVal(resourceTypeID=resourceTypeID, updateTime=entry.updateTime, oldBand=entry.numBands, planetology=0, advancedPlanetology=0, remoteSensing=0)
    751         planetInfo = sm.GetService('map').GetPlanetInfo(self.planetID)
    752         planetLoc = cfg.evelocations.Get(planetInfo.solarSystemID)
    753         planetPos = (planetLoc.x, planetLoc.y, planetLoc.z)
    754         playerLoc = cfg.evelocations.Get(session.solarsystemid2)
    755         playerPos = (playerLoc.x, playerLoc.y, playerLoc.z)
    756         dist = geo2.Vec3Distance(playerPos, planetPos) / const.LIGHTYEAR
    757         info.remoteSensing = sm.GetService('skills').GetEffectiveLevel(const.typeRemoteSensing) or 0
    758         if info.remoteSensing == 0:
    759             info.skillMissing = True
    760             return info
    761         if session.solarsystemid2 == planetInfo.solarSystemID or sm.GetService('planetSvc').IsPlanetColonizedByMe(self.planetID):
    762             info.proximity = const.planetResourceProximityPlanet
    763         else:
    764             if not IsKnownSpaceSystem(session.solarsystemid2) or sm.GetService('clientPathfinderService').GetJumpCountFromCurrent(planetInfo.solarSystemID) > 1000:
    765                 info.unreachableSystem = True
    766                 return info
    767             info.proximity = None
    768             for i, scanRange in enumerate(const.planetResourceScanningRanges):
    769                 if scanRange >= dist:
    770                     info.proximity = i
    771 
    772             if info.proximity is None or dist > const.planetResourceScanningRanges[5 - info.remoteSensing]:
    773                 info.systemOutOfRange = True
    774                 info.systemDistance = dist
    775                 info.maxScanDistance = const.planetResourceScanningRanges[5 - info.remoteSensing]
    776                 return info
    777         info.planetology = sm.GetService('skills').GetEffectiveLevel(const.typePlanetology) or 0
    778         info.advancedPlanetology = sm.GetService('skills').GetEffectiveLevel(const.typeAdvancedPlanetology) or 0
    779         minBand, maxBand = const.planetResourceProximityLimits[info.proximity]
    780         info.newBand = min(maxBand, minBand + info.planetology + info.advancedPlanetology * 2)
    781         requiredSkill = 5 - info.proximity
    782         if info.remoteSensing < requiredSkill:
    783             info.requiredSkill = requiredSkill
    784         return info
    785 
    786     def CreateResourceEntry(self):
    787         entry = utillib.KeyVal(sh=builder.CreateConstantSH(0.0, 1), updateTime=0, numBands=0, proximity=None)
    788         return entry
    789 
    790     def StartTicking(self, forceRestart = False):
    791         if forceRestart:
    792             self.ticking = False
    793             if self.tickThread is not None:
    794                 self.LogInfo('StartTicking :: Forcing restart of tick thread')
    795                 self.tickThread.kill()
    796                 self.tickThread = None
    797         elif self.ticking:
    798             return
    799         self.ticking = True
    800         self.tickThread = uthread.new(self._Tick, session.charid)
    801 
    802     def StopTicking(self):
    803         self.ticking = False
    804         if self.tickThread is not None:
    805             self.tickThread.kill()
    806             self.tickThread = None
    807 
    808     def GetNextTickTime(self, charID):
    809         if self.colony is None or self.colony.colonyData is None:
    810             return
    811         nextTickTime = None
    812         for pin in self.colony.colonyData.pins.itervalues():
    813             if pin.IsActive() or pin.CanActivate():
    814                 pinTickTime = pin.GetNextRunTime()
    815                 if pinTickTime is None or pinTickTime < blue.os.GetWallclockTime():
    816                     nextTickTime = blue.os.GetWallclockTime()
    817                     break
    818                 elif nextTickTime is None or pinTickTime < nextTickTime:
    819                     nextTickTime = pinTickTime
    820 
    821         return nextTickTime
    822 
    823     def _Tick(self, charID):
    824         while self.ticking:
    825             if not self:
    826                 return
    827             if self.colony is not None:
    828                 self.colony.RunSimulation(beNice=True)
    829                 if self.colony.colonyData is not None:
    830                     sm.ScatterEvent('OnRefreshPins', self.colony.colonyData.pins.keys())
    831             nextTime = self.GetNextTickTime(charID)
    832             if nextTime is None:
    833                 self.ticking = False
    834             else:
    835                 nextTime = max(const.SEC, nextTime - blue.os.GetWallclockTime() + 1)
    836                 self.LogInfo(self.planetID, ': Active Client Tick: sleeping for', FmtTimeInterval(nextTime))
    837                 blue.pyos.synchro.SleepWallclock(nextTime / const.MSEC)
    838 
    839         self.tickThread = None
    840 
    841     def GMRunDepletionSim(self, typeID, info):
    842         self.remoteHandler.GMRunDepletionSim(typeID, info)
    843 
    844     def RestartExtractors(self):
    845         if self.IsEditingPlanet():
    846             raise UserError('CustomNotify', {'notify': GetByLabel('UI/PI/Common/CannotRestartWhileEditing')})
    847         if sm.GetService('planetSvc').IsSubmittingInProgressOrThrottled():
    848             raise UserError('CustomNotify', {'notify': GetByLabel('UI/PI/Common/PlanetBusyUpdating')})
    849         ecuPins = self.colony.colonyData.GetECUPins()
    850         for pin in ecuPins:
    851             if not pin.programType:
    852                 continue
    853             if pin.IsActive():
    854                 continue
    855             currentRadius = max(min(pin.headRadius, planetCommon.RADIUS_DRILLAREAMAX), planetCommon.RADIUS_DRILLAREAMIN)
    856             self.InstallProgram(pin.id, pin.programType, currentRadius)
    857 
    858         try:
    859             if self.changes.GetStreamLength():
    860                 if sm.GetService('planetSvc').IsSubmittingInProgressOrThrottled():
    861                     raise UserError('CustomNotify', {'notify': GetByLabel('UI/PI/Common/PlanetBusyUpdating')})
    862                 sm.ScatterEvent('OnPlanetSubmittingChanges')
    863                 self.SubmitChanges()
    864                 return True
    865             return False
    866         except Exception as e:
    867             self.RevertChanges()
    868             raise
    869 
    870     def IsEditingPlanet(self):
    871         if self.commandPinChange == CP_COMMANDPINREMOVED:
    872             return True
    873         if self.changes.GetStreamLength():
    874             return True
    875         return False