Version 0.98 BETA

This commit is contained in:
OTCv8 2019-10-04 11:08:01 +02:00
parent 2b925dc52d
commit bb3782fb03
17 changed files with 271 additions and 43 deletions

View File

@ -1,6 +1,7 @@
OTClient is made available under the MIT License OTClientV8 is made available under the MIT License
Copyright (c) 2010-2017 OTClient <https://github.com/edubart/otclient> Copyright (c) 2010-2017 OTClient <https://github.com/edubart/otclient>
Copyright (c) 2018-2019 OTClientV8 <https://github.com/OTCv8/otclientv8>
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal

View File

@ -1,10 +1,45 @@
# OTClientV8 # OTClientV8
Preview version of OTClientV8, it's v0.95 beta, version v1.0 with all tutorial will be released soon Preview version of OTClientV8, it's v0.95 beta, version v1.0 with all tutorial will be released soon.
It's based on https://github.com/edubart/otclient. It's not backward compatible It's based on https://github.com/edubart/otclient and it's not backward compatible.
# DISCORD # DISCORD
OTClientV8 discord channel: https://discord.gg/DExGSs OTClientV8 discord channel: https://discord.gg/feySup6 (new, working link!)
# FEATURES
- Rewrited and optimized rendering (60 fps on 11 years old computer)
- Better DirectX9 and DirectX11 support
- Adaptive rendering (automated graphics optimizations)
- Rewrited light rendering
- Rewrited path finding and auto walking
- Rewrited walking system
- HTTP lua API with JSON support
- Auto updater
- New filesystem
- File encryption and compression
- Automatic diagnostic system
- Refreshed interface
- New crash and error handler
- New HTTP login protocol
- Ingame shop and news
- Updated hotkey manager
- Updated and optimized battle list
- Crosshair, floor fading, extra health/mana bars and panels
- Removed a lot of useless and outdated things
- Support for proxies to lower latency and protect against DDoS (extra paid option)
# And hundreds of smaller features, optimizations and bug fixes!
# Check out directory `tutorials` to see how active and use features
### There's github repo of tfs 1.3 with otclientv8 features: https://github.com/OTCv8/otclientv8-tfs
# Facts
### It took almost 1000h to make this project
### OTClientV8 has been used by over 6000 unique players!
### You can check last active players on: http://otclient.ovh/clients.php
# Paid version
The difference between paid version and this one is that the 1st one comes with c++ sources and has professional support. You may need c++ source if you want to add some more advanced modifications, better encryption, bot protection or some other things. The free version doesn't offer technical support, you need to follow tutorials and in case of any bug or problem you should submit an issue on github. Check http://otclient.ovh if you want more about paid version and other extra services.
# Quick Start # Quick Start
@ -38,7 +73,6 @@ ALLOW_CUSTOM_SERVERS = true -- if true it will show option ANOTHER on server lis
Also remember to add your sprite and data file to data/things Also remember to add your sprite and data file to data/things
That's it, you're ready to use OTClientV8. That's it, you're ready to use OTClientV8.
Soon I will add tutorial how to activate extra features (there are a lot of them)
DirectX version requires 3 dlls: libEGL.dll libGLESv2.dll d3dcompiler_46.dll DirectX version requires 3 dlls: libEGL.dll libGLESv2.dll d3dcompiler_46.dll

View File

