loginII.py (22956B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\client\script\ui\login\loginII.py 2 import sys 3 import blue 4 import carbon.common.script.util.format as fmtutil 5 import evecamera 6 import localization 7 import locks 8 import log 9 import pytelemetry.zoning as telemetry 10 import trinity 11 import types 12 import uthread 13 import utillib 14 from carbon.common.lib.serverInfo import GetServerInfo, GetServerIP, GetServerName, LIVE_SERVER, TEST_SERVER1, TEST_SERVER2, TEST_SERVER3 15 from carbonui import uiconst 16 from carbonui.control.button import Button 17 from carbonui.control.buttonIcon import ButtonIcon 18 from carbonui.control.layer import LayerCore 19 from carbonui.control.singlelineedits.singleLineEditPassword import SingleLineEditPassword 20 from carbonui.control.singlelineedits.singleLineEditText import SingleLineEditText 21 from carbonui.primitives.container import Container 22 from carbonui.primitives.containerAutoSize import ContainerAutoSize 23 from carbonui.primitives.layoutGrid import LayoutGrid 24 from carbonui.primitives.sprite import Sprite 25 from carbonui.uianimations import animations 26 from carbonui.uicore import uicore 27 from eve.client.script.environment import nodemanager 28 from eve.client.script.ui.control import eveLabel 29 from eve.client.script.ui.control.themeColored import FillThemeColored 30 from eve.common.lib import appConst as const 31 from eveexceptions import UserError 32 from eveprefs import prefs, boot 33 from player_messaging.client.ui_message import prompt_player_fsd_dialog 34 35 def GetVersion(): 36 buildno = 'Undefined' 37 try: 38 buildno = '%s.%s' % (boot.keyval['version'].split('=', 1)[1], boot.build) 39 except Exception: 40 log.LogException() 41 42 return buildno 43 44 45 try: 46 if not GetServerInfo().isLive: 47 if prefs.GetValue('nominidump', 0): 48 log.general.Log('Running against a test server. Crash minidump is NOT active because of nominidump=1 in prefs.ini', log.LGNOTICE) 49 else: 50 log.general.Log('Running against a test server. Crash minidump is active. You can disable this with nominidump=1 in prefs.ini', log.LGNOTICE) 51 blue.os.miniDump = True 52 except Exception: 53 log.LogException() 54 55 class Login(LayerCore): 56 __guid__ = 'form.LoginII' 57 __notifyevents__ = ['OnEndChangeDevice', 'OnGraphicSettingsChanged', 'ProcessUIRefresh'] 58 isTopLevelWindow = True 59 60 def OnCloseView(self): 61 if uicore.layer.systemmenu.isopen: 62 uthread.new(uicore.layer.systemmenu.CloseMenu) 63 self.Reset() 64 sm.GetService('sceneManager').SetActiveScene(None) 65 sm.UnregisterNotify(self) 66 del self.scene.curveSets[:] 67 self.scene = None 68 self.ship = None 69 self.Flush() 70 71 def ProcessUIRefresh(self): 72 if self.isopen: 73 if self.reloading: 74 self.pendingReload = 1 75 return 76 currentUsername = self.usernameEditCtrl.GetValue() 77 currentPassword = self.passwordEditCtrl.GetValue() 78 self.reloading = 1 79 self.Layout(False, None, currentUsername, currentPassword) 80 self.reloading = 0 81 if self.pendingReload: 82 self.pendingReload = 0 83 84 def OnEndChangeDevice(self, *args): 85 if self.isopen: 86 if self.reloading: 87 self.pendingReload = 1 88 return 89 currentUsername = self.usernameEditCtrl.GetValue() 90 currentPassword = self.passwordEditCtrl.GetValue() 91 self.reloading = 1 92 self.Layout(1, True, currentUsername, currentPassword) 93 self.reloading = 0 94 if self.pendingReload: 95 self.pendingReload = 0 96 self.OnEndChangeDevice() 97 98 @telemetry.ZONE_METHOD 99 def Reset(self): 100 self.serverStatus = {} 101 self.serverStatusTextControl = None 102 self.serverStatusTextFunc = None 103 self.serverNameTextControl = None 104 self.serverVersionTextControl = None 105 self.mainBrowserParent = None 106 self.mainBrowser = None 107 self.usernameEditCtrl = None 108 self.passwordEditCtrl = None 109 self.connecting = False 110 self.acceptbtns = None 111 self.scrollText = None 112 self.reloading = 0 113 self.pendingReload = 0 114 self.maintabs = None 115 self.isShowingUpdateDialog = False 116 117 @telemetry.ZONE_METHOD 118 def OnOpenView(self, **kwargs): 119 self.Reset() 120 uthread.worker('login::StatusTextWorker', self.__StatusTextWorker) 121 blue.resMan.Wait() 122 self.serverName = utillib.GetServerName() 123 self.serverIP = GetServerIP(self.serverName) 124 self.serverName = GetServerName(self.serverIP) 125 self.serverPort = utillib.GetServerPort() 126 self.firstCheck = True 127 self.isShowingUpdateDialog = False 128 self.Layout() 129 sm.ScatterEvent('OnClientReady', 'login') 130 self.isopen = 1 131 uthread.new(self.UpdateServerStatus) 132 133 def ClickExit(self): 134 uicore.cmd.GetCommandAndExecute('CmdQuitGame') 135 136 @telemetry.ZONE_METHOD 137 def Layout(self, reloading = 0, pushBtnArgs = None, setUsername = None, setPassword = None): 138 if not reloading: 139 self.sceneLoadedEvent = locks.Event('loginScene') 140 uthread.new(self.LoadScene) 141 self.Flush() 142 bar_height = uicore.desktop.height / 6 143 top_bar = Container(name='underlayContainer', parent=self, align=uiconst.TOTOP, height=bar_height) 144 FillThemeColored(bgParent=top_bar, colorType=uiconst.COLORTYPE_UIBASE, opacity=0.5) 145 eveLabel.EveLabelSmall(parent=top_bar, align=uiconst.TOPLEFT, state=uiconst.UI_NORMAL, left=16, top=16, text=localization.GetByLabel('UI/Login/Version', versionNumber=GetVersion())) 146 if trinity.mainWindow.GetWindowState().windowMode != trinity.Tr2WindowMode.WINDOWED: 147 ButtonIcon(parent=top_bar, align=uiconst.TOPRIGHT, state=uiconst.UI_NORMAL, top=16, left=16, texturePath='res:/UI/Texture/Shared/DarkStyle/windowClose.png', hint=localization.GetByLabel('UI/Login/QuitGame'), func=self.ClickExit, args=()) 148 bottom_bar = Container(name='underlayContainer_Bottom', parent=self, align=uiconst.TOBOTTOM, height=bar_height) 149 FillThemeColored(bgParent=bottom_bar, colorType=uiconst.COLORTYPE_UIBASE, opacity=0.5) 150 bottomArea = Container(name='bottomArea', parent=bottom_bar, idx=0) 151 bottomSub = Container(name='bottomSub', parent=bottomArea, align=uiconst.CENTER, idx=0, height=bottom_bar.height, width=800) 152 Button(parent=bottom_bar, align=uiconst.TOPLEFT, top=16, left=16, label=localization.GetByLabel('UI/Login/Settings'), func=self.OpenSettings, args=()) 153 login_container = ContainerAutoSize(parent=bottom_bar, align=uiconst.CENTERTOP, top=16, width=160, alignMode=uiconst.TOTOP) 154 is_sso_login = sm.GetService('gameui').UsingSingleSignOn() 155 if not is_sso_login: 156 selected_username = setUsername or settings.public.ui.Get('username', '') 157 self.usernameEditCtrl = SingleLineEditText(name='username', parent=login_container, align=uiconst.TOTOP, maxLength=64, hintText=localization.GetByLabel('UI/Login/Username'), OnReturn=self.Connect, setvalue=selected_username) 158 self.usernameEditCtrl.SetHistoryVisibility(0) 159 knownUserNames = settings.public.ui.Get('usernames', []) 160 if knownUserNames: 161 self.usernameEditCtrl.LoadCombo(id='usernamecombo', options=[ (name, name) for name in knownUserNames ], callback=self.OnComboChange, setvalue=selected_username, comboIsTabStop=0) 162 self.passwordEditCtrl = SingleLineEditPassword(name='password', parent=login_container, align=uiconst.TOTOP, top=8, maxLength=64, setvalue=setPassword, hintText=localization.GetByLabel('UI/Login/Password'), OnReturn=self.Connect) 163 if trinity.app.IsActive(): 164 if selected_username: 165 uicore.registry.SetFocus(self.passwordEditCtrl) 166 else: 167 uicore.registry.SetFocus(self.usernameEditCtrl) 168 Button(parent=login_container, align=uiconst.TOTOP, top=8 if not is_sso_login else 0, label=localization.GetByLabel('UI/Login/Connect'), func=self.Connect, btn_default=1) 169 status_container = LayoutGrid(parent=login_container, align=uiconst.TOPLEFT, left=login_container.width + 16, columns=1, cellSpacing=(0, 4)) 170 self.serverNameTextControl = eveLabel.EveLabelSmall(parent=status_container, align=uiconst.TOPLEFT, state=uiconst.UI_DISABLED, text=localization.GetByLabel('UI/Login/CheckingStatus')) 171 self.serverStatusTextControl = eveLabel.EveLabelSmall(parent=status_container, align=uiconst.TOPLEFT, state=uiconst.UI_DISABLED) 172 self.serverVersionTextControl = eveLabel.EveLabelSmall(parent=status_container, align=uiconst.TOPLEFT, state=uiconst.UI_DISABLED) 173 if not self.IsChina(): 174 esrbNoticeHeight = 70 175 esrbNoticeWidth = 200 176 allowedSizes = [1.0, 0.9, 0.8] 177 desktopWidth = uicore.desktop.width 178 useHeight = int(esrbNoticeHeight * 0.7) 179 useWidth = int(esrbNoticeWidth * 0.7) 180 for multiplier in allowedSizes: 181 tempWidth = esrbNoticeWidth * multiplier 182 if tempWidth <= desktopWidth * 0.11: 183 useWidth = int(tempWidth) 184 useHeight = int(esrbNoticeHeight * multiplier) 185 break 186 187 cont = Container(name='esrbParent', parent=top_bar, align=uiconst.CENTERLEFT, state=uiconst.UI_NORMAL, left=16, width=useWidth, height=useHeight) 188 sprite = Sprite(name='ESRB', parent=cont, align=uiconst.TOALL, state=uiconst.UI_DISABLED, texturePath='res:/UI/Texture/ESRBnotice.dds', color=(1.0, 1.0, 1.0, 1.0)) 189 sprite.rectWidth = esrbNoticeWidth 190 sprite.rectHeight = esrbNoticeHeight 191 animations.FadeOut(cont, duration=0.5, timeOffset=6.0) 192 193 def OnGraphicSettingsChanged(self, changes): 194 if self.isopen and 'shaderQuality' in changes and getattr(self, 'scene', None): 195 self.CheckHeightMaps() 196 197 @telemetry.ZONE_METHOD 198 def CheckHeightMaps(self): 199 if 'LO' in trinity.GetShaderModel(): 200 heightMapParams = nodemanager.FindNodes(self.scene, 'HeightMap', 'trinity.TriTextureParameter') 201 for param in heightMapParams: 202 param.resourcePath = param.resourcePath.replace('_hi.dds', '_lo.dds') 203 204 else: 205 heightMapParams = nodemanager.FindNodes(self.scene, 'HeightMap', 'trinity.TriTextureParameter') 206 for param in heightMapParams: 207 param.resourcePath = param.resourcePath.replace('_lo.dds', '_hi.dds') 208 209 @telemetry.ZONE_METHOD 210 def LoadScene(self): 211 self.scene = trinity.Load('res:/dx9/scene/login_screen.red') 212 blue.resMan.Wait() 213 self.CheckHeightMaps() 214 stations = self.scene.Find('trinity.EveStation2') 215 for station in stations: 216 station.PlayAnimationEx('NormalLoop', 0, 0, 0.2) 217 218 sceneMan = sm.GetService('sceneManager') 219 sceneMan.SetActiveScene(self.scene) 220 sceneMan.SetPrimaryCamera(evecamera.CAM_LOGIN) 221 self.sceneLoadedEvent.set() 222 blue.pyos.synchro.Yield() 223 224 def OnEsc(self): 225 if uicore.layer.systemmenu.isopen: 226 uthread.new(uicore.layer.systemmenu.CloseMenu) 227 else: 228 uthread.new(uicore.layer.systemmenu.OpenView) 229 230 def OpenSettings(self): 231 if not uicore.layer.systemmenu.isopen: 232 uthread.new(uicore.layer.systemmenu.OpenView) 233 234 def OnComboChange(self, combo, header, value, *args): 235 self.usernameEditCtrl.SetValue(value) 236 self.passwordEditCtrl.SetValue('') 237 uthread.new(uicore.registry.SetFocus, self.passwordEditCtrl) 238 239 @telemetry.ZONE_METHOD 240 def __StatusTextWorker(self): 241 while not session.userid: 242 blue.pyos.synchro.SleepWallclock(750) 243 try: 244 if getattr(self, 'serverStatusTextFunc', None) is not None: 245 if not getattr(self, 'connecting', 0): 246 self.__SetServerStatusText(refreshOnNone=True) 247 except: 248 log.LogException('Exception in status text worker') 249 sys.exc_clear() 250 251 @telemetry.ZONE_METHOD 252 def __SetServerStatusText(self, refreshOnNone = False): 253 if self.serverStatusTextFunc is None: 254 self.ClearServerStatus() 255 return 256 statusText = apply(self.serverStatusTextFunc[0]) 257 if statusText is None: 258 self.ClearServerStatus() 259 if refreshOnNone: 260 uthread.new(self.UpdateServerStatus, False) 261 return 262 serverversion, serverbuild = self.serverStatusTextFunc[1:] 263 self.SetNameText(localization.GetByLabel('UI/Login/ServerStatus/Server', serverName=self.serverName)) 264 label, parameters = statusText 265 self.SetStatusText(localization.GetByLabel('UI/Login/ServerStatus/Status', statusText=localization.GetByLabel(label, **parameters))) 266 if serverversion and serverbuild: 267 if '%.2f' % serverversion != '%.2f' % boot.version or serverbuild > boot.build: 268 self.SetVersionText(localization.GetByLabel('UI/Login/ServerStatus/VersionIncompatible', serverVersion=serverversion, serverBuild=serverbuild)) 269 if label == '/Carbon/MachoNet/ServerStatus/OK': 270 sm.GetService('connection').TryAutomaticLogin() 271 272 def IsChina(self): 273 return boot.region == 'optic' 274 275 def GetIsAutoPatch(self, allowPatch): 276 isAutoPatch = self.serverIP == LIVE_SERVER or self.serverIP in [TEST_SERVER1, TEST_SERVER2, TEST_SERVER3] or prefs.GetValue('forceAutopatch', 0) == 1 277 if not allowPatch: 278 isAutoPatch = False 279 return isAutoPatch 280 281 def IsServerPortValid(self): 282 try: 283 int(self.serverPort) 284 except Exception as e: 285 log.LogError(e) 286 sys.exc_clear() 287 self.SetStatusText(localization.GetByLabel('UI/Login/InvalidPortNumber', port=self.serverPort)) 288 self.serverStatusTextFunc = None 289 return False 290 291 return True 292 293 def UpdateServerStatus(self, allowPatch = True): 294 self.InternalUpdateServerStatus(allowPatch=allowPatch, bootbuild=boot.build, bootversion=boot.version) 295 296 def DisplayOutOfDateMessageAndQuitGame(self, reason = None): 297 self.isShowingUpdateDialog = True 298 prompt_player_fsd_dialog('LoginUpdateAvailable', {'info': 'Client is out of date'}) 299 uicore.cmd.DoQuitGame() 300 301 def CompareVersionsAndAct(self, bootbuild, bootversion, isAutoPatch, serverbuild, serverversion, statusMessage): 302 if statusMessage is not None and 'Incompatible' in statusMessage[0] or '%.2f' % serverversion != '%.2f' % bootversion or serverbuild > bootbuild: 303 if serverbuild > bootbuild and isAutoPatch: 304 self.DisplayOutOfDateMessageAndQuitGame('OutOfDate') 305 306 def GetActualStatusMessage(self, serverbuild, serverversion, statusMessage): 307 self.serverStatusTextFunc = None 308 if type(statusMessage) in (types.LambdaType, types.FunctionType, types.MethodType): 309 self.serverStatusTextFunc = (statusMessage, serverversion, serverbuild) 310 else: 311 self.serverStatusTextFunc = (lambda : statusMessage, serverversion, serverbuild) 312 self.__SetServerStatusText() 313 resolvedStatusMessage = apply(self.serverStatusTextFunc[0]) 314 messagePart = resolvedStatusMessage[0] 315 return messagePart 316 317 @telemetry.ZONE_METHOD 318 def InternalUpdateServerStatus(self, allowPatch, bootbuild, bootversion): 319 self.SetStatusText(localization.GetByLabel('UI/Login/CheckingStatus')) 320 self.serverStatusTextFunc = None 321 blue.pyos.synchro.Yield() 322 if self.isShowingUpdateDialog: 323 return 324 if not self.IsServerPortValid(): 325 return 326 serverversion = serverbuild = servercodename = None 327 isAutoPatch = self.GetIsAutoPatch(allowPatch) 328 try: 329 log.LogInfo('checking status of %s' % self.serverIP) 330 try: 331 if self.firstCheck: 332 forceQueueCheck = True 333 self.firstCheck = False 334 else: 335 forceQueueCheck = False 336 statusMessage, serverStatus = sm.GetService('machoNet').GetServerStatus('%s:%s' % (self.serverIP, self.serverPort), forceQueueCheck=forceQueueCheck) 337 except UserError as e: 338 if e.msg == 'AlreadyConnecting': 339 sys.exc_clear() 340 return 341 raise 342 343 if not self.isopen: 344 return 345 self.serverStatus[self.serverIP] = (serverStatus.get('boot_version', None), 346 serverStatus.get('boot_build', None), 347 str(serverStatus.get('boot_codename', const.responseUnknown)), 348 serverStatus.get('update_info', const.responseUnknown)) 349 serverversion, serverbuild, servercodename, updateinfo = self.serverStatus[self.serverIP] 350 actualStatusMsg = self.GetActualStatusMessage(serverbuild, serverversion, statusMessage) 351 if serverversion and serverbuild: 352 self.CompareVersionsAndAct(bootbuild, bootversion, isAutoPatch, serverbuild, serverversion, actualStatusMsg) 353 elif actualStatusMsg is not None and 'IncompatibleProtocol' in actualStatusMsg: 354 self.DisplayOutOfDateMessageAndQuitGame('Incompatable protocol') 355 else: 356 raise Exception('Invalid answer from server GetServerStatus') 357 except Exception as e: 358 log.LogException(e) 359 sys.exc_clear() 360 self.SetStatusText(localization.GetByLabel('UI/Login/UnableToConnect', IP=self.serverIP, port=self.serverPort)) 361 self.serverStatusTextFunc = None 362 363 def SetNameText(self, text): 364 if self.serverNameTextControl and not self.serverNameTextControl.destroyed: 365 self.serverNameTextControl.text = text 366 367 def SetStatusText(self, text): 368 if self.serverStatusTextControl and not self.serverStatusTextControl.destroyed: 369 self.serverStatusTextControl.text = text 370 371 def SetVersionText(self, text): 372 if self.serverVersionTextControl and not self.serverVersionTextControl.destroyed: 373 self.serverVersionTextControl.text = text 374 375 def ClearServerStatus(self, *args): 376 self.SetStatusText('') 377 self.serverStatusTextFunc = None 378 return True 379 380 def Connect(self, *args): 381 uthread.new(self._Connect) 382 383 @telemetry.ZONE_METHOD 384 def _Connect(self): 385 if self.connecting: 386 return 387 self.connecting = True 388 giveFocus = None 389 try: 390 if sm.GetService('gameui').UsingSingleSignOn(): 391 for arg in blue.pyos.GetArg()[1:]: 392 if arg.startswith('/ssoToken'): 393 try: 394 argName, token = arg.split('=') 395 except: 396 raise RuntimeError('Invalid format of SSO token, should be /ssoToken=<token>') 397 398 sm.GetService('gameui').DoLogin(token) 399 return 400 user = self.usernameEditCtrl.GetValue() 401 password = fmtutil.PasswordString(self.passwordEditCtrl.GetValue(raw=1)) 402 giveFocus = None 403 if user is None or len(user) == 0: 404 giveFocus = 'username' 405 if password is None or len(password) == 0: 406 giveFocus = 'password' if giveFocus is None else giveFocus 407 if giveFocus is not None: 408 prompt_player_fsd_dialog('LoginAuthFailed') 409 self.CancelLogin() 410 self.SetFocus(giveFocus) 411 return 412 log.LogInfo('server: %s selected' % self.serverIP) 413 blue.pyos.synchro.Yield() 414 if self.serverPort == sm.StartService('machoNet').defaultProxyPortOffset: 415 if self.serverIP not in self.serverStatus: 416 self.UpdateServerStatus() 417 try: 418 serverversion, serverbuild, servercodename, updateinfo = self.serverStatus[self.serverIP] 419 if serverbuild > boot.build: 420 if self.serverIP == LIVE_SERVER: 421 response = prompt_player_fsd_dialog('PatchLiveServerConnectWrongVersion', {'serverVersion': serverbuild, 422 'clientVersion': boot.build}, uiconst.YESNO) 423 if response == uiconst.ID_YES: 424 self.UpdateServerStatus() 425 else: 426 prompt_player_fsd_dialog('PatchTestServerWarning', {'serverVersion': serverbuild, 427 'clientVersion': boot.build}) 428 self.CancelLogin() 429 return 430 except: 431 log.LogInfo('No serverStatus found for server %s' % self.serverIP) 432 sys.exc_clear() 433 prompt_player_fsd_dialog('UnableToConnectToServer') 434 self.CancelLogin() 435 return 436 437 sm.GetService('loading').ProgressWnd(localization.GetByLabel('UI/Login/LoggingIn'), localization.GetByLabel('UI/Login/ConnectingToCluster'), 1, 100) 438 blue.pyos.synchro.Yield() 439 prompt_player_fsd_dialog('OnConnecting') 440 blue.pyos.synchro.Yield() 441 prompt_player_fsd_dialog('OnConnecting2') 442 blue.pyos.synchro.Yield() 443 try: 444 sm.GetService('connection').Login([user, 445 password, 446 self.serverIP, 447 self.serverPort, 448 0]) 449 except Exception: 450 self.CancelLogin() 451 raise 452 453 settings.public.ui.Set('username', user or '-') 454 prefs.newbie = 0 455 knownUserNames = settings.public.ui.Get('usernames', [])[:] 456 if user and user not in knownUserNames: 457 knownUserNames.append(user) 458 settings.public.ui.Set('usernames', knownUserNames) 459 except UserError as e: 460 if e.msg.startswith('LoginAuthFailed'): 461 giveFocus = 'password' 462 prompt_player_fsd_dialog(e.msg, e.dict) 463 self.CancelLogin() 464 self.SetFocus(giveFocus) 465 finally: 466 if not self.destroyed: 467 self.connecting = 0 468 469 def CancelLogin(self): 470 sm.GetService('loading').CleanUp() 471 472 def SetFocus(self, where = None): 473 if where is None: 474 return 475 if where == 'username': 476 uicore.registry.SetFocus(self.usernameEditCtrl) 477 elif where == 'password': 478 self.passwordEditCtrl.SetValue('') 479 uicore.registry.SetFocus(self.passwordEditCtrl)