mirror of
https://github.com/OTCv8/otclientv8.git
synced 2026-01-21 09:56:23 +01:00
Version 1.4 - Websockets and bug fixes
This commit is contained in:
@@ -108,12 +108,6 @@ if ($conn->connect_error) {
|
|||||||
die("SQL connection failed: " . $conn->connect_error);
|
die("SQL connection failed: " . $conn->connect_error);
|
||||||
}
|
}
|
||||||
|
|
||||||
if($data->quick == 1) {
|
|
||||||
require_once("quick.php");
|
|
||||||
|
|
||||||
die();
|
|
||||||
}
|
|
||||||
|
|
||||||
$account = $data->account;
|
$account = $data->account;
|
||||||
if($encryption == "sha1")
|
if($encryption == "sha1")
|
||||||
$password = sha1($data->password);
|
$password = sha1($data->password);
|
||||||
|
|||||||
BIN
data/images/ui/qauth.png
Normal file
BIN
data/images/ui/qauth.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.4 KiB |
8
init.lua
8
init.lua
@@ -12,13 +12,13 @@ Services = {
|
|||||||
feedback = "http://otclient.ovh/api/feedback.php"
|
feedback = "http://otclient.ovh/api/feedback.php"
|
||||||
}
|
}
|
||||||
|
|
||||||
-- Servers accept http login url or ip:port:version
|
-- Servers accept http login url, websocket login url or ip:port:version
|
||||||
Servers = {
|
Servers = {
|
||||||
OTClientV8 = "http://otclient.ovh/api/login.php",
|
OTClientV8 = "http://otclient.ovh/api/login.php",
|
||||||
|
OTClientV8Websocket = "wss://otclient.ovh:3000/",
|
||||||
OTClientV8proxy = "http://otclient.ovh/api/login.php?proxy=1",
|
OTClientV8proxy = "http://otclient.ovh/api/login.php?proxy=1",
|
||||||
OTClientV8classic = "otclient.ovh:7171:1099",
|
OTClientV8c = "otclient.ovh:7171:1099:25:30:80:90",
|
||||||
OTClientV8cwithfeatures = "otclient.ovh:7171:1099:25:30:80:90",
|
OTClientV8Test = "http://otclient.ovh/api/login2.php",
|
||||||
OTClientV8Test = "http://otclient.ovh/api/login2.php"
|
|
||||||
}
|
}
|
||||||
ALLOW_CUSTOM_SERVERS = true -- if true it shows option ANOTHER on server list
|
ALLOW_CUSTOM_SERVERS = true -- if true it shows option ANOTHER on server list
|
||||||
-- CONFIG END
|
-- CONFIG END
|
||||||
|
|||||||
@@ -50,11 +50,7 @@ StaticMainWindow
|
|||||||
@onSetup: |
|
@onSetup: |
|
||||||
g_keyboard.bindKeyPress('Up', function() self:getChildById('characters'):focusPreviousChild(KeyboardFocusReason) end, self)
|
g_keyboard.bindKeyPress('Up', function() self:getChildById('characters'):focusPreviousChild(KeyboardFocusReason) end, self)
|
||||||
g_keyboard.bindKeyPress('Down', function() self:getChildById('characters'):focusNextChild(KeyboardFocusReason) end, self)
|
g_keyboard.bindKeyPress('Down', function() self:getChildById('characters'):focusNextChild(KeyboardFocusReason) end, self)
|
||||||
if g_game.getFeature(GamePreviewState) then
|
|
||||||
self:setSize({width = 350, height = 400})
|
self:setSize({width = 350, height = 400})
|
||||||
else
|
|
||||||
self:setSize({width = 250, height = 248})
|
|
||||||
end
|
|
||||||
|
|
||||||
TextList
|
TextList
|
||||||
id: characters
|
id: characters
|
||||||
|
|||||||
@@ -9,10 +9,6 @@ local protocolLogin
|
|||||||
local server = nil
|
local server = nil
|
||||||
local versionsFound = false
|
local versionsFound = false
|
||||||
|
|
||||||
local newLogin = nil
|
|
||||||
local newLoginUrl = nil
|
|
||||||
local newLoginEvent
|
|
||||||
|
|
||||||
local customServerSelectorPanel
|
local customServerSelectorPanel
|
||||||
local serverSelectorPanel
|
local serverSelectorPanel
|
||||||
local serverSelector
|
local serverSelector
|
||||||
@@ -21,6 +17,8 @@ local serverHostTextEdit
|
|||||||
local rememberPasswordBox
|
local rememberPasswordBox
|
||||||
local protos = {"740", "760", "772", "800", "810", "854", "860", "1077", "1090", "1096", "1098", "1099", "1100"}
|
local protos = {"740", "760", "772", "800", "810", "854", "860", "1077", "1090", "1096", "1098", "1099", "1100"}
|
||||||
|
|
||||||
|
local webSocket
|
||||||
|
local webSocketLoginPacket
|
||||||
|
|
||||||
-- private functions
|
-- private functions
|
||||||
local function onProtocolError(protocol, message, errorCode)
|
local function onProtocolError(protocol, message, errorCode)
|
||||||
@@ -125,6 +123,10 @@ local function onHTTPResult(data, err)
|
|||||||
if #incorrectThings > 0 then
|
if #incorrectThings > 0 then
|
||||||
g_logger.info(incorrectThings)
|
g_logger.info(incorrectThings)
|
||||||
if Updater then
|
if Updater then
|
||||||
|
if webSocket then
|
||||||
|
webSocket:close()
|
||||||
|
webSocket = nil
|
||||||
|
end
|
||||||
return Updater.updateThings(things, incorrectThings)
|
return Updater.updateThings(things, incorrectThings)
|
||||||
else
|
else
|
||||||
return EnterGame.onError(incorrectThings)
|
return EnterGame.onError(incorrectThings)
|
||||||
@@ -175,6 +177,10 @@ local function onHTTPResult(data, err)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if webSocket then
|
||||||
|
webSocket:close()
|
||||||
|
webSocket = nil
|
||||||
|
end
|
||||||
onCharacterList(nil, characters, account, nil)
|
onCharacterList(nil, characters, account, nil)
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -244,7 +250,10 @@ end
|
|||||||
function EnterGame.terminate()
|
function EnterGame.terminate()
|
||||||
g_keyboard.unbindKeyDown('Ctrl+G')
|
g_keyboard.unbindKeyDown('Ctrl+G')
|
||||||
|
|
||||||
removeEvent(newLoginEvent)
|
if webSocket then
|
||||||
|
webSocket.close()
|
||||||
|
webSocket = nil
|
||||||
|
end
|
||||||
|
|
||||||
enterGame:destroy()
|
enterGame:destroy()
|
||||||
if newLogin then
|
if newLogin then
|
||||||
@@ -269,7 +278,7 @@ function EnterGame.show()
|
|||||||
enterGame:raise()
|
enterGame:raise()
|
||||||
enterGame:focus()
|
enterGame:focus()
|
||||||
enterGame:getChildById('accountNameTextEdit'):focus()
|
enterGame:getChildById('accountNameTextEdit'):focus()
|
||||||
EnterGame.checkNewLogin()
|
EnterGame.checkWebsocket()
|
||||||
end
|
end
|
||||||
|
|
||||||
function EnterGame.hide()
|
function EnterGame.hide()
|
||||||
@@ -294,33 +303,74 @@ function EnterGame.clearAccountFields()
|
|||||||
g_settings.remove('password')
|
g_settings.remove('password')
|
||||||
end
|
end
|
||||||
|
|
||||||
function EnterGame.hideNewLogin()
|
function EnterGame.checkWebsocket()
|
||||||
newLogin:hide()
|
if enterGame:isHidden() then return end
|
||||||
newLoginUrl = nil
|
local url = serverHostTextEdit:getText()
|
||||||
|
if url:find("ws://") == nil and url:find("wss://") == nil then
|
||||||
|
if webSocket then
|
||||||
|
webSocket:close()
|
||||||
|
webSocket = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
function EnterGame.checkNewLoginEvent()
|
|
||||||
newLoginEvent = scheduleEvent(function() EnterGame.checkNewLoginEvent() end, 1000)
|
|
||||||
EnterGame.checkNewLogin()
|
|
||||||
end
|
|
||||||
|
|
||||||
function EnterGame.checkNewLogin()
|
|
||||||
if not newLoginUrl then
|
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
local url = newLoginUrl
|
if webSocket then
|
||||||
HTTP.postJSON(newLoginUrl, { quick = 1 }, function(data, err)
|
if webSocket.url == url then
|
||||||
if url ~= newLoginUrl then return end
|
if newLogin:isHidden() and newLogin.code:getText():len() > 1 then
|
||||||
if err then return end
|
newLogin:show()
|
||||||
if not data["qrcode"] then return end
|
newLogin:raise()
|
||||||
newLogin.qrcode:setImageSourceBase64(data["qrcode"])
|
end
|
||||||
newLogin.code:setText(data["code"])
|
return
|
||||||
|
end
|
||||||
|
webSocket:close()
|
||||||
|
webSocket = nil
|
||||||
|
end
|
||||||
|
newLogin.code:setText("")
|
||||||
|
webSocket = HTTP.WebSocketJSON(url, {
|
||||||
|
onOpen = function(message, webSocketId)
|
||||||
|
if webSocket and webSocket.id == webSocketId then
|
||||||
|
webSocket.send({type="init", uid=G.uuid, version=APP_VERSION})
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
onMessage = function(message, webSocketId)
|
||||||
|
if webSocket and webSocket.id == webSocketId then
|
||||||
|
if message.type == "login" then
|
||||||
|
webSocketLoginPacket = nil
|
||||||
|
onHTTPResult(message, nil)
|
||||||
|
elseif message.type == "quick_login" and message.code and message.qrcode then
|
||||||
|
EnterGame.showNewLogin(message.code, message.qrcode)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
onClose = function(message, webSocketId)
|
||||||
|
if webSocket and webSocket.id == webSocketId then
|
||||||
|
webSocket = nil
|
||||||
|
if webSocketLoginPacket then
|
||||||
|
webSocketLoginPacket = nil
|
||||||
|
onHTTPResult(nil, "WebSocket disconnected")
|
||||||
|
end
|
||||||
|
EnterGame.checkWebsocket() -- reconnect
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
onError = function(message, webSocketId)
|
||||||
|
if webSocket and webSocket.id == webSocketId then
|
||||||
|
-- handle error
|
||||||
|
end
|
||||||
|
end
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
function EnterGame.hideNewLogin()
|
||||||
|
newLogin:hide()
|
||||||
|
end
|
||||||
|
|
||||||
|
function EnterGame.showNewLogin(code, qrcode)
|
||||||
if enterGame:isHidden() then return end
|
if enterGame:isHidden() then return end
|
||||||
|
newLogin.code:setText(code)
|
||||||
|
newLogin.qrcode:setQRCode(qrcode, 1)
|
||||||
if newLogin:isHidden() then
|
if newLogin:isHidden() then
|
||||||
newLogin:show()
|
newLogin:show()
|
||||||
newLogin:raise()
|
newLogin:raise()
|
||||||
end
|
end
|
||||||
end)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function EnterGame.onServerChange()
|
function EnterGame.onServerChange()
|
||||||
@@ -338,8 +388,7 @@ function EnterGame.onServerChange()
|
|||||||
end
|
end
|
||||||
if Servers and Servers[server] ~= nil then
|
if Servers and Servers[server] ~= nil then
|
||||||
serverHostTextEdit:setText(Servers[server])
|
serverHostTextEdit:setText(Servers[server])
|
||||||
newLoginUrl = Servers[server]
|
EnterGame.checkWebsocket()
|
||||||
EnterGame.checkNewLogin()
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -371,6 +420,9 @@ function EnterGame.doLogin()
|
|||||||
g_settings.set('client-version', G.clientVersion)
|
g_settings.set('client-version', G.clientVersion)
|
||||||
g_settings.save()
|
g_settings.save()
|
||||||
|
|
||||||
|
if G.host:find("ws://") ~= nil or G.host:find("wss://") ~= nil then
|
||||||
|
return EnterGame.doLoginWs()
|
||||||
|
end
|
||||||
if G.host:find("http") ~= nil then
|
if G.host:find("http") ~= nil then
|
||||||
return EnterGame.doLoginHttp()
|
return EnterGame.doLoginHttp()
|
||||||
end
|
end
|
||||||
@@ -446,6 +498,36 @@ function EnterGame.doLogin()
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function EnterGame.doLoginWs()
|
||||||
|
-- PREVIEW, need to implement websocket reconnect and error handling
|
||||||
|
if G.host == nil or G.host:len() < 10 then
|
||||||
|
return EnterGame.onError("Invalid server url: " .. G.host)
|
||||||
|
end
|
||||||
|
if not webSocket then
|
||||||
|
return EnterGame.onError("There's no websocket connection to: " .. G.host)
|
||||||
|
end
|
||||||
|
|
||||||
|
loadBox = displayCancelBox(tr('Please wait'), tr('Connecting to login server...'))
|
||||||
|
connect(loadBox, { onCancel = function(msgbox)
|
||||||
|
loadBox = nil
|
||||||
|
webSocketLoginPacket = nil
|
||||||
|
EnterGame.show()
|
||||||
|
end })
|
||||||
|
|
||||||
|
local data = {
|
||||||
|
type = "login",
|
||||||
|
account = G.account,
|
||||||
|
password = G.password,
|
||||||
|
token = G.authenticatorToken,
|
||||||
|
version = APP_VERSION,
|
||||||
|
uid = G.UUID
|
||||||
|
}
|
||||||
|
webSocketLoginPacket = data
|
||||||
|
webSocket.send(data)
|
||||||
|
EnterGame.hide()
|
||||||
|
end
|
||||||
|
|
||||||
function EnterGame.doLoginHttp()
|
function EnterGame.doLoginHttp()
|
||||||
if G.host == nil or G.host:len() < 10 then
|
if G.host == nil or G.host:len() < 10 then
|
||||||
return EnterGame.onError("Invalid server url: " .. G.host)
|
return EnterGame.onError("Invalid server url: " .. G.host)
|
||||||
|
|||||||
@@ -4,21 +4,33 @@ StaticWindow
|
|||||||
margin-right: 20
|
margin-right: 20
|
||||||
id: newLoginPanel
|
id: newLoginPanel
|
||||||
width: 230
|
width: 230
|
||||||
height: 330
|
height: 350
|
||||||
!text: tr('Quick Login & Registration')
|
!text: tr('Quick Login & Registration')
|
||||||
|
|
||||||
Label
|
Label
|
||||||
id: qrcode
|
id: qrcode
|
||||||
width: 200
|
width: 200
|
||||||
height: 180
|
height: 200
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
image-fixed-ratio: true
|
||||||
|
image-smooth: false
|
||||||
margin-top: 5
|
margin-top: 5
|
||||||
|
|
||||||
Label
|
Label
|
||||||
anchors.top: prev.bottom
|
id: quathlogo
|
||||||
anchors.left: prev.left
|
width: 66
|
||||||
anchors.right: prev.right
|
height: 40
|
||||||
|
anchors.verticalCenter: prev.verticalCenter
|
||||||
|
anchors.horizontalCenter: prev.horizontalCenter
|
||||||
|
image-fixed-ratio: true
|
||||||
|
image-smooth: false
|
||||||
|
image-source: /images/ui/qauth
|
||||||
|
|
||||||
|
Label
|
||||||
|
anchors.top: qrcode.bottom
|
||||||
|
anchors.left: qrcode.left
|
||||||
|
anchors.right: qrcode.right
|
||||||
text-align: center
|
text-align: center
|
||||||
text-auto-resize: true
|
text-auto-resize: true
|
||||||
!text: tr("Scan QR code or process\nbellow code to register or login")
|
!text: tr("Scan QR code or process\nbellow code to register or login")
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ function terminate()
|
|||||||
end
|
end
|
||||||
|
|
||||||
function show()
|
function show()
|
||||||
if Services.feedback == nil or Services.feedback:len() < 4 then
|
if not Services or not Services.feedback or Services.feedback:len() < 4 then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -303,8 +303,8 @@ function setOption(key, value, force)
|
|||||||
end
|
end
|
||||||
--elseif key == 'ignoreServerDirection' then
|
--elseif key == 'ignoreServerDirection' then
|
||||||
-- g_game.ignoreServerDirection(value)
|
-- g_game.ignoreServerDirection(value)
|
||||||
elseif key == 'realDirection' then
|
--elseif key == 'realDirection' then
|
||||||
g_game.showRealDirection(value)
|
-- g_game.showRealDirection(value)
|
||||||
elseif key == 'hotkeyDelay' then
|
elseif key == 'hotkeyDelay' then
|
||||||
generalPanel:getChildById('hotkeyDelayLabel'):setText(tr('Hotkey delay: %s ms', value))
|
generalPanel:getChildById('hotkeyDelayLabel'):setText(tr('Hotkey delay: %s ms', value))
|
||||||
elseif key == 'walkFirstStepDelay' then
|
elseif key == 'walkFirstStepDelay' then
|
||||||
|
|||||||
@@ -49,6 +49,11 @@ function init()
|
|||||||
|
|
||||||
updateFps()
|
updateFps()
|
||||||
|
|
||||||
|
if not Services or not Services.feedback or Services.feedback:len() < 4 then
|
||||||
|
topMenu.reportBug:setVisible(false)
|
||||||
|
topMenu.reportBug:setWidth(0)
|
||||||
|
end
|
||||||
|
|
||||||
if HIDE_TOPMENU then
|
if HIDE_TOPMENU then
|
||||||
topMenu:setHeight(0)
|
topMenu:setHeight(0)
|
||||||
topMenu:hide()
|
topMenu:hide()
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
HTTP = {
|
HTTP = {
|
||||||
timeout=5,
|
timeout=5,
|
||||||
|
websocketTimeout=15,
|
||||||
imageId=1000,
|
imageId=1000,
|
||||||
images={},
|
images={},
|
||||||
operations={}
|
operations={}
|
||||||
@@ -55,6 +56,30 @@ function HTTP.downloadImage(url, callback)
|
|||||||
return operation
|
return operation
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function HTTP.webSocket(url, callbacks, jsonWebsocket)
|
||||||
|
local operation = g_http.ws(url, HTTP.websocketTimeout)
|
||||||
|
HTTP.operations[operation] = {type="ws", json=jsonWebsocket, url=url, callbacks=callbacks}
|
||||||
|
return {
|
||||||
|
id = operation,
|
||||||
|
url = url,
|
||||||
|
close = function()
|
||||||
|
g_http.wsClose(operation)
|
||||||
|
end,
|
||||||
|
send = function(message)
|
||||||
|
if type(message) == "table" then
|
||||||
|
message = json.encode(message)
|
||||||
|
end
|
||||||
|
g_http.wsSend(operation, message)
|
||||||
|
end
|
||||||
|
}
|
||||||
|
end
|
||||||
|
HTTP.WebSocket = HTTP.webSocket
|
||||||
|
|
||||||
|
function HTTP.webSocketJSON(url, callbacks)
|
||||||
|
return HTTP.webSocket(url, callbacks, true)
|
||||||
|
end
|
||||||
|
HTTP.WebSocketJSON = HTTP.webSocketJSON
|
||||||
|
|
||||||
function HTTP.cancel(operationId)
|
function HTTP.cancel(operationId)
|
||||||
return g_http.cancel(operationId)
|
return g_http.cancel(operationId)
|
||||||
end
|
end
|
||||||
@@ -71,6 +96,9 @@ function HTTP.onGet(operationId, url, err, data)
|
|||||||
local status, result = pcall(function() return json.decode(data) end)
|
local status, result = pcall(function() return json.decode(data) end)
|
||||||
if not status then
|
if not status then
|
||||||
err = "JSON ERROR: " .. result
|
err = "JSON ERROR: " .. result
|
||||||
|
if data and data:len() > 0 then
|
||||||
|
err = err .. " (" .. data:sub(1, 100) .. ")"
|
||||||
|
end
|
||||||
end
|
end
|
||||||
data = result
|
data = result
|
||||||
end
|
end
|
||||||
@@ -99,6 +127,9 @@ function HTTP.onPost(operationId, url, err, data)
|
|||||||
local status, result = pcall(function() return json.decode(data) end)
|
local status, result = pcall(function() return json.decode(data) end)
|
||||||
if not status then
|
if not status then
|
||||||
err = "JSON ERROR: " .. result
|
err = "JSON ERROR: " .. result
|
||||||
|
if data and data:len() > 0 then
|
||||||
|
err = err .. " (" .. data:sub(1, 100) .. ")"
|
||||||
|
end
|
||||||
end
|
end
|
||||||
data = result
|
data = result
|
||||||
end
|
end
|
||||||
@@ -142,6 +173,64 @@ function HTTP.onDownloadProgress(operationId, url, progress, speed)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function HTTP.onWsOpen(operationId, message)
|
||||||
|
local operation = HTTP.operations[operationId]
|
||||||
|
if operation == nil then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
if operation.callbacks.onOpen then
|
||||||
|
operation.callbacks.onOpen(message, operationId)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function HTTP.onWsMessage(operationId, message)
|
||||||
|
local operation = HTTP.operations[operationId]
|
||||||
|
if operation == nil then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
if operation.callbacks.onMessage then
|
||||||
|
if operation.json then
|
||||||
|
local status, result = pcall(function() return json.decode(message) end)
|
||||||
|
local err = nil
|
||||||
|
if not status then
|
||||||
|
err = "JSON ERROR: " .. result
|
||||||
|
if message and message:len() > 0 then
|
||||||
|
err = err .. " (" .. message:sub(1, 100) .. ")"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if err then
|
||||||
|
if operation.callbacks.onError then
|
||||||
|
operation.callbacks.onError(err, operationId)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
operation.callbacks.onMessage(result, operationId)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
operation.callbacks.onMessage(message, operationId)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function HTTP.onWsClose(operationId, message)
|
||||||
|
local operation = HTTP.operations[operationId]
|
||||||
|
if operation == nil then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
if operation.callbacks.onClose then
|
||||||
|
operation.callbacks.onClose(message, operationId)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function HTTP.onWsError(operationId, message)
|
||||||
|
local operation = HTTP.operations[operationId]
|
||||||
|
if operation == nil then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
if operation.callbacks.onError then
|
||||||
|
operation.callbacks.onError(message, operationId)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
connect(g_http,
|
connect(g_http,
|
||||||
{
|
{
|
||||||
onGet = HTTP.onGet,
|
onGet = HTTP.onGet,
|
||||||
@@ -149,6 +238,10 @@ connect(g_http,
|
|||||||
onPost = HTTP.onPost,
|
onPost = HTTP.onPost,
|
||||||
onPostProgress = HTTP.onPostProgress,
|
onPostProgress = HTTP.onPostProgress,
|
||||||
onDownload = HTTP.onDownload,
|
onDownload = HTTP.onDownload,
|
||||||
onDownloadProgress = HTTP.onDownloadProgress
|
onDownloadProgress = HTTP.onDownloadProgress,
|
||||||
|
onWsOpen = HTTP.onWsOpen,
|
||||||
|
onWsMessage = HTTP.onWsMessage,
|
||||||
|
onWsClose = HTTP.onWsClose,
|
||||||
|
onWsError = HTTP.onWsError,
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -227,6 +227,9 @@ function checkCreatures()
|
|||||||
end
|
end
|
||||||
|
|
||||||
local player = g_game.getLocalPlayer()
|
local player = g_game.getLocalPlayer()
|
||||||
|
if not player then
|
||||||
|
return
|
||||||
|
end
|
||||||
local dimension = modules.game_interface.getMapPanel():getVisibleDimension()
|
local dimension = modules.game_interface.getMapPanel():getVisibleDimension()
|
||||||
local spectators = g_map.getSpectatorsInRangeEx(player:getPosition(), false, math.floor(dimension.width / 2), math.floor(dimension.width / 2), math.floor(dimension.height / 2), math.floor(dimension.height / 2))
|
local spectators = g_map.getSpectatorsInRangeEx(player:getPosition(), false, math.floor(dimension.width / 2), math.floor(dimension.width / 2), math.floor(dimension.height / 2), math.floor(dimension.height / 2))
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
MiniWindow
|
MiniWindow
|
||||||
id: botWindow
|
id: botWindow
|
||||||
!text: tr('Bot')
|
!text: tr('Bot')
|
||||||
height: 200
|
height: 600
|
||||||
icon: /images/topbuttons/bot
|
icon: /images/topbuttons/bot
|
||||||
@onClose: modules.game_bot.onMiniWindowClose()
|
@onClose: modules.game_bot.onMiniWindowClose()
|
||||||
&save: true
|
&save: true
|
||||||
@@ -16,7 +16,7 @@ MiniWindow
|
|||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
margin-top: 5
|
margin-top: 2
|
||||||
margin-right: 90
|
margin-right: 90
|
||||||
text-offset: 3 0
|
text-offset: 3 0
|
||||||
|
|
||||||
@@ -43,7 +43,7 @@ MiniWindow
|
|||||||
anchors.top: prev.bottom
|
anchors.top: prev.bottom
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
margin-top: 5
|
margin-top: 3
|
||||||
text-auto-resize: true
|
text-auto-resize: true
|
||||||
!text: tr('Status: waiting')
|
!text: tr('Status: waiting')
|
||||||
text-align: center
|
text-align: center
|
||||||
@@ -53,7 +53,7 @@ MiniWindow
|
|||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.top: prev.bottom
|
anchors.top: prev.bottom
|
||||||
margin-top: 5
|
margin-top: 3
|
||||||
|
|
||||||
Panel
|
Panel
|
||||||
anchors.top: prev.bottom
|
anchors.top: prev.bottom
|
||||||
@@ -75,7 +75,7 @@ MiniWindow
|
|||||||
anchors.top: prev.bottom
|
anchors.top: prev.bottom
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
tab-spacing: 2
|
tab-spacing: 1
|
||||||
height: 20
|
height: 20
|
||||||
movable: false
|
movable: false
|
||||||
|
|
||||||
|
|||||||
@@ -10,9 +10,9 @@ botDefaultConfig = {
|
|||||||
--#panels
|
--#panels
|
||||||
|
|
||||||
local healTab = addTab("HP")
|
local healTab = addTab("HP")
|
||||||
local attackTab = addTab("Atck")
|
local batTab = addTab("Batt")
|
||||||
local warTab = addTab("War")
|
|
||||||
local caveTab = addTab("Cave")
|
local caveTab = addTab("Cave")
|
||||||
|
local toolsTab = addTab("Tools")
|
||||||
|
|
||||||
Panels.TradeMessage()
|
Panels.TradeMessage()
|
||||||
Panels.AutoStackItems()
|
Panels.AutoStackItems()
|
||||||
@@ -45,12 +45,12 @@ Panels.Equip(healTab)
|
|||||||
Panels.Equip(healTab)
|
Panels.Equip(healTab)
|
||||||
Panels.Eating(healTab)
|
Panels.Eating(healTab)
|
||||||
|
|
||||||
Panels.AttackSpell(attackTab)
|
Panels.AttackSpell(batTab)
|
||||||
Panels.AttackItem(attackTab)
|
Panels.AttackItem(batTab)
|
||||||
|
|
||||||
Panels.AttackLeaderTarget(warTab)
|
Panels.AttackLeaderTarget(batTab)
|
||||||
Panels.LimitFloor(warTab)
|
Panels.LimitFloor(batTab)
|
||||||
Panels.AntiPush(warTab)
|
Panels.AntiPush(batTab)
|
||||||
|
|
||||||
local waypoints = Panels.Waypoints(caveTab)
|
local waypoints = Panels.Waypoints(caveTab)
|
||||||
local attacking = Panels.Attacking(caveTab)
|
local attacking = Panels.Attacking(caveTab)
|
||||||
@@ -61,6 +61,18 @@ end, caveTab)
|
|||||||
|
|
||||||
--#macros
|
--#macros
|
||||||
|
|
||||||
|
macro(1000, "exchange money", function()
|
||||||
|
local containers = getContainers()
|
||||||
|
for i, container in pairs(containers) do
|
||||||
|
for j, item in ipairs(container:getItems()) do
|
||||||
|
if item:isStackable() and (item:getId() == 3035 or item:getId() == 3031) and item:getCount() == 100 then
|
||||||
|
g_game.use(item)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
macro(1000, "this macro does nothing", "f7", function()
|
macro(1000, "this macro does nothing", "f7", function()
|
||||||
|
|
||||||
end)
|
end)
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ context.playSound = function(file)
|
|||||||
end
|
end
|
||||||
botSoundChannel:setEnabled(true)
|
botSoundChannel:setEnabled(true)
|
||||||
botSoundChannel:stop(0)
|
botSoundChannel:stop(0)
|
||||||
botSoundChannel:play(file, 0, 0)
|
botSoundChannel:play(file, 0, 1.0)
|
||||||
return botSoundChannel
|
return botSoundChannel
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -456,7 +456,7 @@ Panels.Attacking = function(parent)
|
|||||||
local ui = context.setupUI([[
|
local ui = context.setupUI([[
|
||||||
Panel
|
Panel
|
||||||
id: attacking
|
id: attacking
|
||||||
height: 150
|
height: 140
|
||||||
|
|
||||||
BotLabel
|
BotLabel
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
@@ -486,7 +486,7 @@ Panel
|
|||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
text: Add
|
text: Add
|
||||||
width: 60
|
width: 60
|
||||||
height: 20
|
height: 17
|
||||||
|
|
||||||
Button
|
Button
|
||||||
id: edit
|
id: edit
|
||||||
@@ -494,7 +494,7 @@ Panel
|
|||||||
anchors.horizontalCenter: parent.horizontalCenter
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
text: Edit
|
text: Edit
|
||||||
width: 60
|
width: 60
|
||||||
height: 20
|
height: 17
|
||||||
|
|
||||||
Button
|
Button
|
||||||
id: remove
|
id: remove
|
||||||
@@ -502,7 +502,7 @@ Panel
|
|||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
text: Remove
|
text: Remove
|
||||||
width: 60
|
width: 60
|
||||||
height: 20
|
height: 17
|
||||||
|
|
||||||
TextList
|
TextList
|
||||||
id: list
|
id: list
|
||||||
@@ -531,7 +531,7 @@ Panel
|
|||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
text: Add
|
text: Add
|
||||||
width: 60
|
width: 60
|
||||||
height: 20
|
height: 17
|
||||||
|
|
||||||
Button
|
Button
|
||||||
id: mEdit
|
id: mEdit
|
||||||
@@ -539,7 +539,7 @@ Panel
|
|||||||
anchors.horizontalCenter: parent.horizontalCenter
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
text: Edit
|
text: Edit
|
||||||
width: 60
|
width: 60
|
||||||
height: 20
|
height: 17
|
||||||
|
|
||||||
Button
|
Button
|
||||||
id: mRemove
|
id: mRemove
|
||||||
@@ -547,7 +547,7 @@ Panel
|
|||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
text: Remove
|
text: Remove
|
||||||
width: 60
|
width: 60
|
||||||
height: 20
|
height: 17
|
||||||
|
|
||||||
]], parent)
|
]], parent)
|
||||||
|
|
||||||
@@ -897,6 +897,9 @@ Panel
|
|||||||
if #lootContainers == 0 or not context.storage.looting.enabled then
|
if #lootContainers == 0 or not context.storage.looting.enabled then
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
if modules.game_walking.lastManualWalk + 500 > context.now then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
local pos = context.player:getPosition()
|
local pos = context.player:getPosition()
|
||||||
table.sort(lootContainers, function(pos1, pos2)
|
table.sort(lootContainers, function(pos1, pos2)
|
||||||
@@ -993,7 +996,7 @@ Panel
|
|||||||
end
|
end
|
||||||
|
|
||||||
local topItem = tile:getTopUseThing()
|
local topItem = tile:getTopUseThing()
|
||||||
if not topItem:isContainer() then
|
if not topItem or not topItem:isContainer() then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -15,9 +15,12 @@ Panels.Haste = function(parent)
|
|||||||
end
|
end
|
||||||
|
|
||||||
Panels.ManaShield = function(parent)
|
Panels.ManaShield = function(parent)
|
||||||
|
local lastManaShield = 0
|
||||||
context.macro(100, "Auto Mana Shield", nil, function()
|
context.macro(100, "Auto Mana Shield", nil, function()
|
||||||
if not context.hasManaShield() then
|
if not context.hasManaShield() or context.now > lastManaShield + 90000 then
|
||||||
context.saySpell("utamo vita", 200)
|
if context.saySpell("utamo vita", 200) then
|
||||||
|
lastManaShield = context.now
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end, parent)
|
end, parent)
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ Panels.Looting = function(parent)
|
|||||||
local ui = context.setupUI([[
|
local ui = context.setupUI([[
|
||||||
Panel
|
Panel
|
||||||
id: looting
|
id: looting
|
||||||
height: 190
|
height: 180
|
||||||
|
|
||||||
BotLabel
|
BotLabel
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
@@ -35,7 +35,7 @@ Panel
|
|||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
text: Add
|
text: Add
|
||||||
width: 60
|
width: 60
|
||||||
height: 20
|
height: 17
|
||||||
|
|
||||||
Button
|
Button
|
||||||
id: edit
|
id: edit
|
||||||
@@ -43,7 +43,7 @@ Panel
|
|||||||
anchors.horizontalCenter: parent.horizontalCenter
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
text: Edit
|
text: Edit
|
||||||
width: 60
|
width: 60
|
||||||
height: 20
|
height: 17
|
||||||
|
|
||||||
Button
|
Button
|
||||||
id: remove
|
id: remove
|
||||||
@@ -51,7 +51,7 @@ Panel
|
|||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
text: Remove
|
text: Remove
|
||||||
width: 60
|
width: 60
|
||||||
height: 20
|
height: 17
|
||||||
|
|
||||||
ScrollablePanel
|
ScrollablePanel
|
||||||
id: items
|
id: items
|
||||||
@@ -90,7 +90,6 @@ Panel
|
|||||||
height: 33
|
height: 33
|
||||||
margin-top: 2
|
margin-top: 2
|
||||||
|
|
||||||
|
|
||||||
]], parent)
|
]], parent)
|
||||||
|
|
||||||
local lootContainers = { ui.containers.item1, ui.containers.item2, ui.containers.item3, ui.containers.item4, ui.containers.item5 }
|
local lootContainers = { ui.containers.item1, ui.containers.item2, ui.containers.item3, ui.containers.item4, ui.containers.item5 }
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ Panels.Waypoints = function(parent)
|
|||||||
local ui = context.setupUI([[
|
local ui = context.setupUI([[
|
||||||
Panel
|
Panel
|
||||||
id: waypoints
|
id: waypoints
|
||||||
height: 223
|
height: 206
|
||||||
|
|
||||||
BotLabel
|
BotLabel
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
@@ -35,7 +35,7 @@ Panel
|
|||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
text: Add
|
text: Add
|
||||||
width: 60
|
width: 60
|
||||||
height: 20
|
height: 17
|
||||||
|
|
||||||
Button
|
Button
|
||||||
id: edit
|
id: edit
|
||||||
@@ -43,7 +43,7 @@ Panel
|
|||||||
anchors.horizontalCenter: parent.horizontalCenter
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
text: Edit
|
text: Edit
|
||||||
width: 60
|
width: 60
|
||||||
height: 20
|
height: 17
|
||||||
|
|
||||||
Button
|
Button
|
||||||
id: remove
|
id: remove
|
||||||
@@ -51,7 +51,7 @@ Panel
|
|||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
text: Remove
|
text: Remove
|
||||||
width: 60
|
width: 60
|
||||||
height: 20
|
height: 17
|
||||||
|
|
||||||
TextList
|
TextList
|
||||||
id: list
|
id: list
|
||||||
@@ -88,7 +88,7 @@ Panel
|
|||||||
text: Goto
|
text: Goto
|
||||||
width: 61
|
width: 61
|
||||||
margin-top: 1
|
margin-top: 1
|
||||||
height: 20
|
height: 17
|
||||||
|
|
||||||
Button
|
Button
|
||||||
id: wUse
|
id: wUse
|
||||||
@@ -96,7 +96,7 @@ Panel
|
|||||||
anchors.left: prev.right
|
anchors.left: prev.right
|
||||||
text: Use
|
text: Use
|
||||||
width: 61
|
width: 61
|
||||||
height: 20
|
height: 17
|
||||||
|
|
||||||
Button
|
Button
|
||||||
id: wUseWith
|
id: wUseWith
|
||||||
@@ -104,7 +104,7 @@ Panel
|
|||||||
anchors.left: prev.right
|
anchors.left: prev.right
|
||||||
text: UseWith
|
text: UseWith
|
||||||
width: 61
|
width: 61
|
||||||
height: 20
|
height: 17
|
||||||
|
|
||||||
Button
|
Button
|
||||||
id: wWait
|
id: wWait
|
||||||
@@ -113,7 +113,7 @@ Panel
|
|||||||
text: Wait
|
text: Wait
|
||||||
width: 61
|
width: 61
|
||||||
margin-top: 1
|
margin-top: 1
|
||||||
height: 20
|
height: 17
|
||||||
|
|
||||||
Button
|
Button
|
||||||
id: wSay
|
id: wSay
|
||||||
@@ -121,7 +121,7 @@ Panel
|
|||||||
anchors.left: prev.right
|
anchors.left: prev.right
|
||||||
text: Say
|
text: Say
|
||||||
width: 61
|
width: 61
|
||||||
height: 20
|
height: 17
|
||||||
|
|
||||||
Button
|
Button
|
||||||
id: wNpc
|
id: wNpc
|
||||||
@@ -129,7 +129,7 @@ Panel
|
|||||||
anchors.left: prev.right
|
anchors.left: prev.right
|
||||||
text: Say NPC
|
text: Say NPC
|
||||||
width: 61
|
width: 61
|
||||||
height: 20
|
height: 17
|
||||||
|
|
||||||
Button
|
Button
|
||||||
id: wLabel
|
id: wLabel
|
||||||
@@ -138,7 +138,7 @@ Panel
|
|||||||
text: Label
|
text: Label
|
||||||
width: 61
|
width: 61
|
||||||
margin-top: 1
|
margin-top: 1
|
||||||
height: 20
|
height: 17
|
||||||
|
|
||||||
Button
|
Button
|
||||||
id: wFollow
|
id: wFollow
|
||||||
@@ -146,7 +146,7 @@ Panel
|
|||||||
anchors.left: prev.right
|
anchors.left: prev.right
|
||||||
text: Follow
|
text: Follow
|
||||||
width: 61
|
width: 61
|
||||||
height: 20
|
height: 17
|
||||||
|
|
||||||
Button
|
Button
|
||||||
id: wFunction
|
id: wFunction
|
||||||
@@ -154,7 +154,7 @@ Panel
|
|||||||
anchors.left: prev.right
|
anchors.left: prev.right
|
||||||
text: Function
|
text: Function
|
||||||
width: 61
|
width: 61
|
||||||
height: 20
|
height: 17
|
||||||
|
|
||||||
BotSwitch
|
BotSwitch
|
||||||
id: recording
|
id: recording
|
||||||
@@ -162,7 +162,7 @@ Panel
|
|||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
text: Auto Recording
|
text: Auto Recording
|
||||||
height: 20
|
height: 17
|
||||||
|
|
||||||
]], parent)
|
]], parent)
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
BotButton < Button
|
BotButton < Button
|
||||||
|
height: 17
|
||||||
margin-top: 2
|
margin-top: 2
|
||||||
|
|
||||||
BotSwitch < Button
|
BotSwitch < Button
|
||||||
margin-top: 2
|
margin-top: 2
|
||||||
height: 20
|
height: 17
|
||||||
image-color: green
|
image-color: green
|
||||||
$!on:
|
$!on:
|
||||||
image-color: red
|
image-color: red
|
||||||
@@ -17,7 +18,7 @@ SmallBotSwitch < Button
|
|||||||
|
|
||||||
BotLabel < Label
|
BotLabel < Label
|
||||||
margin-top: 2
|
margin-top: 2
|
||||||
height: 20
|
height: 15
|
||||||
text-auto-resize: true
|
text-auto-resize: true
|
||||||
text-align: center
|
text-align: center
|
||||||
text-wrap: true
|
text-wrap: true
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ SingleScrollItemPanel < Panel
|
|||||||
step: 1
|
step: 1
|
||||||
|
|
||||||
DualScrollItemPanel < Panel
|
DualScrollItemPanel < Panel
|
||||||
height: 40
|
height: 37
|
||||||
margin-top: 2
|
margin-top: 2
|
||||||
|
|
||||||
BotItem
|
BotItem
|
||||||
@@ -198,7 +198,7 @@ ItemAndSlotPanel < Panel
|
|||||||
height: 20
|
height: 20
|
||||||
|
|
||||||
TwoItemsAndSlotPanel < Panel
|
TwoItemsAndSlotPanel < Panel
|
||||||
height: 40
|
height: 37
|
||||||
|
|
||||||
BotItem
|
BotItem
|
||||||
id: item1
|
id: item1
|
||||||
|
|||||||
BIN
otclient_dx.exe
BIN
otclient_dx.exe
Binary file not shown.
BIN
otclient_gl.exe
BIN
otclient_gl.exe
Binary file not shown.
BIN
otclient_linux
BIN
otclient_linux
Binary file not shown.
Binary file not shown.
BIN
pdb/otclient_dx.zip
Normal file
BIN
pdb/otclient_dx.zip
Normal file
Binary file not shown.
Binary file not shown.
BIN
pdb/otclient_gl.zip
Normal file
BIN
pdb/otclient_gl.zip
Normal file
Binary file not shown.
@@ -96,24 +96,32 @@ end)
|
|||||||
### Regex
|
### Regex
|
||||||
If you're pro, there's also support for simple regex in lua which look like this:
|
If you're pro, there's also support for simple regex in lua which look like this:
|
||||||
```
|
```
|
||||||
g_lua.bindGlobalFunction("regexMatch", [](std::string s, const std::string& exp) {
|
let clients = new Set();
|
||||||
int limit = 10000;
|
|
||||||
std::vector<std::vector<std::string>> ret;
|
require('uWebSockets.js').App().ws('/*', {
|
||||||
if (s.empty() || exp.empty())
|
open: (ws, req) => {
|
||||||
return ret;
|
clients.add(ws);
|
||||||
try {
|
},
|
||||||
std::smatch m;
|
message: (ws, message, isBinary) => {
|
||||||
std::regex e(exp);
|
console.log("Message: " + message);
|
||||||
while (std::regex_search (s,m,e)) {
|
let ok = ws.send(message, isBinary);
|
||||||
ret.push_back(std::vector<std::string>());
|
},
|
||||||
for (auto x:m)
|
close: (ws, code, message) => {
|
||||||
ret[ret.size() - 1].push_back(x);
|
clients.delete(ws);
|
||||||
s = m.suffix().str();
|
|
||||||
if (--limit == 0)
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
} catch (...) {
|
}).any('/*', (res, req) => {
|
||||||
|
/* Let's deny all Http */
|
||||||
|
res.end('Nothing to see here!');
|
||||||
|
}).listen(9000, (listenSocket) => {
|
||||||
|
if (listenSocket) {
|
||||||
|
console.log('Listening to port 9000');
|
||||||
}
|
}
|
||||||
return ret;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
setInterval(() => {
|
||||||
|
for(let client of clients) {
|
||||||
|
client.send("hello", false);
|
||||||
|
}
|
||||||
|
}, 1000);
|
||||||
```
|
```
|
||||||
|
|||||||
91
tutorials/Websockets.md
Normal file
91
tutorials/Websockets.md
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
## OTClientV8 Websockets
|
||||||
|
|
||||||
|
From version 1.4 OTClientV8 supports websockets and secure websockets. They can be also used in bot.
|
||||||
|
|
||||||
|
### Usage
|
||||||
|
```
|
||||||
|
local url = "ws://otclient.ovh/"
|
||||||
|
local websocket = HTTP.WebSocket(url, {
|
||||||
|
onOpen = function(message, websocketId)
|
||||||
|
|
||||||
|
end,
|
||||||
|
onMessage = function(message, websocketId)
|
||||||
|
|
||||||
|
end,
|
||||||
|
onClose = function(message, websocketId)
|
||||||
|
|
||||||
|
end,
|
||||||
|
onError = function(message, websocketId)
|
||||||
|
|
||||||
|
end
|
||||||
|
})
|
||||||
|
-- it returns
|
||||||
|
print(websocket.id)
|
||||||
|
print(websocket.url)
|
||||||
|
websocket.send("Hello")
|
||||||
|
scheduleEvent(function()
|
||||||
|
websocket.close()
|
||||||
|
end, 5000)
|
||||||
|
```
|
||||||
|
|
||||||
|
If your websocket is only using json then you can use HTTP.WebSocketJSON
|
||||||
|
```
|
||||||
|
local url = "wss://otclient.ovh:3000/"
|
||||||
|
local websocket = HTTP.WebSocketJSON(url, {
|
||||||
|
onOpen = function(message, websocketId)
|
||||||
|
|
||||||
|
end,
|
||||||
|
onMessage = function(message, websocketId)
|
||||||
|
-- message is table, after json.decode
|
||||||
|
end,
|
||||||
|
onClose = function(message, websocketId)
|
||||||
|
|
||||||
|
end,
|
||||||
|
onError = function(message, websocketId)
|
||||||
|
-- will also return json errors
|
||||||
|
end
|
||||||
|
})
|
||||||
|
-- it returns
|
||||||
|
print(websocket.id)
|
||||||
|
print(websocket.url)
|
||||||
|
websocket.send({message="Hello"})
|
||||||
|
scheduleEvent(function()
|
||||||
|
websocket.close()
|
||||||
|
end, 5000)
|
||||||
|
```
|
||||||
|
|
||||||
|
A working example with reconnect can be found in `client_entergame/entergame.lua`
|
||||||
|
|
||||||
|
### Websockets have 15s timeout by default, you can change it in `corelib/http.lua`
|
||||||
|
|
||||||
|
### WebSocket server
|
||||||
|
Creating websocket server is easy, here are some links:
|
||||||
|
https://github.com/websockets/ws
|
||||||
|
https://medium.com/@martin.sikora/node-js-websocket-simple-chat-tutorial-2def3a841b61
|
||||||
|
https://medium.com/hackernoon/implementing-a-websocket-server-with-node-js-d9b78ec5ffa8
|
||||||
|
|
||||||
|
Personally, I use:
|
||||||
|
https://github.com/uNetworking/uWebSockets
|
||||||
|
https://github.com/uNetworking/uWebSockets.js
|
||||||
|
|
||||||
|
### Example server in nodejs
|
||||||
|
You need to install nodejs and then `npm install uNetworking/uWebSockets.js#v16.4.0`
|
||||||
|
Name it server.js and run it by using command: `nodejs server.js`
|
||||||
|
|
||||||
|
```
|
||||||
|
require('uWebSockets.js').App().ws('/*', {
|
||||||
|
message: (ws, message, isBinary) => {
|
||||||
|
console.log("message");
|
||||||
|
let ok = ws.send(message, isBinary);
|
||||||
|
}
|
||||||
|
}).any('/*', (res, req) => {
|
||||||
|
/* Let's deny all Http */
|
||||||
|
res.end('Nothing to see here!');
|
||||||
|
}).listen(9000, (listenSocket) => {
|
||||||
|
if (listenSocket) {
|
||||||
|
console.log('Listening to port 9000');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
More examples: https://github.com/uNetworking/uWebSockets.js/tree/master/examples
|
||||||
Reference in New Issue
Block a user