@ -1,6 +1,6 @@
-- CONFIG -- CONFIG
APP_NAME = "otclientv8" -- important, change it, it's name for config dir and files in appdata APP_NAME = "otclientv8" -- important, change it, it's name for config dir and files in appdata
APP_VERSION = 1337 -- client version for updater and login to indentify outdated client APP_VERSION = 1337 -- client version for updater and login to identify outdated client
-- If you don't use updater or other service, set it to updater = "" -- If you don't use updater or other service, set it to updater = ""
Services = { Services = {
@ -16,9 +16,11 @@ Services = {
Servers = { Servers = {
OTClientV8 = "http://otclient.ovh/api/login.php", OTClientV8 = "http://otclient.ovh/api/login.php",
OTClientV8proxy = "http://otclient.ovh/api/login.php?proxy=1", OTClientV8proxy = "http://otclient.ovh/api/login.php?proxy=1",
OTClientV8c = "otclient.ovh:7171:1099" OTClientV8classic = "otclient.ovh:7171:1099",
OTClientV8cwithfeatures = "otclient.ovh:7171:1099:25:30:80:90",
OTClientV8Test = "http://otclient.ovh/api/login2.php"
} }
ALLOW_CUSTOM_SERVERS = true -- if true it will show option ANOTHER on server list ALLOW_CUSTOM_SERVERS = true -- if true it shows option ANOTHER on server list
-- CONFIG END -- CONFIG END
-- print first terminal message -- print first terminal message

View File

@ -214,7 +214,6 @@ function EnterGame.init()
local server = g_settings.get('server') local server = g_settings.get('server')
local host = g_settings.get('host') local host = g_settings.get('host')
local clientVersion = g_settings.get('client-version') local clientVersion = g_settings.get('client-version')
local hdSprites = g_settings.getBoolean('hdSprites', false)
if serverSelector:isOption(server) then if serverSelector:isOption(server) then
serverSelector:setCurrentOption(server, false) serverSelector:setCurrentOption(server, false)
@ -230,11 +229,7 @@ function EnterGame.init()
enterGame:getChildById('accountPasswordTextEdit'):setText(password) enterGame:getChildById('accountPasswordTextEdit'):setText(password)
enterGame:getChildById('accountNameTextEdit'):setText(account) enterGame:getChildById('accountNameTextEdit'):setText(account)
rememberPasswordBox:setChecked(#account > 0) rememberPasswordBox:setChecked(#account > 0)
if enterGame.hdSprites then
enterGame.hdSprites:setChecked(hdSprites)
end
g_keyboard.bindKeyDown('Ctrl+G', EnterGame.openWindow) g_keyboard.bindKeyDown('Ctrl+G', EnterGame.openWindow)
if g_game.isOnline() then if g_game.isOnline() then
@ -361,7 +356,6 @@ function EnterGame.doLogin()
G.password = enterGame:getChildById('accountPasswordTextEdit'):getText() G.password = enterGame:getChildById('accountPasswordTextEdit'):getText()
--G.authenticatorToken = enterGame:getChildById('authenticatorTokenTextEdit'):getText() --G.authenticatorToken = enterGame:getChildById('authenticatorTokenTextEdit'):getText()
G.authenticatorToken = "" G.authenticatorToken = ""
G.hdSprites = enterGame.hdSprites and enterGame.hdSprites:isChecked()
G.stayLogged = true G.stayLogged = true
G.server = serverSelector:getText():trim() G.server = serverSelector:getText():trim()
G.host = serverHostTextEdit:getText() G.host = serverHostTextEdit:getText()
@ -374,7 +368,6 @@ function EnterGame.doLogin()
g_settings.set('host', G.host) g_settings.set('host', G.host)
g_settings.set('server', G.server) g_settings.set('server', G.server)
g_settings.set('client-version', G.clientVersion) g_settings.set('client-version', G.clientVersion)
g_settings.set('hdSprites', G.hdSprites)
g_settings.save() g_settings.save()
if G.host:find("http") ~= nil then if G.host:find("http") ~= nil then
@ -399,10 +392,6 @@ function EnterGame.doLogin()
sprites = {G.clientVersion .. "/Tibia.spr", ""}, sprites = {G.clientVersion .. "/Tibia.spr", ""},
} }
if G.hdSprites then
things.sprites_hd = {G.clientVersion .. "/Tibia_hd.spr", ""}
end
local incorrectThings = validateThings(things) local incorrectThings = validateThings(things)
if #incorrectThings > 0 then if #incorrectThings > 0 then
g_logger.info(incorrectThings) g_logger.info(incorrectThings)
@ -432,10 +421,12 @@ function EnterGame.doLogin()
g_game.setProtocolVersion(g_game.getClientProtocolVersion(G.clientVersion)) g_game.setProtocolVersion(g_game.getClientProtocolVersion(G.clientVersion))
g_game.setCustomProtocolVersion(0) g_game.setCustomProtocolVersion(0)
g_game.chooseRsa(G.host) g_game.chooseRsa(G.host)
g_game.setCustomOs(2) -- windows -- g_game.setCustomOs(2) -- windows, optional
-- you can add custom features here -- extra features from init.lua
g_game.enableFeature(GameBot) for i = 4, #server_params do
g_game.enableFeature(tonumber(server_params[i]))
end
-- proxies -- proxies
if g_proxy then if g_proxy then
@ -443,7 +434,7 @@ function EnterGame.doLogin()
end end
if modules.game_things.isLoaded() then if modules.game_things.isLoaded() then
g_logger.info("Connection to: " .. server_ip .. ":" .. server_port) g_logger.info("Connecting to: " .. server_ip .. ":" .. server_port)
protocolLogin:login(server_ip, server_port, G.account, G.password, G.authenticatorToken, G.stayLogged) protocolLogin:login(server_ip, server_port, G.account, G.password, G.authenticatorToken, G.stayLogged)
else else
loadBox:destroy() loadBox:destroy()
@ -467,7 +458,6 @@ function EnterGame.doLoginHttp()
account = G.account, account = G.account,
password = G.password, password = G.password,
token = G.authenticatorToken, token = G.authenticatorToken,
hdSprites = G.hdSprites,
version = APP_VERSION, version = APP_VERSION,
uid = G.UUID uid = G.UUID
} }

