From ddec9627b859431d48837b8535912992f791e1a1 Mon Sep 17 00:00:00 2001 From: TheSumm Date: Sun, 18 Jan 2015 15:14:07 +0100 Subject: [PATCH] Protocol 10.72 (Authenticator) Support, Unjustified Points diplay - Unjustified Points (Better topbar icon would be nice) ![Unjustified Points](http://i.gyazo.com/81286f46d9b4d56b3fe864140173cf34.png) - Authenticator token support - adjusted 'can change pvp frame' to 1054 - ... --- data/images/game/skull_socket.png | Bin 0 -> 338 bytes data/images/topbuttons/unjustifiedpoints.png | Bin 0 -> 421 bytes modules/client_entergame/characterlist.lua | 14 +- modules/client_entergame/characterlist.otui | 6 +- modules/client_entergame/entergame.lua | 60 +++++++- modules/client_entergame/entergame.otui | 22 ++- modules/game_interface/interface.otmod | 1 + .../unjustifiedpoints.lua | 135 ++++++++++++++++++ .../unjustifiedpoints.otmod | 8 ++ .../unjustifiedpoints.otui | 80 +++++++++++ modules/gamelib/const.lua | 2 + modules/gamelib/creature.lua | 7 + modules/gamelib/game.lua | 2 +- modules/gamelib/protocollogin.lua | 37 ++++- src/client/const.h | 2 + src/client/game.cpp | 47 +++++- src/client/game.h | 33 ++++- src/client/luafunctions.cpp | 4 + src/client/luavaluecasts.cpp | 42 ++++++ src/client/luavaluecasts.h | 4 + src/client/protocolcodes.h | 1 + src/client/protocolgame.cpp | 3 +- src/client/protocolgame.h | 4 +- src/client/protocolgameparse.cpp | 39 +++-- src/client/protocolgamesend.cpp | 3 + 25 files changed, 525 insertions(+), 31 deletions(-) create mode 100644 data/images/game/skull_socket.png create mode 100644 data/images/topbuttons/unjustifiedpoints.png create mode 100644 modules/game_unjustifiedpoints/unjustifiedpoints.lua create mode 100644 modules/game_unjustifiedpoints/unjustifiedpoints.otmod create mode 100644 modules/game_unjustifiedpoints/unjustifiedpoints.otui diff --git a/data/images/game/skull_socket.png b/data/images/game/skull_socket.png new file mode 100644 index 0000000000000000000000000000000000000000..a2d30e2d65d30ea88e973a0837277cfe8e924975 GIT binary patch literal 338 zcmeAS@N?(olHy`uVBq!ia0vp@Ak4uAB#T}@sR2@KN#5=*4A~&q>6~Z;6yYrJh%9Dc z;1&j9Muu5)B!GhKC7!;n?DrXk7!@S)pQYFWh3mq)y?*lf%aZ96R5(LJJDGl1$Sr;Ud$!Z8Wm8f$51jY? zeEg^H$!%{9`!CgPpMLbw%U9EE&Odcxx{-HZg`>$>u`ju6(S*(F|4l7V8zo1I^*s)_ d{?+xo_-RFBUk_s@8K74gJYD@<);T3K0RTv*gKz)< literal 0 HcmV?d00001 diff --git a/data/images/topbuttons/unjustifiedpoints.png b/data/images/topbuttons/unjustifiedpoints.png new file mode 100644 index 0000000000000000000000000000000000000000..67245fa61ef796623cc8a5c183db1eda644bce9d GIT binary patch literal 421 zcmeAS@N?(olHy`uVBq!ia0vp^+#t-s1|(OmDOUqhjKx9jP7LeL$-D$|*pj^6T^Rm@ z;DWu&Cj&(|3p^r=fm(z?n2}-D90{Nxdx@v7EBhTrHc?3p*6M_ZKvPsbT^vIsE|*?3 z^p0i}Ir{N_HH(U-M`2H}QCW7gz`=&e@(VPrI_4`a?RFO5@4TCB;jSGPEj^Jf&lB1l zthd@!II*=)aq5hHRGN__&-%XR-OlfS{3l&Cx-f71VdKeHH?e4GKfM0&#%i1A4;ydx zTP*l3qHs3w$^dy#z7WUKK3}zb4{TF-V#)D6nO6UD-fA^`qhM-^VICWB)|$3QLGuZ*65=JY|_kYyaJK{1q2p zUdZ`%<-NUXYe$&&KEaJUCG$HYqPu^7(sc= 1072) +end + function EnterGame.doLogin() G.account = enterGame:getChildById('accountNameTextEdit'):getText() G.password = enterGame:getChildById('accountPasswordTextEdit'):getText() + G.authenticatorToken = enterGame:getChildById('authenticatorTokenTextEdit'):getText() G.host = enterGame:getChildById('serverHostTextEdit'):getText() G.port = tonumber(enterGame:getChildById('serverPortTextEdit'):getText()) local clientVersion = tonumber(clientBox:getText()) @@ -251,7 +296,7 @@ function EnterGame.doLogin() g_game.chooseRsa(G.host) if modules.game_things.isLoaded() then - protocolLogin:login(G.host, G.port, G.account, G.password) + protocolLogin:login(G.host, G.port, G.account, G.password, G.authenticatorToken) else loadBox:destroy() loadBox = nil @@ -272,6 +317,7 @@ function EnterGame.setDefaultServer(host, port, protocol) local clientLabel = enterGame:getChildById('clientLabel') local accountTextEdit = enterGame:getChildById('accountNameTextEdit') local passwordTextEdit = enterGame:getChildById('accountPasswordTextEdit') + local authenticatorTokenTextEdit = enterGame:getChildById('authenticatorTokenTextEdit') if hostTextEdit:getText() ~= host then hostTextEdit:setText(host) @@ -279,6 +325,7 @@ function EnterGame.setDefaultServer(host, port, protocol) clientBox:setCurrentOption(protocol) accountTextEdit:setText('') passwordTextEdit:setText('') + authenticatorTokenTextEdit:setText('') end end @@ -291,6 +338,13 @@ function EnterGame.setUniqueServer(host, port, protocol, windowWidth, windowHeig portTextEdit:setText(port) portTextEdit:setVisible(false) portTextEdit:setHeight(0) + local authenticatorTokenTextEdit = enterGame:getChildById('authenticatorTokenTextEdit') + authenticatorTokenTextEdit:setText('') + authenticatorTokenTextEdit:setVisible(false) + authenticatorTokenTextEdit:setHeight(0) + local authenticatorTokenLabel = enterGame:getChildById('authenticatorTokenLabel') + authenticatorTokenLabel:setVisible(false) + authenticatorTokenLabel:setHeight(0) clientBox:setCurrentOption(protocol) clientBox:setVisible(false) @@ -312,7 +366,7 @@ function EnterGame.setUniqueServer(host, port, protocol, windowWidth, windowHeig serverListButton:setWidth(0) local rememberPasswordBox = enterGame:getChildById('rememberPasswordBox') - rememberPasswordBox:setMarginTop(-5) + rememberPasswordBox:setMarginTop(-14) if not windowWidth then windowWidth = 236 end enterGame:setWidth(windowWidth) diff --git a/modules/client_entergame/entergame.otui b/modules/client_entergame/entergame.otui index 52c60e01..debb0ea9 100644 --- a/modules/client_entergame/entergame.otui +++ b/modules/client_entergame/entergame.otui @@ -21,6 +21,8 @@ ServerListButton < UIButton EnterGameWindow id: enterGame + &authenticatorEnabled: false + &authenticatorHeight: 44 @onEnter: EnterGame.doLogin() MenuLabel @@ -50,12 +52,30 @@ EnterGameWindow anchors.top: prev.bottom margin-top: 2 + MenuLabel + id: authenticatorTokenLabel + !text: tr('Authenticator Token') + anchors.left: prev.left + anchors.top: prev.bottom + text-auto-resize: true + margin-top: 8 + visible: false + + TextEdit + id: authenticatorTokenTextEdit + anchors.left: parent.left + anchors.right: parent.right + anchors.top: prev.bottom + margin-top: 2 + visible: false + max-length: 8 + MenuLabel id: serverLabel !text: tr('Server') anchors.left: prev.left anchors.top: prev.bottom - margin-top: 8 + margin-top: -36 text-auto-resize: true ServerListButton diff --git a/modules/game_interface/interface.otmod b/modules/game_interface/interface.otmod index 91f0973c..bdb40fd4 100644 --- a/modules/game_interface/interface.otmod +++ b/modules/game_interface/interface.otmod @@ -30,5 +30,6 @@ Module - game_spelllist - game_cooldown - game_modaldialog + - game_unjustifiedpoints @onLoad: init() @onUnload: terminate() diff --git a/modules/game_unjustifiedpoints/unjustifiedpoints.lua b/modules/game_unjustifiedpoints/unjustifiedpoints.lua new file mode 100644 index 00000000..ad01e15d --- /dev/null +++ b/modules/game_unjustifiedpoints/unjustifiedpoints.lua @@ -0,0 +1,135 @@ +unjustifiedPointsWindow = nil +unjustifiedPointsButton = nil +contentsPanel = nil + +openPvpSituationsLabel = nil +currentSkullWidget = nil +skullTimeLabel = nil + +dayProgressBar = nil +weekProgressBar = nil +monthProgressBar = nil + +daySkullWidget = nil +weekSkullWidget = nil +monthSkullWidget = nil + +function init() + connect(g_game, { onGameStart = online, + onUnjustifiedPointsChange = onUnjustifiedPointsChange, + onOpenPvpSituationsChange = onOpenPvpSituationsChange }) + connect(LocalPlayer, { onSkullChange = onSkullChange } ) + + unjustifiedPointsButton = modules.client_topmenu.addRightGameToggleButton('unjustifiedPointsButton', + tr('Unjustified Points'), '/images/topbuttons/unjustifiedpoints', toggle) + unjustifiedPointsButton:setOn(true) + unjustifiedPointsButton:hide() + + unjustifiedPointsWindow = g_ui.loadUI('unjustifiedpoints', modules.game_interface.getRightPanel()) + unjustifiedPointsWindow:disableResize() + unjustifiedPointsWindow:setup() + + contentsPanel = unjustifiedPointsWindow:getChildById('contentsPanel') + + openPvpSituationsLabel = contentsPanel:getChildById('openPvpSituationsLabel') + currentSkullWidget = contentsPanel:getChildById('currentSkullWidget') + skullTimeLabel = contentsPanel:getChildById('skullTimeLabel') + + dayProgressBar = contentsPanel:getChildById('dayProgressBar') + weekProgressBar = contentsPanel:getChildById('weekProgressBar') + monthProgressBar = contentsPanel:getChildById('monthProgressBar') + daySkullWidget = contentsPanel:getChildById('daySkullWidget') + weekSkullWidget = contentsPanel:getChildById('weekSkullWidget') + monthSkullWidget = contentsPanel:getChildById('monthSkullWidget') + + if g_game.isOnline() then + online() + end +end + +function terminate() + disconnect(g_game, { onGameStart = online, + onUnjustifiedPointsChange = onUnjustifiedPointsChange, + onOpenPvpSituationsChange = onOpenPvpSituationsChange }) + disconnect(LocalPlayer, { onSkullChange = onSkullChange } ) + + unjustifiedPointsWindow:destroy() + unjustifiedPointsButton:destroy() +end + +function onMiniWindowClose() + unjustifiedPointsButton:setOn(false) +end + +function toggle() + if unjustifiedPointsButton:isOn() then + unjustifiedPointsWindow:close() + unjustifiedPointsButton:setOn(false) + else + unjustifiedPointsWindow:open() + unjustifiedPointsButton:setOn(true) + end +end + +function online() + if g_game.getFeature(GameUnjustifiedPoints) then + unjustifiedPointsButton:show() + else + unjustifiedPointsButton:hide() + unjustifiedPointsWindow:close() + end + + refresh() +end + +function refresh() + local localPlayer = g_game.getLocalPlayer() + + local unjustifiedPoints = g_game.getUnjustifiedPoints() + onUnjustifiedPointsChange(unjustifiedPoints) + + onSkullChange(localPlayer, localPlayer:getSkull()) + onOpenPvpSituationsChange(g_game.getOpenPvpSituations()) +end + +function onSkullChange(localPlayer, skull) + if not localPlayer:isLocalPlayer() then return end + + if skull == SkullRed or skull == SkullBlack then + currentSkullWidget:setIcon(getSkullImagePath(skull)) + currentSkullWidget:setTooltip('Remaining skull time') + else + currentSkullWidget:setIcon('') + currentSkullWidget:setTooltip('You have no skull') + end + + daySkullWidget:setIcon(getSkullImagePath(getNextSkullId(skull))) + weekSkullWidget:setIcon(getSkullImagePath(getNextSkullId(skull))) + monthSkullWidget:setIcon(getSkullImagePath(getNextSkullId(skull))) +end + +function onOpenPvpSituationsChange(amount) + openPvpSituationsLabel:setText(amount) +end + +function onUnjustifiedPointsChange(unjustifiedPoints) + if unjustifiedPoints.skullTime == 0 then + skullTimeLabel:setText('No skull') + skullTimeLabel:setTooltip('You have no skull') + else + skullTimeLabel:setText(unjustifiedPoints.skullTime .. ' days') + skullTimeLabel:setTooltip('Remaining skull time') + end + + dayProgressBar:setValue(unjustifiedPoints.killsDay, 0, 100) + dayProgressBar:setTooltip(string.format('Unjustified points gained during the last 24 hours.\n%i kills left.', unjustifiedPoints.killsDayRemaining)) + dayProgressBar:setText(unjustifiedPoints.killsDayRemaining .. ' kills left') + + weekProgressBar:setValue(unjustifiedPoints.killsWeek, 0, 100) + weekProgressBar:setTooltip(string.format('Unjustified points gained during the last 7 days.\n%i kills left.', unjustifiedPoints.killsWeekRemaining)) + weekProgressBar:setText(unjustifiedPoints.killsWeekRemaining .. ' kills left') + + monthProgressBar:setValue(unjustifiedPoints.killsMonth, 0, 100) + monthProgressBar:setTooltip(string.format('Unjustified points gained during the last 30 days.\n%i kills left.', unjustifiedPoints.killsMonthRemaining)) + monthProgressBar:setText(unjustifiedPoints.killsMonthRemaining .. ' kills left') +end diff --git a/modules/game_unjustifiedpoints/unjustifiedpoints.otmod b/modules/game_unjustifiedpoints/unjustifiedpoints.otmod new file mode 100644 index 00000000..178a414d --- /dev/null +++ b/modules/game_unjustifiedpoints/unjustifiedpoints.otmod @@ -0,0 +1,8 @@ +Module + name: game_unjustifiedpoints + description: View unjustified points + author: Summ + sandboxed: true + scripts: [ unjustifiedpoints ] + @onLoad: init() + @onUnload: terminate() diff --git a/modules/game_unjustifiedpoints/unjustifiedpoints.otui b/modules/game_unjustifiedpoints/unjustifiedpoints.otui new file mode 100644 index 00000000..dc052464 --- /dev/null +++ b/modules/game_unjustifiedpoints/unjustifiedpoints.otui @@ -0,0 +1,80 @@ +SkullProgressBar < ProgressBar + height: 13 + margin: 4 18 0 10 + anchors.top: prev.bottom + anchors.left: parent.left + anchors.right: parent.right + +SkullWidget < UIWidget + size: 13 13 + margin-right: 2 + anchors.right: parent.right + image-source: /images/game/skull_socket + +MiniWindow + id: unjustifiedPointsWindow + !text: tr('Unjustified Points') + height: 114 + icon: /images/topbuttons/unjustifiedpoints + @onClose: modules.game_unjustifiedpoints.onMiniWindowClose() + &save: true + + MiniWindowContents + Label + anchors.top: parent.top + anchors.left: parent.left + !text: tr('Open PvP') + !tooltip: tr('Open PvP Situations') + phantom: false + margin-top: 2 + margin-left: 10 + + Label + id: openPvpSituationsLabel + anchors.top: prev.bottom + anchors.left: parent.left + font: verdana-11px-rounded + margin-left: 12 + phantom: false + + Label + anchors.top: parent.top + anchors.right: parent.right + !text: tr('Skull Time') + margin-top: 2 + margin-right: 10 + + SkullWidget + id: currentSkullWidget + anchors.top: prev.bottom + margin-right: 10 + + Label + id: skullTimeLabel + anchors.top: prev.top + anchors.right: prev.left + font: verdana-11px-rounded + margin-right: 6 + phantom: false + + SkullProgressBar + id: dayProgressBar + margin-top: 10 + + SkullWidget + id: daySkullWidget + anchors.top: prev.top + + SkullProgressBar + id: weekProgressBar + + SkullWidget + id: weekSkullWidget + anchors.top: prev.top + + SkullProgressBar + id: monthProgressBar + + SkullWidget + id: monthSkullWidget + anchors.top: prev.top diff --git a/modules/gamelib/const.lua b/modules/gamelib/const.lua index 16f1cfaf..a27b1fa4 100644 --- a/modules/gamelib/const.lua +++ b/modules/gamelib/const.lua @@ -127,6 +127,8 @@ GameLoginPacketEncryption = 63 GameClientVersion = 64 GameContentRevision = 65 GameExperienceBonus = 66 +GameAuthenticator = 67 +GameUnjustifiedPoints = 68 TextColors = { red = '#f55e5e', --'#c83200' diff --git a/modules/gamelib/creature.lua b/modules/gamelib/creature.lua index 5a734008..382c468c 100644 --- a/modules/gamelib/creature.lua +++ b/modules/gamelib/creature.lua @@ -35,6 +35,13 @@ NpcIconTradeQuest = 4 -- @} +function getNextSkullId(skullId) + if skullId == SkullRed or skullId == SkullBlack then + return SkullBlack + end + return SkullRed +end + function getSkullImagePath(skullId) local path if skullId == SkullYellow then diff --git a/modules/gamelib/game.lua b/modules/gamelib/game.lua index cc283d38..cc273b54 100644 --- a/modules/gamelib/game.lua +++ b/modules/gamelib/game.lua @@ -74,7 +74,7 @@ function g_game.getSupportedClients() 1040, 1041, 1050, 1051, 1052, 1053, 1054, 1055, 1056, 1057, 1058, 1059, 1060, 1061, 1062, - 1063, 1064, 1070, 1071 + 1063, 1064, 1070, 1071, 1072 } end diff --git a/modules/gamelib/protocollogin.lua b/modules/gamelib/protocollogin.lua index e3d20630..5d107eca 100644 --- a/modules/gamelib/protocollogin.lua +++ b/modules/gamelib/protocollogin.lua @@ -2,13 +2,15 @@ ProtocolLogin = extends(Protocol, "ProtocolLogin") LoginServerError = 10 +LoginServerTokenSuccess = 12 +LoginServerTokenError = 13 LoginServerUpdate = 17 LoginServerMotd = 20 LoginServerUpdateNeeded = 30 LoginServerCharacterList = 100 LoginServerExtendedCharacterList = 101 -function ProtocolLogin:login(host, port, accountName, accountPassword) +function ProtocolLogin:login(host, port, accountName, accountPassword, authenticatorToken) if string.len(host) == 0 or port == nil or port == 0 then signalcall(self.onLoginError, self, tr("You must enter a valid server address and port.")) return @@ -16,6 +18,7 @@ function ProtocolLogin:login(host, port, accountName, accountPassword) self.accountName = accountName self.accountPassword = accountPassword + self.authenticatorToken = authenticatorToken self.connectCallback = self.sendLoginPacket self:connect(host, port) @@ -78,7 +81,10 @@ function ProtocolLogin:sendLoginPacket() local paddingBytes = g_crypt.rsaGetSize() - (msg:getMessageSize() - offset) assert(paddingBytes >= 0) - msg:addPaddingBytes(paddingBytes, 0) + for i = 1, paddingBytes do + msg:addU8(math.random(0, 0xff)) + end + if g_game.getFeature(GameLoginPacketEncryption) then msg:encryptRsa() end @@ -86,10 +92,32 @@ function ProtocolLogin:sendLoginPacket() if g_game.getFeature(GameOGLInformation) then msg:addU8(1) --unknown msg:addU8(1) --unknown - msg:addString(g_graphics.getRenderer()) + + if g_game.getClientVersion() >= 1072 then + msg:addString(string.format('%s %s', g_graphics.getVendor(), g_graphics.getRenderer())) + else + msg:addString(g_graphics.getRenderer()) + end msg:addString(g_graphics.getVersion()) end + -- add RSA encrypted auth token + if g_game.getFeature(GameAuthenticator) then + offset = msg:getMessageSize() + + -- first RSA byte must be 0 + msg:addU8(0) + msg:addString(self.authenticatorToken) + + paddingBytes = g_crypt.rsaGetSize() - (msg:getMessageSize() - offset) + assert(paddingBytes >= 0) + for i = 1, paddingBytes do + msg:addU8(math.random(0, 0xff)) + end + + msg:encryptRsa() + end + if g_game.getFeature(GameProtocolChecksum) then self:enableChecksum() end @@ -116,6 +144,9 @@ function ProtocolLogin:onRecv(msg) self:parseMotd(msg) elseif opcode == LoginServerUpdateNeeded then signalcall(self.onLoginError, self, tr("Client needs update.")) + elseif opcode == LoginServerTokenError then + -- TODO: prompt for token here + signalcall(self.onLoginError, self, tr("Invalid authentification token.")) elseif opcode == LoginServerCharacterList then self:parseCharacterList(msg) elseif opcode == LoginServerExtendedCharacterList then diff --git a/src/client/const.h b/src/client/const.h index 902cb7d5..18ffa33b 100644 --- a/src/client/const.h +++ b/src/client/const.h @@ -399,6 +399,8 @@ namespace Otc GameClientVersion = 64, GameContentRevision = 65, GameExperienceBonus = 66, + GameAuthenticator = 67, + GameUnjustifiedPoints = 68, LastGameFeature = 101 }; diff --git a/src/client/game.cpp b/src/client/game.cpp index dde46699..fe133e3f 100644 --- a/src/client/game.cpp +++ b/src/client/game.cpp @@ -84,6 +84,7 @@ void Game::resetGameStates() m_localPlayer = nullptr; m_pingSent = 0; m_pingReceived = 0; + m_unjustifiedPoints = UnjustifiedPoints(); for(auto& it : m_containers) { const ContainerPtr& container = it.second; @@ -155,6 +156,11 @@ void Game::processLoginWait(const std::string& message, int time) g_lua.callGlobalField("g_game", "onLoginWait", message, time); } +void Game::processLoginToken(bool unknown) +{ + g_lua.callGlobalField("g_game", "onLoginToken", unknown); +} + void Game::processLogin() { g_lua.callGlobalField("g_game", "onLogin"); @@ -528,7 +534,7 @@ void Game::processWalkCancel(Otc::Direction direction) m_localPlayer->cancelWalk(direction); } -void Game::loginWorld(const std::string& account, const std::string& password, const std::string& worldName, const std::string& worldHost, int worldPort, const std::string& characterName) +void Game::loginWorld(const std::string& account, const std::string& password, const std::string& worldName, const std::string& worldHost, int worldPort, const std::string& characterName, const std::string& authenticatorToken) { if(m_protocolGame || isOnline()) stdext::throw_exception("Unable to login into a world while already online or logging."); @@ -543,7 +549,7 @@ void Game::loginWorld(const std::string& account, const std::string& password, c m_localPlayer->setName(characterName); m_protocolGame = ProtocolGamePtr(new ProtocolGame); - m_protocolGame->login(account, password, worldHost, (uint16)worldPort, characterName); + m_protocolGame->login(account, password, worldHost, (uint16)worldPort, characterName, authenticatorToken); m_characterName = characterName; m_worldName = worldName; } @@ -1204,6 +1210,31 @@ void Game::setPVPMode(Otc::PVPModes pvpMode) g_lua.callGlobalField("g_game", "onPVPModeChange", pvpMode); } +void Game::setUnjustifiedPoints(UnjustifiedPoints unjustifiedPoints) +{ + if(!canPerformGameAction()) + return; + if(!getFeature(Otc::GameUnjustifiedPoints)) + return; + if(m_unjustifiedPoints == unjustifiedPoints) + return; + + m_unjustifiedPoints = unjustifiedPoints; + g_lua.callGlobalField("g_game", "onUnjustifiedPointsChange", unjustifiedPoints); +} + +void Game::setOpenPvpSituations(int openPvpSituations) +{ + if(!canPerformGameAction()) + return; + if(m_openPvpSituations == openPvpSituations) + return; + + m_openPvpSituations = openPvpSituations; + g_lua.callGlobalField("g_game", "onOpenPvpSituationsChange", openPvpSituations); +} + + void Game::inspectNpcTrade(const ItemPtr& item) { if(!canPerformGameAction() || !item) @@ -1425,7 +1456,7 @@ void Game::setProtocolVersion(int version) if(isOnline()) stdext::throw_exception("Unable to change protocol version while online"); - if(version != 0 && (version < 740 || version > 1071)) + if(version != 0 && (version < 740 || version > 1072)) stdext::throw_exception(stdext::format("Protocol version %d not supported", version)); m_protocolVersion = version; @@ -1443,7 +1474,7 @@ void Game::setClientVersion(int version) if(isOnline()) stdext::throw_exception("Unable to change client version while online"); - if(version != 0 && (version < 740 || version > 1071)) + if(version != 0 && (version < 740 || version > 1072)) stdext::throw_exception(stdext::format("Client version %d not supported", version)); m_features.reset(); @@ -1563,6 +1594,10 @@ void Game::setClientVersion(int version) enableFeature(Otc::GameEnhancedAnimations); } + if(version >= 1053) { + enableFeature(Otc::GameUnjustifiedPoints); + } + if(version >= 1054) { enableFeature(Otc::GameExperienceBonus); } @@ -1575,6 +1610,10 @@ void Game::setClientVersion(int version) enableFeature(Otc::GameContentRevision); } + if(version >= 1072) { + enableFeature(Otc::GameAuthenticator); + } + m_clientVersion = version; g_lua.callGlobalField("g_game", "onClientVersionChange", version); diff --git a/src/client/game.h b/src/client/game.h index 1bf3228f..8d3a6a9b 100644 --- a/src/client/game.h +++ b/src/client/game.h @@ -36,6 +36,25 @@ #include +struct UnjustifiedPoints { + bool operator==(const UnjustifiedPoints& other) { + return killsDay == other.killsDay && + killsDayRemaining == other.killsDayRemaining && + killsWeek == other.killsWeek && + killsWeekRemaining == other.killsWeekRemaining && + killsMonth == other.killsMonth && + killsMonthRemaining == other.killsMonthRemaining && + skullTime == other.skullTime; + } + uint8 killsDay; + uint8 killsDayRemaining; + uint8 killsWeek; + uint8 killsWeekRemaining; + uint8 killsMonth; + uint8 killsMonthRemaining; + uint8 skullTime; +}; + typedef std::tuple Vip; //@bindsingleton g_game @@ -60,6 +79,7 @@ protected: void processLoginError(const std::string& error); void processLoginAdvice(const std::string& message); void processLoginWait(const std::string& message, int time); + void processLoginToken(bool unknown); void processLogin(); void processPendingGame(); void processEnterGame(); @@ -139,7 +159,7 @@ protected: public: // login related - void loginWorld(const std::string& account, const std::string& password, const std::string& worldName, const std::string& worldHost, int worldPort, const std::string& characterName); + void loginWorld(const std::string& account, const std::string& password, const std::string& worldName, const std::string& worldHost, int worldPort, const std::string& characterName, const std::string& authenticatorToken); void cancelLogin(); void forceLogout(); void safeLogout(); @@ -218,6 +238,12 @@ public: bool isSafeFight() { return m_safeFight; } Otc::PVPModes getPVPMode() { return m_pvpMode; } + // pvp related + void setUnjustifiedPoints(UnjustifiedPoints unjustifiedPoints); + UnjustifiedPoints getUnjustifiedPoints() { return m_unjustifiedPoints; }; + void setOpenPvpSituations(int openPvpSitations); + int getOpenPvpSituations() { return m_openPvpSituations; } + // npc trade related void inspectNpcTrade(const ItemPtr& item); void buyItem(const ItemPtr& item, int amount, bool ignoreCapacity, bool buyWithBackpack); @@ -304,6 +330,8 @@ public: int getServerBeat() { return m_serverBeat; } void setCanReportBugs(bool enable) { m_canReportBugs = enable; } bool canReportBugs() { return m_canReportBugs; } + void setExpertPvpMode(bool enable) { m_expertPvpMode = enable; } + bool getExpertPvpMode() { return m_expertPvpMode; } LocalPlayerPtr getLocalPlayer() { return m_localPlayer; } ProtocolGamePtr getProtocolGame() { return m_protocolGame; } std::string getCharacterName() { return m_characterName; } @@ -333,6 +361,7 @@ private: bool m_online; bool m_denyBotCall; bool m_dead; + bool m_expertPvpMode; int m_serverBeat; ticks_t m_ping; uint m_pingSent; @@ -345,6 +374,8 @@ private: Otc::ChaseModes m_chaseMode; Otc::PVPModes m_pvpMode; Otc::Direction m_lastWalkDir; + UnjustifiedPoints m_unjustifiedPoints; + int m_openPvpSituations; bool m_safeFight; bool m_canReportBugs; std::vector m_gmActions; diff --git a/src/client/luafunctions.cpp b/src/client/luafunctions.cpp index f8cdcccb..e4f8b60f 100644 --- a/src/client/luafunctions.cpp +++ b/src/client/luafunctions.cpp @@ -238,6 +238,10 @@ void Client::registerLuaFunctions() g_lua.bindSingletonFunction("g_game", "getChaseMode", &Game::getChaseMode, &g_game); g_lua.bindSingletonFunction("g_game", "getFightMode", &Game::getFightMode, &g_game); g_lua.bindSingletonFunction("g_game", "getPVPMode", &Game::getPVPMode, &g_game); + g_lua.bindSingletonFunction("g_game", "setUnjustifiedPoints", &Game::setUnjustifiedPoints, &g_game); + g_lua.bindSingletonFunction("g_game", "getUnjustifiedPoints", &Game::getUnjustifiedPoints, &g_game); + g_lua.bindSingletonFunction("g_game", "setOpenPvpSituations", &Game::setOpenPvpSituations, &g_game); + g_lua.bindSingletonFunction("g_game", "getOpenPvpSituations", &Game::getOpenPvpSituations, &g_game); g_lua.bindSingletonFunction("g_game", "isSafeFight", &Game::isSafeFight, &g_game); g_lua.bindSingletonFunction("g_game", "inspectNpcTrade", &Game::inspectNpcTrade, &g_game); g_lua.bindSingletonFunction("g_game", "buyItem", &Game::buyItem, &g_game); diff --git a/src/client/luavaluecasts.cpp b/src/client/luavaluecasts.cpp index a4c4e524..c2041a9e 100644 --- a/src/client/luavaluecasts.cpp +++ b/src/client/luavaluecasts.cpp @@ -165,3 +165,45 @@ bool luavalue_cast(int index, Light& light) } return false; } + +int push_luavalue(const UnjustifiedPoints& unjustifiedPoints) +{ + g_lua.createTable(0, 7); + g_lua.pushInteger(unjustifiedPoints.killsDay); + g_lua.setField("killsDay"); + g_lua.pushInteger(unjustifiedPoints.killsDayRemaining); + g_lua.setField("killsDayRemaining"); + g_lua.pushInteger(unjustifiedPoints.killsWeek); + g_lua.setField("killsWeek"); + g_lua.pushInteger(unjustifiedPoints.killsWeekRemaining); + g_lua.setField("killsWeekRemaining"); + g_lua.pushInteger(unjustifiedPoints.killsMonth); + g_lua.setField("killsMonth"); + g_lua.pushInteger(unjustifiedPoints.killsMonthRemaining); + g_lua.setField("killsMonthRemaining"); + g_lua.pushInteger(unjustifiedPoints.skullTime); + g_lua.setField("skullTime"); + return 1; +} + +bool luavalue_cast(int index, UnjustifiedPoints& unjustifiedPoints) +{ + if(g_lua.isTable(index)) { + g_lua.getField("killsDay", index); + unjustifiedPoints.killsDay = g_lua.popInteger(); + g_lua.getField("killsDayRemaining", index); + unjustifiedPoints.killsDayRemaining = g_lua.popInteger(); + g_lua.getField("killsWeek", index); + unjustifiedPoints.killsWeek = g_lua.popInteger(); + g_lua.getField("killsWeekRemaining", index); + unjustifiedPoints.killsWeekRemaining = g_lua.popInteger(); + g_lua.getField("killsMonth", index); + unjustifiedPoints.killsMonth = g_lua.popInteger(); + g_lua.getField("killsMonthRemaining", index); + unjustifiedPoints.killsMonthRemaining = g_lua.popInteger(); + g_lua.getField("skullTime", index); + unjustifiedPoints.skullTime = g_lua.popInteger(); + return true; + } + return false; +} diff --git a/src/client/luavaluecasts.h b/src/client/luavaluecasts.h index 8d35b19b..d4548bfb 100644 --- a/src/client/luavaluecasts.h +++ b/src/client/luavaluecasts.h @@ -44,4 +44,8 @@ bool luavalue_cast(int index, MarketData& data); int push_luavalue(const Light& light); bool luavalue_cast(int index, Light& light); +// unjustified points +int push_luavalue(const UnjustifiedPoints& unjustifiedPoints); +bool luavalue_cast(int index, UnjustifiedPoints& unjustifiedPoints); + #endif diff --git a/src/client/protocolcodes.h b/src/client/protocolcodes.h index 69780587..26fda831 100644 --- a/src/client/protocolcodes.h +++ b/src/client/protocolcodes.h @@ -50,6 +50,7 @@ namespace Proto { GameServerLoginAdvice = 21, GameServerLoginWait = 22, GameServerLoginSuccess = 23, + GameServerLoginToken = 24, GameServerPingBack = 29, GameServerPing = 30, GameServerChallenge = 31, diff --git a/src/client/protocolgame.cpp b/src/client/protocolgame.cpp index 0d3ba266..bab30ef1 100644 --- a/src/client/protocolgame.cpp +++ b/src/client/protocolgame.cpp @@ -26,10 +26,11 @@ #include "item.h" #include "localplayer.h" -void ProtocolGame::login(const std::string& accountName, const std::string& accountPassword, const std::string& host, uint16 port, const std::string& characterName) +void ProtocolGame::login(const std::string& accountName, const std::string& accountPassword, const std::string& host, uint16 port, const std::string& characterName, const std::string& authenticatorToken) { m_accountName = accountName; m_accountPassword = accountPassword; + m_authenticatorToken = authenticatorToken; m_characterName = characterName; connect(host, port); diff --git a/src/client/protocolgame.h b/src/client/protocolgame.h index 7be5b44c..6d65e8f9 100644 --- a/src/client/protocolgame.h +++ b/src/client/protocolgame.h @@ -31,7 +31,7 @@ class ProtocolGame : public Protocol { public: - void login(const std::string& accountName, const std::string& accountPassword, const std::string& host, uint16 port, const std::string& characterName); + void login(const std::string& accountName, const std::string& accountPassword, const std::string& host, uint16 port, const std::string& characterName, const std::string& authenticatorToken); void send(const OutputMessagePtr& outputMessage); void sendExtendedOpcode(uint8 opcode, const std::string& buffer); @@ -143,6 +143,7 @@ private: void parseLoginError(const InputMessagePtr& msg); void parseLoginAdvice(const InputMessagePtr& msg); void parseLoginWait(const InputMessagePtr& msg); + void parseLoginToken(const InputMessagePtr& msg); void parsePing(const InputMessagePtr& msg); void parsePingBack(const InputMessagePtr& msg); void parseChallenge(const InputMessagePtr& msg); @@ -246,6 +247,7 @@ private: stdext::boolean m_firstRecv; std::string m_accountName; std::string m_accountPassword; + std::string m_authenticatorToken; std::string m_characterName; LocalPlayerPtr m_localPlayer; }; diff --git a/src/client/protocolgameparse.cpp b/src/client/protocolgameparse.cpp index 0fd626cc..8853c150 100644 --- a/src/client/protocolgameparse.cpp +++ b/src/client/protocolgameparse.cpp @@ -79,6 +79,9 @@ void ProtocolGame::parseMessage(const InputMessagePtr& msg) case Proto::GameServerLoginWait: parseLoginWait(msg); break; + case Proto::GameServerLoginToken: + parseLoginToken(msg); + break; case Proto::GameServerPing: case Proto::GameServerPingBack: if((opcode == Proto::GameServerPing && g_game.getFeature(Otc::GameClientPing)) || @@ -385,11 +388,13 @@ void ProtocolGame::parseLogin(const InputMessagePtr& msg) } bool canReportBugs = msg->getU8(); - if(g_game.getClientVersion() >= 1053) + if(g_game.getClientVersion() >= 1054) msg->getU8(); // can change pvp frame option - if(g_game.getClientVersion() >= 1058) - msg->getU8(); // expert mode enabled + if(g_game.getClientVersion() >= 1058) { + int expertModeEnabled = msg->getU8(); + g_game.setExpertPvpMode(expertModeEnabled); + } m_localPlayer->setId(playerId); g_game.setServerBeat(serverBeat); @@ -428,19 +433,23 @@ void ProtocolGame::parsePreset(const InputMessagePtr& msg) void ProtocolGame::parseUnjustifiedStats(const InputMessagePtr& msg) { - // Unjustified Kills display since 10.55 - msg->getU8(); - msg->getU8(); - msg->getU8(); - msg->getU8(); - msg->getU8(); - msg->getU8(); - msg->getU8(); + UnjustifiedPoints unjustifiedPoints; + unjustifiedPoints.killsDay = msg->getU8(); + unjustifiedPoints.killsDayRemaining = msg->getU8(); + unjustifiedPoints.killsWeek = msg->getU8(); + unjustifiedPoints.killsWeekRemaining = msg->getU8(); + unjustifiedPoints.killsMonth = msg->getU8(); + unjustifiedPoints.killsMonthRemaining = msg->getU8(); + unjustifiedPoints.skullTime = msg->getU8(); + + g_game.setUnjustifiedPoints(unjustifiedPoints); } void ProtocolGame::parsePvpSituations(const InputMessagePtr& msg) { - msg->getU8(); // amount of open pvp situations + uint8 openPvpSituations = msg->getU8(); + + g_game.setOpenPvpSituations(openPvpSituations); } void ProtocolGame::parsePlayerHelpers(const InputMessagePtr& msg) @@ -501,6 +510,12 @@ void ProtocolGame::parseLoginWait(const InputMessagePtr& msg) g_game.processLoginWait(message, time); } +void ProtocolGame::parseLoginToken(const InputMessagePtr& msg) +{ + bool unknown = (msg->getU8() == 0); + g_game.processLoginToken(unknown); +} + void ProtocolGame::parsePing(const InputMessagePtr& msg) { g_game.processPing(); diff --git a/src/client/protocolgamesend.cpp b/src/client/protocolgamesend.cpp index a32ee396..f0e2d167 100644 --- a/src/client/protocolgamesend.cpp +++ b/src/client/protocolgamesend.cpp @@ -87,6 +87,9 @@ void ProtocolGame::sendLoginPacket(uint challengeTimestamp, uint8 challengeRando msg->addString(m_characterName); msg->addString(m_accountPassword); + if(g_game.getFeature(Otc::GameAuthenticator)) + msg->addString(m_authenticatorToken); + if(g_game.getFeature(Otc::GameChallengeOnLogin)) { msg->addU32(challengeTimestamp); msg->addU8(challengeRandom);