mirror of
https://github.com/ErikasKontenis/SabrehavenServer.git
synced 2025-10-15 06:54:54 +02:00
Resolve "Merge the best from 7.40 branch"
This commit is contained in:
300
SabrehavenOTClient/modules/gamelib/protocollogin.lua
Normal file
300
SabrehavenOTClient/modules/gamelib/protocollogin.lua
Normal file
@@ -0,0 +1,300 @@
|
||||
-- @docclass
|
||||
ProtocolLogin = extends(Protocol, "ProtocolLogin")
|
||||
|
||||
LoginServerError = 10
|
||||
LoginServerTokenSuccess = 12
|
||||
LoginServerTokenError = 13
|
||||
LoginServerUpdate = 17
|
||||
LoginServerMotd = 20
|
||||
LoginServerUpdateNeeded = 30
|
||||
LoginServerSessionKey = 40
|
||||
LoginServerCharacterList = 100
|
||||
LoginServerExtendedCharacterList = 101
|
||||
LoginServerProxyList = 110
|
||||
|
||||
-- Since 10.76
|
||||
LoginServerRetry = 10
|
||||
LoginServerErrorNew = 11
|
||||
|
||||
function ProtocolLogin:login(host, port, accountName, accountPassword, authenticatorToken, stayLogged)
|
||||
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
|
||||
end
|
||||
|
||||
self.accountName = accountName
|
||||
self.accountPassword = accountPassword
|
||||
self.authenticatorToken = authenticatorToken
|
||||
self.stayLogged = stayLogged
|
||||
self.connectCallback = self.sendLoginPacket
|
||||
|
||||
self:connect(host, port)
|
||||
end
|
||||
|
||||
function ProtocolLogin:cancelLogin()
|
||||
self:disconnect()
|
||||
end
|
||||
|
||||
function ProtocolLogin:sendLoginPacket()
|
||||
local msg = OutputMessage.create()
|
||||
msg:addU8(ClientOpcodes.ClientEnterAccount)
|
||||
msg:addU16(g_game.getOs())
|
||||
if g_game.getCustomProtocolVersion() > 0 then
|
||||
msg:addU16(g_game.getCustomProtocolVersion())
|
||||
else
|
||||
msg:addU16(g_game.getProtocolVersion())
|
||||
end
|
||||
|
||||
if g_game.getFeature(GameClientVersion) then
|
||||
msg:addU32(g_game.getClientVersion())
|
||||
end
|
||||
|
||||
if g_game.getFeature(GameContentRevision) then
|
||||
msg:addU16(g_things.getContentRevision())
|
||||
msg:addU16(0)
|
||||
else
|
||||
msg:addU32(g_things.getDatSignature())
|
||||
end
|
||||
msg:addU32(g_sprites.getSprSignature())
|
||||
msg:addU32(PIC_SIGNATURE)
|
||||
|
||||
if g_game.getFeature(GamePreviewState) then
|
||||
msg:addU8(0)
|
||||
end
|
||||
|
||||
local offset = msg:getMessageSize()
|
||||
if g_game.getFeature(GameLoginPacketEncryption) then
|
||||
-- first RSA byte must be 0
|
||||
msg:addU8(0)
|
||||
|
||||
-- xtea key
|
||||
self:generateXteaKey()
|
||||
local xteaKey = self:getXteaKey()
|
||||
msg:addU32(xteaKey[1])
|
||||
msg:addU32(xteaKey[2])
|
||||
msg:addU32(xteaKey[3])
|
||||
msg:addU32(xteaKey[4])
|
||||
end
|
||||
|
||||
if g_game.getFeature(GameAccountNames) then
|
||||
msg:addString(self.accountName)
|
||||
else
|
||||
msg:addU32(tonumber(self.accountName))
|
||||
msg:addU32(tonumber(self.accountName))
|
||||
end
|
||||
|
||||
msg:addString(self.accountPassword)
|
||||
|
||||
if self.getLoginExtendedData then
|
||||
local data = self:getLoginExtendedData()
|
||||
msg:addString(data)
|
||||
else
|
||||
msg:addString("OTCv8")
|
||||
local version = g_app.getVersion():split(" ")[1]:gsub("%.", "")
|
||||
if version:len() == 2 then
|
||||
version = version .. "0"
|
||||
end
|
||||
msg:addU16(tonumber(version))
|
||||
end
|
||||
|
||||
local paddingBytes = g_crypt.rsaGetSize() - (msg:getMessageSize() - offset)
|
||||
assert(paddingBytes >= 0)
|
||||
for i = 1, paddingBytes do
|
||||
msg:addU8(math.random(0, 0xff))
|
||||
end
|
||||
|
||||
if g_game.getFeature(GameLoginPacketEncryption) then
|
||||
msg:encryptRsa()
|
||||
end
|
||||
|
||||
if g_game.getFeature(GameOGLInformation) then
|
||||
msg:addU8(1) --unknown
|
||||
msg:addU8(1) --unknown
|
||||
|
||||
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)
|
||||
|
||||
if g_game.getFeature(GameSessionKey) then
|
||||
msg:addU8(booleantonumber(self.stayLogged))
|
||||
end
|
||||
|
||||
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(GamePacketSizeU32) then
|
||||
self:enableBigPackets()
|
||||
end
|
||||
|
||||
if g_game.getFeature(GameProtocolChecksum) then
|
||||
self:enableChecksum()
|
||||
end
|
||||
|
||||
self:send(msg)
|
||||
if g_game.getFeature(GameLoginPacketEncryption) then
|
||||
self:enableXteaEncryption()
|
||||
end
|
||||
self:recv()
|
||||
end
|
||||
|
||||
function ProtocolLogin:onConnect()
|
||||
self.gotConnection = true
|
||||
self:connectCallback()
|
||||
self.connectCallback = nil
|
||||
end
|
||||
|
||||
function ProtocolLogin:onRecv(msg)
|
||||
while not msg:eof() do
|
||||
local opcode = msg:getU8()
|
||||
if opcode == LoginServerErrorNew then
|
||||
self:parseError(msg)
|
||||
elseif opcode == LoginServerError then
|
||||
self:parseError(msg)
|
||||
elseif opcode == LoginServerMotd then
|
||||
self:parseMotd(msg)
|
||||
elseif opcode == LoginServerUpdateNeeded then
|
||||
signalcall(self.onLoginError, self, tr("Client needs update."))
|
||||
elseif opcode == LoginServerTokenSuccess then
|
||||
local unknown = msg:getU8()
|
||||
elseif opcode == LoginServerTokenError then
|
||||
-- TODO: prompt for token here
|
||||
local unknown = msg:getU8()
|
||||
signalcall(self.onLoginError, self, tr("Invalid authentification token."))
|
||||
elseif opcode == LoginServerCharacterList then
|
||||
self:parseCharacterList(msg)
|
||||
elseif opcode == LoginServerExtendedCharacterList then
|
||||
self:parseExtendedCharacterList(msg)
|
||||
elseif opcode == LoginServerUpdate then
|
||||
local signature = msg:getString()
|
||||
signalcall(self.onUpdateNeeded, self, signature)
|
||||
elseif opcode == LoginServerSessionKey then
|
||||
self:parseSessionKey(msg)
|
||||
elseif opcode == LoginServerProxyList then
|
||||
local proxies = {}
|
||||
local proxiesCount = msg:getU8()
|
||||
for i=1, proxiesCount do
|
||||
local host = msg:getString()
|
||||
local port = msg:getU16()
|
||||
local priority = msg:getU16()
|
||||
table.insert(proxies, {host=host, port=port, priority=priority})
|
||||
end
|
||||
signalcall(self.onProxyList, self, proxies)
|
||||
else
|
||||
self:parseOpcode(opcode, msg)
|
||||
end
|
||||
end
|
||||
self:disconnect()
|
||||
end
|
||||
|
||||
function ProtocolLogin:parseError(msg)
|
||||
local errorMessage = msg:getString()
|
||||
signalcall(self.onLoginError, self, errorMessage)
|
||||
end
|
||||
|
||||
function ProtocolLogin:parseMotd(msg)
|
||||
local motd = msg:getString()
|
||||
signalcall(self.onMotd, self, motd)
|
||||
end
|
||||
|
||||
function ProtocolLogin:parseSessionKey(msg)
|
||||
local sessionKey = msg:getString()
|
||||
signalcall(self.onSessionKey, self, sessionKey)
|
||||
end
|
||||
|
||||
function ProtocolLogin:parseCharacterList(msg)
|
||||
local characters = {}
|
||||
|
||||
if g_game.getClientVersion() > 1010 then
|
||||
local worlds = {}
|
||||
|
||||
local worldsCount = msg:getU8()
|
||||
for i=1, worldsCount do
|
||||
local world = {}
|
||||
local worldId = msg:getU8()
|
||||
world.worldName = msg:getString()
|
||||
world.worldIp = msg:getString()
|
||||
world.worldPort = msg:getU16()
|
||||
world.previewState = msg:getU8()
|
||||
worlds[worldId] = world
|
||||
end
|
||||
|
||||
local charactersCount = msg:getU8()
|
||||
for i=1, charactersCount do
|
||||
local character = {}
|
||||
local worldId = msg:getU8()
|
||||
character.name = msg:getString()
|
||||
character.worldName = worlds[worldId].worldName
|
||||
character.worldIp = worlds[worldId].worldIp
|
||||
character.worldPort = worlds[worldId].worldPort
|
||||
character.previewState = worlds[worldId].previewState
|
||||
characters[i] = character
|
||||
end
|
||||
|
||||
else
|
||||
local charactersCount = msg:getU8()
|
||||
for i=1,charactersCount do
|
||||
local character = {}
|
||||
character.name = msg:getString()
|
||||
character.worldName = msg:getString()
|
||||
character.worldIp = iptostring(msg:getU32())
|
||||
character.worldPort = msg:getU16()
|
||||
|
||||
if g_game.getFeature(GamePreviewState) then
|
||||
character.previewState = msg:getU8()
|
||||
end
|
||||
|
||||
characters[i] = character
|
||||
end
|
||||
end
|
||||
|
||||
local account = {}
|
||||
if g_game.getProtocolVersion() > 1077 then
|
||||
account.status = msg:getU8()
|
||||
account.subStatus = msg:getU8()
|
||||
|
||||
account.premDays = msg:getU32()
|
||||
if account.premDays ~= 0 and account.premDays ~= 65535 then
|
||||
account.premDays = math.floor((account.premDays - os.time()) / 86400)
|
||||
end
|
||||
else
|
||||
account.status = AccountStatus.Ok
|
||||
account.premDays = msg:getU16()
|
||||
account.subStatus = account.premDays > 0 and SubscriptionStatus.Premium or SubscriptionStatus.Free
|
||||
end
|
||||
|
||||
signalcall(self.onCharacterList, self, characters, account)
|
||||
end
|
||||
|
||||
function ProtocolLogin:parseExtendedCharacterList(msg)
|
||||
local characters = msg:getTable()
|
||||
local account = msg:getTable()
|
||||
local otui = msg:getString()
|
||||
signalcall(self.onCharacterList, self, characters, account, otui)
|
||||
end
|
||||
|
||||
function ProtocolLogin:parseOpcode(opcode, msg)
|
||||
signalcall(self.onOpcode, self, opcode, msg)
|
||||
end
|
||||
|
||||
function ProtocolLogin:onError(msg, code)
|
||||
local text = translateNetworkError(code, self:isConnecting(), msg)
|
||||
signalcall(self.onLoginError, self, text)
|
||||
end
|
Reference in New Issue
Block a user