View File

@ -8,13 +8,13 @@ HTTP = {
function HTTP.get(url, callback) function HTTP.get(url, callback)
local operation = g_http.get(url, HTTP.timeout) local operation = g_http.get(url, HTTP.timeout)
HTTP.operations[operation] = {type="get", url=url, callback=callback} HTTP.operations[operation] = {type="get", url=url, callback=callback}
return opreation return operation
end end
function HTTP.getJSON(url, callback) function HTTP.getJSON(url, callback)
local operation = g_http.get(url, HTTP.timeout) local operation = g_http.get(url, HTTP.timeout)
HTTP.operations[operation] = {type="get", json=true, url=url, callback=callback} HTTP.operations[operation] = {type="get", json=true, url=url, callback=callback}
return opreation return operation
end end
function HTTP.post(url, data, callback) function HTTP.post(url, data, callback)
@ -23,7 +23,7 @@ function HTTP.post(url, data, callback)
end end
local operation = g_http.post(url, data, HTTP.timeout) local operation = g_http.post(url, data, HTTP.timeout)
HTTP.operations[operation] = {type="post", url=url, callback=callback} HTTP.operations[operation] = {type="post", url=url, callback=callback}
return opreation return operation
end end
function HTTP.postJSON(url, data, callback) function HTTP.postJSON(url, data, callback)
@ -32,13 +32,13 @@ function HTTP.postJSON(url, data, callback)
end end
local operation = g_http.post(url, data, HTTP.timeout) local operation = g_http.post(url, data, HTTP.timeout)
HTTP.operations[operation] = {type="post", json=true, url=url, callback=callback} HTTP.operations[operation] = {type="post", json=true, url=url, callback=callback}
return opreation return operation
end end
function HTTP.download(url, file, callback, progressCallback) function HTTP.download(url, file, callback, progressCallback)
local operation = g_http.download(url, file, HTTP.timeout) local operation = g_http.download(url, file, HTTP.timeout)
HTTP.operations[operation] = {type="download", url=url, file=file, callback=callback, progressCallback=progressCallback} HTTP.operations[operation] = {type="download", url=url, file=file, callback=callback, progressCallback=progressCallback}
return opreation return operation
end end
function HTTP.downloadImage(url, callback) function HTTP.downloadImage(url, callback)
@ -52,7 +52,7 @@ function HTTP.downloadImage(url, callback)
HTTP.imageId = HTTP.imageId + 1 HTTP.imageId = HTTP.imageId + 1
local operation = g_http.download(url, file, HTTP.timeout) local operation = g_http.download(url, file, HTTP.timeout)
HTTP.operations[operation] = {type="image", url=url, file=file, callback=callback} HTTP.operations[operation] = {type="image", url=url, file=file, callback=callback}
return opreation return operation
end end
function HTTP.progress(operationId) function HTTP.progress(operationId)
@ -154,4 +154,5 @@ connect(g_http,
onPostProgress = HTTP.onPostProgress, onPostProgress = HTTP.onPostProgress,
onDownload = HTTP.onDownload, onDownload = HTTP.onDownload,
onDownloadProgress = HTTP.onDownloadProgress onDownloadProgress = HTTP.onDownloadProgress
}) })

