diff --git a/LICENSE b/LICENSE index c3930f3..758ad59 100644 --- a/LICENSE +++ b/LICENSE @@ -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 +Copyright (c) 2018-2019 OTClientV8 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index 91759dd..3ff2961 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,45 @@ # OTClientV8 -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 +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 and it's not backward compatible. # 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 @@ -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 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 diff --git a/init.lua b/init.lua index 592101c..4d6f517 100644 --- a/init.lua +++ b/init.lua @@ -1,6 +1,6 @@ -- CONFIG 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 = "" Services = { @@ -16,9 +16,11 @@ Services = { Servers = { OTClientV8 = "http://otclient.ovh/api/login.php", 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 -- print first terminal message diff --git a/modules/client_entergame/entergame.lua b/modules/client_entergame/entergame.lua index 9432208..ae72a9e 100644 --- a/modules/client_entergame/entergame.lua +++ b/modules/client_entergame/entergame.lua @@ -214,7 +214,6 @@ function EnterGame.init() local server = g_settings.get('server') local host = g_settings.get('host') local clientVersion = g_settings.get('client-version') - local hdSprites = g_settings.getBoolean('hdSprites', false) if serverSelector:isOption(server) then serverSelector:setCurrentOption(server, false) @@ -230,11 +229,7 @@ function EnterGame.init() enterGame:getChildById('accountPasswordTextEdit'):setText(password) enterGame:getChildById('accountNameTextEdit'):setText(account) rememberPasswordBox:setChecked(#account > 0) - - if enterGame.hdSprites then - enterGame.hdSprites:setChecked(hdSprites) - end - + g_keyboard.bindKeyDown('Ctrl+G', EnterGame.openWindow) if g_game.isOnline() then @@ -361,7 +356,6 @@ function EnterGame.doLogin() G.password = enterGame:getChildById('accountPasswordTextEdit'):getText() --G.authenticatorToken = enterGame:getChildById('authenticatorTokenTextEdit'):getText() G.authenticatorToken = "" - G.hdSprites = enterGame.hdSprites and enterGame.hdSprites:isChecked() G.stayLogged = true G.server = serverSelector:getText():trim() G.host = serverHostTextEdit:getText() @@ -374,7 +368,6 @@ function EnterGame.doLogin() g_settings.set('host', G.host) g_settings.set('server', G.server) g_settings.set('client-version', G.clientVersion) - g_settings.set('hdSprites', G.hdSprites) g_settings.save() if G.host:find("http") ~= nil then @@ -399,10 +392,6 @@ function EnterGame.doLogin() sprites = {G.clientVersion .. "/Tibia.spr", ""}, } - if G.hdSprites then - things.sprites_hd = {G.clientVersion .. "/Tibia_hd.spr", ""} - end - local incorrectThings = validateThings(things) if #incorrectThings > 0 then g_logger.info(incorrectThings) @@ -432,10 +421,12 @@ function EnterGame.doLogin() g_game.setProtocolVersion(g_game.getClientProtocolVersion(G.clientVersion)) g_game.setCustomProtocolVersion(0) g_game.chooseRsa(G.host) - g_game.setCustomOs(2) -- windows + -- g_game.setCustomOs(2) -- windows, optional - -- you can add custom features here - g_game.enableFeature(GameBot) + -- extra features from init.lua + for i = 4, #server_params do + g_game.enableFeature(tonumber(server_params[i])) + end -- proxies if g_proxy then @@ -443,7 +434,7 @@ function EnterGame.doLogin() end 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) else loadBox:destroy() @@ -467,7 +458,6 @@ function EnterGame.doLoginHttp() account = G.account, password = G.password, token = G.authenticatorToken, - hdSprites = G.hdSprites, version = APP_VERSION, uid = G.UUID } diff --git a/modules/corelib/http.lua b/modules/corelib/http.lua index a041b5e..7f21646 100644 --- a/modules/corelib/http.lua +++ b/modules/corelib/http.lua @@ -8,13 +8,13 @@ HTTP = { function HTTP.get(url, callback) local operation = g_http.get(url, HTTP.timeout) HTTP.operations[operation] = {type="get", url=url, callback=callback} - return opreation + return operation end function HTTP.getJSON(url, callback) local operation = g_http.get(url, HTTP.timeout) HTTP.operations[operation] = {type="get", json=true, url=url, callback=callback} - return opreation + return operation end function HTTP.post(url, data, callback) @@ -23,7 +23,7 @@ function HTTP.post(url, data, callback) end local operation = g_http.post(url, data, HTTP.timeout) HTTP.operations[operation] = {type="post", url=url, callback=callback} - return opreation + return operation end function HTTP.postJSON(url, data, callback) @@ -32,13 +32,13 @@ function HTTP.postJSON(url, data, callback) end local operation = g_http.post(url, data, HTTP.timeout) HTTP.operations[operation] = {type="post", json=true, url=url, callback=callback} - return opreation + return operation end function HTTP.download(url, file, callback, progressCallback) local operation = g_http.download(url, file, HTTP.timeout) HTTP.operations[operation] = {type="download", url=url, file=file, callback=callback, progressCallback=progressCallback} - return opreation + return operation end function HTTP.downloadImage(url, callback) @@ -52,7 +52,7 @@ function HTTP.downloadImage(url, callback) HTTP.imageId = HTTP.imageId + 1 local operation = g_http.download(url, file, HTTP.timeout) HTTP.operations[operation] = {type="image", url=url, file=file, callback=callback} - return opreation + return operation end function HTTP.progress(operationId) @@ -154,4 +154,5 @@ connect(g_http, onPostProgress = HTTP.onPostProgress, onDownload = HTTP.onDownload, onDownloadProgress = HTTP.onDownloadProgress - }) \ No newline at end of file + }) + \ No newline at end of file diff --git a/modules/game_console/console.lua b/modules/game_console/console.lua index b413c83..2cfac2a 100644 --- a/modules/game_console/console.lua +++ b/modules/game_console/console.lua @@ -208,6 +208,7 @@ function enableChat(temporarily) if temporarily then local quickFunc = function() + if not g_game.isOnline() then return end g_keyboard.unbindKeyDown("Enter") g_keyboard.unbindKeyDown("Escape") disableChat(temporarily) @@ -233,6 +234,7 @@ function disableChat() consoleTextEdit:setText("") local quickFunc = function() + if not g_game.isOnline() then return end if consoleToggleChat:isChecked() then consoleToggleChat:setChecked(false) end diff --git a/modules/game_interface/gameinterface.lua b/modules/game_interface/gameinterface.lua index bfd8d9a..107abaa 100644 --- a/modules/game_interface/gameinterface.lua +++ b/modules/game_interface/gameinterface.lua @@ -862,13 +862,13 @@ function refreshViewMode() modules.client_topmenu.getTopMenu():setImageColor('white') gameBottomPanel:setImageColor('white') - g_game.changeMapAwareRange(20, 16) + g_game.changeMapAwareRange(19, 15) if modules.game_console then modules.game_console.switchMode(false) end else - g_game.changeMapAwareRange(30, 20) + g_game.changeMapAwareRange(29, 19) gameMapPanel:fill('parent') gameRootPanel:fill('parent') gameMapPanel:setKeepAspectRatio(false) diff --git a/modules/game_walking/walking.lua b/modules/game_walking/walking.lua index 9b5dbce..6b4cb23 100644 --- a/modules/game_walking/walking.lua +++ b/modules/game_walking/walking.lua @@ -283,7 +283,7 @@ function walk(dir) dir = nextWalkDir end - local toPos = player:getNewPreWalkingPosition(true) + local toPos = player:getPrewalkingPosition(true) if dir == North then toPos.y = toPos.y - 1 elseif dir == East then @@ -324,11 +324,7 @@ function walk(dir) local preWalked = false if toTile and toTile:isWalkable() then - if g_game.getFeature(GameNewWalking) then - player:newPreWalk(dir) - else - player:preWalk(dir) - end + player:preWalk(dir) preWalked = true else local playerTile = player:getTile() @@ -339,8 +335,7 @@ function walk(dir) end end - g_game.callOnWalk(dir) - g_game.forceWalk(dir, preWalked) + g_game.walk(dir, preWalked) if not firstStep and lastWalkDir ~= dir then walkLock = g_clock.millis() + g_settings.getNumber('walkTurnDelay') diff --git a/otclient_dx.exe b/otclient_dx.exe index 3c17adf..2be5c77 100644 Binary files a/otclient_dx.exe and b/otclient_dx.exe differ diff --git a/otclient_gl.exe b/otclient_gl.exe index 040955b..c4fc156 100644 Binary files a/otclient_gl.exe and b/otclient_gl.exe differ diff --git a/otclientv8.log b/otclientv8.log new file mode 100644 index 0000000..34bce47 --- /dev/null +++ b/otclientv8.log @@ -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.. diff --git a/pdb/otclient_dx.pdb b/pdb/otclient_dx.pdb index d70731a..d3603ce 100644 Binary files a/pdb/otclient_dx.pdb and b/pdb/otclient_dx.pdb differ diff --git a/pdb/otclient_gl.pdb b/pdb/otclient_gl.pdb index e974d7b..def051f 100644 Binary files a/pdb/otclient_gl.pdb and b/pdb/otclient_gl.pdb differ diff --git a/server/shop/shop.lua b/server/shop/shop.lua index 9e5a7d8..dac8217 100644 --- a/server/shop/shop.lua +++ b/server/shop/shop.lua @@ -1,5 +1,5 @@ -- BETA VERSION, net tested yet --- Insteuction: +-- Instruction: -- creaturescripts.xml -- and in login.lua player:registerEvent("Shop") -- create sql table shop_history diff --git a/tutorials/HTTP.md b/tutorials/HTTP.md new file mode 100644 index 0000000..03c4f4b --- /dev/null +++ b/tutorials/HTTP.md @@ -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> 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()); + for (auto x:m) + ret[ret.size() - 1].push_back(x); + s = m.suffix().str(); + if (--limit == 0) + return ret; + } + } catch (...) { + } + return ret; + }); +``` diff --git a/tutorials/OTML.md b/tutorials/OTML.md new file mode 100644 index 0000000..52bda7e --- /dev/null +++ b/tutorials/OTML.md @@ -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. diff --git a/tutorials/Walking.md b/tutorials/Walking.md new file mode 100644 index 0000000..aca967d --- /dev/null +++ b/tutorials/Walking.md @@ -0,0 +1,3 @@ +# OTClientV8 New walking + +## Check out: https://github.com/OTCv8/otclientv8-tfs \ No newline at end of file