gameui.py (45481B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\client\script\parklife\gameui.py 2 from __future__ import absolute_import 3 import datetime 4 import sys 5 import blue 6 import bluepy 7 import carbon.client.script.sys.appUtils as appUtils 8 import carbon.common.script.util.logUtil as log 9 import datetimeutils 10 import eve.common.script.net.eveMoniker as moniker 11 import evegraphics.settings as gfxsettings 12 import everesourceprefetch 13 import gametime 14 import langutils 15 import localization 16 import logmodule 17 import paperdoll 18 import player_messaging 19 import player_messaging.client.ui_message 20 import telemetry 21 import trinity 22 import uthread 23 from achievement_system.client.api import repository as achievement_system_repository 24 from achievement_system.client.ui.fanfare.controller import AchievementFanfareUIController 25 from cosmetics.client.character.title.api import repository as character_titles_repository 26 from auraguidance.client.api import initialize_aura_guidance_repository 27 from campaigns.client.api import initialize_campaigns_repository_v1, initialize_campaigns_repository_v2 28 from carbon.common.lib import const, serverInfo 29 from carbon.common.script.sys.service import Service, SERVICE_RUNNING, SERVICE_START_PENDING, ROLEMASK_ELEVATEDPLAYER 30 from carbonui import uiconst 31 from carbonui.control.contextMenu.menuUtil import ClearMenuLayer 32 from carbonui.control.message import QuickMessage 33 from carbonui.text.settings import get_default_font_size_setting, get_font_size_setting, set_font_size_setting, update_font_size_factor 34 from carbonui.uicore import uicore, GetWindowName 35 from communitytracks.client.api import repository as community_tracks_repository_api 36 from communitytracks.client.qa.settings import ShouldMockSetting as ShouldMockCommunityTracksSetting 37 from content.client.api import initialize_content_registry 38 from eve.client.script.parklife.messagebus.uiMessenger import UIMessenger 39 from eve.client.script.ui.clonegrade.clone_grade_fanfare_ui_controller import CloneGradeFanfareUiController 40 from eve.client.script.ui.clonegrade.upsell_neocom_controller import UpsellNeocomController 41 from eve.client.script.ui.control.resourceLoadingIndicator import ResourceLoadingIndicator 42 from eve.client.script.ui.inflight.shipHud.safeLogoffTimer import SafeLogoffTimer, SafeLogoffTimer2 43 from eve.client.script.ui.mouseInputHandler import MouseInputHandler 44 from eve.client.script.ui.podGuide.megaMenuManager import MegaMenuManager 45 from eve.client.script.ui.services import sessionChangeWindowOpener 46 from eve.client.script.ui.shared import messagebox 47 from eve.client.script.ui.shared.messagebox import MessageBox 48 from eve.client.script.ui.shared.radioButtonMessageBox import RadioButtonMessageBox 49 from eve.client.script.ui.shared.systemMenu.systemmenu import SystemMenu 50 from eve.client.script.ui.structure.structureBrowser.controllers.reinforceTimersBundle import ReinforcementBundle 51 from eve.client.script.ui.structure.structureHackingResult import StructureHackingResultWnd 52 from eve.client.script.ui.util.disconnectNotice import DisconnectNotice 53 from eve.client.script.ui.view.viewStateConfig import SetupViewStates 54 from eve.client.script.ui.view.viewStateConst import ViewState 55 from eve.common.lib import appConst 56 from eve.common.script.sys import eveCfg 57 from eveexceptions import ExceptionEater 58 from evegraphics.environments.environmentManager import EnvironmentManager 59 from eveprefs import prefs 60 from evespacescene.playerdeath import PlayerDeathHandler 61 from evespacescene.routevisualizer import RouteVisualizer 62 from evetypes import GetVolume 63 from freelanceprojects.client.api import initialize_freelance_project_repository 64 from freelanceprojects.client.contributionmethods.qa.settings import ShouldMockContributionMethodsSetting 65 from freelanceprojects.client.qa.settings import ShouldMockFreelanceProjectSetting 66 from globalConfig import AllowCharacterLogoff 67 from inventoryutil.client.cargo_utils import get_cargo_volume_available 68 from kiring.client.apigateway import get_kiring_api_gateway 69 from kiring.common.const import ANTI_ADDICTION_CHECK_FAIL_JUVENILES_BLOCK_AFTER_22_AND_BEFORE_8, ANTI_ADDICTION_CHECK_FAIL_JUVENILES_PLAY_TIME_OVERFLOW, ANTI_ADDICTION_CHECK_FAIL_JUVENILES_PLAY_TIME_OVERFLOW_HOLIDAY 70 from mining.client.location_arrival_indication_service import LocationArrivalIndicationService 71 from newFeatures import newFeatureNotify 72 from omega.client.clone_grade_svc import get_clone_grade_svc 73 from operations.client.operationscontroller import ReleaseOperationsController 74 from operations.client.tutorialOperationsController import ReleaseTutorialOperationsController 75 from player_messaging.client import dialog_handler 76 from player_messaging.client.ui_message import message_player, prompt_player_fsd_dialog 77 from plex.client.api import repository as plex_repository 78 from regionalui import manager 79 from safespace.client.travel_listener import SafeSpaceTravelListener 80 from stationintrocinematic.client.arrival_listener import StationIntroCinematicListener 81 from .sceneManagerConsts import SCENE_TYPE_SPACE 82 from sovereignty.mercenaryden.client.qa.settings.should_mock_data import ShouldMockSetting 83 from sovereignty.mercenaryden.client.repository import setup_singleton 84 from spacecomponents.client.components.mercenaryDen import extract_infomorphs_to_ship 85 AFK_THRESHOLD = datetime.timedelta(minutes=5) 86 DEFAULT_RESOURCE_LOADING_WHEEL_ALIGN = uiconst.BOTTOMLEFT 87 DEFAULT_RESOURCE_LOADING_WHEEL_SIZE = 32 88 DEFAULT_RESOURCE_LOADING_WHEEL_LEFT = 12 89 DEFAULT_RESOURCE_LOADING_WHEEL_TOP = 12 90 91 class GameUI(Service): 92 __guid__ = 'svc.gameui' 93 __startupdependencies__ = ['device', 94 'settings', 95 'viewState', 96 'publicGatewaySvc', 97 'ui_blinker', 98 'station', 99 'seasonService'] 100 __dependencies__ = ['michelle', 101 'machoNet', 102 'inv', 103 'neocom', 104 'infoPanel', 105 'shipTreeUI', 106 'agencyNew', 107 'redeem', 108 'sov', 109 'epicArc'] 110 __notifyevents__ = ['OnConnectionRefused', 111 'OnDisconnect', 112 'OnServerMessage', 113 'OnRemoteMessage', 114 'DoSessionChanging', 115 'ProcessSessionChange', 116 'OnSessionChanged', 117 'DoBallsAdded', 118 'OnNewState', 119 'OnClusterShutdownInitiated', 120 'OnClusterShutdownCancelled', 121 'OnJumpQueueMessage', 122 'OnViewStateChanged', 123 'OnSetDevice', 124 'OnCreateNewMailWindow', 125 'OnStructureHacked', 126 'OnPodKilled', 127 'DoBallClear', 128 'OnAntiAddictionOnlineTimeWarning', 129 'OnAntiAddictionOnlineTimeBlockWarning', 130 'OnSafeLogoffTimerStarted', 131 'OnSafeLogoffActivated', 132 'OnSafeLogoffAborted', 133 'OnSafeLogoffFailed'] 134 135 def __init__(self): 136 self.state = SERVICE_START_PENDING 137 super(GameUI, self).__init__() 138 self.wannaBeEgo = -1 139 self.languages = None 140 self.shutdownTime = None 141 self.podKillPodID = None 142 self.sceneManager = None 143 self.playerDeathHandler = None 144 self.routeVisualizer = None 145 self.uiLayerList = None 146 self.shipAccess = None 147 self.logoffTimer = None 148 self._is_afk = False 149 self._last_ui_interaction_timestamp = None 150 self.ui_messenger = None 151 self._upsell_neocom_controller = None 152 self._clone_grade_fanfare_ui_controller = None 153 self._achievement_fanfare_ui_controller = None 154 self.initialize_services() 155 156 def initialize_services(self): 157 self.regionalUiManager = manager.RegionalUserInterfaceManager(self) 158 LocationArrivalIndicationService.initialize() 159 SafeSpaceTravelListener.initialize() 160 StationIntroCinematicListener.initialize() 161 162 def Run(self, memStream = None): 163 Service.Run(self, memStream) 164 self.ui_messenger = UIMessenger(self.publicGatewaySvc) 165 self.sceneManager = sm.GetService('sceneManager') 166 self.playerDeathHandler = PlayerDeathHandler(self.sceneManager) 167 self.routeVisualizer = RouteVisualizer() 168 self._upsell_neocom_controller = UpsellNeocomController() 169 self._clone_grade_fanfare_ui_controller = CloneGradeFanfareUiController() 170 self._achievement_fanfare_ui_controller = AchievementFanfareUIController() 171 update_font_size_factor() 172 defaults = {'debug': 0, 173 'port': sm.services['machoNet'].defaultProxyPortOffset, 174 'newbie': 1, 175 'inputhost': 'localhost', 176 'digit': ',', 177 'decimal': '.', 178 'eulaagreed': 0, 179 'host': 0} 180 for k, v in defaults.items(): 181 if not prefs.HasKey(k): 182 prefs.SetValue(k, v) 183 184 self.uiLayerList = [('l_hint', None, None), 185 ('l_dragging', None, None), 186 ('l_menu', None, None), 187 ('l_mloading', None, None), 188 ('l_modal', None, [('l_loadingFill', None, None), ('l_systemmenu', SystemMenu, None)]), 189 ('l_utilmenu', None, None), 190 ('l_alwaysvisible', None, None), 191 ('l_abovemain', None, None), 192 ('l_loading', None, None), 193 ('l_videoOverlay', None, None), 194 ('l_infoBubble', None, None), 195 ('l_main', None, None), 196 ('l_viewstate', None, None)] 197 self.shipAccess = None 198 self.state = SERVICE_RUNNING 199 uthread.worker('gameui::ShutdownTimer', self.__ShutdownTimer) 200 uthread.worker('gameui::SessionTimeoutTimer', self.__SessionTimeoutTimer) 201 uthread.new(self._UpdateCrashKeyValues).context = 'gameui::_UpdateCrashKeyValues' 202 203 def _UpdateCrashKeyValues(self): 204 self.LogInfo('UpdateCrashKeyValues loop starting') 205 stats = [] 206 try: 207 info = serverInfo.GetServerInfo() 208 blue.SetCrashKeyValues('serverName', info.name) 209 blue.SetCrashKeyValues('serverIP', info.IP) 210 except: 211 log.LogException() 212 213 statNames = ['Blue/Memory/Malloc', 214 'Blue/Memory/Python', 215 'Blue/Memory/PageFileUsage', 216 'Blue/Memory/WorkingSet'] 217 for each in statNames: 218 s = blue.statistics.Find(each) 219 if s: 220 stats.append(s) 221 222 while self.state == SERVICE_RUNNING: 223 for each in stats: 224 blue.SetCrashKeyValues(each.name, str(each.value)) 225 226 blue.SetCrashKeyValues('Trinity_shader_model', trinity.GetShaderModel()) 227 blue.synchro.SleepWallclock(5000) 228 229 def GetShipAccess(self): 230 if self.shipAccess is not None: 231 shipAccess, locationID, shipID, charID = self.shipAccess 232 if locationID != session.solarsystemid or session.stationid: 233 self.shipAccess = None 234 elif shipID != session.shipid: 235 self.shipAccess = None 236 elif charID != session.charid: 237 self.shipAccess = None 238 if self.shipAccess is None: 239 self.shipAccess = [moniker.GetShipAccess(), 240 session.solarsystemid or session.stationid, 241 session.shipid, 242 session.charid] 243 return self.shipAccess[0] 244 245 def OnDisconnect(self, reason = 0, msg = ''): 246 if MessageBox.is_disconnect_dialog_open(): 247 return 248 disconnectNotice = DisconnectNotice(logProvider=self) 249 disconnectNotice.OnDisconnect(reason, msg) 250 251 @staticmethod 252 def OnConnectionRefused(): 253 sm.GetService('loading').CleanUp() 254 255 def OnServerMessage(self, msg): 256 uthread.new(self.OnServerMessage_thread, msg).context = 'gameui.ServerMessage' 257 258 @staticmethod 259 def OnServerMessage_thread(msg): 260 if isinstance(msg, tuple) and len(msg) == 2: 261 label, kwargs = msg 262 msg = localization.GetByLabel(label, **kwargs) 263 prompt_player_fsd_dialog('ServerMessage', {'msg': msg}) 264 265 def OnClusterShutdownInitiated(self, explanationLabel, when, duration): 266 self.shutdownTime = when 267 268 def OnJumpQueueMessage(self, msg, ready): 269 message_player(msg) 270 271 def OnClusterShutdownCancelled(self, explanationLabel): 272 self.shutdownTime = None 273 274 def __ShutdownTimer(self): 275 while self.state == SERVICE_RUNNING: 276 try: 277 if self.shutdownTime and self.shutdownTime - blue.os.GetWallclockTime() < 5 * const.MIN: 278 timeLeft = max(0, self.shutdownTime - blue.os.GetWallclockTime()) 279 message_player(localization.GetByLabel('UI/Shared/ClusterShutdownInSeconds', timeLeft=timeLeft)) 280 except Exception: 281 log.LogException() 282 sys.exc_clear() 283 284 blue.pyos.synchro.SleepWallclock(5000) 285 286 def __SessionTimeoutTimer(self): 287 while self.state == SERVICE_RUNNING: 288 try: 289 if session.maxSessionTime and session.maxSessionTime - blue.os.GetWallclockTime() < 15 * const.MIN: 290 message_player(localization.GetByLabel('UI/Shared/MaxSessionTimeExpiring', timeLeft=session.maxSessionTime - blue.os.GetWallclockTime())) 291 except Exception: 292 log.LogException() 293 sys.exc_clear() 294 295 blue.pyos.synchro.SleepWallclock(5000) 296 297 def _start_afk_monitor(self): 298 uicore.uilib.RegisterForTriuiEvents([uiconst.UI_MOUSEDOWN, 299 uiconst.UI_MOUSEUP, 300 uiconst.UI_MOUSEWHEEL, 301 uiconst.UI_KEYDOWN], self._handle_global_ui_event) 302 uthread.worker('gameui._afk_timer_loop', self._afk_timer_loop) 303 304 def _handle_global_ui_event(self, *args, **kwargs): 305 self._last_ui_interaction_timestamp = gametime.now() 306 return self.state == SERVICE_RUNNING 307 308 def _afk_timer_loop(self): 309 last_observed_active_timestamp = self._last_ui_interaction_timestamp 310 while self.state == SERVICE_RUNNING: 311 blue.pyos.synchro.SleepWallclock(1000) 312 try: 313 if session.charid is None: 314 continue 315 if self._last_ui_interaction_timestamp is None: 316 continue 317 dt_since_active = gametime.now() - self._last_ui_interaction_timestamp 318 if not self._is_afk and dt_since_active > AFK_THRESHOLD: 319 self._is_afk = True 320 self.LogNotice('I am now AFK after being idle for {dt} seconds.'.format(dt=dt_since_active.total_seconds())) 321 self.ui_messenger.idle_threshold_reached(AFK_THRESHOLD) 322 sm.RemoteSvc('charMgr').SetActivityStatus(status=appConst.PLAYER_STATUS_AFK, extraInfo=datetimeutils.datetime_to_filetime(self._last_ui_interaction_timestamp)) 323 elif self._is_afk and dt_since_active < AFK_THRESHOLD: 324 self._is_afk = False 325 self.LogNotice('I am no longer AFK after being idle for {dt} seconds.'.format(dt=(gametime.now() - last_observed_active_timestamp).total_seconds())) 326 self.ui_messenger.activity_resumed() 327 sm.RemoteSvc('charMgr').SetActivityStatus(status=appConst.PLAYER_STATUS_ACTIVE, extraInfo=datetimeutils.datetime_to_filetime(last_observed_active_timestamp)) 328 last_observed_active_timestamp = self._last_ui_interaction_timestamp 329 except Exception: 330 log.LogException() 331 sys.exc_clear() 332 333 @staticmethod 334 def OnRemoteMessage(msgID, dict = None, kw = None): 335 if kw is None: 336 kw = {} 337 remoteNotifyMessages = ('SelfDestructInitiatedOther', 'SelfDestructImmediateOther', 'SelfDestructAbortedOther2') 338 if msgID in remoteNotifyMessages and not settings.user.ui.Get('notifyMessagesEnabled', 1): 339 return 340 uthread.new(prompt_player_fsd_dialog, msgID, dict, **kw).context = 'gameui.ServerMessage' 341 342 @staticmethod 343 def TransitionCleanup(change): 344 ClearMenuLayer() 345 uicore.layer.utilmenu.Flush() 346 for each in uicore.registry.GetWindows()[:]: 347 if each.name.startswith('infowindow') and 'shipid' in change and each.sr.itemID in change['shipid']: 348 each.Close() 349 350 def ClearCacheFiles(self): 351 if prompt_player_fsd_dialog('AskClearCacheReboot', {}, uiconst.YESNO) == uiconst.ID_YES: 352 prefs.clearcache = 1 353 appUtils.Reboot('clear cache') 354 355 def ClearSettings(self): 356 if prompt_player_fsd_dialog('AskClearSettingsReboot', {}, uiconst.YESNO) == uiconst.ID_YES: 357 prefs.resetsettings = 1 358 appUtils.Reboot('clear settings') 359 360 @telemetry.ZONE_METHOD 361 def ProcessSessionChange(self, isRemote, session, change, cheat = 0): 362 self.settings.SaveSettings() 363 self.LogInfo('ProcessSessionChange: ', change, ',', session) 364 365 def DoSessionChanging(self, isRemote, session, change): 366 wasPodded, movedToStructure, movedToStation = self._ParseStateChange(change) 367 if wasPodded: 368 view = ViewState.Hangar 369 viewState = sm.GetService('viewState') 370 viewState.SetTransitionReason(viewState.GetCurrentViewInfo().name, view, 'clone') 371 self.TransitionCleanup(change) 372 if 'charid' in change and change['charid'][0] or 'userid' in change and change['userid'][0]: 373 self.shipAccess = None 374 375 def _ParseStateChange(self, change): 376 movedFromDestroyedPod = 'shipid' in change and self.podKillPodID and self.podKillPodID == change['shipid'][0] 377 movedToStation = 'stationid' in change and change['stationid'][1] is not None 378 movedToStructure = 'structureid' in change and change['structureid'][1] is not None 379 wasPodded = movedFromDestroyedPod and (movedToStation or movedToStructure) 380 return (wasPodded, movedToStructure, movedToStation) 381 382 @staticmethod 383 def OnSetDevice(*args): 384 uicore.layer.utilmenu.Flush() 385 386 @staticmethod 387 def OnViewStateChanged(oldView, newView): 388 uicore.layer.utilmenu.Flush() 389 if oldView == ViewState.CharacterSelector: 390 newFeatureNotify.CheckOpenNewFeatureNotifyWindow() 391 if oldView == ViewState.CharacterSelector or oldView == ViewState.CharacterCreation and newView == ViewState.Hangar: 392 sm.GetService('activities').CheckIfLoginOpenWindowEnabled() 393 if newView == ViewState.CharacterSelector: 394 sm.GetService('activities').AfterLogout() 395 396 @staticmethod 397 def AnythingImportantInChange(change): 398 ignoreKeys = ('fleetid', 'wingid', 'squadid', 'fleetrole', 'languageID') 399 ck = change.keys() 400 for k in ignoreKeys: 401 try: 402 ck.remove(k) 403 except ValueError: 404 pass 405 406 return bool(ck) 407 408 @telemetry.ZONE_METHOD 409 def OnSessionChanged(self, isRemote, session, change): 410 if not self.AnythingImportantInChange(change): 411 return 412 relevantSessionAttributes = ('userid', 'charid', 'solarsystemid', 'stationid', 'structureid', 'shipid') 413 changeIsRelevant = False 414 for attribute in relevantSessionAttributes: 415 if attribute in change: 416 changeIsRelevant = True 417 break 418 419 if not changeIsRelevant: 420 return 421 if 'userid' in change: 422 sm.GetService('tactical') 423 get_clone_grade_svc().prime_clone_state_with_grace_period() 424 uicore.mouseInputHandler = MouseInputHandler() 425 if 'charid' in change: 426 self.OnCharacterSelected() 427 self._upsell_neocom_controller.update_neocom_button() 428 if 'userid' in change or 'charid' in change: 429 self.settings.LoadSettings() 430 gfx = gfxsettings.GraphicsSettings.GetGlobal() 431 gfx.InitializeSettingsGroup(gfxsettings.SETTINGS_GROUP_UI, settings.user.ui) 432 self.device.ApplyTrinityUserSettings() 433 if 'shipid' in change and session.sessionChangeReason == 'selfdestruct': 434 session.sessionChangeReason = 'board' 435 if session.charid is None: 436 self._HandleUserLogonSessionChange(isRemote, session, change, self.viewState) 437 elif session.stationid is not None: 438 self._HandleSessionChangeInStation(isRemote, session, change, self.viewState) 439 elif session.structureid is not None: 440 self._HandleSessionChangeInStructure(isRemote, session, change, self.viewState) 441 elif session.solarsystemid is not None: 442 self._HandleSessionChangeInSpace(isRemote, session, change, self.viewState) 443 else: 444 self.LogWarn('GameUI::OnSessionChanged, Lame Teardown of the client, it should get propper OnDisconnect event', isRemote, session, change) 445 446 def DoCharacterLogoff(self): 447 sm.GetService('cc').on_character_log_off() 448 sm.GetService('jumpQueue').PrepareQueueForCharID(None) 449 self.LogInfo('ChainEvent ProcessSessionReset with current session', session) 450 sm.ChainEvent('ProcessSessionReset') 451 self.LogInfo('Closing game windows') 452 sessionChangeWindowOpener.CloseOutOfScopeWindows(uiconst.SCOPE_NONE) 453 viewStateSvc = sm.GetService('viewState') 454 viewStateSvc.CloseSecondaryView() 455 self.LogInfo('ScatterEvent OnSessionReset with current session', session) 456 sm.ScatterEvent('OnSessionReset') 457 ReleaseOperationsController() 458 ReleaseTutorialOperationsController() 459 self.LogInfo('Switching to character selection', session) 460 viewStateSvc.ActivateView('charsel') 461 trinity.app.title = GetWindowName() 462 self.LogNotice('Character logoff complete') 463 464 def LogOffCharacter(self): 465 self.LogNotice('Logging out character %s' % cfg.eveowners.Get(session.charid).name) 466 with ExceptionEater('Failed to persist tasks'): 467 tasksUpdated = sm.GetService('monolithTaskTrackerSvc').CheckAchievementStatus() 468 if not tasksUpdated: 469 sm.GetService('monolithTaskTrackerSvc').UpdateClientAchievementsAndCountersOnServer() 470 if sm.GetService('sessionMgr').PerformSessionChange('logoff', sm.RemoteSvc('userSvc').UserLogOffCharacter): 471 return self.DoCharacterLogoff() 472 self.LogNotice('Character logoff denied') 473 474 def OnCharacterSelected(self): 475 sm.ScatterEvent('OnCharacterSelected') 476 self.DoWindowIdentification() 477 478 @staticmethod 479 def _CheckSessionLanguage(userSession): 480 prefsLang = langutils.any_to_comfy_language(prefs.GetValue('languageID', None)) 481 sessionLang = langutils.any_to_comfy_language(userSession.languageID) 482 if prefsLang != sessionLang: 483 userSession.__dict__['languageID'] = prefsLang.mls_language_id() 484 485 def AlertAntiAddictionDialogBoxAndQuit(self, message): 486 if prompt_player_fsd_dialog(message, {}, uiconst.OK) in (uiconst.ID_OK, uiconst.ID_CLOSE, uiconst.ID_CANCEL): 487 uicore.cmd.DoQuitGame() 488 489 def CheckAntiAddiction(self): 490 if not localization.util.AmOnChineseServer(): 491 return 492 kiringApiGateway = get_kiring_api_gateway() 493 code = kiringApiGateway.check_anti_addiction() 494 log.LogInfo('anti-addiction login check code: %s' % code) 495 if code == ANTI_ADDICTION_CHECK_FAIL_JUVENILES_BLOCK_AFTER_22_AND_BEFORE_8: 496 self.AlertAntiAddictionDialogBoxAndQuit('AntiAddictionLoginTimeBlock') 497 elif code == ANTI_ADDICTION_CHECK_FAIL_JUVENILES_PLAY_TIME_OVERFLOW: 498 self.AlertAntiAddictionDialogBoxAndQuit('AntiAddictionLoginBlock') 499 elif code == ANTI_ADDICTION_CHECK_FAIL_JUVENILES_PLAY_TIME_OVERFLOW_HOLIDAY: 500 self.AlertAntiAddictionDialogBoxAndQuit('AntiAddictionLoginBlockHoliday') 501 502 def _HandleUserLogonSessionChange(self, isRemote, session, change, viewSvc): 503 self._CheckSessionLanguage(session) 504 self.regionalUiManager.on_login(session) 505 self.CheckAntiAddiction() 506 self.LogNotice('GameUI::OnSessionChanged, Heading for character selection', isRemote, session, change) 507 self.regionalUiManager.on_splash_screen(session) 508 characters = sm.GetService('cc').GetCharactersToSelect(False) 509 if characters: 510 uthread.pool('GameUI::ActivateView::charsel', viewSvc.ActivateView, 'charsel') 511 else: 512 uthread.pool('GameUI::GoCharacterCreation', self.GoCharacterCreation) 513 514 def _GetStationView(self): 515 view = settings.user.ui.Get('defaultDockingView', ViewState.Hangar) 516 if view == 'station': 517 view = ViewState.Hangar 518 return view 519 520 def _GetStructureView(self): 521 return settings.user.ui.Get('defaultStructureView', ViewState.Hangar) 522 523 def _GetActivateViewFunction(self, viewSvc): 524 if viewSvc.IsViewActive('charactercreation'): 525 activateViewFunc = viewSvc.ActivateView 526 else: 527 activateViewFunc = viewSvc.ChangePrimaryView 528 return activateViewFunc 529 530 def _HandleSessionChangeInStation(self, isRemote, session, change, viewSvc): 531 if 'stationid' in change: 532 self.LogNotice('GameUI::OnSessionChanged, Heading for station', isRemote, session, change) 533 activateViewFunc = self._GetActivateViewFunction(viewSvc) 534 view = self._GetStationView() 535 uthread.pool('GameUI::ActivateView::station', activateViewFunc, view, change=change) 536 537 def _HandleSessionChangeInStructure(self, isRemote, session, change, viewSvc): 538 if not ('shipid' in change or 'structureid' in change): 539 return 540 structureView = None 541 wasPodded, movedToStructure, _ = self._ParseStateChange(change) 542 if movedToStructure: 543 if 'shipid' in change and session.shipid == session.structureid: 544 uicore.layer.shipui.CloseView(recreate=False) 545 structureView = ViewState.Space 546 elif wasPodded: 547 structureView = ViewState.Hangar 548 settings.user.ui.Set('defaultStructureView', structureView) 549 else: 550 structureView = self._GetStructureView() 551 elif 'shipid' in change and session.structureid: 552 if session.shipid == session.structureid: 553 structureView = ViewState.Space 554 elif not self.viewState.IsViewActive('structure', 'hangar'): 555 structureView = self._GetStructureView() 556 ballpark = sm.GetService('michelle').GetBallpark() 557 if ballpark and session.structureid in ballpark.balls: 558 ballpark.ego = session.structureid 559 self.wannaBeEgo = -1 560 self.OnNewState(ballpark) 561 else: 562 self.LogNotice('_HandleSessionChangeInStructure: Postponing ego assignment to', session.structureid, 'until ballpark is ready') 563 self.wannaBeEgo = session.structureid 564 if structureView: 565 uthread.pool('GameUI::ActivateView::structure', self._GetActivateViewFunction(viewSvc), structureView, change=change) 566 567 def _HandleSessionChangeInSpace(self, isRemote, session, change, viewSvc): 568 bp = sm.GetService('michelle').GetBallpark() 569 if 'solarsystemid' in change: 570 oldSolarSystemID, newSolarSystemID = change['solarsystemid'] 571 if oldSolarSystemID: 572 sm.GetService('FxSequencer').ClearAll() 573 self.LogInfo('Cleared effects') 574 if bp and session.shipid in bp.balls: 575 self.LogNotice('GameUI::OnSessionChanged, Heading for inflight with a valid ego', isRemote, session, change) 576 bp.ego = session.shipid 577 self.wannaBeEgo = -1 578 else: 579 self.LogNotice('GameUI::OnSessionChanged:%s - Activating space view without a ego ball properly inserted into a proper ballpark.' % (change,)) 580 self.wannaBeEgo = session.shipid 581 uthread.pool('GameUI::ChangePrimaryView::inflight', self._GetActivateViewFunction(viewSvc), 'inflight', change=change) 582 else: 583 if 'shipid' in change and change['shipid'][1] is not None and bp is not None: 584 uthread.new(sm.GetService('target').ClearTargets) 585 if session.shipid in bp.balls: 586 self.LogNotice('Changing ego:', bp.ego, '->', session.shipid) 587 bp.ego = session.shipid 588 self.wannaBeEgo = -1 589 self.OnNewState(bp) 590 else: 591 self.LogNotice('Postponing ego:', bp.ego, '->', session.shipid) 592 self.wannaBeEgo = session.shipid 593 if 'structureid' in change: 594 self.LogNotice('GameUI::OnSessionChanged, Heading for inflight', isRemote, session, change) 595 uthread.pool('GameUI::ChangePrimaryView::inflight', self._GetActivateViewFunction(viewSvc), 'inflight', change=change) 596 if bp and session.shipid in bp.balls: 597 bp.ego = session.shipid 598 self.wannaBeEgo = -1 599 self.OnNewState(bp) 600 else: 601 self.wannaBeEgo = session.shipid 602 if 'shipid' in change and 'structureid' in change: 603 uicore.layer.shipui.CloseView(recreate=False) 604 605 def StartupUI(self, *args): 606 uthread.new(_ScheduleBackgroundDownloads) 607 self.usingSingleSignOn = False 608 uicore.SetAudioHandler(sm.StartService('audio')) 609 uicore.Startup(self.uiLayerList) 610 desktopIndex = uicore.desktop.children.index(uicore.layer.hint) 611 self.resourceLoadingIndicator = ResourceLoadingIndicator(parent=uicore.desktop, align=DEFAULT_RESOURCE_LOADING_WHEEL_ALIGN, width=DEFAULT_RESOURCE_LOADING_WHEEL_SIZE, height=DEFAULT_RESOURCE_LOADING_WHEEL_SIZE, left=DEFAULT_RESOURCE_LOADING_WHEEL_LEFT, top=DEFAULT_RESOURCE_LOADING_WHEEL_TOP, isGlobal=True, idx=desktopIndex) 612 uicore.SetCommandHandler(sm.StartService('cmd')) 613 import eve.client.script.ui.control.tooltips as tooltipHandler 614 uicore.SetTooltipHandler(tooltipHandler) 615 logmodule.SetUiMessageFunc(prompt_player_fsd_dialog) 616 SetupViewStates(self.viewState, uicore.layer.viewstate) 617 sm.GetService('device').SetupUIScaling() 618 sceneManager = sm.StartService('sceneManager') 619 sceneManager.SetSceneType(SCENE_TYPE_SPACE) 620 sceneManager.Initialize(trinity.EveSpaceScene()) 621 self.RegisterBlueResources() 622 self._initialize_services() 623 self._register_handlers() 624 uicore.megaMenuManager = MegaMenuManager() 625 token = None 626 for arg in blue.pyos.GetArg()[1:]: 627 if arg.startswith('/ssoToken'): 628 try: 629 argName, token = arg.split('=') 630 except: 631 raise RuntimeError('Invalid format of SSO token, should be /ssoToken=<token>') 632 633 if token is not None: 634 self.usingSingleSignOn = True 635 self.DoLogin(token) 636 else: 637 self.viewState.ActivateView('login') 638 self._start_afk_monitor() 639 640 def _register_handlers(self): 641 player_messaging.client.register_message_player_handler(QuickMessage) 642 player_messaging.client.register_prompt_player_handler(messagebox.MessageBox) 643 player_messaging.client.register_prompt_player_fsd_dialogs_handler(dialog_handler) 644 645 def _initialize_services(self): 646 sm.StartService('connection') 647 sm.StartService('logger') 648 sm.StartService('ownerprimer') 649 sm.StartService('petition') 650 sm.StartService('ui') 651 sm.StartService('window') 652 sm.StartService('log') 653 sm.StartService('consider') 654 sm.StartService('incursion') 655 sm.StartService('moonScan') 656 sm.StartService('preview') 657 sm.StartService('crimewatchSvc') 658 sm.StartService('flightControls') 659 sm.StartService('flightPredictionSvc') 660 sm.StartService('sensorSuite') 661 sm.StartService('hackingUI') 662 sm.StartService('radialmenu') 663 sm.StartService('tourneyUISvc') 664 sm.StartService('monolithTaskTrackerSvc') 665 sm.StartService('contextualOfferSvc') 666 sm.StartService('tacticalNavigation') 667 sm.StartService('subway') 668 sm.StartService('paperDollClient') 669 achievement_system_repository.initialize_repository(self.publicGatewaySvc, sm) 670 character_titles_repository.initialize_repository(self.publicGatewaySvc, sm) 671 from content.client.definitions import CONTENT_DEFINITIONS 672 initialize_content_registry(CONTENT_DEFINITIONS, public_gateway=self.publicGatewaySvc) 673 initialize_freelance_project_repository(self.publicGatewaySvc, ShouldMockFreelanceProjectSetting(), ShouldMockContributionMethodsSetting(), sm, session) 674 community_tracks_repository_api.initialize_repository(self.publicGatewaySvc, ShouldMockCommunityTracksSetting()) 675 plex_repository.initialize_repository(self.publicGatewaySvc) 676 setup_singleton(self.publicGatewaySvc, GetVolume, get_cargo_volume_available, extract_infomorphs_to_ship, ShouldMockSetting()) 677 initialize_aura_guidance_repository(self.publicGatewaySvc) 678 initialize_campaigns_repository_v1(self.publicGatewaySvc, sm, message_player) 679 initialize_campaigns_repository_v2(self.publicGatewaySvc, sm, message_player) 680 681 def RegisterBlueResources(self): 682 from carbon.client.script.graphics.resourceConstructors.gradients import Gradient, GradientRadial, Gradient2D 683 blue.resMan.RegisterResourceConstructor('gradient', Gradient) 684 blue.resMan.RegisterResourceConstructor('gradient_radial', GradientRadial) 685 blue.resMan.RegisterResourceConstructor('gradient2d', Gradient2D) 686 687 def _IsResourceLoadingIndicatorAvailable(self): 688 return self.resourceLoadingIndicator and not self.resourceLoadingIndicator.destroyed 689 690 def EnableResourceLoadingIndicator(self): 691 if self._IsResourceLoadingIndicatorAvailable(): 692 self.resourceLoadingIndicator.Enable() 693 694 def DisableResourceLoadingIndicator(self): 695 if self._IsResourceLoadingIndicatorAvailable(): 696 self.resourceLoadingIndicator.Disable() 697 698 def MoveResourceLoadingIndicator(self, newAlignment, newLeft, newTop): 699 if self._IsResourceLoadingIndicatorAvailable(): 700 self.resourceLoadingIndicator.align = newAlignment 701 self.resourceLoadingIndicator.left = newLeft 702 self.resourceLoadingIndicator.top = newTop 703 704 def ResetResourceLoadingIndicatorPosition(self): 705 self.MoveResourceLoadingIndicator(newAlignment=DEFAULT_RESOURCE_LOADING_WHEEL_ALIGN, newLeft=DEFAULT_RESOURCE_LOADING_WHEEL_LEFT, newTop=DEFAULT_RESOURCE_LOADING_WHEEL_TOP) 706 707 def DoLogin(self, token): 708 sm.ScatterEvent('OnClientReady', 'login') 709 try: 710 sm.GetService('connection').LoginSso(token) 711 except: 712 sm.GetService('loading').CleanUp() 713 self.viewState.ActivateView('login') 714 raise 715 716 def SetLanguage(self, key, doReload = False): 717 is_cool = bool(session.role & ROLEMASK_ELEVATEDPLAYER) 718 if is_cool: 719 comfylang = langutils.any_to_comfy_language(key) 720 else: 721 comfylang = langutils.client_valid_or_default(key) 722 if comfylang != prefs.GetValue('languageID', None): 723 if session.userid is not None: 724 sm.RemoteSvc('authentication').SetLanguageID(comfylang.mls_language_id()) 725 session.__dict__['languageID'] = comfylang.mls_language_id() 726 prefs.languageID = comfylang.mls_language_id() 727 blue.os.languageID = comfylang.mls_language_id() 728 if doReload: 729 localization.LoadLanguageData() 730 setting = get_default_font_size_setting(comfylang.mls_language_id()) 731 if setting > get_font_size_setting(): 732 set_font_size_setting(setting) 733 sm.ChainEvent('ProcessUIRefresh') 734 sm.ScatterEvent('OnUIRefresh') 735 sm.ScatterEvent('OnLanguageChanged', comfylang.code) 736 737 def GoCharacterCreationCurrentCharacter(self, *args): 738 if None in (session.charid, session.genderID, session.bloodlineID): 739 return 740 if self.viewState.IsViewActive('charactercreation'): 741 return 742 if sm.GetService('undocking').IsExiting(): 743 return 744 stationSvc = sm.GetService('station') 745 dollState = stationSvc.GetPaperdollStateCache() 746 msg = None 747 if dollState == paperdoll.State.resculpting: 748 msg = 'AskRecustomizeCharacter' 749 elif dollState == paperdoll.State.full_recustomizing: 750 msg = 'AskRecustomizeCharacterChangeBloodline' 751 message = uiconst.ID_NO 752 if msg is not None: 753 message = prompt_player_fsd_dialog(msg, {'charName': cfg.eveowners.Get(session.charid).ownerName}, uiconst.YESNO, default=uiconst.ID_NO, suppress=uiconst.ID_NO) 754 if message == uiconst.ID_YES: 755 self.GoCharacterCreation(session.charid, session.genderID, session.raceID, session.bloodlineID, dollState=dollState) 756 stationSvc.ClearPaperdollStateCache() 757 elif message == uiconst.ID_NO: 758 self.GoCharacterCreation(session.charid, session.genderID, session.raceID, session.bloodlineID, dollState=paperdoll.State.no_recustomization) 759 760 def GoCharacterCreation(self, charID = None, gender = None, raceID = None, bloodlineID = None, dollState = None, *args): 761 if sm.GetService('undocking').IsExiting(): 762 return 763 everesourceprefetch.PullToFront('ui_cc') 764 self.viewState.ActivateView('charactercreation', charID=charID, gender=gender, raceID=raceID, bloodlineID=bloodlineID, dollState=dollState) 765 766 def RadioButtonMessageBox(self, text, title = 'EVE', buttons = None, icon = None, suppText = None, customicon = None, radioOptions = None, height = None, width = None, blockconfirmonreturn = 0, default = None, modal = True): 767 if radioOptions is None: 768 radioOptions = [] 769 if not getattr(uicore, 'desktop', None): 770 return 771 if MessageBox.is_disconnect_dialog_open(): 772 return (default, False) 773 if buttons is None: 774 buttons = uiconst.ID_OK 775 msgbox = RadioButtonMessageBox(useDefaultPos=True) 776 msgbox.isModal = modal 777 msgbox.blockconfirmonreturn = blockconfirmonreturn 778 msgbox._show_message(text, title, buttons, icon, suppText, customicon, height, radioOptions=radioOptions, width=width, default=default, modal=modal) 779 if modal: 780 buttonResult = msgbox.ShowModal() 781 radioSelection = msgbox.GetRadioSelection() 782 ret = (buttonResult, radioSelection) 783 else: 784 buttonResult = msgbox.ShowDialog() 785 radioSelection = msgbox.GetRadioSelection() 786 ret = (buttonResult, radioSelection) 787 return (ret, msgbox.suppress) 788 789 def DoBallsAdded(self, *args, **kw): 790 import stackless 791 import blue 792 t = stackless.getcurrent() 793 timer = t.PushTimer(blue.pyos.taskletTimer.GetCurrent() + '::gameui') 794 try: 795 return self.DoBallsAdded_(*args, **kw) 796 finally: 797 t.PopTimer(timer) 798 799 def DoBallsAdded_(self, lst): 800 for each in lst: 801 self.DoBallAdd(*each) 802 803 def DoBallAdd(self, ball, slimItem): 804 if ball.id == self.wannaBeEgo: 805 self.LogNotice('Ego-wannabe', self.wannaBeEgo, 'added to park') 806 bp = sm.GetService('michelle').GetBallpark() 807 if bp.ego != self.wannaBeEgo: 808 self.LogNotice('Post-ego change: ', bp.ego, '->', self.wannaBeEgo) 809 bp.ego = self.wannaBeEgo 810 self.OnNewState(bp) 811 self.wannaBeEgo = -1 812 sm.ScatterEvent('OnDoBallAddEgoChange') 813 814 def DoBallClear(self, solItem): 815 if sm.GetService('subway').Enabled() and sm.GetService('subway').InJump(): 816 return 817 uthread.new(self._DoBallClear, solItem) 818 819 def _DoBallClear(self, solItem): 820 spaceToSpaceTransition = self.viewState.GetTransitionByName('inflight', 'inflight') 821 sm.GetService('tactical').TearDownOverlay() 822 sc = self.sceneManager.GetScene() 823 if spaceToSpaceTransition.active: 824 spaceToSpaceTransition.Finalize() 825 else: 826 self.sceneManager.UnregisterScene('default', ignoreCamera=True) 827 self.sceneManager.LoadScene(sc, registerKey='default') 828 self.sceneManager.ApplySpaceScene() 829 EnvironmentManager.GetInstance().RefreshEnvironments() 830 if session.solarsystemid: 831 sm.GetService('tactical').CheckInit() 832 833 def OnNewState(self, bp): 834 uthread.pool('GameUI::New shipui state', self._NewState, bp) 835 836 @telemetry.ZONE_METHOD 837 def _NewState(self, bp): 838 if bp and bp.balls.get(bp.ego, None): 839 if eveCfg.InSpace() and uicore.layer.shipui.isopen: 840 uicore.layer.shipui.SetupShip(False) 841 camera = sm.GetService('sceneManager').GetActiveSpaceCamera() 842 camera.LookAtMaintainDistance(bp.ego) 843 844 def DoWindowIdentification(self): 845 trinity.app.title = GetWindowName(session.charid) 846 847 def UsingSingleSignOn(self): 848 return getattr(self, 'usingSingleSignOn', False) 849 850 def OnCreateNewMailWindow(self, recipients, corpOrAllianceRecipient, toListID, subject, body): 851 sm.GetService('mailSvc').SendMsgDlg(toCharacterIDs=recipients, toCorpOrAllianceID=corpOrAllianceRecipient, toListID=toListID, subject=subject, body=body) 852 853 def OnAntiAddictionOnlineTimeWarning(self, countdownSecond, playedSecond): 854 accruedTime = localization.formatters.FormatTimeIntervalWritten(int(playedSecond) * const.SEC, showFrom='hour', showTo='second') 855 leftTime = localization.formatters.FormatTimeIntervalWritten(int(countdownSecond) * const.SEC, showFrom='hour', showTo='second') 856 prompt_player_fsd_dialog('AntiAddictionOnlineTimeWarning', {'accruedTime': accruedTime, 857 'leftTime': leftTime}) 858 859 def OnAntiAddictionOnlineTimeBlockWarning(self, countdownSecond): 860 leftTime = localization.formatters.FormatTimeIntervalWritten(int(countdownSecond) * const.SEC, showFrom='hour', showTo='second') 861 prompt_player_fsd_dialog('AntiAddictionOnlineTimeBlockWarning', {'leftTime': leftTime}) 862 863 def OnStructureHacked(self, structureID, reinforceTiming): 864 structureInfo = sm.GetService('structureDirectory').GetStructureInfo(structureID) 865 reinforceWeekday, reinforceHour, nextReinforceWeekday, nextReinforceHour, applyAtTime = reinforceTiming 866 reinforceTimers = ReinforcementBundle(reinforceHour=reinforceHour, nextReinforceHour=nextReinforceHour, nextReinforceApply=applyAtTime) 867 wnd = StructureHackingResultWnd.GetIfOpen() 868 if wnd: 869 wnd.LoadWndWithResult(structureID, reinforceTimers, structureTypeID=structureInfo.typeID) 870 wnd.Maximize() 871 else: 872 StructureHackingResultWnd.Open(structureID=structureID, reinforceTimers=reinforceTimers, structureTypeID=structureInfo.typeID) 873 874 def OnPodKilled(self, destroyedPodID): 875 self.podKillPodID = destroyedPodID 876 877 def OnSafeLogoffTimerStarted(self, safeLogoffTime): 878 if self.logoffTimer is not None: 879 self.logoffTimer.Close() 880 if AllowCharacterLogoff(sm.GetService('machoNet')): 881 log.LogNotice('Starting safe logoff countdown for character %s' % cfg.eveowners.Get(session.charid).name) 882 logoffTimerClass = SafeLogoffTimer2 883 else: 884 logoffTimerClass = SafeLogoffTimer 885 self.logoffTimer = logoffTimerClass(parent=uicore.layer.abovemain, logoffTime=safeLogoffTime) 886 self.logoffTimer.left = sm.GetService('window').GetCameraLeftOffset(self.logoffTimer.width, self.logoffTimer.align, self.logoffTimer.left) 887 888 def OnSafeLogoffActivated(self): 889 if self.logoffTimer is not None: 890 self.logoffTimer.SetTimerCompleted() 891 if self.logoffTimer.quitting: 892 prompt_player_fsd_dialog('CustomNotify', {'notify': localization.GetByLabel('UI/Inflight/SafeLogoffDisconnect', {'charid': session.charid})}) 893 sm.GetService('clientStatsSvc').OnProcessExit() 894 if AllowCharacterLogoff(sm.GetService('machoNet')): 895 log.LogNotice('Safe logoff countdown for character %s complete. Exiting client.' % cfg.eveowners.Get(session.charid).name) 896 bluepy.TerminateSilently(0, 'User exit after logoff') 897 else: 898 self.logoffTimer.Close() 899 log.LogNotice('Safe logoff countdown for character %s complete. Returning to character selection screen.' % cfg.eveowners.Get(session.charid).name) 900 sm.GetService('sessionMgr').PerformSessionChange('character logoff', sm.GetService('gameui').DoCharacterLogoff) 901 self.logoffTimer = None 902 903 def OnSafeLogoffAborted(self, reasonCode): 904 self.AbortSafeLogoffTimer() 905 prompt_player_fsd_dialog('CustomNotify', {'notify': localization.GetByLabel(reasonCode)}) 906 907 def OnSafeLogoffFailed(self, failedConditions): 908 self.AbortSafeLogoffTimer() 909 prompt_player_fsd_dialog('CustomNotify', {'notify': '<br>'.join([localization.GetByLabel('UI/Inflight/SafeLogoff/ConditionsFailedHeader')] + [ localization.GetByLabel(error) for error in failedConditions ])}) 910 911 def AbortSafeLogoffTimer(self): 912 if self.logoffTimer is not None: 913 self.logoffTimer.AbortLogoff() 914 self.logoffTimer = None 915 916 917 def _ScheduleBackgroundDownloads(): 918 everesourceprefetch.PrepareFilesets() 919 keys = ['staticdata', 920 'ui_basics', 921 'ui_classes', 922 'black_files', 923 'low_detail_ships', 924 'low_detail_nebulas', 925 'ui_cc'] 926 for each in keys: 927 everesourceprefetch.Schedule(each)