View File

@ -208,6 +208,7 @@ function enableChat(temporarily)
if temporarily then if temporarily then
local quickFunc = function() local quickFunc = function()
if not g_game.isOnline() then return end
g_keyboard.unbindKeyDown("Enter") g_keyboard.unbindKeyDown("Enter")
g_keyboard.unbindKeyDown("Escape") g_keyboard.unbindKeyDown("Escape")
disableChat(temporarily) disableChat(temporarily)
@ -233,6 +234,7 @@ function disableChat()
consoleTextEdit:setText("") consoleTextEdit:setText("")
local quickFunc = function() local quickFunc = function()
if not g_game.isOnline() then return end
if consoleToggleChat:isChecked() then if consoleToggleChat:isChecked() then
consoleToggleChat:setChecked(false) consoleToggleChat:setChecked(false)
end end

View File

@ -862,13 +862,13 @@ function refreshViewMode()
modules.client_topmenu.getTopMenu():setImageColor('white') modules.client_topmenu.getTopMenu():setImageColor('white')
gameBottomPanel:setImageColor('white') gameBottomPanel:setImageColor('white')
g_game.changeMapAwareRange(20, 16) g_game.changeMapAwareRange(19, 15)
if modules.game_console then if modules.game_console then
modules.game_console.switchMode(false) modules.game_console.switchMode(false)
end end
else else
g_game.changeMapAwareRange(30, 20) g_game.changeMapAwareRange(29, 19)
gameMapPanel:fill('parent') gameMapPanel:fill('parent')
gameRootPanel:fill('parent') gameRootPanel:fill('parent')
gameMapPanel:setKeepAspectRatio(false) gameMapPanel:setKeepAspectRatio(false)

View File

@ -283,7 +283,7 @@ function walk(dir)
dir = nextWalkDir dir = nextWalkDir
end end
local toPos = player:getNewPreWalkingPosition(true) local toPos = player:getPrewalkingPosition(true)
if dir == North then if dir == North then
toPos.y = toPos.y - 1 toPos.y = toPos.y - 1
elseif dir == East then elseif dir == East then
@ -324,11 +324,7 @@ function walk(dir)
local preWalked = false local preWalked = false
if toTile and toTile:isWalkable() then if toTile and toTile:isWalkable() then
if g_game.getFeature(GameNewWalking) then player:preWalk(dir)
player:newPreWalk(dir)
else
player:preWalk(dir)
end
preWalked = true preWalked = true
else else
local playerTile = player:getTile() local playerTile = player:getTile()
@ -339,8 +335,7 @@ function walk(dir)
end end
end end
g_game.callOnWalk(dir) g_game.walk(dir, preWalked)
g_game.forceWalk(dir, preWalked)
if not firstStep and lastWalkDir ~= dir then if not firstStep and lastWalkDir ~= dir then
walkLock = g_clock.millis() + g_settings.getNumber('walkTurnDelay') walkLock = g_clock.millis() + g_settings.getNumber('walkTurnDelay')

Binary file not shown.

Binary file not shown.

21
otclientv8.log Normal file
View File

