From 8e9f65779c14d4b711099888f4bfe7e230dd4498 Mon Sep 17 00:00:00 2001 From: BeniS Date: Sun, 24 Feb 2013 00:41:21 +1300 Subject: [PATCH] Implemented client_serverlist module! Close #200 * Will store servers that are not already in the list when logging in * Can add servers manually if required too * Fixed a bug in table.size --- data/images/ui/icon_add.png | Bin 0 -> 15817 bytes data/styles/10-buttons.otui | 16 ++- modules/client/client.otmod | 1 + modules/client_entergame/entergame.lua | 44 +++++-- modules/client_entergame/entergame.otui | 24 +++- modules/client_serverlist/addserver.lua | 38 ++++++ modules/client_serverlist/addserver.otui | 73 ++++++++++++ modules/client_serverlist/serverlist.lua | 127 +++++++++++++++++++++ modules/client_serverlist/serverlist.otmod | 18 +++ modules/client_serverlist/serverlist.otui | 113 ++++++++++++++++++ modules/corelib/table.lua | 2 +- 11 files changed, 444 insertions(+), 12 deletions(-) create mode 100644 data/images/ui/icon_add.png create mode 100644 modules/client_serverlist/addserver.lua create mode 100644 modules/client_serverlist/addserver.otui create mode 100644 modules/client_serverlist/serverlist.lua create mode 100644 modules/client_serverlist/serverlist.otmod create mode 100644 modules/client_serverlist/serverlist.otui diff --git a/data/images/ui/icon_add.png b/data/images/ui/icon_add.png new file mode 100644 index 0000000000000000000000000000000000000000..9c2a0f750b5239156b02b340990945df9ca114e6 GIT binary patch literal 15817 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 literal 0 HcmV?d00001 diff --git a/data/styles/10-buttons.otui b/data/styles/10-buttons.otui index 8e1607e1..0eebf67b 100644 --- a/data/styles/10-buttons.otui +++ b/data/styles/10-buttons.otui @@ -66,4 +66,18 @@ PreviousButton < UIButton image-clip: 0 21 12 21 $disabled: - image-color: #ffffff55 \ No newline at end of file + image-color: #ffffff55 + +AddButton < UIButton + size: 20 20 + image-source: /images/ui/icon_add + image-color: #ffffffff + + $hover !disabled: + image-color: #ffffff99 + + $pressed: + image-color: #ffffff44 + + $disabled: + image-color: #ffffff55 diff --git a/modules/client/client.otmod b/modules/client/client.otmod index 28cec272..31ffa32b 100644 --- a/modules/client/client.otmod +++ b/modules/client/client.otmod @@ -18,4 +18,5 @@ Module - client_options - client_terminal - client_modulemanager + - client_serverlist //- client_stats diff --git a/modules/client_entergame/entergame.lua b/modules/client_entergame/entergame.lua index 5a4fd4a2..faef1290 100644 --- a/modules/client_entergame/entergame.lua +++ b/modules/client_entergame/entergame.lua @@ -34,9 +34,19 @@ local function onMotd(protocol, motd) end local function onCharacterList(protocol, characters, account, otui) + -- Try add server to the server list + ServerList.add(G.host, G.port, g_game.getProtocolVersion()) + if enterGame:getChildById('rememberPasswordBox'):isChecked() then - g_settings.set('account', g_crypt.encrypt(G.account)) - g_settings.set('password', g_crypt.encrypt(G.password)) + local account = g_crypt.encrypt(G.account) + local password = g_crypt.encrypt(G.password) + + g_settings.set('account', account) + g_settings.set('password', password) + + ServerList.setServerAccount(G.host, account) + ServerList.setServerPassword(G.host, password) + g_settings.set('autologin', enterGame:getChildById('autoLoginBox'):isChecked()) else EnterGame.clearAccountFields() @@ -90,8 +100,8 @@ function EnterGame.init() motdButton:show() end - local account = g_crypt.decrypt(g_settings.get('account')) - local password = g_crypt.decrypt(g_settings.get('password')) + local account = g_settings.get('account') + local password = g_settings.get('password') local host = g_settings.get('host') local port = g_settings.get('port') local autologin = g_settings.getBoolean('autologin') @@ -99,16 +109,15 @@ function EnterGame.init() if port == nil or port == 0 then port = 7171 end - enterGame:getChildById('accountNameTextEdit'):setText(account) - enterGame:getChildById('accountNameTextEdit'):setCursorPos(-1) - enterGame:getChildById('accountPasswordTextEdit'):setText(password) + EnterGame.setAccountName(account) + EnterGame.setPassword(password) + enterGame:getChildById('serverHostTextEdit'):setText(host) enterGame:getChildById('serverPortTextEdit'):setText(port) enterGame:getChildById('autoLoginBox'):setChecked(autologin) - enterGame:getChildById('rememberPasswordBox'):setChecked(#account > 0) protocolBox = enterGame:getChildById('protocolComboBox') - protocolBox.onOptionChange = onChangeProtocol + protocolBox.onOptionChange = onChangeProtocol for _i, proto in pairs(g_game.getSupportedProtocols()) do protocolBox:addOption(proto) end @@ -184,6 +193,18 @@ function EnterGame.openWindow() end end +function EnterGame.setAccountName(account) + local account = g_crypt.decrypt(account) + enterGame:getChildById('accountNameTextEdit'):setText(account) + enterGame:getChildById('accountNameTextEdit'):setCursorPos(-1) + enterGame:getChildById('rememberPasswordBox'):setChecked(#account > 0) +end + +function EnterGame.setPassword(password) + local password = g_crypt.decrypt(password) + enterGame:getChildById('accountPasswordTextEdit'):setText(password) +end + function EnterGame.clearAccountFields() enterGame:getChildById('accountNameTextEdit'):clearText() enterGame:getChildById('accountPasswordTextEdit'):clearText() @@ -285,6 +306,11 @@ function EnterGame.setUniqueServer(host, port, protocol, windowWidth, windowHeig protocolLabel:setVisible(false) protocolLabel:setHeight(0) + local serverListButton = enterGame:getChildById('serverListButton') + serverListButton:setVisible(false) + serverListButton:setHeight(0) + serverListButton:setWidth(0) + local rememberPasswordBox = enterGame:getChildById('rememberPasswordBox') rememberPasswordBox:setMarginTop(-5) diff --git a/modules/client_entergame/entergame.otui b/modules/client_entergame/entergame.otui index a0065268..b026c430 100644 --- a/modules/client_entergame/entergame.otui +++ b/modules/client_entergame/entergame.otui @@ -1,5 +1,19 @@ EnterGameWindow < MainWindow +ServerListButton < UIButton + size: 17 17 + image-source: /images/topbuttons/minimap + image-color: #ffffffff + + $hover !disabled: + image-color: #ffffff99 + + $pressed: + image-color: #ffffff44 + + $disabled: + image-color: #ffffff55 + EnterGameWindow id: enterGame !text: tr('Enter Game') @@ -41,13 +55,21 @@ EnterGameWindow margin-top: 8 text-auto-resize: true + ServerListButton + id: serverListButton + anchors.right: parent.right + anchors.top: serverLabel.bottom + margin-top: 3 + @onClick: ServerList.show() + TextEdit id: serverHostTextEdit !tooltip: tr('Make sure that your client uses\nthe correct game protocol version') anchors.left: parent.left - anchors.right: parent.right + anchors.right: serverListButton.left anchors.top: serverLabel.bottom margin-top: 2 + margin-right: 4 MenuLabel id: protocolLabel diff --git a/modules/client_serverlist/addserver.lua b/modules/client_serverlist/addserver.lua new file mode 100644 index 00000000..3a4f65d3 --- /dev/null +++ b/modules/client_serverlist/addserver.lua @@ -0,0 +1,38 @@ +AddServer = {} + +-- private variables +local addServerWindow = nil + +-- public functions +function AddServer.init() + addServerWindow = g_ui.displayUI('addserver') +end + +function AddServer.terminate() + addServerWindow:destroy() +end + +function AddServer.add() + local host = addServerWindow:getChildById('host'):getText() + local port = addServerWindow:getChildById('port'):getText() + local protocol = addServerWindow:getChildById('protocol'):getCurrentOption().text + + local added, error = ServerList.add(host, port, protocol) + if not added then + displayErrorBox(tr('Add Error'), tr(error)) + else + AddServer.hide() + end +end + +function AddServer.show() + addServerWindow:show() + addServerWindow:raise() + addServerWindow:focus() + addServerWindow:lock() +end + +function AddServer.hide() + addServerWindow:hide() + addServerWindow:unlock() +end \ No newline at end of file diff --git a/modules/client_serverlist/addserver.otui b/modules/client_serverlist/addserver.otui new file mode 100644 index 00000000..df43e97c --- /dev/null +++ b/modules/client_serverlist/addserver.otui @@ -0,0 +1,73 @@ +MainWindow + id: addServerWindow + !text: tr('New Server') + size: 180 180 + visible: false + @onEscape: AddServer.hide() + @onEnter: | + AddServer.add() + + Label + id: hostLabel + !text: tr('Host:') + anchors.top: parent.top + anchors.left: parent.left + margin-bottom: 2 + + TextEdit + id: host + anchors.top: hostLabel.bottom + anchors.left: hostLabel.left + anchors.right: parent.right + auto-focus: first + + Label + id: portLabel + !text: tr('Port:') + anchors.top: host.bottom + anchors.left: host.left + margin-top: 3 + margin-bottom: 2 + + TextEdit + id: port + text: 7171 + anchors.top: portLabel.bottom + anchors.left: portLabel.left + anchors.right: host.right + + Label + id: protocolLabel + !text: tr('Protocol:') + anchors.top: port.bottom + anchors.left: port.left + margin-top: 3 + margin-bottom: 2 + + ComboBox + id: protocol + anchors.top: protocolLabel.bottom + anchors.left: protocolLabel.left + anchors.right: port.right + @onSetup: | + for _, proto in pairs(g_game.getSupportedProtocols()) do + self:addOption(proto) + end + + Button + id: buttonAdd + !text: tr('Add') + width: 64 + anchors.right: parent.horizontalCenter + anchors.bottom: parent.bottom + margin-right: 5 + @onClick: | + AddServer.add() + + Button + id: buttonCancel + !text: tr('Cancel') + width: 64 + anchors.left: parent.horizontalCenter + anchors.bottom: parent.bottom + @onClick: AddServer.hide() diff --git a/modules/client_serverlist/serverlist.lua b/modules/client_serverlist/serverlist.lua new file mode 100644 index 00000000..48e88395 --- /dev/null +++ b/modules/client_serverlist/serverlist.lua @@ -0,0 +1,127 @@ +ServerList = {} + +-- private variables +local serverListWindow = nil +local serverTextList = nil +local servers = {} + +-- private functions +function getServer(host) + for k,server in pairs(servers) do + if server.host == host then + return server + end + end +end + +function getServerKey(host) + for k,server in pairs(servers) do + if server.host == host then + return k + end + end +end + +-- public functions +function ServerList.init() + serverListWindow = g_ui.displayUI('serverlist') + serverTextList = serverListWindow:getChildById('serverList') + + servers = g_settings.getNode('ServerList') or {} + ServerList.load() +end + +function ServerList.terminate() + ServerList.destroy() + + g_settings.setNode('ServerList', servers) + + ServerList = nil +end + +function ServerList.load() + for k,server in pairs(servers) do + ServerList.add(server.host, server.port, server.protocol, true) + end +end + +function ServerList.select() + local selected = serverTextList:getFocusedChild() + if selected then + local server = servers[getServerKey(selected:getId())] + if server then + EnterGame.setDefaultServer(server.host, server.port, server.protocol) + EnterGame.setAccountName(server.account) + EnterGame.setPassword(server.password) + ServerList.hide() + end + end +end + +function ServerList.add(host, port, protocol, load) + if not load and getServerKey(host) then + return false, 'Server already exists' + elseif host == '' or port == '' then + return false, 'Required fields are missing' + end + local widget = g_ui.createWidget('ServerWidget', serverTextList) + widget:setId(host) + + if not load then + servers[table.size(servers)+1] = { + host = host, + port = port, + protocol = protocol, + account = '', + password = '' + } + end + + local details = widget:getChildById('details') + details:setText(host..':'..port) + + local proto = widget:getChildById('protocol') + proto:setText(protocol) + + connect(widget, { onDoubleClick = function () ServerList.select() return true end } ) + return true +end + +function ServerList.remove(host) + servers[getServerKey(host)] = nil +end + +function ServerList.destroy() + if serverListWindow then + serverTextList = nil + serverListWindow:destroy() + serverListWindow = nil + end +end + +function ServerList.show() + if g_game.isOnline() then + return + end + serverListWindow:show() + serverListWindow:raise() + serverListWindow:focus() +end + +function ServerList.hide() + serverListWindow:hide() +end + +function ServerList.setServerAccount(host, account) + local key = getServerKey(host) + if servers[key] then + servers[key].account = account + end +end + +function ServerList.setServerPassword(host, password) + local key = getServerKey(host) + if servers[key] then + servers[key].password = password + end +end \ No newline at end of file diff --git a/modules/client_serverlist/serverlist.otmod b/modules/client_serverlist/serverlist.otmod new file mode 100644 index 00000000..75427090 --- /dev/null +++ b/modules/client_serverlist/serverlist.otmod @@ -0,0 +1,18 @@ +Module + name: client_serverlist + description: Manages a server list of previously entered servers + author: BeniS + website: www.otclient.info + + dependencies: + - client_entergame + + @onLoad: | + dofile 'serverlist' + dofile 'addserver' + ServerList.init() + AddServer.init() + + @onUnload: | + ServerList.terminate() + AddServer.terminate() diff --git a/modules/client_serverlist/serverlist.otui b/modules/client_serverlist/serverlist.otui new file mode 100644 index 00000000..8da715de --- /dev/null +++ b/modules/client_serverlist/serverlist.otui @@ -0,0 +1,113 @@ +ServerWidget < UIWidget + height: 14 + background-color: alpha + &updateOnStates: | + function(self) + local children = self:getChildren() + for i=1,#children do + children[i]:setOn(self:isFocused()) + end + end + @onFocusChange: self:updateOnStates() + @onSetup: self:updateOnStates() + + $focus: + background-color: #ffffff22 + + Label + id: details + color: #aaaaaa + anchors.top: parent.top + anchors.left: parent.left + font: verdana-11px-monochrome + text-auto-resize: true + background-color: alpha + text-offset: 2 0 + + $on: + color: #ffffff + + Label + id: protocol + color: #ffffff + color: #aaaaaa + anchors.top: parent.top + anchors.right: next.left + margin-right: 5 + font: verdana-11px-monochrome + text-auto-resize: true + background-color: alpha + &baseText: '(%s)' + + $on: + color: #ffffff + + Button + id: remove + !text: tr('x') + width: 12 + height: 12 + anchors.top: parent.top + anchors.right: parent.right + margin-right: 4 + margin-top: 1 + @onClick: | + local parent = self:getParent() + ServerList.remove(parent:getId()) + parent:destroy() + +MainWindow + id: serverListWindow + !text: tr('Server List') + size: 340 290 + visible: false + @onEnter: ServerList.select() + @onEscape: ServerList.hide() + @onSetup: | + g_keyboard.bindKeyPress('Up', function() self:getChildById('serverList'):focusPreviousChild(KeyboardFocusReason) end, self) + g_keyboard.bindKeyPress('Down', function() self:getChildById('serverList'):focusNextChild(KeyboardFocusReason) end, self) + + TextList + id: serverList + anchors.top: parent.top + anchors.left: parent.left + anchors.right: serverListScrollBar.left + anchors.bottom: buttonOk.top + margin-bottom: 5 + padding: 1 + focusable: false + vertical-scrollbar: serverListScrollBar + auto-focus: first + + VerticalScrollBar + id: serverListScrollBar + anchors.top: parent.top + anchors.bottom: buttonOk.top + anchors.right: parent.right + margin-bottom: 5 + step: 14 + pixels-scroll: true + + AddButton + id: buttonAdd + !tooltip: tr('Add new server') + anchors.left: parent.left + anchors.bottom: parent.bottom + @onClick: AddServer.show() + + Button + id: buttonOk + !text: tr('Select') + width: 64 + anchors.right: next.left + anchors.bottom: parent.bottom + margin-right: 10 + @onClick: ServerList.select() + + Button + id: buttonCancel + !text: tr('Cancel') + width: 64 + anchors.right: parent.right + anchors.bottom: parent.bottom + @onClick: ServerList.hide() \ No newline at end of file diff --git a/modules/corelib/table.lua b/modules/corelib/table.lua index c90c8545..8a7b0d59 100644 --- a/modules/corelib/table.lua +++ b/modules/corelib/table.lua @@ -146,7 +146,7 @@ end function table.size(t) local size = 0 - for i, n in pairs(table) do + for i, n in pairs(t) do size = size + 1 end