mirror of
https://github.com/OTCv8/otclientv8.git
synced 2025-04-30 03:09:20 +02:00
Added websocket login server and botserver
This commit is contained in:
parent
ddb155333d
commit
cf8b21263d
@ -1,96 +1,96 @@
|
|||||||
import { App } from 'uWebSockets.js';
|
import { App } from 'uWebSockets.js';
|
||||||
import * as Login from './login';
|
import * as Login from './login';
|
||||||
const config = require("./config.json");
|
const config = require("./config.json");
|
||||||
|
|
||||||
let Sessions = new Set();
|
let Sessions = new Set();
|
||||||
let Clients = {};
|
let Clients = {};
|
||||||
let QuickLogin = {};
|
let QuickLogin = {};
|
||||||
|
|
||||||
App({
|
App({
|
||||||
// options for ssl
|
// options for ssl
|
||||||
key_file_name: 'key.pem',
|
key_file_name: 'key.pem',
|
||||||
cert_file_name: 'cert.pem'
|
cert_file_name: 'cert.pem'
|
||||||
}).ws('/*', {
|
}).ws('/*', {
|
||||||
compression: 0,
|
compression: 0,
|
||||||
maxPayloadLength: 64 * 1024,
|
maxPayloadLength: 64 * 1024,
|
||||||
idleTimeout: 10,
|
idleTimeout: 10,
|
||||||
open: (ws, req) => {
|
open: (ws, req) => {
|
||||||
ws.uid = null;
|
ws.uid = null;
|
||||||
Sessions.add(ws);
|
Sessions.add(ws);
|
||||||
},
|
},
|
||||||
close: (ws, code, message) => {
|
close: (ws, code, message) => {
|
||||||
if (ws.uid && Clients[ws.uid] == ws) {
|
if (ws.uid && Clients[ws.uid] == ws) {
|
||||||
delete Clients[ws.uid];
|
delete Clients[ws.uid];
|
||||||
delete QuickLogin[ws.short_code];
|
delete QuickLogin[ws.short_code];
|
||||||
delete QuickLogin[ws.full_code];
|
delete QuickLogin[ws.full_code];
|
||||||
}
|
}
|
||||||
Sessions.delete(ws);
|
Sessions.delete(ws);
|
||||||
},
|
},
|
||||||
message: (ws, message, isBinary) => {
|
message: (ws, message, isBinary) => {
|
||||||
try {
|
try {
|
||||||
let data = JSON.parse(String.fromCharCode.apply(null, new Uint8Array(message)));
|
let data = JSON.parse(String.fromCharCode.apply(null, new Uint8Array(message)));
|
||||||
if (data["type"] == "init") {
|
if (data["type"] == "init") {
|
||||||
if (ws.uid || typeof (data["uid"]) != "string" || data["uid"].length < 10) {
|
if (ws.uid || typeof (data["uid"]) != "string" || data["uid"].length < 10) {
|
||||||
return ws.end(1, "Invalid init message"); // already has an uid or uid is invalid
|
return ws.end(1, "Invalid init message"); // already has an uid or uid is invalid
|
||||||
}
|
}
|
||||||
ws.uid = data["uid"];
|
ws.uid = data["uid"];
|
||||||
ws.version = data["version"]
|
ws.version = data["version"]
|
||||||
if (Clients[ws.uid]) {
|
if (Clients[ws.uid]) {
|
||||||
Clients[ws.uid].close();
|
Clients[ws.uid].close();
|
||||||
}
|
}
|
||||||
ws.short_code = "XXXX";
|
ws.short_code = "XXXX";
|
||||||
ws.full_code = "Login on server otclient.ovh. XXXX";
|
ws.full_code = "Login on server otclient.ovh. XXXX";
|
||||||
Clients[ws.uid] = ws;
|
Clients[ws.uid] = ws;
|
||||||
QuickLogin[ws.short_code] = ws;
|
QuickLogin[ws.short_code] = ws;
|
||||||
QuickLogin[ws.full_code] = ws;
|
QuickLogin[ws.full_code] = ws;
|
||||||
return ws.send(JSON.stringify({
|
return ws.send(JSON.stringify({
|
||||||
"type": "quick_login",
|
"type": "quick_login",
|
||||||
"code": ws.short_code,
|
"code": ws.short_code,
|
||||||
"qrcode": ws.full_code,
|
"qrcode": ws.full_code,
|
||||||
"message": ""
|
"message": ""
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
if (!ws.uid) {
|
if (!ws.uid) {
|
||||||
return ws.end(2, "Missing uid");
|
return ws.end(2, "Missing uid");
|
||||||
}
|
}
|
||||||
if (data["type"] == "login") {
|
if (data["type"] == "login") {
|
||||||
return Login.login(ws, data["account"], data["password"]);
|
return Login.login(ws, data["account"], data["password"]);
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
try {
|
try {
|
||||||
return ws.end(3, "Exception");
|
return ws.end(3, "Exception");
|
||||||
} catch (e) {}
|
} catch (e) {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}).any('/login', (res, req) => {
|
}).any('/login', (res, req) => {
|
||||||
let buffer: string = "";
|
let buffer: string = "";
|
||||||
res.onData((chunk, last) => {
|
res.onData((chunk, last) => {
|
||||||
try {
|
try {
|
||||||
buffer += String.fromCharCode.apply(null, new Uint8Array(chunk));
|
buffer += String.fromCharCode.apply(null, new Uint8Array(chunk));
|
||||||
if (!last) {
|
if (!last) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const data = JSON.parse(buffer);
|
const data = JSON.parse(buffer);
|
||||||
const code = data["code"];
|
const code = data["code"];
|
||||||
const client = QuickLogin[code];
|
const client = QuickLogin[code];
|
||||||
if (!client) {
|
if (!client) {
|
||||||
return res.end("Invalid code");
|
return res.end("Invalid code");
|
||||||
}
|
}
|
||||||
Login.quickLogin(res, client, data);
|
Login.quickLogin(res, client, data);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
res.end("Exception");
|
res.end("Exception");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
res.onAborted(() => {
|
res.onAborted(() => {
|
||||||
return res.end("Aborted");
|
return res.end("Aborted");
|
||||||
});
|
});
|
||||||
}).any('/*', (res, req) => {
|
}).any('/*', (res, req) => {
|
||||||
res.end('404');
|
res.end('404');
|
||||||
}).listen(config.port, (listenSocket) => {
|
}).listen(config.port, (listenSocket) => {
|
||||||
if (listenSocket) {
|
if (listenSocket) {
|
||||||
console.log(`Listening to port ${config.port}`);
|
console.log(`Listening to port ${config.port}`);
|
||||||
} else {
|
} else {
|
||||||
console.log(`Error, can't listen on port ${config.port}`)
|
console.log(`Error, can't listen on port ${config.port}`)
|
||||||
}
|
}
|
||||||
});
|
});
|
@ -1,36 +1,36 @@
|
|||||||
{
|
{
|
||||||
"port": 88,
|
"port": 88,
|
||||||
"sql": {
|
"sql": {
|
||||||
"host": "otclient.ovh",
|
"host": "otclient.ovh",
|
||||||
"user": "otclient",
|
"user": "otclient",
|
||||||
"password": "otclient",
|
"password": "otclient",
|
||||||
"database": "otclient"
|
"database": "otclient"
|
||||||
},
|
},
|
||||||
"maxLogins": 10,
|
"maxLogins": 10,
|
||||||
"blockTime": 60,
|
"blockTime": 60,
|
||||||
"hash": "sha1",
|
"hash": "sha1",
|
||||||
"serverName": "OTClientV8",
|
"serverName": "OTClientV8",
|
||||||
"serverIP": "otclient.ovh",
|
"serverIP": "otclient.ovh",
|
||||||
"serverPort": 7172,
|
"serverPort": 7172,
|
||||||
"version": 1099,
|
"version": 1099,
|
||||||
"things": {
|
"things": {
|
||||||
"sprites": [ "1099/Tibia.spr", "63d38646597649a55a8be463d6c0fb49" ],
|
"sprites": [ "1099/Tibia.spr", "63d38646597649a55a8be463d6c0fb49" ],
|
||||||
"data": [ "1099/Tibia.dat", "ae7157cfff42f14583d6363e77044df7" ]
|
"data": [ "1099/Tibia.dat", "ae7157cfff42f14583d6363e77044df7" ]
|
||||||
},
|
},
|
||||||
"customProtocol": null,
|
"customProtocol": null,
|
||||||
"options": {
|
"options": {
|
||||||
"allowFullView": true
|
"allowFullView": true
|
||||||
},
|
},
|
||||||
"features": {
|
"features": {
|
||||||
"22": true,
|
"22": true,
|
||||||
"25": true,
|
"25": true,
|
||||||
"30": true,
|
"30": true,
|
||||||
"80": true,
|
"80": true,
|
||||||
"90": true,
|
"90": true,
|
||||||
"95": true
|
"95": true
|
||||||
},
|
},
|
||||||
"proxies": {
|
"proxies": {
|
||||||
|
|
||||||
},
|
},
|
||||||
"rsa": "109120132967399429278860960508995541528237502902798129123468757937266291492576446330739696001110603907230888610072655818825358503429057592827629436413108566029093628212635953836686562675849720620786279431090218017681061521755056710823876476444260558147179707119674283982419152118103759076030616683978566631413"
|
"rsa": "109120132967399429278860960508995541528237502902798129123468757937266291492576446330739696001110603907230888610072655818825358503429057592827629436413108566029093628212635953836686562675849720620786279431090218017681061521755056710823876476444260558147179707119674283982419152118103759076030616683978566631413"
|
||||||
}
|
}
|
@ -1,84 +1,84 @@
|
|||||||
import { HttpResponse, WebSocket } from 'uWebSockets.js';
|
import { HttpResponse, WebSocket } from 'uWebSockets.js';
|
||||||
import * as mysql from 'mysql2/promise';
|
import * as mysql from 'mysql2/promise';
|
||||||
import * as crypto from 'crypto';
|
import * as crypto from 'crypto';
|
||||||
const config = require("./config.json");
|
const config = require("./config.json");
|
||||||
|
|
||||||
function hash(algorithm: string, data: string): string {
|
function hash(algorithm: string, data: string): string {
|
||||||
return crypto.createHash(algorithm).update(data).digest("hex");
|
return crypto.createHash(algorithm).update(data).digest("hex");
|
||||||
}
|
}
|
||||||
|
|
||||||
function time(): number {
|
function time(): number {
|
||||||
return new Date().getTime();
|
return new Date().getTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function login(ws: WebSocket, login: string, password: string) {
|
export async function login(ws: WebSocket, login: string, password: string) {
|
||||||
let sql : mysql.Connection = null;
|
let sql : mysql.Connection = null;
|
||||||
try {
|
try {
|
||||||
sql = await mysql.createConnection({
|
sql = await mysql.createConnection({
|
||||||
host: config.sql.host,
|
host: config.sql.host,
|
||||||
user: config.sql.user,
|
user: config.sql.user,
|
||||||
password: config.sql.password,
|
password: config.sql.password,
|
||||||
database: config.sql.database
|
database: config.sql.database
|
||||||
});
|
});
|
||||||
|
|
||||||
let hash_password = password
|
let hash_password = password
|
||||||
if (config.hash == "md5") {
|
if (config.hash == "md5") {
|
||||||
hash_password = hash("md5", password);
|
hash_password = hash("md5", password);
|
||||||
} else if (config.hash == "sha1") {
|
} else if (config.hash == "sha1") {
|
||||||
hash_password = hash("sha1", password);
|
hash_password = hash("sha1", password);
|
||||||
}
|
}
|
||||||
|
|
||||||
const [accounts, accountFields] = await sql.execute('SELECT * FROM `accounts` where `name` = ? and `password` = ?', [login, hash_password]);
|
const [accounts, accountFields] = await sql.execute('SELECT * FROM `accounts` where `name` = ? and `password` = ?', [login, hash_password]);
|
||||||
if (accounts.length != 1) {
|
if (accounts.length != 1) {
|
||||||
await sql.end();
|
await sql.end();
|
||||||
return ws.send(JSON.stringify({"type": "login", "error": "Invalid account/password"}), false);
|
return ws.send(JSON.stringify({"type": "login", "error": "Invalid account/password"}), false);
|
||||||
}
|
}
|
||||||
const account = accounts[0];
|
const account = accounts[0];
|
||||||
const [players, playersFields] = await sql.execute('SELECT * FROM `players` where `account_id` = ?', [account.id]);
|
const [players, playersFields] = await sql.execute('SELECT * FROM `players` where `account_id` = ?', [account.id]);
|
||||||
await sql.end();
|
await sql.end();
|
||||||
|
|
||||||
let response = {
|
let response = {
|
||||||
"type": "login",
|
"type": "login",
|
||||||
"error": "",
|
"error": "",
|
||||||
"rsa": config.rsa,
|
"rsa": config.rsa,
|
||||||
"version": config.version,
|
"version": config.version,
|
||||||
"things": config.things,
|
"things": config.things,
|
||||||
"customProtocol": config.customProtocol,
|
"customProtocol": config.customProtocol,
|
||||||
"session": "",
|
"session": "",
|
||||||
"characters": [],
|
"characters": [],
|
||||||
"account": {},
|
"account": {},
|
||||||
"options": config.options,
|
"options": config.options,
|
||||||
"features": config.features,
|
"features": config.features,
|
||||||
"proxies": config.proxies
|
"proxies": config.proxies
|
||||||
}
|
}
|
||||||
|
|
||||||
response["session"] = `${login}\n${password}\n\n${time()}`;
|
response["session"] = `${login}\n${password}\n\n${time()}`;
|
||||||
|
|
||||||
response["account"]["status"] = 0; // 0=ok, 1=frozen, 2=supsended
|
response["account"]["status"] = 0; // 0=ok, 1=frozen, 2=supsended
|
||||||
response["account"]["subStatus"] = 1; // 0=free, 1=premium
|
response["account"]["subStatus"] = 1; // 0=free, 1=premium
|
||||||
response["account"]["premDays"] = 65535;
|
response["account"]["premDays"] = 65535;
|
||||||
|
|
||||||
for (let i = 0; i < players.length; ++i) {
|
for (let i = 0; i < players.length; ++i) {
|
||||||
response.characters.push({
|
response.characters.push({
|
||||||
"name": players[i].name,
|
"name": players[i].name,
|
||||||
"worldName": config.serverName,
|
"worldName": config.serverName,
|
||||||
"worldIp": config.serverIP,
|
"worldIp": config.serverIP,
|
||||||
"worldPort": config.serverPort
|
"worldPort": config.serverPort
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(response);
|
console.log(response);
|
||||||
ws.send(JSON.stringify(response), false);
|
ws.send(JSON.stringify(response), false);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
try {
|
try {
|
||||||
await sql.end()
|
await sql.end()
|
||||||
} catch (e) { };
|
} catch (e) { };
|
||||||
try {
|
try {
|
||||||
ws.end(5, "Login exception");
|
ws.end(5, "Login exception");
|
||||||
} catch (e) { };
|
} catch (e) { };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function quickLogin(res : HttpResponse, ws: WebSocket, data: any) {
|
export async function quickLogin(res : HttpResponse, ws: WebSocket, data: any) {
|
||||||
|
|
||||||
}
|
}
|
@ -1,22 +1,22 @@
|
|||||||
{
|
{
|
||||||
"name": "otcv8socks",
|
"name": "otcv8socks",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"description": "Websockets server for otclientv8",
|
"description": "Websockets server for otclientv8",
|
||||||
"main": "app.js",
|
"main": "app.js",
|
||||||
"author": {
|
"author": {
|
||||||
"name": ""
|
"name": ""
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "tsc --build",
|
"build": "tsc --build",
|
||||||
"clean": "tsc --build --clean"
|
"clean": "tsc --build --clean"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/mysql2": "github:types/mysql2",
|
"@types/mysql2": "github:types/mysql2",
|
||||||
"@types/node": "^8.0.14",
|
"@types/node": "^8.0.14",
|
||||||
"typescript": "^3.2.2"
|
"typescript": "^3.2.2"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"mysql2": "^2.0.1",
|
"mysql2": "^2.0.1",
|
||||||
"uWebSockets.js": "github:uNetworking/uWebSockets.js#v16.4.0"
|
"uWebSockets.js": "github:uNetworking/uWebSockets.js#v16.4.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
{
|
{
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"module": "commonjs",
|
"module": "commonjs",
|
||||||
"target": "es6",
|
"target": "es6",
|
||||||
"lib": ["es6"],
|
"lib": ["es6"],
|
||||||
"sourceMap": true
|
"sourceMap": true
|
||||||
},
|
},
|
||||||
"exclude": [
|
"exclude": [
|
||||||
"node_modules"
|
"node_modules"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -56,8 +56,11 @@ function HTTP.downloadImage(url, callback)
|
|||||||
return operation
|
return operation
|
||||||
end
|
end
|
||||||
|
|
||||||
function HTTP.webSocket(url, callbacks, jsonWebsocket)
|
function HTTP.webSocket(url, callbacks, timeout, jsonWebsocket)
|
||||||
local operation = g_http.ws(url, HTTP.websocketTimeout)
|
if not timeout or timeout < 1 then
|
||||||
|
timeout = HTTP.websocketTimeout
|
||||||
|
end
|
||||||
|
local operation = g_http.ws(url, timeout)
|
||||||
HTTP.operations[operation] = {type="ws", json=jsonWebsocket, url=url, callbacks=callbacks}
|
HTTP.operations[operation] = {type="ws", json=jsonWebsocket, url=url, callbacks=callbacks}
|
||||||
return {
|
return {
|
||||||
id = operation,
|
id = operation,
|
||||||
@ -75,8 +78,8 @@ function HTTP.webSocket(url, callbacks, jsonWebsocket)
|
|||||||
end
|
end
|
||||||
HTTP.WebSocket = HTTP.webSocket
|
HTTP.WebSocket = HTTP.webSocket
|
||||||
|
|
||||||
function HTTP.webSocketJSON(url, callbacks)
|
function HTTP.webSocketJSON(url, callbacks, timeout)
|
||||||
return HTTP.webSocket(url, callbacks, true)
|
return HTTP.webSocket(url, callbacks, timeout, true)
|
||||||
end
|
end
|
||||||
HTTP.WebSocketJSON = HTTP.webSocketJSON
|
HTTP.WebSocketJSON = HTTP.webSocketJSON
|
||||||
|
|
||||||
|
@ -8,6 +8,7 @@ configEditorText = nil
|
|||||||
configList = nil
|
configList = nil
|
||||||
botTabs = nil
|
botTabs = nil
|
||||||
botPanel = nil
|
botPanel = nil
|
||||||
|
local botWebSockets = {}
|
||||||
local botMessages = nil
|
local botMessages = nil
|
||||||
local configCopy = ""
|
local configCopy = ""
|
||||||
local enableButton = nil
|
local enableButton = nil
|
||||||
@ -343,6 +344,11 @@ function clearConfig()
|
|||||||
|
|
||||||
botMessages:destroyChildren()
|
botMessages:destroyChildren()
|
||||||
botMessages:updateLayout()
|
botMessages:updateLayout()
|
||||||
|
|
||||||
|
for socket in pairs(botWebSockets) do
|
||||||
|
g_http.cancel(socket)
|
||||||
|
botWebSockets[socket] = nil
|
||||||
|
end
|
||||||
|
|
||||||
for i, widget in pairs(g_ui.getRootWidget():getChildren()) do
|
for i, widget in pairs(g_ui.getRootWidget():getChildren()) do
|
||||||
if widget.botWidget then
|
if widget.botWidget then
|
||||||
@ -385,7 +391,7 @@ function refreshConfig()
|
|||||||
end
|
end
|
||||||
errorOccured = false
|
errorOccured = false
|
||||||
g_game.enableTileThingLuaCallback(false)
|
g_game.enableTileThingLuaCallback(false)
|
||||||
local status, result = pcall(function() return executeBot(config.script, config.storage, botTabs, botMsgCallback, saveConfig) end)
|
local status, result = pcall(function() return executeBot(config.script, config.storage, botTabs, botMsgCallback, saveConfig, botWebSockets) end)
|
||||||
if not status then
|
if not status then
|
||||||
errorOccured = true
|
errorOccured = true
|
||||||
statusLabel:setText("Error: " .. tostring(result))
|
statusLabel:setText("Error: " .. tostring(result))
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
function executeBot(config, storage, tabs, msgCallback, saveConfigCallback)
|
function executeBot(config, storage, tabs, msgCallback, saveConfigCallback, websockets)
|
||||||
local context = {}
|
local context = {}
|
||||||
context.tabs = tabs
|
context.tabs = tabs
|
||||||
context.panel = context.tabs:addTab("Main", g_ui.createWidget('BotPanel')).tabPanel
|
context.panel = context.tabs:addTab("Main", g_ui.createWidget('BotPanel')).tabPanel
|
||||||
context.saveConfig = saveConfigCallback
|
context.saveConfig = saveConfigCallback
|
||||||
|
context._websockets = websockets
|
||||||
|
|
||||||
context.storage = storage
|
context.storage = storage
|
||||||
if context.storage._macros == nil then
|
if context.storage._macros == nil then
|
||||||
@ -65,6 +66,7 @@ function executeBot(config, storage, tabs, msgCallback, saveConfigCallback)
|
|||||||
context.StaticText = StaticText
|
context.StaticText = StaticText
|
||||||
context.Config = Config
|
context.Config = Config
|
||||||
context.HTTP = HTTP
|
context.HTTP = HTTP
|
||||||
|
context.modules = modules
|
||||||
|
|
||||||
-- log functions
|
-- log functions
|
||||||
context.info = function(text) return msgCallback("info", tostring(text)) end
|
context.info = function(text) return msgCallback("info", tostring(text)) end
|
||||||
|
@ -3,13 +3,10 @@ local context = G.botContext
|
|||||||
-- MAIN BOT FUNCTION
|
-- MAIN BOT FUNCTION
|
||||||
-- macro(timeout, callback)
|
-- macro(timeout, callback)
|
||||||
-- macro(timeout, name, callback)
|
-- macro(timeout, name, callback)
|
||||||
|
-- macro(timeout, name, callback, parent)
|
||||||
-- macro(timeout, name, hotkey, callback)
|
-- macro(timeout, name, hotkey, callback)
|
||||||
-- macro(timeout, name, hotkey, callback, parent)
|
-- macro(timeout, name, hotkey, callback, parent)
|
||||||
context.macro = function(timeout, name, hotkey, callback, parent)
|
context.macro = function(timeout, name, hotkey, callback, parent)
|
||||||
if not parent then
|
|
||||||
parent = context.panel
|
|
||||||
end
|
|
||||||
|
|
||||||
if type(timeout) ~= 'number' or timeout < 1 then
|
if type(timeout) ~= 'number' or timeout < 1 then
|
||||||
error("Invalid timeout for macro: " .. tostring(timeout))
|
error("Invalid timeout for macro: " .. tostring(timeout))
|
||||||
end
|
end
|
||||||
@ -18,8 +15,9 @@ context.macro = function(timeout, name, hotkey, callback, parent)
|
|||||||
name = ""
|
name = ""
|
||||||
hotkey = ""
|
hotkey = ""
|
||||||
elseif type(hotkey) == 'function' then
|
elseif type(hotkey) == 'function' then
|
||||||
|
parent = callback
|
||||||
callback = hotkey
|
callback = hotkey
|
||||||
hotkey = ""
|
hotkey = ""
|
||||||
elseif type(callback) ~= 'function' then
|
elseif type(callback) ~= 'function' then
|
||||||
error("Invalid callback for macro: " .. tostring(callback))
|
error("Invalid callback for macro: " .. tostring(callback))
|
||||||
end
|
end
|
||||||
@ -29,6 +27,9 @@ context.macro = function(timeout, name, hotkey, callback, parent)
|
|||||||
if type(name) ~= 'string' or type(hotkey) ~= 'string' then
|
if type(name) ~= 'string' or type(hotkey) ~= 'string' then
|
||||||
error("Invalid name or hotkey for macro")
|
error("Invalid name or hotkey for macro")
|
||||||
end
|
end
|
||||||
|
if not parent then
|
||||||
|
parent = context.panel
|
||||||
|
end
|
||||||
if hotkey:len() > 0 then
|
if hotkey:len() > 0 then
|
||||||
hotkey = retranslateKeyComboDesc(hotkey)
|
hotkey = retranslateKeyComboDesc(hotkey)
|
||||||
end
|
end
|
||||||
@ -63,16 +64,18 @@ context.macro = function(timeout, name, hotkey, callback, parent)
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- hotkey(keys, callback)
|
-- hotkey(keys, callback)
|
||||||
|
-- hotkey(keys, callback, parent)
|
||||||
-- hotkey(keys, name, callback)
|
-- hotkey(keys, name, callback)
|
||||||
-- hotkey(keys, name, callback, parent)
|
-- hotkey(keys, name, callback, parent)
|
||||||
context.hotkey = function(keys, name, callback, single, parent)
|
context.hotkey = function(keys, name, callback, parent, single)
|
||||||
if not parent then
|
|
||||||
parent = context.panel
|
|
||||||
end
|
|
||||||
if type(name) == 'function' then
|
if type(name) == 'function' then
|
||||||
|
parent = callback
|
||||||
callback = name
|
callback = name
|
||||||
name = ""
|
name = ""
|
||||||
end
|
end
|
||||||
|
if not parent then
|
||||||
|
parent = context.panel
|
||||||
|
end
|
||||||
keys = retranslateKeyComboDesc(keys)
|
keys = retranslateKeyComboDesc(keys)
|
||||||
if not keys or #keys == 0 then
|
if not keys or #keys == 0 then
|
||||||
return context.error("Invalid hotkey keys " .. tostring(name))
|
return context.error("Invalid hotkey keys " .. tostring(name))
|
||||||
@ -107,14 +110,16 @@ context.hotkey = function(keys, name, callback, single, parent)
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- singlehotkey(keys, callback)
|
-- singlehotkey(keys, callback)
|
||||||
|
-- singlehotkey(keys, callback, parent)
|
||||||
-- singlehotkey(keys, name, callback)
|
-- singlehotkey(keys, name, callback)
|
||||||
-- singlehotkey(keys, name, callback, parent)
|
-- singlehotkey(keys, name, callback, parent)
|
||||||
context.singlehotkey = function(keys, name, callback, parent)
|
context.singlehotkey = function(keys, name, callback, parent)
|
||||||
if type(name) == 'function' then
|
if type(name) == 'function' then
|
||||||
|
parent = callback
|
||||||
callback = name
|
callback = name
|
||||||
name = ""
|
name = ""
|
||||||
end
|
end
|
||||||
return context.hotkey(keys, name, callback, true, parent)
|
return context.hotkey(keys, name, callback, parent, true)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- schedule(timeout, callback)
|
-- schedule(timeout, callback)
|
||||||
|
@ -92,6 +92,9 @@ context.sayNPC = context.talkNpc
|
|||||||
context.talkNPC = context.talkNpc
|
context.talkNPC = context.talkNpc
|
||||||
|
|
||||||
context.saySpell = function(text, lastSpellTimeout)
|
context.saySpell = function(text, lastSpellTimeout)
|
||||||
|
if not text or text:len() < 1 then
|
||||||
|
return
|
||||||
|
end
|
||||||
if context.lastSpell == nil then
|
if context.lastSpell == nil then
|
||||||
context.lastSpell = 0
|
context.lastSpell = 0
|
||||||
end
|
end
|
||||||
|
88
modules/game_bot/functions/server.lua
Normal file
88
modules/game_bot/functions/server.lua
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
local context = G.botContext
|
||||||
|
|
||||||
|
context.BotServer = {}
|
||||||
|
context.BotServer.url = "ws://bot.otclient.ovh:8000/"
|
||||||
|
context.BotServer.timeout = 3
|
||||||
|
context.BotServer._callbacks = {}
|
||||||
|
context.BotServer._lastMessageId = 0
|
||||||
|
context.BotServer._wasConnected = true -- show first warning
|
||||||
|
|
||||||
|
context.BotServer.init = function(name, channel)
|
||||||
|
if not channel or not name or channel:len() < 1 or name:len() < 1 then
|
||||||
|
return context.error("Invalid params for BotServer.init")
|
||||||
|
end
|
||||||
|
if context.BotServer._websocket then
|
||||||
|
return context.error("BotServer is already initialized")
|
||||||
|
end
|
||||||
|
context.BotServer._websocket = HTTP.WebSocketJSON(context.BotServer.url, {
|
||||||
|
onMessage = function(message, socketId)
|
||||||
|
if not context._websockets[socketId] then
|
||||||
|
return g_http.cancel(socketId)
|
||||||
|
end
|
||||||
|
if not context.BotServer._websocket or context.BotServer._websocket.id ~= socketId then
|
||||||
|
return g_http.cancel(socketId)
|
||||||
|
end
|
||||||
|
context.BotServer._wasConnected = true
|
||||||
|
if message["type"] == "ping" then
|
||||||
|
return context.BotServer._websocket.send({type="ping"})
|
||||||
|
end
|
||||||
|
if message["type"] == "message" then
|
||||||
|
context.BotServer._lastMessageId = message["id"]
|
||||||
|
local topics = context.BotServer._callbacks[message["topic"]]
|
||||||
|
if topics then
|
||||||
|
for i=1,#topics do
|
||||||
|
topics[i](message["name"], message["message"], message["topic"])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
topics = context.BotServer._callbacks["*"]
|
||||||
|
if topics then
|
||||||
|
for i=1,#topics do
|
||||||
|
topics[i](message["name"], message["message"], message["topic"])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
onClose = function(message, socketId)
|
||||||
|
if not context._websockets[socketId] then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
context._websockets[socketId] = nil
|
||||||
|
if not context.BotServer._websocket or context.BotServer._websocket.id ~= socketId then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
if context.BotServer._wasConnected then
|
||||||
|
context.warn("BotServer disconnected")
|
||||||
|
end
|
||||||
|
context.BotServer._wasConnected = false
|
||||||
|
context.BotServer._websocket = nil
|
||||||
|
context.BotServer.init(name, channel)
|
||||||
|
end
|
||||||
|
}, context.BotServer.timeout)
|
||||||
|
context._websockets[context.BotServer._websocket.id] = 1
|
||||||
|
context.BotServer._websocket.send({type="init", name=name, channel=channel, lastMessage=context.BotServer._lastMessageId})
|
||||||
|
end
|
||||||
|
|
||||||
|
context.BotServer.terminate = function()
|
||||||
|
if context.BotServer._websocket then
|
||||||
|
context.BotServer._websocket:close()
|
||||||
|
context.BotServer._websocket = nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context.BotServer.listen = function(topic, callback) -- callback = function(name, message, topic) -- message is parsed json = table
|
||||||
|
if not context.BotServer._websocket then
|
||||||
|
return context.error("BotServer is not initialized")
|
||||||
|
end
|
||||||
|
if not context.BotServer._callbacks[topic] then
|
||||||
|
context.BotServer._callbacks[topic] = {}
|
||||||
|
end
|
||||||
|
table.insert(context.BotServer._callbacks[topic], callback)
|
||||||
|
end
|
||||||
|
|
||||||
|
context.BotServer.send = function(topic, message)
|
||||||
|
if not context.BotServer._websocket then
|
||||||
|
return context.error("BotServer is not initialized")
|
||||||
|
end
|
||||||
|
context.BotServer._websocket.send({type="message", topic=topic, message=message})
|
||||||
|
end
|
@ -871,7 +871,8 @@ function refreshViewMode()
|
|||||||
gameBottomPanel:addAnchor(AnchorRight, 'gameRightPanels', AnchorLeft)
|
gameBottomPanel:addAnchor(AnchorRight, 'gameRightPanels', AnchorLeft)
|
||||||
bottomSplitter:addAnchor(AnchorLeft, 'gameLeftPanels', AnchorRight)
|
bottomSplitter:addAnchor(AnchorLeft, 'gameLeftPanels', AnchorRight)
|
||||||
bottomSplitter:addAnchor(AnchorRight, 'gameRightPanels', AnchorLeft)
|
bottomSplitter:addAnchor(AnchorRight, 'gameRightPanels', AnchorLeft)
|
||||||
|
bottomSplitter:setMarginLeft(0)
|
||||||
|
|
||||||
modules.client_topmenu.getTopMenu():setImageColor('white')
|
modules.client_topmenu.getTopMenu():setImageColor('white')
|
||||||
gameBottomPanel:setImageColor('white')
|
gameBottomPanel:setImageColor('white')
|
||||||
g_game.changeMapAwareRange(19, 15)
|
g_game.changeMapAwareRange(19, 15)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user