@ -0,0 +1,21 @@
GPU ANGLE (Intel(R) UHD Graphics 620 Direct3D9Ex vs_3_0 ps_3_0)
OpenGL OpenGL ES 2.0 (ANGLE 2.1.a502c749b249)
== application started at Oct 03 2019 06:05:49
OTClientV8 0.95 beta rev 0 (alpha) made by otclient.ovh built on Oct 3 2019 for arch x86
GPU ANGLE (Intel(R) UHD Graphics 620 Direct3D9Ex vs_3_0 ps_3_0)
OpenGL OpenGL ES 2.0 (ANGLE 2.1.a502c749b249)
== application started at Oct 03 2019 06:18:44
OTClientV8 0.95 beta rev 0 (alpha) made by otclient.ovh built on Oct 3 2019 for arch x86
ERROR: protected lua call failed: attempt to call a boolean value
GPU Intel(R) UHD Graphics 620
OpenGL 4.5.0 - Build 24.20.100.6287
== application started at Oct 03 2019 06:22:12
OTClientV8 0.95 beta rev 0 (alpha) made by otclient.ovh built on Oct 2 2019 for arch x86
[Atlas] Texture size is: 4096x4096 (max: 16384x16384)
Exiting application..
GPU Intel(R) UHD Graphics 620
OpenGL 4.5.0 - Build 24.20.100.6287
== application started at Oct 03 2019 06:49:55
OTClientV8 0.95 beta rev 0 (alpha) made by otclient.ovh built on Oct 2 2019 for arch x86
[Atlas] Texture size is: 4096x4096 (max: 16384x16384)
Exiting application..

Binary file not shown.

Binary file not shown.

View File

@ -1,5 +1,5 @@
-- BETA VERSION, net tested yet -- BETA VERSION, net tested yet
-- Insteuction: -- Instruction:
-- creaturescripts.xml <event type="extendedopcode" name="Shop" script="shop.lua" /> -- creaturescripts.xml <event type="extendedopcode" name="Shop" script="shop.lua" />
-- and in login.lua player:registerEvent("Shop") -- and in login.lua player:registerEvent("Shop")
-- create sql table shop_history -- create sql table shop_history

120
tutorials/HTTP.md Normal file
View File

