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