base.py (23556B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\client\script\ui\station\base.py 2 import sys 3 import blue 4 import evetypes 5 import localization 6 import log 7 import uthread 8 from carbon.common.script.sys import service 9 from carbon.common.script.sys.row import Row 10 from carbonui import uiconst 11 from carbonui.button.group import ButtonGroup 12 from carbonui.control.layer import LayerCore 13 from carbonui.window.underlay import WindowUnderlay 14 from carbonui.primitives.container import Container 15 from carbonui.primitives.line import Line 16 from carbonui.primitives.sprite import Sprite 17 from carbonui.uianimations import animations 18 from carbonui.uicore import uicore 19 from eve.client.script.environment.model import turretSet 20 from eve.client.script.ui.control import eveIcon, eveLabel 21 from eve.client.script.ui.shared.dockedUI import ReloadLobbyWnd 22 from eve.client.script.ui.shared.dockedUI.lobbyWnd import LobbyWnd 23 from eve.client.script.ui.shared.skillRequirementDialog import prompt_missing_skill_requirements 24 from eve.client.script.ui.station import stationServiceConst 25 from eve.client.script.ui.util import uix 26 from eve.common.lib.appConst import CLONE_STATION_SERVICES 27 from eve.common.script.sys import eveCfg, idCheckers 28 from eve.common.script.sys.eveCfg import IsControllingStructure 29 from eve.common.script.sys.idCheckers import IsCapsule, IsNewbieShip 30 from eve.common.script.util.structuresCommon import IsStationServiceAvailable 31 from eveSpaceObject import spaceobjanimation 32 from fsdBuiltData.common.graphicIDs import GetSofFactionName 33 from player_messaging.client.ui_message import prompt_player_fsd_dialog 34 from reprocessing.ui.reprocessingWnd import ReprocessingWnd 35 36 class StationSvc(service.Service): 37 __guid__ = 'svc.station' 38 __update_on_reload__ = 0 39 __exportedcalls__ = {'GetGuests': [], 40 'IsGuest': [], 41 'Setup': [], 42 'GetSvc': [], 43 'LoadSvc': [], 44 'GiveHint': [], 45 'ClearHint': [], 46 'StopAllStationServices': [], 47 'CleanUp': [], 48 'SelectShipDlg': [], 49 'GetServiceState': [], 50 'GetStationItem': []} 51 __dependencies__ = ['journal', 'insurance', 'crimewatchSvc'] 52 __notifyevents__ = ['OnCharNowInStation', 53 'OnCharNoLongerInStation', 54 'OnDogmaItemChange', 55 'OnCharacterHandler', 56 'OnDogmaAttributeChanged', 57 'OnCharacterSelected', 58 'OnSessionChanged', 59 'OnActiveShipModelChange', 60 'OnStanceActive', 61 'ProcessSessionChange', 62 'OnSessionReset'] 63 64 def __init__(self): 65 super(StationSvc, self).__init__() 66 self.guests = {} 67 68 @property 69 def stationItem(self): 70 return self.GetStationItem() 71 72 def OnCharacterSelected(self): 73 self._stationItem = None 74 self.CleanUp(clearGuestList=True) 75 76 def OnSessionReset(self): 77 self.CleanUp(clearGuestList=True) 78 79 def OnSessionChanged(self, isRemote, session, change): 80 if 'locationid' in change: 81 oldLocation, newLocation = change['locationid'] 82 if idCheckers.IsStation(oldLocation): 83 self.CleanUp(clearGuestList=True) 84 85 def ProcessSessionChange(self, isRemote, session, change): 86 if 'stationid' in change or 'structureid' in change: 87 self.ClearStationItem() 88 89 def OnCharNowInStation(self, rec): 90 charID, corpID, allianceID, warFactionID = rec 91 if charID not in self.guests: 92 self.guests[charID] = (corpID, allianceID, warFactionID) 93 94 def OnCharNoLongerInStation(self, rec): 95 charID, corpID, allianceID, factionID = rec 96 if charID in self.guests: 97 self.guests.pop(charID) 98 99 def GetGuests(self): 100 currentStationID = session.stationid 101 if not self.guestListReceived or self.guestListReceived != currentStationID: 102 self.guests.clear() 103 guests = sm.RemoteSvc('station').GetGuests() 104 for charID, corpID, allianceID, warFactionID in guests: 105 self.guests[charID] = (corpID, allianceID, warFactionID) 106 107 self.guestListReceived = currentStationID 108 return self.guests 109 110 def IsGuest(self, whoID): 111 if len(self.guests) == 0: 112 self.GetGuests() 113 return whoID in self.guests 114 115 def Stop(self, memStream = None): 116 self.LogInfo('Stopping Station Service') 117 self.CleanUp(clearGuestList=True) 118 119 def GetServiceDisplayName(self, service): 120 s = self.GetStationServiceData(service) 121 if s: 122 return s.label 123 return localization.GetByLabel('UI/Common/Unknown') 124 125 def GetStationServiceData(self, serviceName): 126 return stationServiceConst.serviceDataByNameID.get(serviceName, None) 127 128 def IsCloneServiceAvailable(self): 129 for stationServiceID in CLONE_STATION_SERVICES: 130 if self.IsStationServiceAvailable(stationServiceID): 131 return True 132 133 return False 134 135 def IsStationServiceAvailable(self, stationServiceID): 136 return IsStationServiceAvailable(session.solarsystemid2, self.stationItem, stationServiceID) 137 138 def CleanUp(self, storeCamera = 1, clearGuestList = False): 139 try: 140 if getattr(self, 'underlay', None): 141 uicore.registry.UnregisterWindow(self.underlay) 142 self.underlay.OnClick = None 143 self.underlay.Minimize = None 144 self.underlay.Maximize = None 145 except: 146 pass 147 148 uix.Close(self, ['closeBtn', 149 'hint', 150 'underlay', 151 'lobby']) 152 self.lobby = None 153 self.underlay = None 154 self.closeBtn = None 155 self.hint = None 156 self.selected_service = None 157 self.loading = None 158 self.active_service = None 159 self.refreshingfitting = False 160 self.activeShipItem = None 161 self.activeShipTypeID = None 162 self.activeshipmodel = None 163 self.loadingSvc = 0 164 self.activatingShip = 0 165 self.leavingShip = 0 166 self.paperdollState = None 167 self.station = None 168 if clearGuestList: 169 self.guests = {} 170 self.guestListReceived = None 171 172 def StopAllStationServices(self): 173 for serviceData in stationServiceConst.serviceData: 174 if sm.IsServiceRunning(serviceData.name): 175 sm.services[serviceData.name].Stop() 176 177 def Setup(self, reloading = 0): 178 self.CleanUp(0) 179 self.loading = 1 180 if not reloading: 181 prompt_player_fsd_dialog('OnEnterStation') 182 if self.station is None and session.stationid: 183 self.station = sm.GetService('ui').GetStation(session.stationid) 184 sm.GetService('autoPilot').SetOff('toggled by Station Entry') 185 if sm.GetService('viewState').IsViewActive('starmap', 'systemmap'): 186 sm.StartService('map').MinimizeWindows() 187 if sm.GetService('viewState').IsViewActive('planet'): 188 sm.GetService('planetUI').MinimizeWindows() 189 self.loading = 0 190 self.sprite = None 191 192 def GetPaperdollStateCache(self): 193 if self.paperdollState is None: 194 self.paperdollState = sm.RemoteSvc('charMgr').GetPaperdollState() 195 return self.paperdollState 196 197 def OnCharacterHandler(self): 198 self.ClearPaperdollStateCache() 199 200 def ClearPaperdollStateCache(self): 201 self.paperdollState = None 202 203 def BlinkButton(self, what): 204 lobby = LobbyWnd.GetIfOpen() 205 if lobby: 206 lobby.BlinkButton(what) 207 208 def TryActivateShip(self, invitem, onSessionChanged = 0, secondTry = 0): 209 shipid = invitem.itemID 210 dogmaLocation = sm.GetService('clientDogmaIM').GetDogmaLocation() 211 if shipid == dogmaLocation.GetCurrentShipID(): 212 return 213 if self.activatingShip or IsControllingStructure(): 214 return 215 if len(dogmaLocation.GetMissingSkills(invitem.typeID)) > 0: 216 prompt_missing_skill_requirements(invitem.typeID) 217 return 218 sm.GetService('invCache').TryLockItem(shipid, 'lockItemActivating', {'itemType': invitem.typeID}, 1) 219 self.activatingShip = 1 220 try: 221 dogmaLocation = sm.GetService('clientDogmaIM').GetDogmaLocation() 222 dogmaLocation.MakeShipActive(shipid) 223 self.activeShipItem = invitem 224 sm.GetService('fleet').UpdateFleetInfo() 225 finally: 226 self.activatingShip = 0 227 sm.GetService('invCache').UnlockItem(shipid) 228 229 def TryLeaveShip(self, invitem, onSessionChanged = 0, secondTry = 0): 230 shipid = invitem.itemID 231 dogmaLocation = sm.GetService('clientDogmaIM').GetDogmaLocation() 232 if shipid != dogmaLocation.GetCurrentShipID(): 233 return 234 if self.leavingShip: 235 return 236 sm.GetService('invCache').TryLockItem(shipid, 'lockItemLeavingShip', {'itemType': invitem.typeID}, 1) 237 self.leavingShip = 1 238 try: 239 shipsvc = sm.GetService('gameui').GetShipAccess() 240 shipsvc.LeaveShip(shipid) 241 finally: 242 self.leavingShip = 0 243 sm.GetService('invCache').UnlockItem(shipid) 244 245 def OnDogmaItemChange(self, item, change): 246 if session.stationid is None: 247 return 248 if item.groupID in const.turretModuleGroups: 249 self.FitHardpoints() 250 251 def OnActiveShipModelChange(self, model, shipItem): 252 self.activeshipmodel = model 253 self.activeShipTypeID = shipItem.typeID 254 self.FitHardpoints() 255 256 def OnStanceActive(self, shipID, stanceID): 257 if eveCfg.GetActiveShip() == shipID: 258 if self.activeshipmodel is not None: 259 spaceobjanimation.SetShipAnimationStance(self.activeshipmodel, stanceID) 260 261 def FitHardpoints(self): 262 if not self.activeshipmodel or self.activeShipTypeID is None or self.refreshingfitting: 263 return 264 self.refreshingfitting = True 265 activeShip = eveCfg.GetActiveShip() 266 sofFactionName = GetSofFactionName(evetypes.GetGraphicID(self.activeShipTypeID)) 267 turretSet.TurretSet.FitTurrets(activeShip, self.activeshipmodel, sofFactionName) 268 self.refreshingfitting = False 269 270 def GetUnderlay(self): 271 if self.underlay is None: 272 for each in uicore.layer.main.children[:]: 273 if each is not None and not each.destroyed and each.name == 'services': 274 uicore.registry.UnregisterWindow(each) 275 each.OnClick = None 276 each.Minimize = None 277 each.Maximize = None 278 each.Close() 279 280 self.underlay = Sprite(name='services', parent=uicore.layer.main, align=uiconst.TOTOP, state=uiconst.UI_HIDDEN) 281 self.underlay.scope = uiconst.SCOPE_STATION 282 self.underlay.minimized = 0 283 self.underlay.Minimize = self.MinimizeUnderlay 284 self.underlay.Maximize = self.MaximizeUnderlay 285 main = Container(name='mainparentXX', parent=self.underlay, align=uiconst.TOALL, pos=(0, 0, 0, 0)) 286 main.OnClick = self.ClickParent 287 main.state = uiconst.UI_NORMAL 288 sub = Container(name='subparent', parent=main, align=uiconst.TOALL, pos=(0, 0, 0, 0)) 289 captionparent = Container(name='captionparent', parent=main, align=uiconst.TOPLEFT, left=128, top=36, idx=0) 290 caption = eveLabel.CaptionLabel(text='', parent=captionparent) 291 self.closeBtn = ButtonGroup(btns=[[localization.GetByLabel('UI/Commands/CmdClose'), 292 self.CloseSvc, 293 None, 294 81]], parent=sub) 295 self.sr.underlay = WindowUnderlay(parent=main) 296 self.sr.underlay.padding = (-1, -10, -1, 0) 297 svcparent = Container(name='serviceparent', parent=sub, align=uiconst.TOALL, pos=(0, 0, 0, 0)) 298 self.underlay.sr.main = main 299 self.underlay.sr.svcparent = svcparent 300 self.underlay.sr.caption = caption 301 uicore.registry.RegisterWindow(self.underlay) 302 return self.underlay 303 304 def MinimizeUnderlay(self, *args): 305 self.underlay.state = uiconst.UI_HIDDEN 306 307 def MaximizeUnderlay(self, *args): 308 self.underlay.state = uiconst.UI_PICKCHILDREN 309 self.ClickParent() 310 311 def ClickParent(self, *args): 312 for each in uicore.layer.main.children: 313 if getattr(each, 'isDockWnd', 0) == 1 and each.state == uiconst.UI_NORMAL: 314 each.SetOrder(-1) 315 316 def LoadSvc(self, service, close = 1): 317 serviceInfo = self.GetStationServiceData(service) 318 if service is not None and serviceInfo is not None: 319 self.ExecuteCommand(serviceInfo.command) 320 return 321 if getattr(self, 'loadingSvc', 0): 322 return 323 self.loadingSvc = 1 324 while self.loading: 325 blue.pyos.synchro.SleepWallclock(500) 326 327 if self.selected_service is None: 328 if service: 329 self._LoadSvc(1, service) 330 elif service == self.selected_service: 331 if close: 332 self._LoadSvc(0) 333 else: 334 self._LoadSvc(0, service) 335 self.loadingSvc = 0 336 337 def ExecuteCommand(self, cmdstr): 338 func = getattr(uicore.cmd, cmdstr, None) 339 if func: 340 func() 341 342 def GetSvc(self, svcname = None): 343 if self.active_service is not None: 344 if svcname is not None: 345 if self.selected_service == svcname: 346 return self.active_service 347 else: 348 return self.active_service 349 350 def ReloadLobby(self): 351 ReloadLobbyWnd() 352 353 def _LoadSvc(self, inout, service = None): 354 self.loading = 1 355 wnd = self.GetUnderlay() 356 newsvc = None 357 if inout == 1 and wnd is not None: 358 self.ClearHint() 359 newsvc, svctype = self.SetupService(wnd, service) 360 if wnd.absoluteRight - wnd.absoluteLeft < 700 and inout == 1: 361 sm.GetService('neocom').Minimize() 362 height = uicore.desktop.height - 180 363 wnd.state = uiconst.UI_PICKCHILDREN 364 if inout == 1: 365 sm.GetService('neocom').SetLocationInfoState(0) 366 topStart = -height if inout else height 367 topEnd = 0 if inout else -height 368 animations.MorphScalar(wnd, 'top', startVal=topStart, endVal=topEnd, duration=0.5) 369 snd = service 370 if inout == 0: 371 snd = self.selected_service 372 if snd is not None: 373 prompt_player_fsd_dialog('LoadSvc_%s%s' % (snd, ['Out', 'In'][inout])) 374 blue.pyos.synchro.SleepWallclock([750, 1250][inout]) 375 if inout == 0: 376 sm.GetService('neocom').SetLocationInfoState(1) 377 if newsvc is not None: 378 if svctype == 'form': 379 newsvc.Startup(self) 380 elif settings.user.ui.Get('nottry', 0): 381 newsvc.Initialize(wnd.sr.svcparent) 382 else: 383 try: 384 newsvc.Initialize(wnd.sr.svcparent) 385 except: 386 log.LogException(channel=self.__guid__) 387 sys.exc_clear() 388 389 self.active_service = newsvc 390 self.selected_service = service 391 else: 392 wnd.sr.svcparent.Flush() 393 if self.active_service and hasattr(self.active_service, 'Reset'): 394 self.active_service.Reset() 395 self.active_service = None 396 self.selected_service = service 397 self.loading = 0 398 if inout == 0 and service is not None: 399 self._LoadSvc(1, service) 400 if inout == 0 and service is None: 401 wnd.sr.svcparent.Flush() 402 403 def Startup(self, svc): 404 uthread.new(svc.Startup, self) 405 406 def GiveHint(self, hintstr, left = 80, top = 320, width = 300): 407 self.ClearHint() 408 if self.hint is None: 409 par = Container(name='captionParent', parent=self.GetUnderlay().sr.main, align=uiconst.TOPLEFT, top=top, left=left, width=width, height=256, idx=0) 410 self.hint = eveLabel.CaptionLabel(text='', parent=par, align=uiconst.TOALL, left=0, top=0) 411 self.hint.parent.top = top 412 self.hint.parent.left = left 413 self.hint.parent.width = width 414 self.hint.text = hintstr or '' 415 416 def ClearHint(self): 417 if self.hint is not None: 418 self.hint.text = '' 419 420 def SetupService(self, wnd, servicename): 421 wnd.sr.svcparent.Flush() 422 svc = None 423 topheight = 128 424 btmheight = 0 425 icon = 'ui_9_64_14' 426 sz = 128 427 top = -16 428 icon = eveIcon.Icon(icon=icon, parent=wnd.sr.svcparent, left=0, top=top, size=sz, idx=0) 429 iconpar = Container(name='iconpar', parent=wnd.sr.svcparent, align=uiconst.TOTOP, height=96, clipChildren=1, state=uiconst.UI_PICKCHILDREN) 430 bigicon = icon.CopyTo() 431 bigicon.width = bigicon.height = sz * 2 432 bigicon.top = -64 433 bigicon.opacity = 0.1 434 iconpar.children.append(bigicon) 435 closeX = eveIcon.Icon(icon='ui_38_16_220') 436 closeX.align = uiconst.TOPRIGHT 437 closeX.left = closeX.top = 2 438 closeX.OnClick = self.CloseSvc 439 iconpar.children.append(closeX) 440 Line(parent=iconpar, align=uiconst.TOPRIGHT, height=1, left=2, top=16, width=18) 441 icon.state = uiconst.UI_DISABLED 442 wnd.sr.caption.text = self.GetServiceDisplayName(servicename) 443 wnd.sr.caption.state = uiconst.UI_DISABLED 444 return (svc, 'service') 445 446 def CloseSvc(self, *args): 447 uthread.new(self.LoadSvc, None) 448 449 def UndockAttempt(self, shipID): 450 return self._DoUndockAttempt(False, True, shipID) 451 452 def _DoUndockAttempt(self, ignoreContraband, observedSuppressed, shipID): 453 try: 454 shipsvc = sm.GetService('gameui').GetShipAccess() 455 undockingLogLabel = localization.GetByLabel('UI/Station/UndockingFromStationToSystem', fromStation=session.stationid, toSystem=session.solarsystemid2) 456 sm.GetService('logger').AddText(undockingLogLabel) 457 if observedSuppressed: 458 ignoreContraband = settings.user.suppress.Get('suppress.ShipContrabandWarningUndock', None) == uiconst.ID_OK 459 onlineModules = sm.GetService('clientDogmaIM').GetDogmaLocation().GetOnlineModules(shipID) 460 try: 461 sm.GetService('space').PrioritizeLoadingForIDs([session.stationid]) 462 sm.GetService('sessionMgr').PerformSessionChange('undock', shipsvc.Undock, shipID, ignoreContraband, onlineModules=onlineModules) 463 except UserError as e: 464 if e.msg == 'ShipNotInHangar': 465 capsuleID = e.dict.get('capsuleID', None) 466 dogmaLocation = sm.GetService('clientDogmaIM').GetDogmaLocation() 467 if capsuleID is not None: 468 dogmaLocation.MakeShipActive(capsuleID) 469 raise 470 elif e.msg == 'ShipContrabandWarningUndock': 471 if prompt_player_fsd_dialog(e.msg, e.dict, uiconst.OKCANCEL, suppress=uiconst.ID_OK) == uiconst.ID_OK: 472 sys.exc_clear() 473 return self._DoUndockAttempt(True, False, shipID) 474 else: 475 return False 476 else: 477 raise 478 479 self.CloseStationWindows() 480 except Exception as e: 481 sm.GetService('undocking').AbortUndock() 482 raise 483 484 return True 485 486 def CloseStationWindows(self): 487 ReprocessingWnd.CloseIfOpen() 488 489 def SelectShipDlg(self): 490 hangarInv = sm.GetService('invCache').GetInventory(const.containerHangar) 491 items = hangarInv.List(const.flagHangar) 492 tmplst = [] 493 activeShipID = eveCfg.GetActiveShip() 494 for item in items: 495 if item[const.ixCategoryID] == const.categoryShip and item[const.ixSingleton]: 496 tmplst.append((evetypes.GetName(item[const.ixTypeID]), item, item[const.ixTypeID])) 497 498 if not tmplst: 499 prompt_player_fsd_dialog('NeedShipToUndock') 500 return 501 ret = uix.ListWnd(tmplst, 'item', localization.GetByLabel('UI/Station/SelectShip'), None, 1) 502 if ret is None or ret[1].itemID == activeShipID: 503 return 504 newActiveShip = ret[1] 505 try: 506 self.TryActivateShip(newActiveShip) 507 except: 508 raise 509 510 def OnDogmaAttributeChanged(self, shipID, itemID, attributeID, value): 511 if self.activeshipmodel and attributeID == const.attributeIsOnline and shipID == eveCfg.GetActiveShip(): 512 dogmaLocation = sm.GetService('clientDogmaIM').GetDogmaLocation() 513 slot = None 514 if not dogmaLocation.IsItemLoaded(shipID): 515 dogmaLocation.LoadItem(shipID) 516 if dogmaLocation.IsItemLoading(shipID): 517 dogmaLocation.loadingItems[shipID].receive() 518 for module in dogmaLocation.GetDogmaItem(shipID).GetFittedItems().itervalues(): 519 if module.itemID != itemID: 520 continue 521 slot = module.flagID - const.flagHiSlot0 + 1 522 sceneShip = self.activeshipmodel 523 for turretSet in sceneShip.turretSets: 524 if turretSet.slotNumber == slot: 525 if module.IsOnline(): 526 turretSet.EnterStateIdle() 527 else: 528 turretSet.EnterStateDeactive() 529 530 def GetStationItem(self): 531 if session.stationid and self.HasInvalidStationItem(): 532 self.SetStationItemBits(sm.RemoteSvc('stationSvc').GetStationItemBits()) 533 return self._stationItem 534 535 def ClearStationItem(self): 536 self._stationItem = None 537 538 def SetStationItemBits(self, bits): 539 self._stationItem = Row(['ownerID', 540 'itemID', 541 'operationID', 542 'stationTypeID'], bits) 543 544 def HasInvalidStationItem(self): 545 return self._stationItem is None or self._stationItem.itemID != session.stationid 546 547 def OnStationInformationUpdated(self, stationID): 548 sm.GetService('objectCaching').InvalidateCachedMethodCall('stationSvc', 'GetStation', stationID) 549 550 def IsInNewbieShip(self): 551 shipItem = sm.GetService('clientDogmaIM').GetDogmaLocation().GetShipItem() 552 return shipItem and IsNewbieShip(shipItem.groupID) 553 554 def CreateNewbieShip(self): 555 locationID = session.stationid or session.structureid 556 if not locationID: 557 raise stationServiceConst.NewbieShipError('MustBeDocked') 558 shipItem = sm.GetService('clientDogmaIM').GetDogmaLocation().GetShipItem() 559 if not shipItem: 560 raise stationServiceConst.NewbieShipError('ErrorCreatingNewbieShip') 561 shipID = shipItem.itemID 562 shipGroupID = shipItem.groupID 563 if IsNewbieShip(shipGroupID): 564 raise stationServiceConst.NewbieShipError('AlreadyInNewbieShip') 565 if not IsCapsule(shipGroupID): 566 areYouSureMessage = localization.GetByLabel('UI/Station/ConfirmMoveToNewbieShip') 567 if prompt_player_fsd_dialog('AskAreYouSure', {'cons': areYouSureMessage}, uiconst.YESNO) != uiconst.ID_YES: 568 return 569 try: 570 sm.RemoteSvc('dogmaIM').CreateNewbieShip(shipID, locationID) 571 except UserError: 572 raise 573 except Exception: 574 raise stationServiceConst.NewbieShipError('ErrorCreatingNewbieShip') 575 576 577 class StationLayer(LayerCore): 578 __guid__ = 'form.StationLayer' 579 580 def OnCloseView(self): 581 sm.GetService('station').CleanUp() 582 583 def OnOpenView(self, **kwargs): 584 pass