@ -0,0 +1,120 @@
## OTClientV8 HTTP protocol
OTClientV8 comes with HTTP/HTTPS and JSON support in lua.
### Available functions
```
HTTP.get(url, callback)
HTTP.getJSON(url, callback) -- website should return json
HTTP.post(url, data, callback)
HTTP.postJSON(url, data, callback) -- data should be a table {} and website should return json
HTTP.download(url, file, downloadCallback, progressCallback) -- progressCallback can be null
HTTP.downloadImage(url, downloadImageCallback)
HTTP.progress(operationId) -- return -1 on error or number from 0 to 100
HTTP.cancel(operationId)
```
Each function, except `cancel` and `progress` return operationId, you can use it to cancel or get progress of http request.
Those functions came from `modules/corelib/http.lua` and they use more advanced g_http API.
Files from download are available in virtual "/downloads" directory. Downloading of images is using cache based on url (so if you change image it won't refresh until restart or change url).
### Callbacks
For get, getJSON, post and postJSON HTTP callback should look like this:
```
function callback(data, err)
if err then
-- handle error, if err is not null then err is a string
return
end
-- handle data
-- if it's data from getJSON/postJSON then data is a table {}
end
```
For download:
```
function downloadCallback(path, checksum, err)
if err then
-- handle error, if err is not null then err is a string
return
end
-- do something with path and checksum
end
function progressCallback(progress, speed)
-- progress is from 0 to 100
-- speed is in kbps
end
```
For downloadImage:
```
function downloadImageCallback(path, err)
if err then
-- handle error, if err is not null then err is a string
return
end
-- do something with path to downloaded image
end
```
### Support for images from base64
If you want to load image from base64 there's special function for it: `Image:setImageSourceBase64(base64code)`
You can find an example of that in `modules/client_news/news.lua`. Only PNG images are supported.
### Timeout
Default timeout for every operations is 5s, you can change it in `modules/corelib/http.lua`.
### Examples
There are few lua scripts using HTTP api:
```
modules/client_entergame/entergame.lua
modules/client_feedback/feedback.lua
modules/client_news/news.lua
modules/client_updater/updater.lua
modules/game_shop/shop.lua
```
Examples:
```
HTTP.get("https://api.ipify.org/", function(data, err)
if err then
g_logger.info("Whoops! Error occured: " .. err)
return
end
g_logger.info("My IP is: " .. data)
end)
HTTP.getJSON("https://api.ipify.org/?format=json", function(data, err)
if err then
g_logger.info("Whoops! Error occured: " .. err)
return
end
g_logger.info("My IP is: " .. tostring(data['ip']))
end)
```
### Regex
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) {
int limit = 10000;
std::vector<std::vector<std::string>> ret;
if (s.empty() || exp.empty())
return ret;
try {
std::smatch m;
std::regex e(exp);
while (std::regex_search (s,m,e)) {
ret.push_back(std::vector<std::string>());
for (auto x:m)
ret[ret.size() - 1].push_back(x);
s = m.suffix().str();
if (--limit == 0)
return ret;
}
} catch (...) {
}
return ret;
});
```

59
tutorials/OTML.md Normal file
View File

@ -0,0 +1,59 @@
## OTClientV8 OTML extension
In many modules which are using OTML, you can see such code:
```
...
spelllistWindow = g_ui.displayUI('spelllist', modules.game_interface.getRightPanel())
spelllistWindow:hide()
nameValueLabel = spelllistWindow:getChildById('labelNameValue')
formulaValueLabel = spelllistWindow:getChildById('labelFormulaValue')
vocationValueLabel = spelllistWindow:getChildById('labelVocationValue')
groupValueLabel = spelllistWindow:getChildById('labelGroupValue')
typeValueLabel = spelllistWindow:getChildById('labelTypeValue')
cooldownValueLabel = spelllistWindow:getChildById('labelCooldownValue')
levelValueLabel = spelllistWindow:getChildById('labelLevelValue')
manaValueLabel = spelllistWindow:getChildById('labelManaValue')
premiumValueLabel = spelllistWindow:getChildById('labelPremiumValue')
descriptionValueLabel = spelllistWindow:getChildById('labelDescriptionValue')
...
```
Calling getChildById for every element in our OTML is annoying, taking unnecessary cpu time and looks awful. That's why there's new feature which creates reference to children automatically so you don't need to use getChildById ever again.
Instead of using:
```
spelllistWindow = g_ui.displayUI('spelllist', modules.game_interface.getRightPanel())
nameValueLabel = spelllistWindow:getChildById('labelNameValue')
formulaValueLabel = spelllistWindow:getChildById('labelFormulaValue')
vocationValueLabel = spelllistWindow:getChildById('labelVocationValue')
```
In OTClientV8 you can use:
```
spelllistWindow = g_ui.displayUI('spelllist', modules.game_interface.getRightPanel())
spelllistWindow.nameValueLabel
spelllistWindow.formulaValueLabel
spelllistWindow.vocationValueLabel
```
It has been added recently so most of the modules don't use this feature, but you can see it in action for example in `modules/game_shop` module.
In `shop.lua` there're 0 calls for getChildById, code looks like this:
```
shop = g_ui.displayUI('shop')
connect(shop.categories, { onChildFocusChange = changeCategory })
while shop.offers:getChildCount() > 0 do
local child = shop.offers:getLastChild()
shop.offers:destroyChildren(child)
end
shop.adPanel:setHeight(shop.infoPanel:getHeight())
shop.adPanel.ad:setText("")
category = g_ui.createWidget('ShopCategoryItem', shop.categories)
category.item:setItemId(data["item"])
category.item:setItemCount(data["count"])
```
So whenever possible, don't use getChildById. Use this new feature which is nicer and faster.

3
tutorials/Walking.md Normal file
View File

@ -0,0 +1,3 @@
# OTClientV8 New walking
## Check out: https://github.com/OTCv8/otclientv8-tfs