diff --git a/ChangeLog b/ChangeLog index 05a5e94..33a3caa 100644 --- a/ChangeLog +++ b/ChangeLog @@ -77,3 +77,40 @@ Changes Fix problems when path settings have trailing (back-)slashes. Support for Python 3.x, PyQt 4.6+ and OpenSSL 1.x Enable server authentication for better security (Python 3.2+ only currently) + +0.2.1 Fixes for launcher.config XML Changes and version bump to 0.2.1 + Fix for 20-Nov-2014 slight changes to WorldQueue.config by Turbine which + broke pylotro. + +0.2.2 Fixes for Update 15.1 changes to launcher.config argument template. Turbine is now + using crashserverurl and DefaultUploadThrottleMbps in the argument template. + Version bump to 0.2.2. + +0.2.3 Localization changes from hcjiv1 and Arek75. Turbine has removed the client local + files for each language. Now each language has a separate subdirectory. If + the client local file is not found then I (hcjiv1) pick languages based on those + subdirectories. Thanks to hcjiv1 and Arek75. Version bump to 0.2.3 + +0.2.4 News feed fixed - Apparently Turbine changed the content encoding of the news feed to + gzip and retrieving the news feed was failing. We now accept gzip content + encoding for the news feed by default and check the Content-Encoding header and + uncompress if content is gzip. + Also some palette adjustments to the widgets (darker theme) + +0.2.5 Added code to check for local game client override in TurbineLauncher.exe.config in game + directory. This is to handle workaround from SSG for game client crashes on + Windows XP/Vista platforms that also affects Linux users running the game under + wine. For more information see link below. + + https://www.lotro.com/forums/showthread.php?654273-Windows-XP-and-Vista-Launcher-Issues-Solution + +0.2.6 Updated certificate chain to new SSL certificates after recent update (22.0.1 or possibly 22) update + by SSG broke authentication using the old certs. + +0.2.7 Added option in Game Settings to select which game client to use. + The choices are 32-bit, 32-bit Legacy ("Awesomium"), and 64-bit. The 32-bit + Legacy Awesomium client is recommended for Linux users. Game client override + code that checked TurbineLauncher.exe.config has been removed since it is no + longer needed with this option. + +0.2.8 Updated certificate chain after game update 29.5 invalidated old certs. diff --git a/PyLotRO.iss b/PyLotRO.iss index 08fd992..994adaf 100755 --- a/PyLotRO.iss +++ b/PyLotRO.iss @@ -7,7 +7,7 @@ ; (To generate a new GUID, click Tools | Generate GUID inside the IDE.) AppId={{EB42F98E-B61B-4EE7-AF06-CAAF8D1825A3} AppName=PyLotRO -AppVerName=PyLotRO 0.2.0 +AppVerName=PyLotRO 0.2.8 AppPublisher=AJackson AppPublisherURL=http://www.lotrolinux.com AppSupportURL=http://www.lotrolinux.com diff --git a/PyLotROLauncher/CheckConfig.py b/PyLotROLauncher/CheckConfig.py index d9da51c..dd98685 100644 --- a/PyLotROLauncher/CheckConfig.py +++ b/PyLotROLauncher/CheckConfig.py @@ -40,6 +40,7 @@ def __init__(self, parent, settings, homeDir, osType, rootDir): self.osType = osType self.winCheckConfig = QtGui.QDialog(parent) + self.winCheckConfig.setPalette(parent.palette()) uifile = None diff --git a/PyLotROLauncher/Information.py b/PyLotROLauncher/Information.py index 12a2c59..e652d19 100644 --- a/PyLotROLauncher/Information.py +++ b/PyLotROLauncher/Information.py @@ -1,5 +1,5 @@ # coding=utf-8 -Version = "0.2.0" +Version = "0.2.8" Description = "LOTRO/DDO Launcher" Author = "Alan Jackson" Email = "ajackson@bcs.org.uk" diff --git a/PyLotROLauncher/MainWindow.py b/PyLotROLauncher/MainWindow.py index 7c17a48..80ab829 100644 --- a/PyLotROLauncher/MainWindow.py +++ b/PyLotROLauncher/MainWindow.py @@ -30,6 +30,7 @@ import os import sys import xml.dom.minidom +import zlib from PyQt4 import QtCore, QtGui, uic from .SettingsWindow import SettingsWindow from .SettingsWizard import SettingsWizard @@ -83,6 +84,30 @@ def __init__(self): self.uiMain = Ui_winMain() self.uiMain.setupUi(self.winMain) + # Set window palette + self.palette = QtGui.QPalette() + self.palette.setColor(QtGui.QPalette.Base, QtCore.Qt.black) + self.palette.setColor(QtGui.QPalette.AlternateBase, QtGui.QColor(22,21,21)) + self.palette.setColor(QtGui.QPalette.ToolTipBase, QtGui.QColor(255,255,220)) + self.palette.setColor(QtGui.QPalette.ToolTipText, QtCore.Qt.black) + self.palette.setColor(QtGui.QPalette.Window, QtGui.QColor(44,43,42)) + self.palette.setColor(QtGui.QPalette.WindowText, QtCore.Qt.white) + self.palette.setColor(QtGui.QPalette.Text, QtCore.Qt.white) + self.palette.setColor(QtGui.QPalette.BrightText, QtCore.Qt.white) + self.palette.setColor(QtGui.QPalette.ButtonText, QtCore.Qt.white) + self.palette.setColor(QtGui.QPalette.Button, QtGui.QColor(44,43,42)) + self.winMain.setPalette(self.palette) + + # find menubar object and save it so we can find the menus + for child in self.winMain.children(): + if isinstance(child, QtGui.QMenuBar): + self.menubar = child + + # find menu objects and set the palette on them + for child in self.menubar.children(): + if isinstance(child, QtGui.QMenu): + child.setPalette(self.palette) + self.webMainExists = True try: self.webMain = QtWebKit.QWebView(self.uiMain.centralwidget) @@ -162,6 +187,7 @@ def actionCheckSelected(self): def actionAboutSelected(self): dlgAbout = QtGui.QDialog(self.winMain) + dlgAbout.setPalette(self.winMain.palette()) uifile = None @@ -198,11 +224,13 @@ def actionPatchSelected(self): def actionOptionsSelected(self): winSettings = SettingsWindow(self.winMain, self.settings.hiResEnabled, self.settings.app, self.settings.wineProg, self.settings.wineDebug, self.settings.patchClient, - self.settings.winePrefix, self.settings.gameDir, self.valHomeDir, self.osType, self.rootDir) + self.settings.winePrefix, self.settings.gameDir, self.valHomeDir, self.osType, self.rootDir, + self.settings.gameClientIdx) self.hideWinMain() if winSettings.Run() == QtGui.QDialog.Accepted: self.settings.hiResEnabled = winSettings.getHiRes() + self.settings.gameClientIdx = winSettings.getGameClientIdx() self.settings.app = winSettings.getApp() self.settings.patchClient = winSettings.getPatchClient() self.settings.gameDir = winSettings.getGameDir() @@ -226,6 +254,7 @@ def actionWizardSelected(self): self.settings.usingDND = winWizard.getUsingDND() self.settings.usingTest = winWizard.getUsingTest() self.settings.hiResEnabled = winWizard.getHiRes() + self.settings.gameClientIdx = winSettings.getGameClientIdx() self.settings.app = winWizard.getApp() self.settings.wineProg = winWizard.getProg() self.settings.wineDebug = winWizard.getDebug() @@ -240,6 +269,7 @@ def actionWizardSelected(self): def actionSwitchSelected(self): dlgChooseAccount = QtGui.QDialog(self.winMain) + dlgChooseAccount.setPalette(self.winMain.palette()) uifile = None @@ -360,13 +390,28 @@ def AuthAccount(self): self.AddLog(self.account.messError) def LaunchGame(self): - game = StartGame(self.winMain, self.worldQueueConfig.gameClientFilename, + gameClientIdx = int(self.settings.gameClientIdx) + + if gameClientIdx == 0: + gameClientFilename = self.worldQueueConfig.gameClientFilename32 + elif gameClientIdx == 1: + gameClientFilename = self.worldQueueConfig.gameClientFilenameLegacy + elif gameClientIdx == 2: + gameClientFilename = "x64/" + self.worldQueueConfig.gameClientFilename64 + + game = StartGame(self.winMain, gameClientFilename, self.worldQueueConfig.gameClientArgTemplate, self.accNumber, self.urlLoginServer, self.account.ticket, self.urlChatServer, self.langConfig.langList[self.uiMain.cboLanguage.currentIndex()].code, self.settings.gameDir, self.settings.wineProg, self.settings.wineDebug, self.settings.winePrefix, self.settings.hiResEnabled, self.settings.app, - self.osType, self.valHomeDir, self.gameType.icoFile, self.rootDir) + self.osType, self.valHomeDir, self.gameType.icoFile, self.rootDir, + self.worldQueueConfig.crashreceiver, self.worldQueueConfig.DefaultUploadThrottleMbps, + self.worldQueueConfig.bugurl, self.worldQueueConfig.authserverurl, + self.worldQueueConfig.supporturl, self.worldQueueConfig.supportserviceurl, + self.worldQueueConfig.glsticketlifetime, + self.uiMain.cboRealm.currentText(), + self.uiMain.txtAccount.text()) self.winMain.hide() game.Run() @@ -618,7 +663,7 @@ def AccessGLSDataCentre(self, urlGLS, gameName): QtCore.QObject.emit(self.winMain, QtCore.SIGNAL("AddLog(QString)"), "[E04] Error accessing GLS data centre.") def GetWorldQueueConfig(self, urlWorldQueueServer): - self.worldQueueConfig = WorldQueueConfig(urlWorldQueueServer, self.settings.usingDND, self.baseDir, self.osType) + self.worldQueueConfig = WorldQueueConfig(urlWorldQueueServer, self.settings.usingDND, self.baseDir, self.osType, self.settings.gameDir) if self.worldQueueConfig.loadSuccess: QtCore.QObject.emit(self.winMain, QtCore.SIGNAL("AddLog(QString)"), "World queue configuration read") @@ -636,11 +681,15 @@ def GetNews(self): webservice, post = WebConnection(self.worldQueueConfig.newsStyleSheetURL) webservice.putrequest("GET", post) + webservice.putheader("Accept-Encoding", "gzip") webservice.endheaders() webresp = webservice.getresponse() - tempxml = webresp.read() + if webresp.getheader('Content-Encoding', '') == 'gzip': + tempxml = zlib.decompress(webresp.read(), 16+zlib.MAX_WBITS) + else: + tempxml = webresp.read() doc = xml.dom.minidom.parseString(tempxml) @@ -659,6 +708,9 @@ def GetNews(self): if link.nodeType == link.ELEMENT_NODE: href = link.attributes["href"] + # Ignore broken href (as of 3/30/16) in the style sheet and use Launcher.NewsFeedCSSUrl defined in launcher.config + href.value = self.worldQueueConfig.newsFeedCSSURL + HTMLTEMPLATE = '
' @@ -669,18 +721,27 @@ def GetNews(self): webservice, post = WebConnection(urlNewsFeed) webservice.putrequest("GET", post) + webservice.putheader("Accept-Encoding", "gzip") webservice.endheaders() webresp = webservice.getresponse() - tempxml = webresp.read() + if webresp.getheader('Content-Encoding', '') == 'gzip': + tempxml = zlib.decompress(webresp.read(), 16+zlib.MAX_WBITS) + else: + tempxml = webresp.read() if len(tempxml) == 0: webservice, post = WebConnection(webresp.getheader("location")) webservice.putrequest("GET", post) + webservice.putheader("Accept-Encoding", "gzip") webservice.endheaders() webresp = webservice.getresponse() - tempxml = webresp.read() + + if webresp.getheader('Content-Encoding', '') == 'gzip': + tempxml = zlib.decompress(webresp.read(), 16+zlib.MAX_WBITS) + else: + tempxml = webresp.read() result = HTMLTEMPLATE diff --git a/PyLotROLauncher/PatchWindow.py b/PyLotROLauncher/PatchWindow.py index fd17341..8257850 100644 --- a/PyLotROLauncher/PatchWindow.py +++ b/PyLotROLauncher/PatchWindow.py @@ -40,6 +40,7 @@ def __init__(self, parent, urlPatchServer, prodCode, language, runDir, patchClie self.winMain = parent self.homeDir = homeDir self.winLog = QtGui.QDialog(parent) + self.winLog.setPalette(parent.palette()) self.osType = osType uifile = None diff --git a/PyLotROLauncher/PyLotROUtils.py b/PyLotROLauncher/PyLotROUtils.py index c01485e..a3bdae8 100644 --- a/PyLotROLauncher/PyLotROUtils.py +++ b/PyLotROLauncher/PyLotROUtils.py @@ -31,11 +31,21 @@ import subprocess import sys import glob +import codecs from PyQt4 import QtCore import xml.dom.minidom from xml.sax.saxutils import escape as xml_escape import ssl +# Python 3 on windows needs Turbine-supplied config files +# to be written in UTF-8, but Python 2 doesn't, and won't +# convert an ascii string for use in codecs.open() +if sys.version_info >= (3,): + from codecs import open as uopen +else: + def uopen(name, mode, dummy): + return open(name, mode) + # If Python >3.0 is in use use http otherwise httplib # Python >3.0 uses unicode strings by default, so also # need to take care of encoding/decoding for sending/receiving @@ -340,7 +350,7 @@ def __init__(self, urlGLSDataCentreService, gameName, baseDir, osType): tempxml = string_decode(webresp.read()) filename = "%s%sGLSDataCenter.config" % (baseDir, osType.appDir) - outfile = open(filename, "w") + outfile = uopen(filename, "w", "utf-8") outfile.write(tempxml) outfile.close() @@ -375,15 +385,18 @@ def __init__(self, urlGLSDataCentreService, gameName, baseDir, osType): class Language: def __init__(self, code): - self.code = code.upper() + # make code uppercase for easier testing - don't use self.code here unless you want to test against self.code instead of code. + code = code.upper() self.news = "en" if code == "EN_GB": self.name = "English (UK)" self.code = "ENGLISH" - elif code == "ENGLISH": + self.news = "en" + elif code == "ENGLISH" or code == "EN": self.name = "English" self.code = "ENGLISH" + self.news = "en" elif code == "FR": self.name = "French" self.code = "FR" @@ -406,6 +419,13 @@ def __init__(self, runDir): # remove "client_local_" (13 chars) and ".dat" (4 chars) from filename temp = os.path.basename(name)[13:-4] self.langList.append(Language(temp)) + # Handle newer clients where the language is a subdir + for name in os.listdir(runDir): + path = os.path.join(runDir, name) + if os.path.exists(os.path.join(path, "Licenses")): + lang = Language(name) + self.langList.append(lang) + self.langFound = True class Realm: def __init__(self, name, urlChatServer, urlServerStatus): @@ -429,7 +449,7 @@ def CheckRealm(self, useDND, baseDir, osType): tempxml = string_decode(webresp.read()) filename = "%s%sserver.config" % (baseDir, osType.appDir) - outfile = open(filename, "w") + outfile = uopen(filename, "w", "utf-8") outfile.write(tempxml) outfile.close() @@ -455,9 +475,19 @@ def CheckRealm(self, useDND, baseDir, osType): self.realmAvailable = False class WorldQueueConfig: - def __init__(self, urlConfigServer, usingDND, baseDir, osType): + def __init__(self, urlConfigServer, usingDND, baseDir, osType, gameDir): self.gameClientFilename = "" + self.gameClientFilename32 = "" + self.gameClientFilename64 = "" + self.gameClientFilenameLegacy = "" self.gameClientArgTemplate = "" + self.crashreceiver = "" + self.DefaultUploadThrottleMbps = "" + self.bugurl = "" + self.authserverurl = "" + self.supporturl = "" + self.supportserviceurl = "" + self.glsticketlifetime = "" self.newsFeedURL = "" self.newsStyleSheetURL = "" self.patchProductCode = "" @@ -475,7 +505,7 @@ def __init__(self, urlConfigServer, usingDND, baseDir, osType): tempxml = string_decode(webresp.read()) filename = "%s%slauncher.config" % (baseDir, osType.appDir) - outfile = open(filename, "w") + outfile = uopen(filename, "w", "utf-8") outfile.write(tempxml) outfile.close() @@ -487,10 +517,30 @@ def __init__(self, urlConfigServer, usingDND, baseDir, osType): nodes = doc.getElementsByTagName("appSettings")[0].childNodes for node in nodes: if node.nodeType == node.ELEMENT_NODE: - if node.getAttribute("key") == "GameClient.Filename": - self.gameClientFilename = node.getAttribute("value") - elif node.getAttribute("key") == "GameClient.ArgTemplate": + if node.getAttribute("key") == "GameClient.WIN32.Filename": + self.gameClientFilename32 = node.getAttribute("value") + if node.getAttribute("key") == "GameClient.WIN64.Filename": + self.gameClientFilename64 = node.getAttribute("value") + if node.getAttribute("key") == "GameClient.WIN32Legacy.Filename": + self.gameClientFilenameLegacy = node.getAttribute("value") + elif node.getAttribute("key") == "GameClient.WIN32.ArgTemplate": self.gameClientArgTemplate = node.getAttribute("value") + elif node.getAttribute("key") == "GameClient.Arg.crashreceiver": + self.crashreceiver = node.getAttribute("value") + elif node.getAttribute("key") == "GameClient.Arg.DefaultUploadThrottleMbps": + self.DefaultUploadThrottleMbps = node.getAttribute("value") + elif node.getAttribute("key") == "GameClient.Arg.bugurl": + self.bugurl = node.getAttribute("value") + elif node.getAttribute("key") == "GameClient.Arg.authserverurl": + self.authserverurl = node.getAttribute("value") + elif node.getAttribute("key") == "GameClient.Arg.supporturl": + self.supporturl = node.getAttribute("value") + elif node.getAttribute("key") == "GameClient.Arg.supportserviceurl": + self.supportserviceurl = node.getAttribute("value") + elif node.getAttribute("key") == "GameClient.Arg.glsticketlifetime": + self.glsticketlifetime = node.getAttribute("value") + elif node.getAttribute("key") == "Launcher.NewsFeedCSSUrl": + self.newsFeedCSSURL = node.getAttribute("value") elif node.getAttribute("key") == "URL.NewsFeed": self.newsFeedURL = node.getAttribute("value") elif node.getAttribute("key") == "URL.NewsStyleSheet": @@ -505,6 +555,7 @@ def __init__(self, urlConfigServer, usingDND, baseDir, osType): self.loadSuccess = True except: self.loadSuccess = False + raise class Game: def __init__(self, name, description): @@ -547,7 +598,7 @@ def __init__(self, urlLoginServer, name, password, game, baseDir, osType): tempxml = string_decode(webresp.read()) filename = "%s%sGLSAuthServer.config" % (baseDir, osType.appDir) - outfile = open(filename, "w") + outfile = uopen(filename, "w", "utf-8") outfile.write(tempxml) outfile.close() @@ -613,7 +664,7 @@ def __init__(self, argTemplate, account, ticket, queue, urlIn, baseDir, osType): tempxml = string_decode(webresp.read()) filename = "%s%sWorldQueue.config" % (baseDir, osType.appDir) - outfile = open(filename, "w") + outfile = uopen(filename, "w", "utf-8") outfile.write(tempxml) outfile.close() diff --git a/PyLotROLauncher/Settings.py b/PyLotROLauncher/Settings.py index 8e8e916..2664ecb 100644 --- a/PyLotROLauncher/Settings.py +++ b/PyLotROLauncher/Settings.py @@ -52,6 +52,7 @@ def LoadSettings(self, useGame=None): self.focusAccount = True self.winePrefix = os.environ.get('WINEPREFIX') self.gameDir = "" + self.gameClientIdx = 0 self.hideWinMain = False success = False @@ -95,6 +96,8 @@ def LoadSettings(self, useGame=None): self.hiResEnabled = True else: self.hiResEnabled = False + elif node.nodeName == "Game.Client.Index": + self.gameClientIdx = GetText(node.childNodes) elif node.nodeName == "Game.Directory": self.gameDir = GetText(node.childNodes) elif node.nodeName == "Realm": @@ -191,6 +194,10 @@ def SaveSettings(self, saveAccountDetails): tempNode.appendChild(doc.createTextNode("%s" % (self.gameDir))) gameConfigNode.appendChild(tempNode) + tempNode = doc.createElementNS(EMPTY_NAMESPACE, "Game.Client.Index") + tempNode.appendChild(doc.createTextNode("%s" % (self.gameClientIdx))) + gameConfigNode.appendChild(tempNode) + tempNode = doc.createElementNS(EMPTY_NAMESPACE, "PatchClient") tempNode.appendChild(doc.createTextNode("%s" % (self.patchClient))) gameConfigNode.appendChild(tempNode) diff --git a/PyLotROLauncher/SettingsWindow.py b/PyLotROLauncher/SettingsWindow.py index 6caef30..fa6ed20 100644 --- a/PyLotROLauncher/SettingsWindow.py +++ b/PyLotROLauncher/SettingsWindow.py @@ -34,12 +34,13 @@ class SettingsWindow: def __init__(self, parent, hiRes, app, wineProg, wineDebug, patchClient, winePrefix, - gameDir, homeDir, osType, rootDir): + gameDir, homeDir, osType, rootDir, gameClientIdx): self.homeDir = homeDir self.osType = osType self.winSettings = QtGui.QDialog(parent) + self.winSettings.setPalette(parent.palette()) uifile = None @@ -76,6 +77,9 @@ def __init__(self, parent, hiRes, app, wineProg, wineDebug, patchClient, winePre self.uiSettings.txtGameDir.setText(gameDir) self.uiSettings.cboGraphics.addItem("Enabled") self.uiSettings.cboGraphics.addItem("Disabled") + self.uiSettings.cboGameClient.addItem("32-bit") + self.uiSettings.cboGameClient.addItem("32-bit Legacy (\"Awesomium\")") + self.uiSettings.cboGameClient.addItem("64-bit") self.uiSettings.chkAdvanced.setChecked(False) self.uiSettings.txtPatchClient.setText(patchClient) self.uiSettings.txtPatchClient.setEnabled(False) @@ -101,6 +105,8 @@ def __init__(self, parent, hiRes, app, wineProg, wineDebug, patchClient, winePre else: self.uiSettings.cboGraphics.setCurrentIndex(1) + self.uiSettings.cboGameClient.setCurrentIndex(int(gameClientIdx)) + QtCore.QObject.connect(self.uiSettings.btnGameDir, QtCore.SIGNAL("clicked()"), self.btnGameDirClicked) QtCore.QObject.connect(self.uiSettings.chkAdvanced, QtCore.SIGNAL("clicked()"), self.chkAdvancedClicked) @@ -202,6 +208,9 @@ def getHiRes(self): else: return False + def getGameClientIdx(self): + return self.uiSettings.cboGameClient.currentIndex() + def Run(self): return self.winSettings.exec_() diff --git a/PyLotROLauncher/SettingsWizard.py b/PyLotROLauncher/SettingsWizard.py index da6afff..1ed74be 100644 --- a/PyLotROLauncher/SettingsWizard.py +++ b/PyLotROLauncher/SettingsWizard.py @@ -48,6 +48,7 @@ def __init__(self, parent, homeDir, osType, rootDir): self.gameDir = "" self.winSettings = QtGui.QDialog(parent) + self.winSettings.setPalette(parent.palette()) uifile = None diff --git a/PyLotROLauncher/StartGame.py b/PyLotROLauncher/StartGame.py index 1573338..eb339f2 100644 --- a/PyLotROLauncher/StartGame.py +++ b/PyLotROLauncher/StartGame.py @@ -34,12 +34,17 @@ class StartGame: def __init__(self, parent, appName, argTemplate, account, server, ticket, chatServer, language, runDir, wineProgram, wineDebug, winePrefix, - hiResEnabled, wineApp, osType, homeDir, icoFileIn, rootDir): + hiResEnabled, wineApp, osType, homeDir, icoFileIn, rootDir, + crashreceiver, DefaultUploadThrottleMbps, bugurl, authserverurl, + supporturl, supportserviceurl, glsticketlifetime, realmName, accountText): self.winMain = parent self.homeDir = homeDir self.winLog = QtGui.QDialog(parent) + self.winLog.setPalette(parent.palette()) self.osType = osType + self.realmName = realmName + self.accountText = accountText uifile = None icofile = None @@ -84,8 +89,12 @@ def __init__(self, parent, appName, argTemplate, account, server, ticket, self.command = "" self.arguments = [] - gameParams = argTemplate.replace("{0}", account).replace("{1}", server)\ - .replace("{2}", ticket).replace("{3}", chatServer).replace("{4}", language) + gameParams = argTemplate.replace("{SUBSCRIPTION}", account).replace("{LOGIN}", server)\ + .replace("{GLS}", ticket).replace("{CHAT}", chatServer).replace("{LANG}", language)\ + .replace("{CRASHRECEIVER}", crashreceiver).replace("{UPLOADTHROTTLE}", DefaultUploadThrottleMbps)\ + .replace("{BUGURL}", bugurl).replace("{AUTHSERVERURL}", authserverurl)\ + .replace("{GLSTICKETLIFETIME}", glsticketlifetime).replace("{SUPPORTURL}", supporturl)\ + .replace("{SUPPORTSERVICEURL}",supportserviceurl) if not hiResEnabled: gameParams = gameParams + " --HighResOutOfDate" @@ -172,6 +181,11 @@ def __init__(self, parent, appName, argTemplate, account, server, ticket, for arg in tempArg.split(" "): self.arguments.append(arg) + self.uiLog.txtLog.append("Connecting to server: " + realmName) + self.uiLog.txtLog.append("Account: " + accountText) + self.uiLog.txtLog.append("Game Directory: " + runDir) + self.uiLog.txtLog.append("Game Client: " + appName) + def readOutput(self): self.uiLog.txtLog.append(QByteArray2str(self.process.readAllStandardOutput())) diff --git a/PyLotROLauncher/certificates/README b/PyLotROLauncher/certificates/README new file mode 100644 index 0000000..d8f04d4 --- /dev/null +++ b/PyLotROLauncher/certificates/README @@ -0,0 +1,33 @@ +In order to connect via SSL/TLS, the server's certificate is validated against +the certificate chain stored in this file. When Turbine updates their +certificate chain, this program will break (again) with the error message: + + [E15] SSL Error occured in HTTPS connection + +In that case you will need re-assemble the certificate chain and place it into +this file. Useful commands at the time of this writing include: + + openssl s_client -connect gls.lotro.com:443 + +...which will attempt to connect to the LotRO authentication server and +allow you to copy+paste the server's certificate and begin hunting down the +chain. In order to read each certificate as you work your way up the chain, +you can use: + + openssl x509 -in -text + +...in order to dump information about the specified certificate. You may +need to add '-inform der' if the certificate is in binary format. Look +for the 'Authority Information Access' under 'X509v3 extensions' in order +to quickly retrieve URLs for the certificate chain. You may also need to +retrieve the root certificate from your local '/etc/ssl/certs/'. + +When you have retrieved all of the certificates, you will need to concatenate +them together. In order to verify that this has been done correctly, again use +the 'openssl verify' command, and in addition use the '-CAfile ' +argument. It's best to start with the root authority and then work your way +down (in the order opposite of which the certificates were retrieved). Note +that, when I did this, the root authority wasn't required for the command +to verify, but was necessary for the program to actually work. + +Good luck. diff --git a/PyLotROLauncher/certificates/ca_certs.pem b/PyLotROLauncher/certificates/ca_certs.pem index 85e7722..d5ec2dc 100644 --- a/PyLotROLauncher/certificates/ca_certs.pem +++ b/PyLotROLauncher/certificates/ca_certs.pem @@ -1,53 +1,90 @@ ------BEGIN CERTIFICATE----- -MIIEpjCCA46gAwIBAgIQEOd26KZabjd+BQMG1Dwl6jANBgkqhkiG9w0BAQUFADCB -lzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug -Q2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho -dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xHzAdBgNVBAMTFlVUTi1VU0VSRmlyc3Qt -SGFyZHdhcmUwHhcNMDYwNDEwMDAwMDAwWhcNMjAwNTMwMTA0ODM4WjBiMQswCQYD -VQQGEwJVUzEhMB8GA1UEChMYTmV0d29yayBTb2x1dGlvbnMgTC5MLkMuMTAwLgYD -VQQDEydOZXR3b3JrIFNvbHV0aW9ucyBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwggEi -MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDD3TbMg8MYVbCW2RMl0yaGSDi7 -Fn/xnyn2/QPx7U0mmlbwtRoazebMhVVApLXQDcoi7z0jxn5szLyh6XxQRuC9FK1l -EsILEWlSCgeSH3NvwbrXYvDOAC40pcjmLw/sDepEYXVo5eTcgDZP2nhdUyWUlPVP -Ljpgbwym2bP2Ki4DEtUmQgdRsmRXcdwhHInHaaPm+8J7bu8Mh/tQZOhOS+/ncZuD -Y2HJMo2M7BSn5ImtPysmZOSFQvKJUOE6vhXjRSXiWsuMP+AzHjUJWoTqfl2h9ZGA -CigGt8sxQSVhiwHpVqL2Pl8v88RD9hmUdYNMoYJCOsa6xAkwpuF1AlG5XmSLAgMB -AAGjggEgMIIBHDAfBgNVHSMEGDAWgBShcl8mGyiYQ5VdBzfVhZadS9LDRTAdBgNV -HQ4EFgQUPEHijwgIqUwliY1txTjQ/IWMYhcwDgYDVR0PAQH/BAQDAgEGMBIGA1Ud -EwEB/wQIMAYBAf8CAQAwGQYDVR0gBBIwEDAOBgwrBgEEAYYOAQIBAwEwRAYDVR0f -BD0wOzA5oDegNYYzaHR0cDovL2NybC51c2VydHJ1c3QuY29tL1VUTi1VU0VSRmly -c3QtSGFyZHdhcmUuY3JsMFUGCCsGAQUFBwEBBEkwRzBFBggrBgEFBQcwAoY5aHR0 -cDovL3d3dy51c2VydHJ1c3QuY29tL2NhY2VydHMvVVROQWRkVHJ1c3RTZXJ2ZXJf -Q0EuY3J0MA0GCSqGSIb3DQEBBQUAA4IBAQBoq/zvgGsYsrCzo0WJy1PFouavCKn9 -/w9JrP/kn9dBfKPFouiq4FchLcOqfAxMKAt59O5MMq15Dn6iXjQYT99U8b1ofOPT -10ZebWTC922IgnMM75mF6qnvMkrwg59zkQykPisxUaZijxWE+aY6EjA/2m74zMcZ -kg9c9P4X8ZUIR1IsUI/om6XurnAziZGC/jCqdnZZ12wY0ysSWx0oHXhx9s02oukH -SEQ751duggqtxYrd6FO0ca8T0gadN21TP4o1CPr+ohbmuW9cVjnWxqrvGWfOE8W4 -lQX7CkTJn6lAJUsyEa8H/gjVQnHp4VOLFR/dKgeVcCRvZF7Tt5AuiyHY ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIEdDCCA1ygAwIBAgIQRL4Mi1AAJLQR0zYq/mUK/TANBgkqhkiG9w0BAQUFADCB -lzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug -Q2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho -dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xHzAdBgNVBAMTFlVUTi1VU0VSRmlyc3Qt -SGFyZHdhcmUwHhcNOTkwNzA5MTgxMDQyWhcNMTkwNzA5MTgxOTIyWjCBlzELMAkG -A1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0eTEe -MBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8v -d3d3LnVzZXJ0cnVzdC5jb20xHzAdBgNVBAMTFlVUTi1VU0VSRmlyc3QtSGFyZHdh -cmUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCx98M4P7Sof885glFn -0G2f0v9Y8+efK+wNiVSZuTiZFvfgIXlIwrthdBKWHTxqctU8EGc6Oe0rE81m65UJ -M6Rsl7HoxuzBdXmcRl6Nq9Bq/bkqVRcQVLMZ8Jr28bFdtqdt++BxF2uiiPsA3/4a -MXcMmgF6sTLjKwEHOG7DpV4jvEWbe1DByTCP2+UretNb+zNAHqDVmBe8i4fDidNd -oI6yqqr2jmmIBsX6iSHzCJ1pLgkzmykNRg+MzEk0sGlRvfkGzWitZky8PqxhvQqI -DsjfPe58BEydCl5rkdbux+0ojatNh4lz0G6k0B4WixThdkQDf2Os5M1JnMWS9Ksy -oUhbAgMBAAGjgbkwgbYwCwYDVR0PBAQDAgHGMA8GA1UdEwEB/wQFMAMBAf8wHQYD -VR0OBBYEFKFyXyYbKJhDlV0HN9WFlp1L0sNFMEQGA1UdHwQ9MDswOaA3oDWGM2h0 -dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9VVE4tVVNFUkZpcnN0LUhhcmR3YXJlLmNy -bDAxBgNVHSUEKjAoBggrBgEFBQcDAQYIKwYBBQUHAwUGCCsGAQUFBwMGBggrBgEF -BQcDBzANBgkqhkiG9w0BAQUFAAOCAQEARxkP3nTGmZev/K0oXnWO6y1n7k57K9cM -//bey1WiCuFMVGWTYGufEpytXoMs61quwOQt9ABjHbjAbPLPSbtNk28Gpgoiskli -CE7/yMgUsogWXecB5BKV5UU0s4tpvc+0hY91UZ59Ojg6FEgSxvunOxqNDYJAB+gE -CJChicsZUN/KHAG8HQQZexB2lzvukJDKxA4fFm517zP4029bHpbj4HR3dHuKom4t -3XbWOTCC8KucUvIqx69JXn7HaOWCgchqJ/kniCrVWFCVH/A7HFe7fRQ5YiuayZSS -KqMiDP+JJn1fIytH1xUdqWqeUQ0qUZ6B+dQ7XnASfxAynB67nfhmqA== ------END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD +QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT +MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j +b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG +9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB +CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97 +nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt +43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P +T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4 +gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO +BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR +TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw +DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr +hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg +06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF +PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls +YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk +CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIE6jCCA9KgAwIBAgIQCjUI1VwpKwF9+K1lwA/35DANBgkqhkiG9w0BAQsFADBh +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD +QTAeFw0yMDA5MjQwMDAwMDBaFw0zMDA5MjMyMzU5NTlaME8xCzAJBgNVBAYTAlVT +MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxKTAnBgNVBAMTIERpZ2lDZXJ0IFRMUyBS +U0EgU0hBMjU2IDIwMjAgQ0ExMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC +AQEAwUuzZUdwvN1PWNvsnO3DZuUfMRNUrUpmRh8sCuxkB+Uu3Ny5CiDt3+PE0J6a +qXodgojlEVbbHp9YwlHnLDQNLtKS4VbL8Xlfs7uHyiUDe5pSQWYQYE9XE0nw6Ddn +g9/n00tnTCJRpt8OmRDtV1F0JuJ9x8piLhMbfyOIJVNvwTRYAIuE//i+p1hJInuW +raKImxW8oHzf6VGo1bDtN+I2tIJLYrVJmuzHZ9bjPvXj1hJeRPG/cUJ9WIQDgLGB +Afr5yjK7tI4nhyfFK3TUqNaX3sNk+crOU6JWvHgXjkkDKa77SU+kFbnO8lwZV21r +eacroicgE7XQPUDTITAHk+qZ9QIDAQABo4IBrjCCAaowHQYDVR0OBBYEFLdrouqo +qoSMeeq02g+YssWVdrn0MB8GA1UdIwQYMBaAFAPeUDVW0Uy7ZvCj4hsbw5eyPdFV +MA4GA1UdDwEB/wQEAwIBhjAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIw +EgYDVR0TAQH/BAgwBgEB/wIBADB2BggrBgEFBQcBAQRqMGgwJAYIKwYBBQUHMAGG +GGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBABggrBgEFBQcwAoY0aHR0cDovL2Nh +Y2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0R2xvYmFsUm9vdENBLmNydDB7BgNV +HR8EdDByMDegNaAzhjFodHRwOi8vY3JsMy5kaWdpY2VydC5jb20vRGlnaUNlcnRH +bG9iYWxSb290Q0EuY3JsMDegNaAzhjFodHRwOi8vY3JsNC5kaWdpY2VydC5jb20v +RGlnaUNlcnRHbG9iYWxSb290Q0EuY3JsMDAGA1UdIAQpMCcwBwYFZ4EMAQEwCAYG +Z4EMAQIBMAgGBmeBDAECAjAIBgZngQwBAgMwDQYJKoZIhvcNAQELBQADggEBAHer +t3onPa679n/gWlbJhKrKW3EX3SJH/E6f7tDBpATho+vFScH90cnfjK+URSxGKqNj +OSD5nkoklEHIqdninFQFBstcHL4AGw+oWv8Zu2XHFq8hVt1hBcnpj5h232sb0HIM +ULkwKXq/YFkQZhM6LawVEWwtIwwCPgU7/uWhnOKK24fXSuhe50gG66sSmvKvhMNb +g0qZgYOrAKHKCjxMoiWJKiKnpPMzTFuMLhoClw+dj20tlQj7T9rxkTgl4ZxuYRiH +as6xuwAwapu3r9rxxZf+ingkquqTgLozZXq8oXfpf2kUCwA/d5KxTVtzhwoT0JzI +8ks5T1KESaZMkE4f97Q= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIGwDCCBaigAwIBAgIQDuAmwkWKDUFDxKxfPW7GOjANBgkqhkiG9w0BAQsFADBP +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMSkwJwYDVQQDEyBE +aWdpQ2VydCBUTFMgUlNBIFNIQTI1NiAyMDIwIENBMTAeFw0yMTA0MTMwMDAwMDBa +Fw0yMjA0MjgyMzU5NTlaMHAxCzAJBgNVBAYTAlVTMRYwFAYDVQQIEw1NYXNzYWNo +dXNldHRzMRAwDgYDVQQHEwdOZWVkaGFtMSEwHwYDVQQKExhTdGFuZGluZyBTdG9u +ZSBHYW1lcyBMTEMxFDASBgNVBAMMCyoubG90cm8uY29tMIIBIjANBgkqhkiG9w0B +AQEFAAOCAQ8AMIIBCgKCAQEAztIfPfYhzT2nevQqOrtm8M4NF5j5FWG7UkZm7ab0 +BfzPcqdV+EaoJntDP30/QpvoLryACDBJ+iO2g+EWISaK0uWaW2agCOiYjTcZFOoQ +ecRqQFNrRZKDZ/kFU5qqyV3ex4DHc0mBmssuaale4IFqj/NcApAt/xaSLzyfXerU +J9zgJYLbphIpZcUB/7YofhOc2dgzqgSoPA0N31SUvyZQWJJu3F1q4YPa8ApZ+5OG +xNbruwzjwZs8NUbiP2v2HqjxkpYdU5CjYFB8JeF8nGa3aM7xTLf2NxdGBPp2zr0h +ybmGeoJNL6FtV0ieMzQiH+VY8hhw0QT8xTdUDCpzalnitQIDAQABo4IDdTCCA3Ew +HwYDVR0jBBgwFoAUt2ui6qiqhIx56rTaD5iyxZV2ufQwHQYDVR0OBBYEFK5HJlnj +BHYloLJvDYjGYAb1sd0LMCEGA1UdEQQaMBiCCyoubG90cm8uY29tgglsb3Ryby5j +b20wDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcD +AjCBiwYDVR0fBIGDMIGAMD6gPKA6hjhodHRwOi8vY3JsMy5kaWdpY2VydC5jb20v +RGlnaUNlcnRUTFNSU0FTSEEyNTYyMDIwQ0ExLmNybDA+oDygOoY4aHR0cDovL2Ny +bDQuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0VExTUlNBU0hBMjU2MjAyMENBMS5jcmww +PgYDVR0gBDcwNTAzBgZngQwBAgIwKTAnBggrBgEFBQcCARYbaHR0cDovL3d3dy5k +aWdpY2VydC5jb20vQ1BTMH0GCCsGAQUFBwEBBHEwbzAkBggrBgEFBQcwAYYYaHR0 +cDovL29jc3AuZGlnaWNlcnQuY29tMEcGCCsGAQUFBzAChjtodHRwOi8vY2FjZXJ0 +cy5kaWdpY2VydC5jb20vRGlnaUNlcnRUTFNSU0FTSEEyNTYyMDIwQ0ExLmNydDAM +BgNVHRMBAf8EAjAAMIIBgAYKKwYBBAHWeQIEAgSCAXAEggFsAWoAdgApeb7wnjk5 +IfBWc59jpXflvld9nGAK+PlNXSZcJV3HhAAAAXjIzphwAAAEAwBHMEUCIFznUqt4 +r3oqLf0EJCxckG8w65dl9TtIqWYlJRBNsEyqAiEAqei2Ma1amnDqPEgub2+AbiKa +HRByKwNyQHAlJIKZ0SUAdwAiRUUHWVUkVpY/oS/x922G4CMmY63AS39dxoNcbuIP +AgAAAXjIzpjQAAAEAwBIMEYCIQCJmFsghrbvklCc8uTa3PNQ3/oXFCbZ9M52ynCj +yNjrLQIhAJ9/iL3H/Vp3I7vXfvjY76g5holbnikmBxZHzGFrhScbAHcAQcjKsd8i +RkoQxqE6CUKHXk4xixsD6+tLx2jwkGKWBvYAAAF4yM6YbAAABAMASDBGAiEArRTv +870dWCMuGYddzSbZv3sy0f7ZBuNENtaN1VFjlIICIQDtKbotdQgKgrbkjOnAgyPp +R7SZ4nAtl3KkKRvFBjR8sDANBgkqhkiG9w0BAQsFAAOCAQEATpQsD909GlE+R72y +e/ZiIDZLpV2hEXmVXoMwiTbGieh3aoQTXCY7kNMVJ36hCtflOEbREaKcjsF5mhDs +kXAtttg3eLrP092Nof5dfVkNKZx6dNs0tuU0jT/1hr7J2j1Q4DhoLepzH8FK40pz +/05+H/1nfrSgAEEbP6kXpKk6rjY7fBsouESgA2ht+jk3opPUoZeZRvavL9CnKYQM +DUIhYcPx3F8EgQRL0uHDgXTyswXrEtJdFY2X5vSFzF5/MxSnW+XqeYRjfuuS437c +TRNMvO/B7/IzA1/mQNbO1KBDyruP6sr8VK5L8n+kap8WJuVBKX5I1F6CodaIjS2m +/uP+YA== +-----END CERTIFICATE----- diff --git a/PyLotROLauncher/ui/winSettings.ui b/PyLotROLauncher/ui/winSettings.ui index 6e6927f..cf5e14e 100644 --- a/PyLotROLauncher/ui/winSettings.ui +++ b/PyLotROLauncher/ui/winSettings.ui @@ -1,47 +1,48 @@ - + + dlgSettings - - + + Qt::ApplicationModal - + 0 0 460 - 338 + 379 - + Verdana 12 - + Game Settings - + true - - + + - 5 - 301 + 0 + 340 450 32 - + Qt::Horizontal - + QDialogButtonBox::Cancel|QDialogButtonBox::Save - - + + 5 10 @@ -49,12 +50,12 @@ 23 - + Application - - + + 155 5 @@ -63,8 +64,8 @@ - - + + 5 47 @@ -72,12 +73,12 @@ 23 - + WINEDEBUG - - + + 155 43 @@ -86,8 +87,8 @@ - - + + 5 85 @@ -95,12 +96,12 @@ 23 - + WINEPREFIX - - + + 155 80 @@ -109,11 +110,11 @@ - - + + true - + 155 79 @@ -122,8 +123,8 @@ - - + + 155 117 @@ -132,8 +133,8 @@ - - + + 419 117 @@ -141,12 +142,12 @@ 30 - + ... - - + + 5 121 @@ -154,12 +155,12 @@ 23 - + Game Directory - - + + 5 158 @@ -167,12 +168,12 @@ 23 - + Hi-Res Graphics - - + + 155 153 @@ -181,68 +182,91 @@ - - + + - 5 - 196 + 0 + 237 280 28 - + Advanced Options - + false - - + + - 155 - 229 + 150 + 270 300 31 - - + + - 5 - 233 + 0 + 274 140 23 - + Wine Program - - + + - 155 - 265 + 150 + 306 300 31 - - + + - 5 - 269 + 0 + 310 150 23 - + Patch Client DLL + + + + 155 + 193 + 300 + 33 + + + + + + + 5 + 197 + 150 + 23 + + + + Game Client + + @@ -252,11 +276,11 @@ dlgSettings accept() - + 248 254 - + 157 274 @@ -268,11 +292,11 @@ dlgSettings reject() - + 316 260 - + 286 274 diff --git a/PyLotROLauncher/ui/winSettingsNative.ui b/PyLotROLauncher/ui/winSettingsNative.ui index d5fd1df..cf8aded 100644 --- a/PyLotROLauncher/ui/winSettingsNative.ui +++ b/PyLotROLauncher/ui/winSettingsNative.ui @@ -1,47 +1,48 @@ - + + dlgSettings - - + + Qt::ApplicationModal - + 0 0 460 - 190 + 236 - + Verdana 12 - + Game Settings - + true - - + + 5 - 150 + 192 450 32 - + Qt::Horizontal - + QDialogButtonBox::Cancel|QDialogButtonBox::Save - - + + 155 6 @@ -50,8 +51,8 @@ - - + + 419 6 @@ -59,12 +60,12 @@ 30 - + ... - - + + 5 10 @@ -72,12 +73,12 @@ 23 - + Game Directory - - + + 5 47 @@ -85,12 +86,12 @@ 23 - + Hi-Res Graphics - - + + 155 42 @@ -99,45 +100,68 @@ - - + + 5 - 80 + 122 280 28 - + Advanced Options - + false - - + + 155 - 113 + 155 300 31 - - + + 5 - 117 + 159 150 23 - + Patch Client DLL + + + + 5 + 85 + 150 + 23 + + + + Game Client + + + + + + 155 + 81 + 300 + 33 + + + @@ -147,11 +171,11 @@ dlgSettings accept() - + 248 254 - + 157 274 @@ -163,11 +187,11 @@ dlgSettings reject() - + 316 260 - + 286 274 diff --git a/README b/README index 7c96c65..414ad8b 100644 --- a/README +++ b/README @@ -57,7 +57,7 @@ find relevant installations of LotRO or DDO. For CrossOver and CrossOver Games it searches in the default bottle location. For Wine it looks for wine folders in your home directory -(folders tarting with a full stop with a +(folders starting with a full stop with a directory called drive_c under that). For all options it tries to find the game in the "Program Files" directory (or directories off