Multi-protocol
Lots of chagnes to add multi protocol flexibility, not really completed yet, still have to rework text messages opcodes and other stuff, so this still a working in progress feature * Rework dat reader, the dat reader can now * dinamically detect dat version * Split game into gamelib and game_interface * Lots of other minor changes
@@ -16,7 +16,6 @@ Module
|
||||
- client_terminal
|
||||
- client_modulemanager
|
||||
- client_entergame
|
||||
- game
|
||||
|
||||
@onLoad: |
|
||||
dofile 'client'
|
||||
|
||||
@@ -11,7 +11,6 @@ function Background.init()
|
||||
local clientVersionLabel = background:getChildById('clientVersionLabel')
|
||||
clientVersionLabel:setText('OTClient ' .. g_app.getVersion() .. '\n' ..
|
||||
'Rev ' .. g_app.getBuildRevision() .. ' ('.. g_app.getBuildCommit() .. ')\n' ..
|
||||
'Protocol ' .. g_game.getProtocolVersion() .. '\n' ..
|
||||
'Built on ' .. g_app.getBuildDate())
|
||||
|
||||
if not g_game.isOnline() then
|
||||
|
||||
@@ -54,7 +54,7 @@ local function updateWait(timeStart, timeEnd)
|
||||
progressBar:setPercent(percent)
|
||||
|
||||
local label = waitingWindow:getChildById('timeLabel')
|
||||
label:setText('Trying to reconnect in ' .. timeStr .. ' seconds.')
|
||||
label:setText(tr('Trying to reconnect in %s seconds.', timeStr))
|
||||
|
||||
updateWaitEvent = scheduleEvent(function() updateWait(timeStart, timeEnd) end, 1000 * progressBar:getPercentPixels() / 100 * (timeEnd - timeStart))
|
||||
return true
|
||||
|
||||
@@ -5,6 +5,7 @@ local loadBox
|
||||
local enterGame
|
||||
local motdButton
|
||||
local enterGameButton
|
||||
local protocolBox
|
||||
|
||||
-- private functions
|
||||
local function onError(protocol, message, errorCode)
|
||||
@@ -66,6 +67,11 @@ function EnterGame.init()
|
||||
local host = g_settings.get('host')
|
||||
local port = g_settings.get('port')
|
||||
local autologin = g_settings.getBoolean('autologin')
|
||||
local protocol = g_settings.getInteger('protocol', 860)
|
||||
|
||||
if not protocol or protocol == 0 then
|
||||
protocol = 860
|
||||
end
|
||||
|
||||
if port == nil or port == 0 then port = 7171 end
|
||||
|
||||
@@ -77,6 +83,12 @@ function EnterGame.init()
|
||||
enterGame:getChildById('rememberPasswordBox'):setChecked(#account > 0)
|
||||
enterGame:getChildById('accountNameTextEdit'):focus()
|
||||
|
||||
protocolBox = enterGame:getChildById('protocolComboBox')
|
||||
for _i,proto in pairs(g_game.getSupportedProtocols()) do
|
||||
protocolBox:addOption(proto)
|
||||
end
|
||||
protocolBox:setCurrentOption(protocol)
|
||||
|
||||
-- only open entergame when app starts
|
||||
if not g_app.isRunning() then
|
||||
if #host > 0 and #password > 0 and #account > 0 and autologin then
|
||||
@@ -95,6 +107,7 @@ function EnterGame.terminate()
|
||||
enterGameButton = nil
|
||||
motdButton:destroy()
|
||||
motdButton = nil
|
||||
protocolBox = nil
|
||||
EnterGame = nil
|
||||
end
|
||||
|
||||
@@ -116,7 +129,6 @@ function EnterGame.openWindow()
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
function EnterGame.clearAccountFields()
|
||||
enterGame:getChildById('accountNameTextEdit'):clearText()
|
||||
enterGame:getChildById('accountPasswordTextEdit'):clearText()
|
||||
@@ -130,16 +142,18 @@ function EnterGame.doLogin()
|
||||
G.password = enterGame:getChildById('accountPasswordTextEdit'):getText()
|
||||
G.host = enterGame:getChildById('serverHostTextEdit'):getText()
|
||||
G.port = tonumber(enterGame:getChildById('serverPortTextEdit'):getText())
|
||||
local protocol = tonumber(protocolBox:getText())
|
||||
EnterGame.hide()
|
||||
|
||||
if G.host == '' or G.port == nil or G.port == 0 then
|
||||
local errorBox = displayErrorBox(tr('Login Error'), tr('Enter a valid server host and port to login.'))
|
||||
if g_game.isOnline() then
|
||||
local errorBox = displayErrorBox(tr('Login Error'), tr('Cannot login while already in game.'))
|
||||
connect(errorBox, { onOk = EnterGame.show })
|
||||
return
|
||||
end
|
||||
|
||||
g_settings.set('host', G.host)
|
||||
g_settings.set('port', G.port)
|
||||
g_settings.set('protocol', protocol)
|
||||
|
||||
local protocolLogin = ProtocolLogin.create()
|
||||
protocolLogin.onError = onError
|
||||
@@ -153,6 +167,8 @@ function EnterGame.doLogin()
|
||||
EnterGame.show()
|
||||
end })
|
||||
|
||||
g_game.chooseRsa(G.host)
|
||||
g_game.setProtocolVersion(protocol)
|
||||
protocolLogin:login(G.host, G.port, G.account, G.password)
|
||||
end
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
MainWindow
|
||||
id: enterGame
|
||||
!text: tr('Enter Game')
|
||||
size: 236 240
|
||||
size: 236 274
|
||||
@onEnter: EnterGame.doLogin()
|
||||
@onEscape: EnterGame.hide()
|
||||
|
||||
@@ -43,26 +43,43 @@ MainWindow
|
||||
TextEdit
|
||||
id: serverHostTextEdit
|
||||
!tooltip: tr('Make sure that your client uses\nthe correct game protocol version')
|
||||
anchors.left: serverLabel.left
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.top: serverLabel.bottom
|
||||
margin-top: 2
|
||||
width: 140
|
||||
|
||||
Label
|
||||
id: protocolLabel
|
||||
!text: tr('Protocol')
|
||||
anchors.left: parent.left
|
||||
anchors.top: serverHostTextEdit.bottom
|
||||
anchors.right: portLabel.left
|
||||
margin-right: 10
|
||||
margin-top: 8
|
||||
|
||||
ComboBox
|
||||
id: protocolComboBox
|
||||
anchors.left: protocolLabel.left
|
||||
anchors.right: protocolLabel.right
|
||||
anchors.top: protocolLabel.bottom
|
||||
margin-top: 2
|
||||
width: 90
|
||||
|
||||
Label
|
||||
id: portLabel
|
||||
!text: tr('Port')
|
||||
anchors.left: serverHostTextEdit.right
|
||||
anchors.top: serverLabel.top
|
||||
margin-left: 10
|
||||
text-auto-resize: true
|
||||
anchors.right: parent.right
|
||||
anchors.top: serverHostTextEdit.bottom
|
||||
margin-top: 8
|
||||
width: 70
|
||||
|
||||
TextEdit
|
||||
id: serverPortTextEdit
|
||||
text: 7171
|
||||
anchors.right: parent.right
|
||||
anchors.left: portLabel.left
|
||||
anchors.top: portLabel.bottom
|
||||
margin-top: 2
|
||||
width: 55
|
||||
|
||||
CheckBox
|
||||
id: rememberPasswordBox
|
||||
|
||||
@@ -55,4 +55,4 @@ function Extended.unregister(opcode)
|
||||
|
||||
callbacks[opcode] = nil
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
@@ -132,6 +132,7 @@ function getfsrcpath(depth)
|
||||
end
|
||||
|
||||
function resolvepath(filePath, depth)
|
||||
if not filePath then return nil end
|
||||
depth = depth or 1
|
||||
if filePath then
|
||||
if filePath:sub(0, 1) ~= '/' then
|
||||
|
||||
@@ -1,44 +0,0 @@
|
||||
Module
|
||||
name: game
|
||||
description: Contains game related classes
|
||||
author: OTClient team
|
||||
website: www.otclient.info
|
||||
|
||||
dependencies:
|
||||
- client_extended
|
||||
- client_background
|
||||
- game_tibiafiles
|
||||
|
||||
load-later:
|
||||
- game_interface
|
||||
- game_hotkeys
|
||||
- game_questlog
|
||||
- game_textmessage
|
||||
- game_console
|
||||
- game_outfit
|
||||
- game_healthinfo
|
||||
- game_skills
|
||||
- game_inventory
|
||||
- game_combatcontrols
|
||||
- game_containers
|
||||
- game_viplist
|
||||
- game_battle
|
||||
- game_minimap
|
||||
- game_npctrade
|
||||
- game_textwindow
|
||||
- game_playertrade
|
||||
- game_ruleviolation
|
||||
- game_bugreport
|
||||
- game_shaders
|
||||
- game_playerdeath
|
||||
- game_playermount
|
||||
- game_market
|
||||
|
||||
@onLoad: |
|
||||
dofile 'const'
|
||||
|
||||
dofile 'protocollogin'
|
||||
|
||||
dofile 'creature'
|
||||
dofile 'player'
|
||||
dofile 'market'
|
||||
@@ -224,7 +224,7 @@ function Battle.checkCreatureSkull(creature, skullId)
|
||||
if creature:getSkull() ~= SkullNone then
|
||||
skullWidget:setWidth(skullWidget:getHeight())
|
||||
local imagePath = getSkullImagePath(creature:getSkull())
|
||||
skullWidget:setImageSource('/game/' .. imagePath)
|
||||
skullWidget:setImageSource(imagePath)
|
||||
labelWidget:setMarginLeft(5)
|
||||
else
|
||||
skullWidget:setWidth(0)
|
||||
@@ -246,7 +246,7 @@ function Battle.checkCreatureEmblem(creature, emblemId)
|
||||
if emblemId ~= EmblemNone then
|
||||
emblemWidget:setWidth(emblemWidget:getHeight())
|
||||
local imagePath = getEmblemImagePath(emblemId)
|
||||
emblemWidget:setImageSource('/game/' .. imagePath)
|
||||
emblemWidget:setImageSource(imagePath)
|
||||
emblemWidget:setMarginLeft(5)
|
||||
labelWidget:setMarginLeft(5)
|
||||
else
|
||||
|
||||
@@ -4,6 +4,30 @@ Module
|
||||
author: OTClient team
|
||||
website: www.otclient.info
|
||||
|
||||
load-later:
|
||||
- game_hotkeys
|
||||
- game_questlog
|
||||
- game_textmessage
|
||||
- game_console
|
||||
- game_outfit
|
||||
- game_healthinfo
|
||||
- game_skills
|
||||
- game_inventory
|
||||
- game_combatcontrols
|
||||
- game_containers
|
||||
- game_viplist
|
||||
- game_battle
|
||||
- game_minimap
|
||||
- game_npctrade
|
||||
- game_textwindow
|
||||
- game_playertrade
|
||||
- game_ruleviolation
|
||||
- game_bugreport
|
||||
- game_shaders
|
||||
- game_playerdeath
|
||||
- game_playermount
|
||||
- game_market
|
||||
|
||||
@onLoad: |
|
||||
dofile 'widgets/uigamemap'
|
||||
dofile 'widgets/uiitem'
|
||||
|
||||
@@ -4,9 +4,6 @@ Module
|
||||
author: BeniS
|
||||
website: www.otclient.info
|
||||
|
||||
dependencies:
|
||||
- game
|
||||
|
||||
@onLoad: |
|
||||
dofile 'marketoffer'
|
||||
dofile 'marketprotocol'
|
||||
|
||||
@@ -32,7 +32,7 @@ MarketOffer.new = function(offerId, action, itemId, amount, price, playerName, s
|
||||
offer.player = playerName
|
||||
|
||||
state = tonumber(state)
|
||||
if state ~= MarketOfferState.Active and state ~= MarketOfferState.Cancelled
|
||||
if state ~= MarketOfferState.Active and state ~= MarketOfferState.Cancelled
|
||||
and state ~= MarketOfferState.Expired and state ~= MarketOfferState.Accepted then
|
||||
g_logger.error('MarketOffer.new - invalid state provided.')
|
||||
end
|
||||
|
||||
@@ -3,27 +3,6 @@ MarketProtocol = {}
|
||||
local market
|
||||
|
||||
-- private functions
|
||||
|
||||
local function parseOpcode(protocol, opcode, msg)
|
||||
if not g_game.getFeature(GamePlayerMarket) then
|
||||
return false
|
||||
end
|
||||
|
||||
-- process msg
|
||||
if opcode == GameServerOpcodes.GameServerMarketEnter then
|
||||
parseMarketEnter(msg)
|
||||
elseif opcode == GameServerOpcodes.GameServerMarketLeave then
|
||||
parseMarketLeave(msg)
|
||||
elseif opcode == GameServerOpcodes.GameServerMarketDetail then
|
||||
parseMarketDetail(msg)
|
||||
elseif opcode == GameServerOpcodes.GameServerMarketBrowse then
|
||||
parseMarketBrowse(msg)
|
||||
else
|
||||
return false
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
local function send(msg)
|
||||
print(msg:getMessageSize())
|
||||
g_game.getProtocolGame():safeSend(msg)
|
||||
@@ -49,12 +28,11 @@ local function readMarketOffer(msg, action, var)
|
||||
else
|
||||
playerName = msg:getString()
|
||||
end
|
||||
|
||||
|
||||
return MarketOffer.new({timestamp, counter}, action, itemId, amount, price, playerName, state)
|
||||
end
|
||||
|
||||
-- parsing protocols
|
||||
|
||||
local function parseMarketEnter(msg)
|
||||
local balance = msg:getU32()
|
||||
local offers = msg:getU8()
|
||||
@@ -128,14 +106,18 @@ local function parseMarketBrowse(msg)
|
||||
end
|
||||
|
||||
-- public functions
|
||||
|
||||
function MarketProtocol.init()
|
||||
connect(ProtocolGame, { onOpcode = parseOpcode } )
|
||||
|
||||
ProtocolGame.registerOpcode(GameServerOpcodes.GameServerMarketEnter, parseMarketEnter)
|
||||
ProtocolGame.registerOpcode(GameServerOpcodes.GameServerMarketLeave, parseMarketLeave)
|
||||
ProtocolGame.registerOpcode(GameServerOpcodes.GameServerMarketDetail, parseMarketDetail)
|
||||
ProtocolGame.registerOpcode(GameServerOpcodes.GameServerMarketBrowse, parseMarketBrowse)
|
||||
end
|
||||
|
||||
function MarketProtocol.terminate()
|
||||
disconnect(ProtocolGame, { onOpcode = parseOpcode } )
|
||||
ProtocolGame.unregisterOpcode(GameServerOpcodes.GameServerMarketEnter, parseMarketEnter)
|
||||
ProtocolGame.unregisterOpcode(GameServerOpcodes.GameServerMarketLeave, parseMarketLeave)
|
||||
ProtocolGame.unregisterOpcode(GameServerOpcodes.GameServerMarketDetail, parseMarketDetail)
|
||||
ProtocolGame.unregisterOpcode(GameServerOpcodes.GameServerMarketBrowse, parseMarketBrowse)
|
||||
|
||||
market = nil
|
||||
MarketProtocol = nil
|
||||
|
||||
@@ -34,11 +34,6 @@ SouthEast = 5
|
||||
SouthWest = 6
|
||||
NorthWest = 7
|
||||
|
||||
LoginServerError = 10
|
||||
LoginServerMotd = 20
|
||||
LoginServerUpdateNeeded = 30
|
||||
LoginServerCharacterList = 100
|
||||
|
||||
GameExtendedOpcode = 0
|
||||
GameProtocolChecksum = 1
|
||||
GameAccountNames = 2
|
||||
@@ -56,7 +51,7 @@ GameChannelPlayerList = 13
|
||||
GamePlayerMounts = 14
|
||||
GameEnvironmentEffect = 15
|
||||
GameCreatureType = 16
|
||||
GameCreatureAdditionalInfo = 17
|
||||
GameCreatureEmblems = 17
|
||||
GameCreaturePassableInfo = 18
|
||||
GameItemAnimationPhase = 19
|
||||
GameTrucatedPingOpcode = 20
|
||||
@@ -64,6 +59,25 @@ GameReverseCreatureStack = 21
|
||||
GameMagicEffectU16 = 22
|
||||
GamePlayerMarket = 23
|
||||
|
||||
OTSERV_RSA = "109120132967399429278860960508995541528237502902798129123468757937266291492576446330739696001110603907230888610072655818825358503429057592827629436413108566029093628212635953836686562675849720620786279431090218017681061521755056710823876476444260558147179707119674283982419152118103759076030616683978566631413"
|
||||
OTSERV_RSA = "1091201329673994292788609605089955415282375029027981291234687579" ..
|
||||
"3726629149257644633073969600111060390723088861007265581882535850" ..
|
||||
"3429057592827629436413108566029093628212635953836686562675849720" ..
|
||||
"6207862794310902180176810615217550567108238764764442605581471797" ..
|
||||
"07119674283982419152118103759076030616683978566631413"
|
||||
|
||||
-- @}
|
||||
CIPSOFT_RSA = "1321277432058722840622950990822933849527763264961655079678763618" ..
|
||||
"4334395343554449668205332383339435179772895415509701210392836078" ..
|
||||
"6959821132214473291575712138800495033169914814069637740318278150" ..
|
||||
"2907336840325241747827401343576296990629870233111328210165697754" ..
|
||||
"88792221429527047321331896351555606801473202394175817"
|
||||
|
||||
OsTypes = {
|
||||
Linux = 1,
|
||||
Windows = 2,
|
||||
Flash = 3,
|
||||
OtclientLinux = 10,
|
||||
OtclientWindows = 11,
|
||||
OtclientMac = 12
|
||||
}
|
||||
|
||||
-- @}
|
||||
@@ -30,73 +30,81 @@ EmblemBlue = 3
|
||||
-- @}
|
||||
|
||||
function getSkullImagePath(skullId)
|
||||
local path
|
||||
if skullId == SkullYellow then
|
||||
return 'icons/skull_yellow.png'
|
||||
path = 'icons/skull_yellow.png'
|
||||
elseif skullId == SkullGreen then
|
||||
return 'icons/skull_green.png'
|
||||
path = 'icons/skull_green.png'
|
||||
elseif skullId == SkullWhite then
|
||||
return 'icons/skull_white.png'
|
||||
path = 'icons/skull_white.png'
|
||||
elseif skullId == SkullRed then
|
||||
return 'icons/skull_red.png'
|
||||
path = 'icons/skull_red.png'
|
||||
elseif skullId == SkullBlack then
|
||||
return 'icons/skull_black.png'
|
||||
path = 'icons/skull_black.png'
|
||||
elseif skullId == SkullOrange then
|
||||
return 'icons/skull_orange.png'
|
||||
path = 'icons/skull_orange.png'
|
||||
end
|
||||
path = resolvepath(path)
|
||||
return path
|
||||
end
|
||||
|
||||
function getShieldImagePathAndBlink(shieldId)
|
||||
local path
|
||||
if shieldId == ShieldWhiteYellow then
|
||||
return 'icons/shield_yellow_white.png', false
|
||||
path = 'icons/shield_yellow_white.png', false
|
||||
elseif shieldId == ShieldWhiteBlue then
|
||||
return 'icons/shield_blue_white.png', false
|
||||
path = 'icons/shield_blue_white.png', false
|
||||
elseif shieldId == ShieldBlue then
|
||||
return 'icons/shield_blue.png', false
|
||||
path = 'icons/shield_blue.png', false
|
||||
elseif shieldId == ShieldYellow then
|
||||
return 'icons/shield_yellow.png', false
|
||||
path = 'icons/shield_yellow.png', false
|
||||
elseif shieldId == ShieldBlueSharedExp then
|
||||
return 'icons/shield_blue_shared.png', false
|
||||
path = 'icons/shield_blue_shared.png', false
|
||||
elseif shieldId == ShieldYellowSharedExp then
|
||||
return 'icons/shield_yellow_shared.png', false
|
||||
path = 'icons/shield_yellow_shared.png', false
|
||||
elseif shieldId == ShieldBlueNoSharedExpBlink then
|
||||
return 'icons/shield_blue_not_shared.png', true
|
||||
path = 'icons/shield_blue_not_shared.png', true
|
||||
elseif shieldId == ShieldYellowNoSharedExpBlink then
|
||||
return 'icons/shield_yellow_not_shared.png', true
|
||||
path = 'icons/shield_yellow_not_shared.png', true
|
||||
elseif shieldId == ShieldBlueNoSharedExp then
|
||||
return 'icons/shield_blue_not_shared.png', false
|
||||
path = 'icons/shield_blue_not_shared.png', false
|
||||
elseif shieldId == ShieldYellowNoSharedExp then
|
||||
return 'icons/shield_yellow_not_shared.png', false
|
||||
path = 'icons/shield_yellow_not_shared.png', false
|
||||
end
|
||||
path = resolvepath(path)
|
||||
return path
|
||||
end
|
||||
|
||||
function getEmblemImagePath(emblemId)
|
||||
local path
|
||||
if emblemId == EmblemGreen then
|
||||
return 'icons/emblem_green.png'
|
||||
path = 'icons/emblem_green.png'
|
||||
elseif emblemId == EmblemRed then
|
||||
return 'icons/emblem_red.png'
|
||||
path = 'icons/emblem_red.png'
|
||||
elseif emblemId == EmblemBlue then
|
||||
return 'icons/emblem_blue.png'
|
||||
path = 'icons/emblem_blue.png'
|
||||
end
|
||||
path = resolvepath(path)
|
||||
return path
|
||||
end
|
||||
|
||||
function Creature:onSkullChange(skullId)
|
||||
local imagePath = getSkullImagePath(skullId)
|
||||
if imagePath then
|
||||
self:setSkullTexture(resolvepath(imagePath))
|
||||
self:setSkullTexture(imagePath)
|
||||
end
|
||||
end
|
||||
|
||||
function Creature:onShieldChange(shieldId)
|
||||
local imagePath, blink = getShieldImagePathAndBlink(shieldId)
|
||||
if imagePath then
|
||||
self:setShieldTexture(resolvepath(imagePath), blink)
|
||||
self:setShieldTexture(imagePath, blink)
|
||||
end
|
||||
end
|
||||
|
||||
function Creature:onEmblemChange(emblemId)
|
||||
local imagePath = getEmblemImagePath(emblemId)
|
||||
if imagePath then
|
||||
self:setEmblemTexture(resolvepath(imagePath))
|
||||
self:setEmblemTexture(imagePath)
|
||||
end
|
||||
end
|
||||
|
||||
47
modules/gamelib/game.lua
Normal file
@@ -0,0 +1,47 @@
|
||||
local currentRsa = OTSERV_RSA
|
||||
|
||||
function g_game.getRsa()
|
||||
return currentRsa
|
||||
end
|
||||
|
||||
function g_game.chooseRsa(host)
|
||||
if host:match('.*\.tibia\.com') or host:match('.*\.cipsoft\.com') then
|
||||
currentRsa = CIPSOFT_RSA
|
||||
else
|
||||
currentRsa = OTSERV_RSA
|
||||
end
|
||||
end
|
||||
|
||||
function g_game.setRsa(rsa)
|
||||
currentRsa = rsa
|
||||
end
|
||||
|
||||
function g_game.isOfficialTibia()
|
||||
return currentRsa == CIPSOFT_RSA
|
||||
end
|
||||
|
||||
function g_game.getOsType()
|
||||
if g_game.isOfficialTibia() then
|
||||
if g_app.getOs() == 'windows' then
|
||||
return OsTypes.Windows
|
||||
else
|
||||
return OsTypes.Linux
|
||||
end
|
||||
else
|
||||
if g_app.getOs() == 'windows' then
|
||||
return OsTypes.OtclientWindows
|
||||
elseif g_app.getOs() == 'mac' then
|
||||
return OsTypes.OtclientMac
|
||||
else
|
||||
return OsTypes.OtclientLinux
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function g_game.getSupportedProtocols()
|
||||
return {
|
||||
810, 853, 854, 860, 861, 862, 870, 940,
|
||||
953, 954, 960
|
||||
}
|
||||
end
|
||||
|
||||
20
modules/gamelib/gamelib.otmod
Normal file
@@ -0,0 +1,20 @@
|
||||
Module
|
||||
name: gamelib
|
||||
description: Contains game related classes
|
||||
author: OTClient team
|
||||
website: www.otclient.info
|
||||
|
||||
dependencies:
|
||||
- client_extended
|
||||
- game_tibiafiles
|
||||
|
||||
@onLoad: |
|
||||
dofile 'const'
|
||||
|
||||
dofile 'protocollogin'
|
||||
dofile 'protocolgame'
|
||||
dofile 'game'
|
||||
|
||||
dofile 'creature'
|
||||
dofile 'player'
|
||||
dofile 'market'
|
||||
|
Before Width: | Height: | Size: 385 B After Width: | Height: | Size: 385 B |
|
Before Width: | Height: | Size: 381 B After Width: | Height: | Size: 381 B |
|
Before Width: | Height: | Size: 386 B After Width: | Height: | Size: 386 B |
|
Before Width: | Height: | Size: 352 B After Width: | Height: | Size: 352 B |
|
Before Width: | Height: | Size: 522 B After Width: | Height: | Size: 522 B |
|
Before Width: | Height: | Size: 516 B After Width: | Height: | Size: 516 B |
|
Before Width: | Height: | Size: 404 B After Width: | Height: | Size: 404 B |
|
Before Width: | Height: | Size: 377 B After Width: | Height: | Size: 377 B |
|
Before Width: | Height: | Size: 512 B After Width: | Height: | Size: 512 B |
|
Before Width: | Height: | Size: 494 B After Width: | Height: | Size: 494 B |
|
Before Width: | Height: | Size: 407 B After Width: | Height: | Size: 407 B |
|
Before Width: | Height: | Size: 482 B After Width: | Height: | Size: 482 B |
|
Before Width: | Height: | Size: 438 B After Width: | Height: | Size: 438 B |
|
Before Width: | Height: | Size: 445 B After Width: | Height: | Size: 445 B |
|
Before Width: | Height: | Size: 421 B After Width: | Height: | Size: 421 B |
|
Before Width: | Height: | Size: 437 B After Width: | Height: | Size: 437 B |
|
Before Width: | Height: | Size: 437 B After Width: | Height: | Size: 437 B |
@@ -52,4 +52,3 @@ function Player:hasVip(creatureName)
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
23
modules/gamelib/protocolgame.lua
Normal file
@@ -0,0 +1,23 @@
|
||||
local opcodeCallbacks = {}
|
||||
|
||||
function ProtocolGame:onOpcode(opcode, msg)
|
||||
for i, callback in pairs(opcodeCallbacks) do
|
||||
if i == opcode then
|
||||
callback(msg)
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function ProtocolGame.registerOpcode(opcode, callback)
|
||||
if opcodeCallbacks[opcode] then
|
||||
error('opcode ' .. opcode .. ' already registered will be overriden')
|
||||
end
|
||||
|
||||
opcodeCallbacks[opcode] = callback
|
||||
end
|
||||
|
||||
function ProtocolGame.unregisterOpcode(opcode)
|
||||
opcodeCallbacks[opcode] = nil
|
||||
end
|
||||
@@ -1,16 +1,25 @@
|
||||
-- @docclass
|
||||
ProtocolLogin = extends(Protocol)
|
||||
|
||||
-- set to the latest Tibia.pic signature to make otclient compatible with official tibia
|
||||
local PIC_SIGNATURE = 0
|
||||
|
||||
LoginServerError = 10
|
||||
LoginServerMotd = 20
|
||||
LoginServerUpdateNeeded = 30
|
||||
LoginServerCharacterList = 100
|
||||
|
||||
|
||||
-- private functions
|
||||
local function sendLoginPacket(protocol)
|
||||
local msg = OutputMessage.create()
|
||||
msg:addU8(ClientOpcodes.ClientEnterAccount)
|
||||
msg:addU16(1) -- todo: ClientOs
|
||||
msg:addU16(g_game.getClientVersion())
|
||||
msg:addU16(g_game.getOsType())
|
||||
msg:addU16(g_game.getProtocolVersion())
|
||||
|
||||
msg:addU32(g_things.getDatSignature())
|
||||
msg:addU32(g_sprites.getSprSignature())
|
||||
msg:addU32(0) -- todo: pic signature
|
||||
msg:addU32(PIC_SIGNATURE)
|
||||
|
||||
local paddingBytes = 128
|
||||
msg:addU8(0) -- first RSA byte must be 0
|
||||
@@ -40,7 +49,7 @@ local function sendLoginPacket(protocol)
|
||||
end
|
||||
|
||||
msg:addPaddingBytes(paddingBytes, 0)
|
||||
msg:encryptRSA(128, OTSERV_RSA) -- todo: check whether to use cip or ot rsa
|
||||
msg:encryptRsa(128, g_game.getRsa())
|
||||
|
||||
protocol:send(msg)
|
||||
protocol:enableXteaEncryption()
|
||||
@@ -60,7 +69,7 @@ function ProtocolLogin:onRecv(msg)
|
||||
elseif opcode == LoginServerMotd then
|
||||
self:parseMotd(msg)
|
||||
elseif opcode == LoginServerUpdateNeeded then
|
||||
signalcall(self.onError, self, "Client needs update.")
|
||||
signalcall(self.onError, self, tr("Client needs update."))
|
||||
elseif opcode == LoginServerCharacterList then
|
||||
self:parseCharacterList(msg)
|
||||
else
|
||||
@@ -77,7 +86,11 @@ end
|
||||
|
||||
function ProtocolLogin:login(host, port, accountName, accountPassword)
|
||||
if string.len(accountName) == 0 or string.len(accountPassword) == 0 then
|
||||
signalcall(self.onError, self, "You must enter an account name and password.")
|
||||
signalcall(self.onError, self, tr("You must enter an account name and password."))
|
||||
return
|
||||
end
|
||||
if string.len(host) == 0 or port == nil or port == 0 then
|
||||
signalcall(self.onError, self, tr("You must enter a valid server address and port."))
|
||||
return
|
||||
end
|
||||
|
||||