diff --git a/.dockerignore b/.dockerignore index 2f1255d2c0..f46d814c7d 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,2 +1,12 @@ +/.git/ +/.github/ +/.idea/ +/.vs/ +/android/ /build/ +/cmake-build* +/vc17/ Dockerfile +*.dll +*.exe +*.pdb diff --git a/.github/workflows/analysis-sonarcloud.yml b/.github/workflows/analysis-sonarcloud.yml index 6ae1659c6a..9555b18a66 100644 --- a/.github/workflows/analysis-sonarcloud.yml +++ b/.github/workflows/analysis-sonarcloud.yml @@ -79,6 +79,7 @@ jobs: with: vcpkgGitURL: "https://github.com/microsoft/vcpkg.git" vcpkgGitCommitId: ${{ steps.vcpkg-step.outputs.vcpkgGitCommitId }} + vcpkgJsonIgnores: "['**/vcpkg/**', '**/browser/overlay-ports/**']" - name: Install sonar-scanner uses: SonarSource/sonarcloud-github-c-cpp@v1 diff --git a/.github/workflows/build-ubuntu.yml b/.github/workflows/build-ubuntu.yml index a116a8e4b2..448140cd98 100644 --- a/.github/workflows/build-ubuntu.yml +++ b/.github/workflows/build-ubuntu.yml @@ -52,6 +52,7 @@ jobs: uses: lukka/run-vcpkg@main with: vcpkgGitCommitId: ${{ steps.vcpkg-step.outputs.vcpkgGitCommitId }} + vcpkgJsonIgnores: "['**/vcpkg/**', '**/browser/overlay-ports/**']" - name: Get latest CMake and ninja uses: lukka/get-cmake@main diff --git a/.github/workflows/build-windows.yml b/.github/workflows/build-windows.yml index 4e4f68e7b1..0f40a87a45 100644 --- a/.github/workflows/build-windows.yml +++ b/.github/workflows/build-windows.yml @@ -52,6 +52,7 @@ jobs: with: vcpkgGitURL: "https://github.com/microsoft/vcpkg.git" vcpkgGitCommitId: ${{ steps.vcpkg-step.outputs.vcpkgGitCommitId }} + vcpkgJsonIgnores: "['**/vcpkg/**', '**/browser/overlay-ports/**']" - name: Get latest CMake and ninja uses: lukka/get-cmake@main diff --git a/README.md b/README.md index 87d01e242f..27a7425a18 100644 --- a/README.md +++ b/README.md @@ -467,6 +467,8 @@ Beyond of it's flexibility with scripts, otclient comes with tons of other featu - Module Shop - Module Oufit - Placeholder +- UIGraph +- keybinds ## Android The Mobile Project The Mobile Project diff --git a/browser/include/bitlib/LICENSE b/browser/include/bitlib/LICENSE new file mode 100644 index 0000000000..bdbdbc8386 --- /dev/null +++ b/browser/include/bitlib/LICENSE @@ -0,0 +1,20 @@ + bitlib + ------ + + by Reuben Thomas + http://luaforge.net/projects/bitlib + + +bitlib is a C library for Lua 5.1 that provides bitwise operations. It +is copyright Reuben Thomas 2000-2009, and is released under the MIT +license, like Lua (see http://www.lua.org/copyright.html; it's +basically the same as the BSD license). There is no warranty. + +Please report bugs and make suggestions to the email address above, or +use the LuaForge trackers. + +Thanks to John Passaniti for his bitwise operations library, some of +whose ideas I used, to Shmuel Zeigerman for the test suite, to +Thatcher Ulrich for portability fixes, and to Enrico Tassi, John +Stiles and Eduardo Ochs for bug reports. + diff --git a/browser/include/bitlib/bit_limits.h b/browser/include/bitlib/bit_limits.h new file mode 100644 index 0000000000..943b2fd7e9 --- /dev/null +++ b/browser/include/bitlib/bit_limits.h @@ -0,0 +1,4 @@ +#define BITLIB_FLOAT_BITS 53 +#define BITLIB_FLOAT_MAX 0xfffffffffffffL +#define BITLIB_FLOAT_MIN (-0x10000000000000L) +#define BITLIB_FLOAT_UMAX 0x1fffffffffffffUL diff --git a/browser/include/bitlib/lbitlib.c b/browser/include/bitlib/lbitlib.c new file mode 100644 index 0000000000..87d736387f --- /dev/null +++ b/browser/include/bitlib/lbitlib.c @@ -0,0 +1,129 @@ +/* Bitwise operations library */ +/* (c) Reuben Thomas 2000-2008 */ +/* See README for license */ + +#include "bit_limits.h" + + +/* FIXME: Assumes lua_Integer is ptrdiff_t */ +#define LUA_INTEGER_MAX PTRDIFF_MAX +#define LUA_INTEGER_MIN PTRDIFF_MIN + +/* FIXME: Assumes size_t is an unsigned lua_Integer */ +typedef size_t lua_UInteger; +#define LUA_UINTEGER_MAX SIZE_MAX + + +/* Bit type size and limits */ + +#define BIT_BITS \ + (CHAR_BIT * sizeof(lua_Integer) > BITLIB_FLOAT_BITS ? \ + BITLIB_FLOAT_BITS : (CHAR_BIT * sizeof(lua_Integer))) + +/* This code may give warnings if BITLIB_FLOAT_* are too big to fit in + long, but that doesn't matter since in that case they won't be + used. */ +#define BIT_MAX \ + (CHAR_BIT * sizeof(lua_Integer) > BITLIB_FLOAT_BITS ? BITLIB_FLOAT_MAX : LUA_INTEGER_MAX) + +#define BIT_MIN \ + (CHAR_BIT * sizeof(lua_Integer) > BITLIB_FLOAT_BITS ? BITLIB_FLOAT_MIN : LUA_INTEGER_MIN) + +#define BIT_UMAX \ + (CHAR_BIT * sizeof(lua_Integer) > BITLIB_FLOAT_BITS ? BITLIB_FLOAT_UMAX : LUA_UINTEGER_MAX) + + +/* Define TOBIT to get a bit value */ +#ifdef BUILTIN_CAST +#define +#define TOBIT(L, n, res) \ + ((void)(res), luaL_checkinteger((L), (n))) +#else +#include +#include + +/* FIXME: Assumes lua_Number fits in a double (use of fmod). */ +#define TOBIT(L, n, res) \ + ((lua_Integer)(((res) = fmod(luaL_checknumber(L, (n)), (double)BIT_UMAX + 1.0)), \ + (res) > BIT_MAX ? ((res) -= (double)BIT_UMAX, (res) -= 1) : \ + ((res) < BIT_MIN ? ((res) += (double)BIT_UMAX, (res) += 1) : (res)))) +#endif + + +#define BIT_TRUNCATE(i) \ + ((i) & BIT_UMAX) + + +/* Operations + + The macros MONADIC and VARIADIC only deal with bitwise operations. + + LOGICAL_SHIFT truncates its left-hand operand before shifting so + that any extra bits at the most-significant end are not shifted + into the result. + + ARITHMETIC_SHIFT does not truncate its left-hand operand, so that + the sign bits are not removed and right shift work properly. + */ + +#define MONADIC(name, op) \ + static int bit_ ## name(lua_State *L) { \ + lua_Number f; \ + lua_pushinteger(L, BIT_TRUNCATE(op TOBIT(L, 1, f))); \ + return 1; \ + } + +#define VARIADIC(name, op) \ + static int bit_ ## name(lua_State *L) { \ + lua_Number f; \ + int n = lua_gettop(L), i; \ + lua_Integer w = TOBIT(L, 1, f); \ + for (i = 2; i <= n; i++) \ + w op TOBIT(L, i, f); \ + lua_pushinteger(L, BIT_TRUNCATE(w)); \ + return 1; \ + } + +#define LOGICAL_SHIFT(name, op) \ + static int bit_ ## name(lua_State *L) { \ + lua_Number f; \ + lua_pushinteger(L, BIT_TRUNCATE(BIT_TRUNCATE((lua_UInteger)TOBIT(L, 1, f)) op \ + (unsigned)luaL_checknumber(L, 2))); \ + return 1; \ + } + +#define ARITHMETIC_SHIFT(name, op) \ + static int bit_ ## name(lua_State *L) { \ + lua_Number f; \ + lua_pushinteger(L, BIT_TRUNCATE((lua_Integer)TOBIT(L, 1, f) op \ + (unsigned)luaL_checknumber(L, 2))); \ + return 1; \ + } + +MONADIC(cast, +) +MONADIC(bnot, ~) +VARIADIC(band, &=) +VARIADIC(bor, |=) +VARIADIC(bxor, ^=) +ARITHMETIC_SHIFT(lshift, <<) +LOGICAL_SHIFT(rshift, >>) +ARITHMETIC_SHIFT(arshift, >>) + +static const struct luaL_reg bitlib[] = { + {"cast", bit_cast}, + {"bnot", bit_bnot}, + {"band", bit_band}, + {"bor", bit_bor}, + {"bxor", bit_bxor}, + {"lshift", bit_lshift}, + {"rshift", bit_rshift}, + {"arshift", bit_arshift}, + {NULL, NULL} +}; + +LUALIB_API int luaopen_bit (lua_State *L) { + luaL_register(L, "bit", bitlib); + lua_pushnumber(L, BIT_BITS); + lua_setfield(L, -2, "bits"); + return 1; +} diff --git a/browser/overlay-ports/abseil/portfile.cmake b/browser/overlay-ports/abseil/portfile.cmake new file mode 100644 index 0000000000..5bddf86eb8 --- /dev/null +++ b/browser/overlay-ports/abseil/portfile.cmake @@ -0,0 +1,55 @@ +if(NOT VCPKG_TARGET_IS_WINDOWS) + vcpkg_check_linkage(ONLY_STATIC_LIBRARY) +endif() + +vcpkg_from_github( + OUT_SOURCE_PATH SOURCE_PATH + REPO abseil/abseil-cpp + REF "${VERSION}" + SHA512 bd2cca8f007f2eee66f51c95a979371622b850ceb2ce3608d00ba826f7c494a1da0fba3c1427728f2c173fe50d59b701da35c2c9fdad2752a5a49746b1c8ef31 + HEAD_REF master + PATCHES + use_pthread.patch +) + +# With ABSL_PROPAGATE_CXX_STD=ON abseil automatically detect if it is being +# compiled with C++14 or C++17, and modifies the installed `absl/base/options.h` +# header accordingly. This works even if CMAKE_CXX_STANDARD is not set. Abseil +# uses the compiler default behavior to update `absl/base/options.h` as needed. +set(ABSL_USE_CXX17_OPTION "") +if("cxx17" IN_LIST FEATURES) + set(ABSL_USE_CXX17_OPTION "-DCMAKE_CXX_STANDARD=17") +endif() + +set(ABSL_STATIC_RUNTIME_OPTION "") +if(VCPKG_TARGET_IS_WINDOWS AND VCPKG_CRT_LINKAGE STREQUAL "static") + set(ABSL_STATIC_RUNTIME_OPTION "-DABSL_MSVC_STATIC_RUNTIME=ON") +endif() + +vcpkg_cmake_configure( + SOURCE_PATH "${SOURCE_PATH}" + DISABLE_PARALLEL_CONFIGURE + OPTIONS + -DABSL_PROPAGATE_CXX_STD=ON + ${ABSL_USE_CXX17_OPTION} + ${ABSL_STATIC_RUNTIME_OPTION} +) + +vcpkg_cmake_install() +vcpkg_cmake_config_fixup(PACKAGE_NAME absl CONFIG_PATH lib/cmake/absl) +vcpkg_fixup_pkgconfig() + +vcpkg_copy_pdbs() +file(REMOVE_RECURSE "${CURRENT_PACKAGES_DIR}/debug/share" + "${CURRENT_PACKAGES_DIR}/debug/include" + "${CURRENT_PACKAGES_DIR}/include/absl/copts" + "${CURRENT_PACKAGES_DIR}/include/absl/strings/testdata" + "${CURRENT_PACKAGES_DIR}/include/absl/time/internal/cctz/testdata" +) + +if(VCPKG_TARGET_IS_WINDOWS AND VCPKG_LIBRARY_LINKAGE STREQUAL "dynamic") + vcpkg_replace_string("${CURRENT_PACKAGES_DIR}/include/absl/base/config.h" "defined(ABSL_CONSUME_DLL)" "1") + vcpkg_replace_string("${CURRENT_PACKAGES_DIR}/include/absl/base/internal/thread_identity.h" "defined(ABSL_CONSUME_DLL)" "1") +endif() + +vcpkg_install_copyright(FILE_LIST "${SOURCE_PATH}/LICENSE") diff --git a/browser/overlay-ports/abseil/use_pthread.patch b/browser/overlay-ports/abseil/use_pthread.patch new file mode 100644 index 0000000000..12b614cc4f --- /dev/null +++ b/browser/overlay-ports/abseil/use_pthread.patch @@ -0,0 +1,13 @@ +diff --git a/CMakeLists.txt b/CMakeLists.txt +index 7c82b3a..48474ec 100644 +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -27,6 +27,8 @@ project(absl LANGUAGES CXX VERSION 20240722) + set(ABSL_SOVERSION "2407.0.0") + include(CTest) + ++add_compile_options(-pthread) ++ + # Output directory is correct by default for most build setups. However, when + # building Abseil as a DLL, it is important to have the DLL in the same + # directory as the executable using it. Thus, we put all executables in a single diff --git a/browser/overlay-ports/abseil/vcpkg.json b/browser/overlay-ports/abseil/vcpkg.json new file mode 100644 index 0000000000..b3b191d1ad --- /dev/null +++ b/browser/overlay-ports/abseil/vcpkg.json @@ -0,0 +1,27 @@ +{ + "name": "abseil", + "version": "20240722.0", + "description": [ + "Abseil is an open-source collection of C++ library code designed to augment the C++ standard library. The Abseil library code is collected from Google's own C++ code base, has been extensively tested and used in production, and is the same code we depend on in our daily coding lives.", + "In some cases, Abseil provides pieces missing from the C++ standard; in others, Abseil provides alternatives to the standard for special needs we've found through usage in the Google code base. We denote those cases clearly within the library code we provide you.", + "Abseil is not meant to be a competitor to the standard library; we've just found that many of these utilities serve a purpose within our code base, and we now want to provide those resources to the C++ community as a whole." + ], + "homepage": "https://github.com/abseil/abseil-cpp", + "license": "Apache-2.0", + "dependencies": [ + { + "name": "vcpkg-cmake", + "host": true + }, + { + "name": "vcpkg-cmake-config", + "host": true + } + ], + "features": { + "cxx17": { + "description": "Enable compiler C++17." + } + }, + "builtin-baseline":"c82f74667287d3dc386bce81e44964370c91a289" +} diff --git a/browser/overlay-ports/physfs/portfile.cmake b/browser/overlay-ports/physfs/portfile.cmake new file mode 100644 index 0000000000..980df74cfa --- /dev/null +++ b/browser/overlay-ports/physfs/portfile.cmake @@ -0,0 +1,45 @@ +vcpkg_minimum_required(VERSION 2022-10-12) # for ${VERSION} +vcpkg_from_github( + OUT_SOURCE_PATH SOURCE_PATH + REPO icculus/physfs + REF "release-${VERSION}" + SHA512 e0d84d6ac6bd8f0973149a5add54ed5ed890b5fabb4592ba61b59a3b3e01c05e05f1754f18d7a1c8d72e68777a23cda0c50dc0512cf57a8310a950bf908f54b1 + PATCHES + use_pthread.patch +) + +string(COMPARE EQUAL "${VCPKG_LIBRARY_LINKAGE}" "static" PHYSFS_STATIC) +string(COMPARE EQUAL "${VCPKG_LIBRARY_LINKAGE}" "dynamic" PHYSFS_SHARED) + +set(generator_param "") +if(VCPKG_TARGET_IS_UWP) + set(generator_param WINDOWS_USE_MSBUILD) +endif() + +vcpkg_cmake_configure( + SOURCE_PATH "${SOURCE_PATH}" + ${generator_param} + OPTIONS + -DPHYSFS_BUILD_STATIC=${PHYSFS_STATIC} + -DPHYSFS_BUILD_SHARED=${PHYSFS_SHARED} + -DPHYSFS_BUILD_TEST=OFF + -DPHYSFS_BUILD_DOCS=OFF +) + +vcpkg_cmake_install() +vcpkg_copy_pdbs() + +vcpkg_cmake_config_fixup(CONFIG_PATH lib/cmake/PhysFS) +vcpkg_fixup_pkgconfig() + +if(PHYSFS_STATIC) + vcpkg_replace_string("${CURRENT_PACKAGES_DIR}/include/physfs.h" "defined(PHYSFS_STATIC)" "1") +else() + vcpkg_replace_string("${CURRENT_PACKAGES_DIR}/include/physfs.h" "dllexport" "dllimport") +endif() + +file(REMOVE_RECURSE "${CURRENT_PACKAGES_DIR}/debug/include") + +file(INSTALL "${CMAKE_CURRENT_LIST_DIR}/vcpkg-cmake-wrapper.cmake" DESTINATION "${CURRENT_PACKAGES_DIR}/share/${PORT}") +file(INSTALL "${CMAKE_CURRENT_LIST_DIR}/usage" DESTINATION "${CURRENT_PACKAGES_DIR}/share/${PORT}") +file(INSTALL "${SOURCE_PATH}/LICENSE.txt" DESTINATION "${CURRENT_PACKAGES_DIR}/share/${PORT}" RENAME copyright) diff --git a/browser/overlay-ports/physfs/usage b/browser/overlay-ports/physfs/usage new file mode 100644 index 0000000000..39a71fd090 --- /dev/null +++ b/browser/overlay-ports/physfs/usage @@ -0,0 +1,10 @@ +physfs provides CMake targets: + + find_package(PhysFS CONFIG REQUIRED) + target_link_libraries(main PRIVATE $,PhysFS::PhysFS,PhysFS::PhysFS-static>) + +physfs is compatible with built-in CMake targets: + + find_package(PhysFS REQUIRED) + target_include_directories(main PRIVATE ${PHYSFS_INCLUDE_DIR}) + target_link_libraries(main PRIVATE ${PHYSFS_LIBRARY}) diff --git a/browser/overlay-ports/physfs/use_pthread.patch b/browser/overlay-ports/physfs/use_pthread.patch new file mode 100644 index 0000000000..8bae3092b4 --- /dev/null +++ b/browser/overlay-ports/physfs/use_pthread.patch @@ -0,0 +1,13 @@ +diff --git a/CMakeLists.txt b/CMakeLists.txt +index b3291cc..a5d8225 100644 +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -25,6 +25,8 @@ set(PHYSFS_CPP_SRCS) + + # I hate that they define "WIN32" ... we're about to move to Win64...I hope! + ++add_compile_options(-pthread) ++ + if(APPLE) + set(OTHER_LDFLAGS ${OTHER_LDFLAGS} "-framework IOKit -framework Foundation") + list(APPEND PHYSFS_M_SRCS src/physfs_platform_apple.m) diff --git a/browser/overlay-ports/physfs/vcpkg-cmake-wrapper.cmake b/browser/overlay-ports/physfs/vcpkg-cmake-wrapper.cmake new file mode 100644 index 0000000000..945206048b --- /dev/null +++ b/browser/overlay-ports/physfs/vcpkg-cmake-wrapper.cmake @@ -0,0 +1,6 @@ +find_library(PHYSFS_LIBRARY_RELEASE NAMES physfs physfs-static NAMES_PER_DIR PATHS "${_VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}/lib" NO_DEFAULT_PATH) +find_library(PHYSFS_LIBRARY_DEBUG NAMES physfs physfs-static NAMES_PER_DIR PATHS "${_VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}/debug/lib" NO_DEFAULT_PATH) +include(SelectLibraryConfigurations) +select_library_configurations(PHYSFS) +unset(PHYSFS_FOUND) +_find_package(${ARGS}) diff --git a/browser/overlay-ports/physfs/vcpkg.json b/browser/overlay-ports/physfs/vcpkg.json new file mode 100644 index 0000000000..4147529ac9 --- /dev/null +++ b/browser/overlay-ports/physfs/vcpkg.json @@ -0,0 +1,19 @@ +{ + "name": "physfs", + "version-semver": "3.2.0", + "port-version": 1, + "description": "a library to provide abstract access to various archives", + "homepage": "https://icculus.org/physfs/", + "license": "Zlib", + "dependencies": [ + { + "name": "vcpkg-cmake", + "host": true + }, + { + "name": "vcpkg-cmake-config", + "host": true + } + ], + "builtin-baseline":"c82f74667287d3dc386bce81e44964370c91a289" +} diff --git a/browser/overlay-ports/protobuf/fix-arm64-msvc.patch b/browser/overlay-ports/protobuf/fix-arm64-msvc.patch new file mode 100644 index 0000000000..2a13f1b77f --- /dev/null +++ b/browser/overlay-ports/protobuf/fix-arm64-msvc.patch @@ -0,0 +1,22 @@ +diff --git a/src/google/protobuf/parse_context.h b/src/google/protobuf/parse_context.h +index df12ee1ab..3eb2e56c7 100644 +--- a/src/google/protobuf/parse_context.h ++++ b/src/google/protobuf/parse_context.h +@@ -653,7 +653,7 @@ inline const char* VarintParseSlow(const char* p, uint32_t res, uint64_t* out) { + return tmp.first; + } + +-#ifdef __aarch64__ ++#if defined(__aarch64__) && !defined(_MSC_VER) + // Generally, speaking, the ARM-optimized Varint decode algorithm is to extract + // and concatenate all potentially valid data bits, compute the actual length + // of the Varint, and mask off the data bits which are not actually part of the +@@ -883,7 +883,7 @@ static const char* VarintParseSlowArm(const char* p, uint64_t* out, + + template + PROTOBUF_NODISCARD const char* VarintParse(const char* p, T* out) { +-#if defined(__aarch64__) && defined(PROTOBUF_LITTLE_ENDIAN) ++#if defined(__aarch64__) && defined(PROTOBUF_LITTLE_ENDIAN) && !defined(_MSC_VER) + // This optimization is not supported in big endian mode + uint64_t first8; + std::memcpy(&first8, p, sizeof(first8)); diff --git a/browser/overlay-ports/protobuf/fix-default-proto-file-path.patch b/browser/overlay-ports/protobuf/fix-default-proto-file-path.patch new file mode 100644 index 0000000000..c30abeb9ba --- /dev/null +++ b/browser/overlay-ports/protobuf/fix-default-proto-file-path.patch @@ -0,0 +1,21 @@ +diff --git a/src/google/protobuf/compiler/command_line_interface.cc b/src/google/protobuf/compiler/command_line_interface.cc +index f9e9666..d453a4c 100644 +--- a/src/google/protobuf/compiler/command_line_interface.cc ++++ b/src/google/protobuf/compiler/command_line_interface.cc +@@ -280,12 +280,15 @@ void AddDefaultProtoPaths( + paths->emplace_back("", std::move(include_path)); + return; + } +- // Check if the upper level directory has an "include" subdirectory. ++ // change "'$/bin' is next to 'include'" assumption to "'$/bin/tools' is next to 'include'" ++ for (int i = 0; i < 2; i++) ++ { + pos = path.find_last_of("/\\"); + if (pos == std::string::npos || pos == 0) { + return; + } + path = path.substr(0, pos); ++ } + include_path = absl::StrCat(path, "/include"); + if (IsInstalledProtoPath(include_path)) { + paths->emplace_back("", std::move(include_path)); diff --git a/browser/overlay-ports/protobuf/fix-static-build.patch b/browser/overlay-ports/protobuf/fix-static-build.patch new file mode 100644 index 0000000000..e0ea7fd095 --- /dev/null +++ b/browser/overlay-ports/protobuf/fix-static-build.patch @@ -0,0 +1,21 @@ +diff --git a/cmake/install.cmake b/cmake/install.cmake +index 998c2e31a..233f9e400 100644 +--- a/cmake/install.cmake ++++ b/cmake/install.cmake +@@ -49,7 +49,7 @@ if (protobuf_BUILD_PROTOC_BINARIES) + install(TARGETS protoc EXPORT protobuf-targets + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT protoc + BUNDLE DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT protoc) +- if (UNIX AND NOT APPLE) ++ if (UNIX AND NOT APPLE AND NOT protobuf_MSVC_STATIC_RUNTIME) + set_property(TARGET protoc + PROPERTY INSTALL_RPATH "$ORIGIN/../${CMAKE_INSTALL_LIBDIR}") + elseif (APPLE) +@@ -68,7 +68,6 @@ set(protobuf_HEADERS + ${cpp_features_proto_proto_srcs} + ${descriptor_proto_proto_srcs} + ${plugin_proto_proto_srcs} +- ${java_features_proto_proto_srcs} + ) + foreach(_header ${protobuf_HEADERS}) + string(FIND ${_header} "${protobuf_SOURCE_DIR}/src" _find_src) diff --git a/browser/overlay-ports/protobuf/fix-utf8-range.patch b/browser/overlay-ports/protobuf/fix-utf8-range.patch new file mode 100644 index 0000000000..d2a4600ec7 --- /dev/null +++ b/browser/overlay-ports/protobuf/fix-utf8-range.patch @@ -0,0 +1,48 @@ +diff --git a/CMakeLists.txt b/CMakeLists.txt +index 4137ce2e9..f1289e08a 100644 +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -294,6 +294,7 @@ endif (protobuf_BUILD_TESTS) + include(${protobuf_SOURCE_DIR}/cmake/abseil-cpp.cmake) + + if (protobuf_BUILD_PROTOBUF_BINARIES) ++ find_package(utf8_range CONFIG REQUIRED) + include(${protobuf_SOURCE_DIR}/cmake/utf8_range.cmake) + include(${protobuf_SOURCE_DIR}/cmake/libprotobuf-lite.cmake) + if (NOT DEFINED protobuf_LIB_PROTOBUF_LITE) +diff --git a/cmake/libprotobuf-lite.cmake b/cmake/libprotobuf-lite.cmake +index f343458cf..f4b1e0faa 100644 +--- a/cmake/libprotobuf-lite.cmake ++++ b/cmake/libprotobuf-lite.cmake +@@ -42,4 +42,4 @@ set_target_properties(libprotobuf-lite PROPERTIES + ) + add_library(protobuf::libprotobuf-lite ALIAS libprotobuf-lite) + +-target_link_libraries(libprotobuf-lite PRIVATE utf8_validity) ++target_link_libraries(libprotobuf-lite PRIVATE utf8_range::utf8_validity) +diff --git a/cmake/libprotobuf.cmake b/cmake/libprotobuf.cmake +index 422754a1a..fa9956685 100644 +--- a/cmake/libprotobuf.cmake ++++ b/cmake/libprotobuf.cmake +@@ -45,4 +45,4 @@ set_target_properties(libprotobuf PROPERTIES + ) + add_library(protobuf::libprotobuf ALIAS libprotobuf) + +-target_link_libraries(libprotobuf PRIVATE utf8_validity) ++target_link_libraries(libprotobuf PRIVATE utf8_range::utf8_validity) +diff --git a/cmake/utf8_range.cmake b/cmake/utf8_range.cmake +index f411a8c5b..21bf8235b 100644 +--- a/cmake/utf8_range.cmake ++++ b/cmake/utf8_range.cmake +@@ -1,4 +1,4 @@ +-if (NOT TARGET utf8_range) ++if (0) + set(utf8_range_ENABLE_TESTS OFF CACHE BOOL "Disable utf8_range tests") + + if (NOT EXISTS "${protobuf_SOURCE_DIR}/third_party/utf8_range/CMakeLists.txt") +@@ -12,4 +12,4 @@ if (NOT TARGET utf8_range) + include_directories(${CMAKE_CURRENT_SOURCE_DIR}/third_party/utf8_range) + endif () + +-set(_protobuf_FIND_UTF8_RANGE "if(NOT TARGET utf8_range)\n find_package(utf8_range CONFIG)\nendif()") ++set(_protobuf_FIND_UTF8_RANGE "if(NOT TARGET utf8_range::utf8_range)\n find_package(utf8_range CONFIG)\nendif()") diff --git a/browser/overlay-ports/protobuf/portfile.cmake b/browser/overlay-ports/protobuf/portfile.cmake new file mode 100644 index 0000000000..fdc2e7ba94 --- /dev/null +++ b/browser/overlay-ports/protobuf/portfile.cmake @@ -0,0 +1,136 @@ +vcpkg_from_github( + OUT_SOURCE_PATH SOURCE_PATH + REPO protocolbuffers/protobuf + REF "v${VERSION}" + SHA512 ce81add9d978a6b63d4205715eac5084e81a6753da1f6c6bad6493e60253215901bffc4a60d704a873333f2b9f94fd86cb7eb5b293035f2268c12692bd808bac + HEAD_REF master + PATCHES + use_pthread.patch + fix-static-build.patch + fix-default-proto-file-path.patch + fix-utf8-range.patch + fix-arm64-msvc.patch +) + +string(COMPARE EQUAL "${TARGET_TRIPLET}" "${HOST_TRIPLET}" protobuf_BUILD_PROTOC_BINARIES) +string(COMPARE EQUAL "${VCPKG_LIBRARY_LINKAGE}" "dynamic" protobuf_BUILD_SHARED_LIBS) +string(COMPARE EQUAL "${VCPKG_CRT_LINKAGE}" "static" protobuf_MSVC_STATIC_RUNTIME) + +vcpkg_check_features(OUT_FEATURE_OPTIONS FEATURE_OPTIONS + FEATURES + zlib protobuf_WITH_ZLIB +) + +if(VCPKG_TARGET_IS_UWP) + set(protobuf_BUILD_LIBPROTOC OFF) +else() + set(protobuf_BUILD_LIBPROTOC ON) +endif() + +if (VCPKG_DOWNLOAD_MODE) + # download PKGCONFIG in download mode which is used in `vcpkg_fixup_pkgconfig()` at the end of this script. + # download it here because `vcpkg_cmake_configure()` halts execution in download mode when running configure process. + vcpkg_find_acquire_program(PKGCONFIG) +endif() + +# Delete language backends we aren't targeting to reduce false positives in automated dependency +# detectors like Dependabot. +file(REMOVE_RECURSE + "${SOURCE_PATH}/csharp" + "${SOURCE_PATH}/java" + "${SOURCE_PATH}/lua" + "${SOURCE_PATH}/objectivec" + "${SOURCE_PATH}/php" + "${SOURCE_PATH}/python" + "${SOURCE_PATH}/ruby" + "${SOURCE_PATH}/rust" +) + +vcpkg_cmake_configure( + SOURCE_PATH "${SOURCE_PATH}" + OPTIONS + -Dprotobuf_BUILD_SHARED_LIBS=${protobuf_BUILD_SHARED_LIBS} + -Dprotobuf_MSVC_STATIC_RUNTIME=${protobuf_MSVC_STATIC_RUNTIME} + -Dprotobuf_BUILD_TESTS=OFF + -DCMAKE_INSTALL_CMAKEDIR:STRING=share/protobuf + -Dprotobuf_BUILD_PROTOC_BINARIES=${protobuf_BUILD_PROTOC_BINARIES} + -Dprotobuf_BUILD_LIBPROTOC=${protobuf_BUILD_LIBPROTOC} + -Dprotobuf_ABSL_PROVIDER=package + ${FEATURE_OPTIONS} +) + +vcpkg_cmake_install() + +if(protobuf_BUILD_PROTOC_BINARIES) + if(VCPKG_TARGET_IS_WINDOWS) + vcpkg_copy_tools(TOOL_NAMES protoc AUTO_CLEAN) + else() + string(REPLACE "." ";" VERSION_LIST ${VERSION}) + list(GET VERSION_LIST 1 VERSION_MINOR) + list(GET VERSION_LIST 2 VERSION_PATCH) + vcpkg_copy_tools(TOOL_NAMES protoc protoc-${VERSION_MINOR}.${VERSION_PATCH}.0 AUTO_CLEAN) + endif() +else() + file(COPY "${CURRENT_HOST_INSTALLED_DIR}/tools/${PORT}" DESTINATION "${CURRENT_PACKAGES_DIR}/tools") +endif() + +vcpkg_replace_string("${CURRENT_PACKAGES_DIR}/share/${PORT}/protobuf-config.cmake" + "if(protobuf_MODULE_COMPATIBLE)" + "if(1)" +) +if(NOT protobuf_BUILD_LIBPROTOC) + vcpkg_replace_string("${CURRENT_PACKAGES_DIR}/share/${PORT}/protobuf-module.cmake" + "_protobuf_find_libraries(Protobuf_PROTOC protoc)" + "" + ) +endif() + +vcpkg_cmake_config_fixup() + +if(VCPKG_LIBRARY_LINKAGE STREQUAL "dynamic") + vcpkg_replace_string("${CURRENT_PACKAGES_DIR}/include/google/protobuf/port_def.inc" + "\#ifdef PROTOBUF_PORT_" + "\#ifndef PROTOBUF_USE_DLLS\n\#define PROTOBUF_USE_DLLS\n\#endif // PROTOBUF_USE_DLLS\n\n\#ifdef PROTOBUF_PORT_" + ) +endif() + +vcpkg_copy_pdbs() + +function(replace_package_string package) + set(debug_file "${CURRENT_PACKAGES_DIR}/debug/lib/pkgconfig/${package}.pc") + set(release_file "${CURRENT_PACKAGES_DIR}/lib/pkgconfig/${package}.pc") + + if(EXISTS "${release_file}") + vcpkg_replace_string("${release_file}" "absl_abseil_dll" "abseil_dll" IGNORE_UNCHANGED) + if(VCPKG_TARGET_IS_WINDOWS AND NOT VCPKG_TARGET_IS_MINGW) + vcpkg_replace_string("${release_file}" "-l${package}" "-llib${package}" IGNORE_UNCHANGED) + endif() + endif() + + if(EXISTS "${debug_file}") + vcpkg_replace_string("${debug_file}" "absl_abseil_dll" "abseil_dll" IGNORE_UNCHANGED) + if(VCPKG_TARGET_IS_WINDOWS AND NOT VCPKG_TARGET_IS_MINGW) + vcpkg_replace_string("${debug_file}" "-l${package}" "-llib${package}d" IGNORE_UNCHANGED) + else() + vcpkg_replace_string("${debug_file}" "-l${package}" "-l${package}d" IGNORE_UNCHANGED) + endif() + endif() +endfunction() + +set(packages protobuf protobuf-lite) +foreach(package IN LISTS packages) + replace_package_string("${package}") +endforeach() + + +vcpkg_fixup_pkgconfig() + +if(NOT protobuf_BUILD_PROTOC_BINARIES) + configure_file("${CMAKE_CURRENT_LIST_DIR}/protobuf-targets-vcpkg-protoc.cmake" "${CURRENT_PACKAGES_DIR}/share/${PORT}/protobuf-targets-vcpkg-protoc.cmake" COPYONLY) +endif() + +configure_file("${CMAKE_CURRENT_LIST_DIR}/vcpkg-cmake-wrapper.cmake" "${CURRENT_PACKAGES_DIR}/share/${PORT}/vcpkg-cmake-wrapper.cmake" @ONLY) + +file(REMOVE_RECURSE "${CURRENT_PACKAGES_DIR}/debug/share" "${CURRENT_PACKAGES_DIR}/debug/include") + +vcpkg_install_copyright(FILE_LIST "${SOURCE_PATH}/LICENSE") diff --git a/browser/overlay-ports/protobuf/protobuf-targets-vcpkg-protoc.cmake b/browser/overlay-ports/protobuf/protobuf-targets-vcpkg-protoc.cmake new file mode 100644 index 0000000000..149e6587ee --- /dev/null +++ b/browser/overlay-ports/protobuf/protobuf-targets-vcpkg-protoc.cmake @@ -0,0 +1,8 @@ +# Create imported target protobuf::protoc +add_executable(protobuf::protoc IMPORTED) + +# Import target "protobuf::protoc" for configuration "Release" +set_property(TARGET protobuf::protoc APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE) +set_target_properties(protobuf::protoc PROPERTIES + IMPORTED_LOCATION_RELEASE "${Protobuf_PROTOC_EXECUTABLE}" +) diff --git a/browser/overlay-ports/protobuf/use_pthread.patch b/browser/overlay-ports/protobuf/use_pthread.patch new file mode 100644 index 0000000000..7dad46efe4 --- /dev/null +++ b/browser/overlay-ports/protobuf/use_pthread.patch @@ -0,0 +1,13 @@ +diff --git a/CMakeLists.txt b/CMakeLists.txt +index 7ca1b21..0984f19 100644 +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -23,6 +23,8 @@ if(protobuf_DEPRECATED_CMAKE_SUBDIRECTORY_USAGE) + get_filename_component(protobuf_SOURCE_DIR ${protobuf_SOURCE_DIR} DIRECTORY) + endif() + ++add_compile_options(-pthread) ++ + # Options + option(protobuf_INSTALL "Install protobuf binaries and files" ON) + option(protobuf_BUILD_TESTS "Build tests" ON) diff --git a/browser/overlay-ports/protobuf/vcpkg-cmake-wrapper.cmake b/browser/overlay-ports/protobuf/vcpkg-cmake-wrapper.cmake new file mode 100644 index 0000000000..4def9a6ea5 --- /dev/null +++ b/browser/overlay-ports/protobuf/vcpkg-cmake-wrapper.cmake @@ -0,0 +1,3 @@ +find_program(Protobuf_PROTOC_EXECUTABLE NAMES protoc PATHS "${CMAKE_CURRENT_LIST_DIR}/../../../@HOST_TRIPLET@/tools/protobuf" NO_DEFAULT_PATH) + +_find_package(${ARGS} CONFIG) diff --git a/browser/overlay-ports/protobuf/vcpkg.json b/browser/overlay-ports/protobuf/vcpkg.json new file mode 100644 index 0000000000..8502333a3c --- /dev/null +++ b/browser/overlay-ports/protobuf/vcpkg.json @@ -0,0 +1,33 @@ +{ + "name": "protobuf", + "version": "4.25.1", + "port-version": 1, + "description": "Google's language-neutral, platform-neutral, extensible mechanism for serializing structured data.", + "homepage": "https://github.com/protocolbuffers/protobuf", + "license": "BSD-3-Clause", + "dependencies": [ + "abseil", + { + "name": "protobuf", + "host": true + }, + "utf8-range", + { + "name": "vcpkg-cmake", + "host": true + }, + { + "name": "vcpkg-cmake-config", + "host": true + } + ], + "features": { + "zlib": { + "description": "ZLib based features like Gzip streams", + "dependencies": [ + "zlib" + ] + } + }, + "builtin-baseline":"c82f74667287d3dc386bce81e44964370c91a289" +} diff --git a/browser/shell.html b/browser/shell.html new file mode 100644 index 0000000000..e12cce9a1f --- /dev/null +++ b/browser/shell.html @@ -0,0 +1,176 @@ + + + + + + Loading + + + +
+ + + + {{{ SCRIPT }}} + + diff --git a/data/images/game/creatureicons/CreatureIcons.png b/data/images/game/creatureicons/CreatureIcons.png new file mode 100644 index 0000000000..f5b50d4d15 Binary files /dev/null and b/data/images/game/creatureicons/CreatureIcons.png differ diff --git a/data/images/game/creatureicons/monsterIcons.png b/data/images/game/creatureicons/monsterIcons.png new file mode 100644 index 0000000000..997e44e0d8 Binary files /dev/null and b/data/images/game/creatureicons/monsterIcons.png differ diff --git a/data/images/topbuttons/debug.png b/data/images/topbuttons/debug.png new file mode 100644 index 0000000000..9768e4cf93 Binary files /dev/null and b/data/images/topbuttons/debug.png differ diff --git a/data/images/ui/containerslot-coloredges.png b/data/images/ui/containerslot-coloredges.png new file mode 100644 index 0000000000..5a6779b114 Binary files /dev/null and b/data/images/ui/containerslot-coloredges.png differ diff --git a/data/images/ui/icon-edit.png b/data/images/ui/icon-edit.png new file mode 100644 index 0000000000..f9b810a70d Binary files /dev/null and b/data/images/ui/icon-edit.png differ diff --git a/data/images/ui/rarity_frames.png b/data/images/ui/rarity_frames.png index cebc6d963b..4c097255b9 100644 Binary files a/data/images/ui/rarity_frames.png and b/data/images/ui/rarity_frames.png differ diff --git a/data/styles/10-items.otui b/data/styles/10-items.otui index 719f26110d..81357f2a82 100644 --- a/data/styles/10-items.otui +++ b/data/styles/10-items.otui @@ -8,6 +8,22 @@ Item < UIItem $disabled: color: #646464 + + Label + id: duration + anchors.bottom: parent.bottom + anchors.left: parent.left + phantom: true + font: "verdana-11px-rounded" + + Label + id: charges + anchors.top: parent.top + anchors.left: parent.left + phantom: true + text-auto-resize: true + font: "verdana-11px-rounded" + UIWidget id: tier size: 10 9 @@ -191,10 +207,18 @@ MainInventoryItem < UIWidget color: white Label - id: Duration + id: duration anchors.bottom: parent.bottom anchors.left: parent.left phantom: true + Label + id: charges + anchors.top: parent.top + anchors.left: parent.left + phantom: true + text-auto-resize: true + font: "verdana-11px-rounded" + UIWidget id: tier size: 10 9 diff --git a/data/styles/10-scrollbars.otui b/data/styles/10-scrollbars.otui index 88beafb2bb..130c0a9b8b 100644 --- a/data/styles/10-scrollbars.otui +++ b/data/styles/10-scrollbars.otui @@ -186,3 +186,23 @@ HorizontalQtScrollBar < UIScrollBar image-clip: 54 10 12 12 HorizontalScrollBarQtSlider + +SmallButton < UIButton + size: 106 20 + font: cipsoftFont + text-offset: 0 2 + image-source: /images/ui/button + image-clip: 0 0 22 23 + image-border: 3 + padding: 5 10 5 10 + change-cursor-image: true + cursor: pointer + color: #ffffff + $hover !disabled: + image-clip: 0 23 22 23 + $pressed: + image-clip: 0 46 22 23 + text-offset: 1 2 + $disabled: + color: #ffffff88 + change-cursor-image: false diff --git a/init.lua b/init.lua index b956d3f851..94464dd715 100644 --- a/init.lua +++ b/init.lua @@ -4,7 +4,7 @@ -- updater Services = { --updater = "http://localhost/api/updater.php", --./updater - --status = "http://localhost/api/status.php", --./client_entergame | ./client_topmenu + --status = "http://localhost/login.php", --./client_entergame | ./client_topmenu --websites = "http://localhost/?subtopic=accountmanagement", --./client_entergame "Forgot password and/or email" } diff --git a/mods/game_bot/default_configs/cavebot_1.3/cavebot/actions.lua b/mods/game_bot/default_configs/cavebot_1.3/cavebot/actions.lua index 8a35b45a04..f31d6eca1f 100644 --- a/mods/game_bot/default_configs/cavebot_1.3/cavebot/actions.lua +++ b/mods/game_bot/default_configs/cavebot_1.3/cavebot/actions.lua @@ -97,7 +97,11 @@ CaveBot.registerAction("function", "red", function(value, retries, prev) prefix = prefix .. "local " .. extension .. " = CaveBot.Extensions." .. extension .. "\n" end local status, result = pcall(function() - return assert(load(prefix .. value, "cavebot_function"))() + if _VERSION == "Lua 5.1" and type(jit) ~= "table" then + return assert(loadstring(prefix .. value))() + else + return assert(load(prefix .. value, "cavebot_function"))() + end end) if not status then error("Error in cavebot function:\n" .. result) diff --git a/mods/game_bot/default_configs/cavebot_1.3/tools.lua b/mods/game_bot/default_configs/cavebot_1.3/tools.lua index 629a9ca36e..c84e5ad987 100644 --- a/mods/game_bot/default_configs/cavebot_1.3/tools.lua +++ b/mods/game_bot/default_configs/cavebot_1.3/tools.lua @@ -18,9 +18,13 @@ end) UI.Separator() for _, scripts in ipairs({storage.ingame_macros, storage.ingame_hotkeys}) do - if type(scripts) == "string" and scripts:len() > 3 then + if type(scripts) == "string" and scripts:len() > 3 then local status, result = pcall(function() - assert(load(scripts, "ingame_editor"))() + if _VERSION == "Lua 5.1" and type(jit) ~= "table" then + assert(loadstring(scripts))() + else + assert(load(scripts, "ingame_editor"))() + end end) if not status then error("Ingame edior error:\n" .. result) diff --git a/mods/game_bot/default_configs/vBot_4.8/cavebot/actions.lua b/mods/game_bot/default_configs/vBot_4.8/cavebot/actions.lua index ba4ed7d48a..eca03e9378 100644 --- a/mods/game_bot/default_configs/vBot_4.8/cavebot/actions.lua +++ b/mods/game_bot/default_configs/vBot_4.8/cavebot/actions.lua @@ -267,7 +267,11 @@ CaveBot.registerAction("function", "red", function(value, retries, prev) prefix = prefix .. "local " .. extension .. " = CaveBot.Extensions." .. extension .. "\n" end local status, result = pcall(function() - return assert(load(prefix .. value, "cavebot_function"))() + if _VERSION == "Lua 5.1" and type(jit) ~= "table" then + return assert(loadstring(prefix .. value))() + else + return assert(load(prefix .. value, "cavebot_function"))() + end end) if not status then warn("warn in cavebot function:\n" .. result) diff --git a/mods/game_bot/default_configs/vBot_4.8/vBot/analyzer.lua b/mods/game_bot/default_configs/vBot_4.8/vBot/analyzer.lua index 8a2eff1f66..60796d04c8 100644 --- a/mods/game_bot/default_configs/vBot_4.8/vBot/analyzer.lua +++ b/mods/game_bot/default_configs/vBot_4.8/vBot/analyzer.lua @@ -133,7 +133,12 @@ local toggle = function() end local drawGraph = function(graph, value) - graph:addValue(value) + if graph:getGraphsCount() == 0 then + graph:createGraph() + graph:setLineWidth(1, 1) + graph:setLineColor(1, "#FF0000") + end + graph:addValue(1, value) end local toggleAnalyzer = function(window) diff --git a/mods/game_bot/default_configs/vBot_4.8/vBot/analyzer.otui b/mods/game_bot/default_configs/vBot_4.8/vBot/analyzer.otui index 761a9b4c99..261a6a7e3e 100644 --- a/mods/game_bot/default_configs/vBot_4.8/vBot/analyzer.otui +++ b/mods/game_bot/default_configs/vBot_4.8/vBot/analyzer.otui @@ -226,8 +226,6 @@ AnalyzerLootItem < UIItem AnalyzerGraph < UIGraph height: 140 capacity: 400 - line-width: 1 - color: red margin-top: 5 margin-left: 5 margin-right: 5 diff --git a/mods/game_bot/default_configs/vBot_4.8/vBot/ingame_editor.lua b/mods/game_bot/default_configs/vBot_4.8/vBot/ingame_editor.lua index 46528fc305..9df4b19945 100644 --- a/mods/game_bot/default_configs/vBot_4.8/vBot/ingame_editor.lua +++ b/mods/game_bot/default_configs/vBot_4.8/vBot/ingame_editor.lua @@ -12,7 +12,11 @@ UI.Button("Ingame script editor", function(newText) for _, scripts in pairs({storage.ingame_hotkeys}) do if type(scripts) == "string" and scripts:len() > 3 then local status, result = pcall(function() - assert(load(scripts, "ingame_editor"))() + if _VERSION == "Lua 5.1" and type(jit) ~= "table" then + return assert(loadstring(scripts))() + else + assert(load(scripts, "ingame_editor"))() + end end) if not status then error("Ingame edior error:\n" .. result) diff --git a/mods/game_bot/executor.lua b/mods/game_bot/executor.lua index e9f0c8f7c6..1cce5efeac 100644 --- a/mods/game_bot/executor.lua +++ b/mods/game_bot/executor.lua @@ -96,10 +96,23 @@ function executeBot(config, storage, tabs, msgCallback, saveConfigCallback, relo date = os.date, clock = os.clock } - context.load = function(str) return assert(load(str, nil, nil, context)) end + if _VERSION == "Lua 5.1" and type(jit) ~= "table" then + context.load = function(str) + local func = assert(loadstring(str)) + setfenv(func, context) + return func + end + context.dofile = function(file) + local func = assert(loadstring(g_resources.readFileContents("/bot/" .. config .. "/" .. file))) + setfenv(func, context) + func() + end + else + context.load = function(str) return assert(load(str, nil, nil, context)) end + context.dofile = function(file) assert(load(g_resources.readFileContents("/bot/" .. config .. "/" .. file), file, nil, context))() end + end context.loadstring = context.load context.assert = assert - context.dofile = function(file) assert(load(g_resources.readFileContents("/bot/" .. config .. "/" .. file), file, nil, context))() end context.gcinfo = gcinfo context.tr = tr context.json = json @@ -164,7 +177,13 @@ function executeBot(config, storage, tabs, msgCallback, saveConfigCallback, relo -- run lua script for i, file in ipairs(luaFiles) do - assert(load(g_resources.readFileContents(file), file, nil, context))() + if _VERSION == "Lua 5.1" and type(jit) ~= "table" then + local func = assert(loadstring(g_resources.readFileContents(file))) + setfenv(func, context) + func() + else + assert(load(g_resources.readFileContents(file), file, nil, context))() + end context.panel = context.mainTab -- reset default tab end diff --git a/mods/game_bot/functions/script_loader.lua b/mods/game_bot/functions/script_loader.lua index 8346634ed0..3619532a3d 100644 --- a/mods/game_bot/functions/script_loader.lua +++ b/mods/game_bot/functions/script_loader.lua @@ -10,9 +10,14 @@ context.loadScript = function(path, onLoadCallback) if not g_resources.fileExists(path) then return context.error("File " .. path .. " doesn't exist") end - local status, result = pcall(function() - assert(load(g_resources.readFileContents(path), path, nil, context))() + if _VERSION == "Lua 5.1" and type(jit) ~= "table" then + local func = assert(loadstring(g_resources.readFileContents(path))) + setfenv(func, context) + func() + else + assert(load(g_resources.readFileContents(path), path, nil, context))() + end end) if not status then return context.error("Error while loading script from: " .. path .. ":\n" .. result) @@ -42,7 +47,13 @@ context.loadRemoteScript = function(url, onLoadCallback) end local status, result = pcall(function() - assert(load(data, url, nil, context))() + if _VERSION == "Lua 5.1" and type(jit) ~= "table" then + local func = assert(loadstring(data)) + setfenv(func, context) + func() + else + assert(load(data, url, nil, context))() + end end) if not status then return context.error("Error while loading script from: " .. url .. ":\n" .. result) diff --git a/mods/game_bot/panels/waypoints.lua b/mods/game_bot/panels/waypoints.lua index b66c699619..3f9412ffb4 100644 --- a/mods/game_bot/panels/waypoints.lua +++ b/mods/game_bot/panels/waypoints.lua @@ -746,7 +746,13 @@ Panel elseif command.command == "function" and lastGotoSuccesful then usedGotoLabel = false local status, result = pcall(function() - return assert(load("return " .. command.text, nil, nil, context))()(functions) + if _VERSION == "Lua 5.1" and type(jit) ~= "table" then + local func = assert(loadstring("return " .. command.text)) + setfenv(func, context) + return func()(functions) + else + return assert(load("return " .. command.text, nil, nil, context))()(functions) + end end) if not status then context.error("Waypoints function execution error:\n" .. result) diff --git a/modules/client/client.otmod b/modules/client/client.otmod index e8d8c780e8..2f09b9e170 100644 --- a/modules/client/client.otmod +++ b/modules/client/client.otmod @@ -18,4 +18,5 @@ Module - client_options - client_entergame - client_terminal + - client_debug_info - client_serverlist diff --git a/modules/client_bottommenu/bottommenu.lua b/modules/client_bottommenu/bottommenu.lua index 17450b7152..6a039afe79 100644 --- a/modules/client_bottommenu/bottommenu.lua +++ b/modules/client_bottommenu/bottommenu.lua @@ -45,7 +45,8 @@ function init() creature_boosted = boostedWindow:recursiveGetChildById('creature') boss_boosted = boostedWindow:recursiveGetChildById('boss') - if not Services.status and default_info then +-- if not Services.status and default_info then + if default_info then local widget = g_ui.createWidget('ShowOffWidget', showOffWindow) local description = widget:recursiveGetChildById('description') local image = widget:recursiveGetChildById('image') @@ -67,6 +68,9 @@ function init() boss2:setImageSource(randomItem.creature2) boss2:setVisible(true) end + if g_game.isOnline() then + hide() + end end function terminate() @@ -494,8 +498,15 @@ end function Booster_creature(data) if modules.game_things.isLoaded() then - -- note: is better image * - creature_boosted:setOutfit(data.creature) - boss_boosted:setOutfit(data.boss) + local creatureraceid = modules.game_cyclopedia.RACE[data.creatureraceid] + local bossraceid = modules.game_cyclopedia.RACE_Bosstiary[data.bossraceid] + if creatureraceid then + creature_boosted:setOutfit({type=creatureraceid.type}) + creature_boosted:getCreature():setStaticWalking(1000) + end + if bossraceid then + boss_boosted:setOutfit({type=bossraceid.type}) + boss_boosted:getCreature():setStaticWalking(1000) + end end end diff --git a/modules/client_bottommenu/bottommenu.otui b/modules/client_bottommenu/bottommenu.otui index 109693c612..e801a89bd4 100644 --- a/modules/client_bottommenu/bottommenu.otui +++ b/modules/client_bottommenu/bottommenu.otui @@ -150,12 +150,16 @@ Panel margin-left: 12 margin-top: 30 size: 64 64 - image-source: /images/ui/panel_flat Creature id: creature anchors.horizontalCenter: parent.horizontalCenter anchors.verticalCenter: parent.verticalCenter + image-source: "" + image-border: 0 + border-width: 0 + border-color: alpha + UIWidget id: creature2 anchors.horizontalCenter: parent.horizontalCenter @@ -174,12 +178,16 @@ Panel margin-right: 12 margin-top: 30 size: 64 64 - image-source: /images/ui/panel_flat Creature id: boss anchors.horizontalCenter: parent.horizontalCenter anchors.verticalCenter: parent.verticalCenter + image-source: "" + image-border: 0 + border-width: 0 + border-color: alpha + UIWidget id: boss2 anchors.horizontalCenter: parent.horizontalCenter diff --git a/modules/client_debug_info/debug_info.lua b/modules/client_debug_info/debug_info.lua new file mode 100644 index 0000000000..57a90e0c47 --- /dev/null +++ b/modules/client_debug_info/debug_info.lua @@ -0,0 +1,65 @@ +local debugInfoWindow = nil +local debugInfoButton = nil + +local updateEvent = nil + +function init() + debugInfoButton = modules.client_topmenu.addTopRightToggleButton('debugInfoButton', tr('Debug Info'), + '/images/topbuttons/debug', toggle) + debugInfoButton:setOn(false) + + debugInfoWindow = g_ui.displayUI('debug_info') + debugInfoWindow:hide() + + Keybind.new("Debug", "Toggle Stats", "Ctrl+Alt+D", "") + Keybind.bind("Debug", "Toggle Stats", { + { + type = KEY_DOWN, + callback = toggle, + } + }) + + updateEvent = scheduleEvent(update, 2000) +end + +function terminate() + debugInfoWindow:destroy() + debugInfoButton:destroy() + + Keybind.delete("Debug", "Toggle Stats") + + removeEvent(updateEvent) +end + +function onClose() + debugInfoButton:setOn(false) +end + +function toggle() + if debugInfoButton:isOn() then + debugInfoWindow:hide() + debugInfoButton:setOn(false) + else + debugInfoWindow:show() + debugInfoWindow:raise() + debugInfoWindow:focus() + debugInfoButton:setOn(true) + end +end + +function update() + updateEvent = scheduleEvent(update, 20) + + if not debugInfoWindow:isVisible() then + return + end + + if g_proxy then + local text = "" + local proxiesDebug = g_proxy.getProxiesDebugInfo() + for proxy_name, proxy_debug in pairs(proxiesDebug) do + text = text .. proxy_name .. " - " .. proxy_debug .. "\n" + end + debugInfoWindow.debugPanel.proxies:setText(text) + end +end diff --git a/modules/client_debug_info/debug_info.otmod b/modules/client_debug_info/debug_info.otmod new file mode 100644 index 0000000000..f3e6ace075 --- /dev/null +++ b/modules/client_debug_info/debug_info.otmod @@ -0,0 +1,9 @@ +Module + name: client_debug_info + description: Showing and sending debug/stats informations + author: otclient@otclient.ovh + sandboxed: true + scripts: [ debug_info ] + dependencies: [ client_topmenu ] + @onLoad: init() + @onUnload: terminate() diff --git a/modules/client_debug_info/debug_info.otui b/modules/client_debug_info/debug_info.otui new file mode 100644 index 0000000000..816849bdf9 --- /dev/null +++ b/modules/client_debug_info/debug_info.otui @@ -0,0 +1,65 @@ +DebugText < Label + font: terminus-10px + text-wrap: false + text-auto-resize: true + text-align: topleft + anchors.right: parent.right + anchors.left: parent.left + anchors.top: prev.bottom + +DebugLabel < Label + text-wrap: false + text-auto-resize: false + text-align: center + anchors.right: parent.right + anchors.left: parent.left + anchors.top: prev.bottom + +MainWindow + id: debugWindow + size: 600 150 + !text: tr('Debug Info') + @onClose: modules.client_debug_info.onMiniWindowClose() + &save: false + margin: 0 0 0 0 + padding: 25 3 3 3 + opacity: 0.9 + $mobile: + size: 600 150 + @onEnter: modules.client_debug_info.toggle() + @onEscape: modules.client_debug_info.toggle() + + + ScrollablePanel + id: debugPanel + anchors.fill: parent + margin-bottom: 5 + margin: 5 5 5 5 + padding-left: 5 + vertical-scrollbar: debugScroll + + DebugLabel + !text: tr('Proxies') + anchors.top: parent.top + + DebugText + id: proxies + text: - + + VerticalScrollBar + id: debugScroll + anchors.top: parent.top + anchors.bottom: parent.bottom + anchors.right: parent.right + step: 48 + pixels-scroll: true + + ResizeBorder + anchors.bottom: parent.bottom + anchors.left: parent.left + anchors.right: parent.right + + ResizeBorder + anchors.right: parent.right + anchors.top: parent.top + anchors.bottom: parent.bottom diff --git a/modules/client_entergame/entergame.lua b/modules/client_entergame/entergame.lua index f8f48af3a9..f99e2d5a47 100644 --- a/modules/client_entergame/entergame.lua +++ b/modules/client_entergame/entergame.lua @@ -127,7 +127,13 @@ end -- public functions function EnterGame.init() enterGame = g_ui.displayUI('entergame') - g_keyboard.bindKeyDown('Ctrl+G', EnterGame.openWindow) + Keybind.new("Misc.", "Change Character", "Ctrl+G", "") + Keybind.bind("Misc.", "Change Character", { + { + type = KEY_DOWN, + callback = EnterGame.openWindow, + } + }) local account = g_settings.get('account') local password = g_settings.get('password') @@ -219,12 +225,16 @@ function EnterGame.init() end function EnterGame.hidePanels() - modules.client_bottommenu.hide() + if g_modules.getModule("client_bottommenu"):isLoaded() then + modules.client_bottommenu.hide() + end modules.client_topmenu.toggle() end function EnterGame.showPanels() - modules.client_bottommenu.show() + if g_modules.getModule("client_bottommenu"):isLoaded() then + modules.client_bottommenu.show() + end modules.client_topmenu.toggle() end @@ -245,15 +255,17 @@ function EnterGame.firstShow() end if Services and Services.status then - EnterGame.postCacheInfo() - EnterGame.postEventScheduler() - EnterGame.postShowOff() - EnterGame.postShowCreatureBoost() + if g_modules.getModule("client_bottommenu"):isLoaded() then + EnterGame.postCacheInfo() + EnterGame.postEventScheduler() + -- EnterGame.postShowOff() -- myacc/znote no send login.php + EnterGame.postShowCreatureBoost() + end end end function EnterGame.terminate() - g_keyboard.unbindKeyDown('Ctrl+G') + Keybind.delete("Misc.", "Change Character") disconnect(clientBox, { onOptionChange = EnterGame.onClientVersionChange @@ -333,26 +345,20 @@ end function EnterGame.postEventScheduler() local onRecvInfo = function(message, err) if err then - -- onError(nil, 'Bad Request. Game_entergame postEventScheduler1', 400) - g_logger.warning("[Webscraping] " .. "Bad Request.Game_entergame postEventScheduler1") + g_logger.warning("[Webscraping] Bad Request.Game_entergame postEventScheduler1") return end - local _, bodyStart = message:find('{') - local _, bodyEnd = message:find('.*}') - if not bodyStart or not bodyEnd then - -- onError(nil, 'Bad Request. Game_entergame postEventScheduler2', 400) - g_logger.warning("[Webscraping] " .. "Bad Request.Game_entergame postEventScheduler2") - return - end + local bodyStart, _ = message:find('{') + local _, bodyEnd = message:find('%}%b{}') - local response = json.decode(message:sub(bodyStart, bodyEnd)) + local jsonString = message:sub(bodyStart, bodyEnd) + + local response = json.decode(jsonString) if response.errorMessage then - -- onError(nil, response.errorMessage, response.errorCode) g_logger.warning("[Webscraping] " .. "response.errorMessage,response.errorCode") return end - modules.client_bottommenu.setEventsSchedulerTimestamp(response.lastupdatetimestamp) modules.client_bottommenu.setEventsSchedulerCalender(response.eventlist) end @@ -365,7 +371,6 @@ end function EnterGame.postShowOff() local onRecvInfo = function(message, err) if err then - -- onError(nil, 'Bad Request. 1 Game_entergame postShowOff', 400) g_logger.warning("[Webscraping] " .. "Bad Request.Game_entergame postShowOff") return end @@ -373,14 +378,12 @@ function EnterGame.postShowOff() local _, bodyStart = message:find('{') local _, bodyEnd = message:find('.*}') if not bodyStart or not bodyEnd then - -- onError(nil, 'Bad Request. 2 Game_entergame postShowOff', 400) g_logger.warning("[Webscraping] " .. "Bad Request.Game_entergame postShowOff") return end local response = json.decode(message:sub(bodyStart, bodyEnd)) if response.errorMessage then - -- onError(nil, response.errorMessage, response.errorCode) g_logger.warning("[Webscraping] " .. response.errorMessage, response.errorCode) return end @@ -420,7 +423,7 @@ function EnterGame.postShowCreatureBoost() end HTTP.post(Services.status, json.encode({ - type = 'Creatureboost' + type = 'boostedcreature' }), onRecvInfo, false) end diff --git a/modules/client_options/audio.otui b/modules/client_options/audio.otui deleted file mode 100644 index 9bef2bea53..0000000000 --- a/modules/client_options/audio.otui +++ /dev/null @@ -1,34 +0,0 @@ -Panel - SmallReversedQtPanel - anchors.left: parent.left - anchors.right: parent.right - anchors.top: parent.top - height: 22 - - OptionCheckBox - id: enableAudio - !text: tr('Enable audio') - - SmallReversedQtPanel - anchors.left: parent.left - anchors.right: parent.right - anchors.top: prev.bottom - margin-top: 7 - height: 44 - - OptionCheckBox - id: enableMusicSound - !text: tr('Enable music sound') - - OptionScaleScroll - id: musicSoundVolume - margin-top: 5 - anchors.top: prev.bottom - anchors.left: parent.left - anchors.right: parent.right - &minimumScrollValue: 1 - &maximumScrollValue: 100 - &scrollSize: 21 - @onSetup: | - local value = modules.client_options.getOption('musicSoundVolume') - self:setText(tr('Music volume: %d', value)) diff --git a/modules/client_options/console.otui b/modules/client_options/console.otui deleted file mode 100644 index 4f57be88c4..0000000000 --- a/modules/client_options/console.otui +++ /dev/null @@ -1,157 +0,0 @@ -Panel - SmallReversedQtPanel - anchors.left: parent.left - anchors.right: parent.right - anchors.top: parent.top - height: 22 - - OptionCheckBox - id: showInfoMessagesInConsole - !text: tr('Show info messages') - - SmallReversedQtPanel - anchors.left: parent.left - anchors.right: parent.right - anchors.top: prev.bottom - margin-top: 7 - height: 22 - - OptionCheckBox - id: showEventMessagesInConsole - !text: tr('Show event messages') - - SmallReversedQtPanel - anchors.left: parent.left - anchors.right: parent.right - anchors.top: prev.bottom - margin-top: 7 - height: 22 - - OptionCheckBox - id: showStatusMessagesInConsole - !text: tr('Show status messages') - - SmallReversedQtPanel - anchors.left: parent.left - anchors.right: parent.right - anchors.top: prev.bottom - margin-top: 7 - height: 22 - - OptionCheckBox - id: showOthersStatusMessagesInConsole - !text: tr('Show others status messages in console') - - SmallReversedQtPanel - anchors.left: parent.left - anchors.right: parent.right - anchors.top: prev.bottom - margin-top: 7 - height: 22 - - OptionCheckBox - id: showTimestampsInConsole - !text: tr('Show timestamps') - - SmallReversedQtPanel - anchors.left: parent.left - anchors.right: parent.right - anchors.top: prev.bottom - margin-top: 7 - height: 22 - - OptionCheckBox - id: showLevelsInConsole - !text: tr('Show levels') - - SmallReversedQtPanel - anchors.left: parent.left - anchors.right: parent.right - anchors.top: prev.bottom - margin-top: 7 - height: 22 - - OptionCheckBox - id: showPrivateMessagesInConsole - !text: tr('Show private messages') - - SmallReversedQtPanel - anchors.left: parent.left - anchors.right: parent.right - anchors.top: prev.bottom - margin-top: 7 - height: 22 - - OptionCheckBox - id: showPrivateMessagesOnScreen - !text: tr('Show private messages on screen') - - SmallReversedQtPanel - anchors.left: parent.left - anchors.right: parent.right - anchors.top: prev.bottom - margin-top: 7 - height: 22 - - OptionScaleScroll - id: creatureInformationScale - anchors.fill: parent - &minimumScrollValue: 1 - &maximumScrollValue: 9 - &scrollSize: 21 - - SmallReversedQtPanel - anchors.left: parent.left - anchors.right: parent.right - anchors.top: prev.bottom - margin-top: 7 - height: 22 - - OptionScaleScroll - id: staticTextScale - anchors.fill: parent - &minimumScrollValue: 1 - &maximumScrollValue: 9 - &scrollSize: 21 - - SmallReversedQtPanel - anchors.left: parent.left - anchors.right: parent.right - anchors.top: prev.bottom - margin-top: 7 - height: 22 - - OptionScaleScroll - id: animatedTextScale - anchors.fill: parent - &minimumScrollValue: 1 - &maximumScrollValue: 9 - &scrollSize: 21 - - SmallReversedQtPanel - anchors.left: parent.left - anchors.right: parent.right - anchors.top: prev.bottom - margin-top: 7 - height: 22 - - OptionScaleScroll - id: setEffectAlphaScroll - anchors.fill: parent - &minimumScrollValue: 10 - &maximumScrollValue: 100 - &scrollSize: 21 - - SmallReversedQtPanel - anchors.left: parent.left - anchors.right: parent.right - anchors.top: prev.bottom - margin-top: 7 - height: 22 - - OptionScaleScroll - id: setMissileAlphaScroll - anchors.fill: parent - &minimumScrollValue: 10 - &maximumScrollValue: 100 - &scrollSize: 21 diff --git a/modules/client_options/control.otui b/modules/client_options/control.otui deleted file mode 100644 index 11aa6b52b9..0000000000 --- a/modules/client_options/control.otui +++ /dev/null @@ -1,127 +0,0 @@ -Panel - SmallReversedQtPanel - anchors.left: parent.left - anchors.right: parent.right - anchors.top: parent.top - height: 22 - - OptionCheckBox - id: classicControl - !text: tr('Classic control') - - SmallReversedQtPanel - anchors.left: parent.left - anchors.right: parent.right - anchors.top: prev.bottom - margin-top: 7 - height: 22 - - OptionCheckBox - id: autoChaseOverride - !text: tr('Allow auto chase override') - - SmallReversedQtPanel - anchors.left: parent.left - anchors.right: parent.right - anchors.top: prev.bottom - margin-top: 7 - height: 22 - - OptionCheckBox - id: moveStack - !text: tr('Move stacks directly') - - SmallReversedQtPanel - anchors.left: parent.left - anchors.right: parent.right - anchors.top: prev.bottom - margin-top: 7 - height: 22 - - OptionCheckBoxMarked - id: smartWalk - !text: tr('Enable smart walking') - !tooltip: tr('Will detect when to use diagonal step based on the\nkeys you are pressing') - - SmallReversedQtPanel - id: hotkeyDelay_label - anchors.left: parent.left - anchors.right: parent.right - anchors.top: prev.bottom - margin-top: 7 - height: 22 - - OptionScaleScroll - id: hotkeyDelay - !text: tr('Hotkey delay: 30ms') - anchors.fill: parent - &minimumScrollValue: 30 - &maximumScrollValue: 250 - &scrollSize: 21 - @onSetup: | - local value = modules.client_options.getOption('hotkeyDelay') - self:setText(tr('Hotkey delay: %dms', value)) - - SmallReversedQtPanel - anchors.left: parent.left - anchors.right: parent.right - anchors.top: prev.bottom - margin-top: 7 - height: 22 - - OptionScaleScroll - id: walkFirstStepDelay - !text: tr('Walk Delay after first step: 50ms') - anchors.fill: parent - &minimumScrollValue: 50 - &maximumScrollValue: 500 - &scrollSize: 21 - @onSetup: | - local value = modules.client_options.getOption('walkFirstStepDelay') - self:setText(tr('Walk Delay after first step: %dms', value)) - - SmallReversedQtPanel - anchors.left: parent.left - anchors.right: parent.right - anchors.top: prev.bottom - margin-top: 7 - height: 22 - - OptionScaleScroll - id: walkTurnDelay - !text: tr('Walk delay after turn: 50ms') - anchors.fill: parent - &minimumScrollValue: 50 - &maximumScrollValue: 500 - &scrollSize: 21 - @onSetup: | - local value = modules.client_options.getOption('walkTurnDelay') - self:setText(tr('Walk delay after turn: %dms', value)) - - SmallReversedQtPanel - anchors.left: parent.left - anchors.right: parent.right - anchors.top: prev.bottom - margin-top: 7 - height: 22 - - OptionScaleScroll - id: turnDelay - !text: tr('Turn delay: 30ms') - anchors.fill: parent - &minimumScrollValue: 30 - &maximumScrollValue: 250 - &scrollSize: 21 - @onSetup: | - local value = modules.client_options.getOption('turnDelay') - self:setText(tr('Turn delay: %dms', value)) - - QtButton - id: hotkeysButton - !text: tr('Hotkeys Manager') - @onClick: modules.game_hotkeys.show() - anchors.top: prev.bottom - anchors.left: parent.left - margin-top: 12 - - size: 120 20 diff --git a/modules/client_options/data_options.lua b/modules/client_options/data_options.lua index 2dc4ad37bc..5b56bd01ce 100644 --- a/modules/client_options/data_options.lua +++ b/modules/client_options/data_options.lua @@ -398,5 +398,56 @@ return { }, profile = { value = 1, - } + }, + showExpiryInInvetory = { + value = true, + event = nil, + action = function(value, options, controller, panels, extraWidgets) + if options.showExpiryInContainers.event ~= nil then + removeEvent(options.showExpiryInInvetory.event) + end + options.showExpiryInInvetory.event = scheduleEvent(function() + modules.game_inventory.reloadInventory() + options.showExpiryInInvetory.event = nil + end, 100) + end + }, + showExpiryInContainers = { + value = true, + event = nil, + action = function(value, options, controller, panels, extraWidgets) + if options.showExpiryInContainers.event ~= nil then + removeEvent(options.showExpiryInContainers.event) + end + options.showExpiryInContainers.event = scheduleEvent(function() + modules.game_containers.reloadContainers() + options.showExpiryInContainers.event = nil + end, 100) + end + }, + showExpiryOnUnusedItems = true, + framesRarity = { + value = 'frames', + event = nil, + action = function(value, options, controller, panels, extraWidgets) + local newValue = value + if newValue == 'None' then + newValue = nil + end + panels.interface:recursiveGetChildById('frames'):setCurrentOptionByData(newValue, true) + if options.framesRarity.event ~= nil then + removeEvent(options.framesRarity.event) + end + options.framesRarity.event = scheduleEvent(function() + modules.game_containers.reloadContainers() + options.framesRarity.event = nil + end, 100) + end + }, + autoSwitchPreset = false, + listKeybindsPanel = { + action = function(value, options, controller, panels, extraWidgets) + listKeybindsComboBox(value) + end + }, } diff --git a/modules/client_options/general.otui b/modules/client_options/general.otui deleted file mode 100644 index 16057d90d4..0000000000 --- a/modules/client_options/general.otui +++ /dev/null @@ -1,178 +0,0 @@ -Panel - SmallReversedQtPanel - anchors.left: parent.left - anchors.right: parent.right - anchors.top: parent.top - height: 22 - - OptionCheckBoxMarked - id: showPing - !text: tr('Show connection ping') - !tooltip: tr('Display connection speed to the server (milliseconds)') - - SmallReversedQtPanel - anchors.left: parent.left - anchors.right: parent.right - anchors.top: prev.bottom - margin-top: 7 - height: 22 - - OptionCheckBox - id: showFps - !text: tr('Show frame rate') - - SmallReversedQtPanel - anchors.left: parent.left - anchors.right: parent.right - anchors.top: prev.bottom - margin-top: 7 - height: 22 - - OptionCheckBox - id: showLeftPanel - !text: tr('Show left panel') - - SmallReversedQtPanel - anchors.left: parent.left - anchors.right: parent.right - anchors.top: prev.bottom - margin-top: 7 - height: 22 - - OptionCheckBox - id: showRightExtraPanel - !text: tr('Show an extra right panel') - - SmallReversedQtPanel - anchors.left: parent.left - anchors.right: parent.right - anchors.top: prev.bottom - margin-top: 7 - height: 22 - - OptionCheckBox - id: showActionbar - !text: tr('Show action bar') - - SmallReversedQtPanel - anchors.left: parent.left - anchors.right: parent.right - anchors.top: prev.bottom - margin-top: 7 - height: 22 - - OptionCheckBox - id: showSpellGroupCooldowns - !text: tr('Show spell group cooldowns') - - SmallReversedQtPanel - anchors.left: parent.left - anchors.right: parent.right - anchors.top: prev.bottom - margin-top: 7 - height: 22 - - OptionCheckBox - id: openMaximized - !text: tr('Open containers maximized') - - SmallReversedQtPanel - anchors.left: parent.left - anchors.right: parent.right - anchors.top: prev.bottom - margin-top: 7 - height: 22 - - OptionCheckBox - id: displayNames - !text: tr('Display creature names') - - SmallReversedQtPanel - anchors.left: parent.left - anchors.right: parent.right - anchors.top: prev.bottom - margin-top: 7 - height: 22 - - OptionCheckBox - id: displayHealth - !text: tr('Display creature health bars') - - SmallReversedQtPanel - anchors.left: parent.left - anchors.right: parent.right - anchors.top: prev.bottom - margin-top: 7 - height: 22 - - OptionCheckBox - id: displayMana - !text: tr('Display player mana bar') - - SmallReversedQtPanel - anchors.left: parent.left - anchors.right: parent.right - anchors.top: prev.bottom - margin-top: 7 - height: 22 - - OptionCheckBox - id: displayText - !text: tr('Display text messages') - - SmallReversedQtPanel - anchors.left: parent.left - anchors.right: parent.right - anchors.top: prev.bottom - margin-top: 7 - height: 22 - - OptionCheckBox - id: enableHighlightMouseTarget - !text: tr('Highlight mouse target') - - SmallReversedQtPanel - anchors.left: parent.left - anchors.right: parent.right - anchors.top: prev.bottom - margin-top: 7 - height: 22 - - OptionCheckBoxMarked - id: asyncTxtLoading - !text: tr('Async texture loading') - !tooltip: tr('This option makes textures load asynchronously and uses less RAM.') - - SmallReversedQtPanel - anchors.left: parent.left - anchors.right: parent.right - anchors.top: prev.bottom - margin-top: 7 - height: 22 - - OptionCheckBoxMarked - id: drawEffectOnTop - !text: tr('Draw Effect On Top') - !tooltip: tr('Draw effect after drawing the entire floor.') - - SmallReversedQtPanel - anchors.left: parent.left - anchors.right: parent.right - anchors.top: prev.bottom - margin-top: 7 - height: 32 - - Label - !text: 'Crosshair:' - anchors.left: parent.left - margin-left: 18 - color: #c0c0c0ff - anchors.verticalCenter: parent.verticalCenter - - QtComboBox - id: crosshair - width: 120 - margin-left: 10 - anchors.verticalCenter: prev.verticalCenter - anchors.left: prev.right - mouse-scroll: false \ No newline at end of file diff --git a/modules/client_options/graphics.otui b/modules/client_options/graphics.otui deleted file mode 100644 index 747a83a669..0000000000 --- a/modules/client_options/graphics.otui +++ /dev/null @@ -1,222 +0,0 @@ -Panel - SmallReversedQtPanel - anchors.left: parent.left - anchors.right: parent.right - anchors.top: parent.top - height: 22 - - OptionCheckBoxMarked - id: vsync - !text: tr('Enable vertical synchronization') - !tooltip: tr('Limits your fps based on monitor refresh rate') - - SmallReversedQtPanel - anchors.left: parent.left - anchors.right: parent.right - anchors.top: prev.bottom - margin-top: 7 - height: 22 - - OptionCheckBoxMarked - id: optimizeFps - !text: tr('Optimize FPS') - !tooltip: tr('Try to optimize when the frame rate is below 60. VISUAL PROBLEMS MAY OCCUR') - - SmallReversedQtPanel - anchors.left: parent.left - anchors.right: parent.right - anchors.top: prev.bottom - margin-top: 7 - height: 22 - - OptionCheckBoxMarked - id: forceEffectOptimization - !text: tr('Force Effect Optimization') - !tooltip: tr('Will avoid drawing effects on certain occasions.') - - SmallReversedQtPanel - anchors.left: parent.left - anchors.right: parent.right - anchors.top: prev.bottom - margin-top: 7 - height: 22 - - OptionCheckBox - id: enableLights - !text: tr('Enable lights') - - SmallReversedQtPanel - anchors.left: parent.left - anchors.right: parent.right - anchors.top: prev.bottom - margin-top: 7 - height: 22 - - OptionCheckBox - id: drawEffectOnTop - !text: tr('Draw Effect On Top') - !tooltip: tr('Draw effect after drawing the entire floor.') - - SmallReversedQtPanel - anchors.left: parent.left - anchors.right: parent.right - anchors.top: prev.bottom - margin-top: 7 - height: 22 - - OptionCheckBoxMarked - id: limitVisibleDimension - !text: tr('Limit Visible Dimension') - !tooltip: tr('The limit is based on your maximum range.') - - SmallReversedQtPanel - anchors.left: parent.left - anchors.right: parent.right - anchors.top: prev.bottom - margin-top: 7 - height: 22 - - OptionCheckBox - id: floatingEffect - !text: 'Draw Floating Effects' - - SmallReversedQtPanel - anchors.left: parent.left - anchors.right: parent.right - anchors.top: prev.bottom - margin-top: 7 - height: 22 - - OptionCheckBoxMarked - id: fullscreen - !text: 'Fullscreen' - !tooltip: 'Ctrl+Shift+F' - - SmallReversedQtPanel - anchors.left: parent.left - anchors.right: parent.right - anchors.top: prev.bottom - margin-top: 7 - height: 22 - - OptionCheckBox - id: dontStretchShrink - !text: 'Don\'t stretch/shrink Game Window' - - SmallReversedQtPanel - anchors.left: parent.left - anchors.right: parent.right - anchors.top: prev.bottom - margin-top: 7 - height: 32 - - Label - !text: 'Floor View Mode:' - anchors.left: parent.left - margin-left: 18 - color: #c0c0c0ff - anchors.verticalCenter: parent.verticalCenter - - QtComboBox - id: floorViewMode - width: 180 - margin-left: 10 - anchors.verticalCenter: prev.verticalCenter - anchors.left: prev.right - mouse-scroll: false - - SmallReversedQtPanel - anchors.left: parent.left - anchors.right: parent.right - anchors.top: prev.bottom - margin-top: 7 - height: 32 - - Label - !text: 'Antialiasing Mode:' - anchors.left: parent.left - margin-left: 18 - color: #c0c0c0ff - anchors.verticalCenter: parent.verticalCenter - - QtComboBox - id: antialiasingMode - width: 180 - margin-left: 10 - anchors.verticalCenter: prev.verticalCenter - anchors.left: prev.right - mouse-scroll: false - - SmallReversedQtPanel - anchors.left: parent.left - anchors.right: parent.right - anchors.top: prev.bottom - margin-top: 7 - height: 22 - - OptionScaleScroll - id: ambientLight - anchors.fill: parent - &minimumScrollValue: 0 - &maximumScrollValue: 100 - &scrollSize: 21 - @onSetup: | - local value = modules.client_options.getOption('ambientLight') - self:setText(string.format('Ambient light: %s%%', value)) - - SmallReversedQtPanel - anchors.left: parent.left - anchors.right: parent.right - anchors.top: prev.bottom - margin-top: 7 - height: 22 - - OptionScaleScroll - id: shadowFloorIntensity - anchors.fill: parent - &minimumScrollValue: 0 - &maximumScrollValue: 100 - &scrollSize: 21 - @onSetup: | - local value = modules.client_options.getOption('shadowFloorIntensity') - self:setText(string.format('Floor Shadowing Intensity: %s%%', value)) - - SmallReversedQtPanel - anchors.left: parent.left - anchors.right: parent.right - anchors.top: prev.bottom - margin-top: 7 - height: 22 - - OptionScaleScroll - id: floorFading - anchors.fill: parent - &minimumScrollValue: 0 - &maximumScrollValue: 1000 - &scrollSize: 21 - @onSetup: | - local value = modules.client_options.getOption('floorFading') - self:setText(tr('Floor Fading: %s ms', value)) - - SmallReversedQtPanel - anchors.left: parent.left - anchors.right: parent.right - anchors.top: prev.bottom - margin-top: 7 - height: 22 - - OptionScaleScroll - id: backgroundFrameRate - !text: tr('Game framerate limit: %s', 'max') - anchors.fill: parent - &minimumScrollValue: 10 - &maximumScrollValue: 201 - &scrollSize: 21 - @onSetup: | - local value = modules.client_options.getOption('backgroundFrameRate') - local text = value - if value <= 0 or value >= 201 then - text = 'max' - end - - self:setText(tr('Game framerate limit: %s', text)) diff --git a/modules/client_options/keybins.lua b/modules/client_options/keybins.lua new file mode 100644 index 0000000000..fa8abf2103 --- /dev/null +++ b/modules/client_options/keybins.lua @@ -0,0 +1,756 @@ +local actionNameLimit = 39 +local changedOptions = {} +local changedKeybinds = {} +local changedHotkeys = {} +local presetWindow = nil +local actionSearchEvent +local keyEditWindow = nil +local chatModeGroup + +-- controls and keybinds +function addNewPreset() + presetWindow:setText(tr('Add hotkey preset')) + + presetWindow.info:setText(tr('Enter a name for the new preset:')) + + presetWindow.field:clearText() + presetWindow.field:show() + presetWindow.field:focus() + + presetWindow:setWidth(360) + + presetWindow.action = 'add' + + presetWindow:show() + presetWindow:raise() + presetWindow:focus() + + controller.ui:hide() +end + +function copyPreset() + presetWindow:setText(tr('Copy hotkey preset')) + + presetWindow.info:setText(tr('Enter a name for the new preset:')) + + presetWindow.field:clearText() + presetWindow.field:show() + presetWindow.field:focus() + + presetWindow.action = 'copy' + + presetWindow:setWidth(360) + presetWindow:show() + presetWindow:raise() + presetWindow:focus() + + controller.ui:hide() +end + +function renamePreset() + presetWindow:setText(tr('Rename hotkey preset')) + + presetWindow.info:setText(tr('Enter a name for the preset:')) + + presetWindow.field:setText(panels.keybindsPanel.presets.list:getCurrentOption().text) + presetWindow.field:setCursorPos(1000) + presetWindow.field:show() + presetWindow.field:focus() + + presetWindow.action = 'rename' + + presetWindow:setWidth(360) + presetWindow:show() + presetWindow:raise() + presetWindow:focus() + + controller.ui:hide() +end + +function removePreset() + presetWindow:setText(tr('Warning')) + + presetWindow.info:setText(tr('Do you really want to delete the hotkey preset %s?', + panels.keybindsPanel.presets.list:getCurrentOption().text)) + presetWindow.field:hide() + presetWindow.action = 'remove' + + presetWindow:setWidth(presetWindow.info:getTextSize().width + presetWindow:getPaddingLeft() + + presetWindow:getPaddingRight()) + presetWindow:show() + presetWindow:raise() + presetWindow:focus() + + controller.ui:hide() +end + +function okPresetWindow() + local presetName = presetWindow.field:getText():trim() + local selectedPreset = panels.keybindsPanel.presets.list:getCurrentOption().text + + presetWindow:hide() + show() + + if presetWindow.action == 'add' then + Keybind.newPreset(presetName) + panels.keybindsPanel.presets.list:addOption(presetName) + panels.keybindsPanel.presets.list:setCurrentOption(presetName) + elseif presetWindow.action == 'copy' then + if not Keybind.copyPreset(selectedPreset, presetName) then + return + end + + panels.keybindsPanel.presets.list:addOption(presetName) + panels.keybindsPanel.presets.list:setCurrentOption(presetName) + elseif presetWindow.action == 'rename' then + if selectedPreset ~= presetName then + panels.keybindsPanel.presets.list:updateCurrentOption(presetName) + if changedOptions['currentPreset'] then + changedOptions['currentPreset'].value = presetName + end + Keybind.renamePreset(selectedPreset, presetName) + end + elseif presetWindow.action == 'remove' then + if Keybind.removePreset(selectedPreset) then + panels.keybindsPanel.presets.list:removeOption(selectedPreset) + end + end +end + +function cancelPresetWindow() + presetWindow:hide() + show() +end + +function editKeybindKeyDown(widget, keyCode, keyboardModifiers) + keyEditWindow.keyCombo:setText(determineKeyComboDesc(keyCode, + keyEditWindow.alone:isVisible() and KeyboardNoModifier or keyboardModifiers)) + + local category = nil + local action = nil + + if keyEditWindow.keybind then + category = keyEditWindow.keybind.category + action = keyEditWindow.keybind.action + end + + local keyCombo = keyEditWindow.keyCombo:getText() + local keyUsed = Keybind.isKeyComboUsed(keyCombo, category, action, getChatMode()) + if not keyUsed then + for _, change in ipairs(changedHotkeys) do + if change.primary == keyCombo or change.secondary == keyCombo then + keyUsed = true + break + end + end + end + + keyEditWindow.buttons.ok:setEnabled(not keyUsed) + keyEditWindow.used:setVisible(keyUsed) +end + +function editKeybind(keybind) + keyEditWindow.buttons.cancel.onClick = function() + disconnect(keyEditWindow, { + onKeyDown = editKeybindKeyDown + }) + keyEditWindow:hide() + keyEditWindow:ungrabKeyboard() + show() + end + + keyEditWindow.info:setText(tr( + 'Click \'Ok\' to assign the keybind. Click \'Clear\' to remove the keybind from \'%s: %s\'.', keybind.category, + keybind.action)) + keyEditWindow.alone:setVisible(keybind.alone) + + connect(keyEditWindow, { + onKeyDown = editKeybindKeyDown + }) + + keyEditWindow:show() + keyEditWindow:raise() + keyEditWindow:focus() + keyEditWindow:grabKeyboard() + hide() +end + +function editKeybindPrimary(button) + local column = button:getParent() + local row = column:getParent() + local index = row.category .. '_' .. row.action + local keybind = Keybind.getAction(row.category, row.action) + local preset = panels.keybindsPanel.presets.list:getCurrentOption().text + + keyEditWindow.keybind = { + category = row.category, + action = row.action + } + + keyEditWindow:setText(tr('Edit Primary Key for \'%s\'', string.format('%s: %s', keybind.category, keybind.action))) + keyEditWindow.keyCombo:setText(Keybind.getKeybindKeys(row.category, row.action, getChatMode(), preset).primary) + + editKeybind(keybind) + + keyEditWindow.buttons.ok.onClick = function() + local keyCombo = keyEditWindow.keyCombo:getText() + + column:setText(keyEditWindow.keyCombo:getText()) + + if not changedKeybinds[preset] then + changedKeybinds[preset] = {} + end + if not changedKeybinds[preset][index] then + changedKeybinds[preset][index] = {} + end + changedKeybinds[preset][index].primary = { + category = row.category, + action = row.action, + keyCombo = keyCombo + } + + disconnect(keyEditWindow, { + onKeyDown = editKeybindKeyDown + }) + keyEditWindow:hide() + keyEditWindow:ungrabKeyboard() + show() + applyChangedOptions() + end + + keyEditWindow.buttons.clear.onClick = function() + if not changedKeybinds[preset] then + changedKeybinds[preset] = {} + end + if not changedKeybinds[preset][index] then + changedKeybinds[preset][index] = {} + end + changedKeybinds[preset][index].primary = { + category = row.category, + action = row.action, + keyCombo = '' + } + + column:setText('') + + disconnect(keyEditWindow, { + onKeyDown = editKeybindKeyDown + }) + keyEditWindow:hide() + keyEditWindow:ungrabKeyboard() + show() + applyChangedOptions() + end +end + +function editKeybindSecondary(button) + local column = button:getParent() + local row = column:getParent() + local index = row.category .. '_' .. row.action + local keybind = Keybind.getAction(row.category, row.action) + local preset = panels.keybindsPanel.presets.list:getCurrentOption().text + + keyEditWindow.keybind = { + category = row.category, + action = row.action + } + + keyEditWindow:setText(tr('Edit Secondary Key for \'%s\'', string.format('%s: %s', keybind.category, keybind.action))) + keyEditWindow.keyCombo:setText(Keybind.getKeybindKeys(row.category, row.action, getChatMode(), preset).secondary) + + editKeybind(keybind) + + keyEditWindow.buttons.ok.onClick = function() + local keyCombo = keyEditWindow.keyCombo:getText() + + column:setText(keyEditWindow.keyCombo:getText()) + + if not changedKeybinds[preset] then + changedKeybinds[preset] = {} + end + if not changedKeybinds[preset][index] then + changedKeybinds[preset][index] = {} + end + changedKeybinds[preset][index].secondary = { + category = row.category, + action = row.action, + keyCombo = keyCombo + } + + disconnect(keyEditWindow, { + onKeyDown = editKeybindKeyDown + }) + keyEditWindow:hide() + keyEditWindow:ungrabKeyboard() + show() + applyChangedOptions() + end + + keyEditWindow.buttons.clear.onClick = function() + if not changedKeybinds[preset] then + changedKeybinds[preset] = {} + end + if not changedKeybinds[preset][index] then + changedKeybinds[preset][index] = {} + end + changedKeybinds[preset][index].secondary = { + category = row.category, + action = row.action, + keyCombo = '' + } + + column:setText('') + + disconnect(keyEditWindow, { + onKeyDown = editKeybindKeyDown + }) + keyEditWindow:hide() + keyEditWindow:ungrabKeyboard() + show() + applyChangedOptions() + end +end + +function resetActions() + changedOptions['resetKeybinds'] = { + value = panels.keybindsPanel.presets.list:getCurrentOption().text + } + updateKeybinds() + applyChangedOptions() +end + +function updateKeybinds() + panels.keybindsPanel.tablePanel.keybinds:clearData() + + local sortedKeybinds = {} + + for index, _ in pairs(Keybind.defaultKeybinds) do + table.insert(sortedKeybinds, index) + end + + table.sort(sortedKeybinds, function(a, b) + local keybindA = Keybind.defaultKeybinds[a] + local keybindB = Keybind.defaultKeybinds[b] + + if keybindA.category ~= keybindB.category then + return keybindA.category < keybindB.category + end + return keybindA.action < keybindB.action + end) + + + local comboBox = panels.keybindsPanel.presets.list:getCurrentOption() + if not comboBox then + return + end + for _, index in ipairs(sortedKeybinds) do + local keybind = Keybind.defaultKeybinds[index] + local keys = Keybind.getKeybindKeys(keybind.category, keybind.action, getChatMode(), comboBox.text, + changedOptions['resetKeybinds']) + addKeybind(keybind.category, keybind.action, keys.primary, keys.secondary) + end +end + +function updateHotkeys() + panels.keybindsPanel.tablePanel.keybinds:clearData() + + local chatMode = getChatMode() + local preset = panels.keybindsPanel.presets.list:getCurrentOption().text + if Keybind.hotkeys[chatMode][preset] then + for _, hotkey in ipairs(Keybind.hotkeys[chatMode][preset]) do + addHotkey(hotkey.hotkeyId, hotkey.action, hotkey.data, hotkey.primary, hotkey.secondary) + end + end +end + +function preAddHotkey(action, data) + local preset = panels.keybindsPanel.presets.list:getCurrentOption().text + local chatMode = getChatMode() + local hotkeyId = #changedHotkeys + 1 + + if Keybind.hotkeys[chatMode] and Keybind.hotkeys[chatMode][preset] then + hotkeyId = hotkeyId + #Keybind.hotkeys[chatMode][preset] + end + + table.insert(changedHotkeys, { + hotkeyId = hotkeyId, + action = action, + data = data, + new = true + }) + + addHotkey(hotkeyId, action, data) +end + +function addKeybind(category, action, primary, secondary) + local rawText = string.format('%s: %s', category, action) + local text = string.format('[color=#ffffff]%s:[/color] %s', category, action) + local tooltip = nil + + if rawText:len() > actionNameLimit then + tooltip = rawText + -- 15 and 8 are length of color codes + text = text:sub(1, actionNameLimit + 15 + 8) .. '...' + end + + local row = panels.keybindsPanel.tablePanel.keybinds:addRow({ { + coloredText = { + text = text, + color = '#c0c0c0' + }, + width = 286 + }, { + style = 'VerticalSeparator' + }, { + style = 'EditableKeybindsTableColumn', + text = primary, + width = 100 + }, { + style = 'VerticalSeparator' + }, { + style = 'EditableKeybindsTableColumn', + text = secondary, + width = 90 + } }) + + row.category = category + row.action = action + + if tooltip then + row:setTooltip(tooltip) + end + + row:getChildByIndex(3).edit.onClick = editKeybindPrimary + row:getChildByIndex(5).edit.onClick = editKeybindSecondary +end + +function clearHotkey(row) + table.insert(changedHotkeys, { + hotkeyId = row.hotkeyId, + remove = true + }) + panels.keybindsPanel.tablePanel.keybinds:removeRow(row) +end + +function editHotkeyKey(text) + keyEditWindow.buttons.cancel.onClick = function() + disconnect(keyEditWindow, { + onKeyDown = editKeybindKeyDown + }) + keyEditWindow:hide() + keyEditWindow:ungrabKeyboard() + show() + end + + keyEditWindow.info:setText(tr( + 'Click \'Ok\' to assign the keybind. Click \'Clear\' to remove the keybind from \'%s\'.', text)) + keyEditWindow.alone:setVisible(false) + + connect(keyEditWindow, { + onKeyDown = editKeybindKeyDown + }) + + keyEditWindow:show() + keyEditWindow:raise() + keyEditWindow:focus() + keyEditWindow:grabKeyboard() + hide() +end + +function editHotkeyPrimary(button) + local column = button:getParent() + local row = column:getParent() + local text = row:getChildByIndex(1):getText() + local hotkeyId = row.hotkeyId + local preset = panels.keybindsPanel.presets.list:getCurrentOption().text + + keyEditWindow:setText(tr('Edit Primary Key for \'%s\'', text)) + keyEditWindow.keyCombo:setText(Keybind.getHotkeyKeys(hotkeyId, preset, getChatMode()).primary) + + editHotkeyKey(text) + + keyEditWindow.buttons.ok.onClick = function() + local keyCombo = keyEditWindow.keyCombo:getText() + + column:setText(keyEditWindow.keyCombo:getText()) + + local changed = table.findbyfield(changedHotkeys, 'hotkeyId', hotkeyId) + if changed then + changed.primary = keyCombo + if not changed.secondary then + changed.secondary = Keybind.getHotkeyKeys(hotkeyId, preset, getChatMode()).secondary + end + changed.editKey = true + else + table.insert(changedHotkeys, { + hotkeyId = hotkeyId, + primary = keyCombo, + secondary = Keybind.getHotkeyKeys(hotkeyId, preset, getChatMode()).secondary, + editKey = true + }) + end + + disconnect(keyEditWindow, { + onKeyDown = editKeybindKeyDown + }) + keyEditWindow:hide() + keyEditWindow:ungrabKeyboard() + show() + end + + keyEditWindow.buttons.clear.onClick = function() + column:setText('') + + local changed = table.findbyfield(changedHotkeys, 'hotkeyId', hotkeyId) + if changed then + changed.primary = nil + if not changed.secondary then + changed.secondary = Keybind.getHotkeyKeys(hotkeyId, preset, getChatMode()).secondary + end + changed.editKey = true + else + table.insert(changedHotkeys, { + hotkeyId = hotkeyId, + secondary = Keybind.getHotkeyKeys(hotkeyId, preset, getChatMode()).secondary, + editKey = true + }) + end + + disconnect(keyEditWindow, { + onKeyDown = editKeybindKeyDown + }) + keyEditWindow:hide() + keyEditWindow:ungrabKeyboard() + show() + end +end + +function editHotkeySecondary(button) + local column = button:getParent() + local row = column:getParent() + local text = row:getChildByIndex(1):getText() + local hotkeyId = row.hotkeyId + local preset = panels.keybindsPanel.presets.list:getCurrentOption().text + + keyEditWindow:setText(tr('Edit Secondary Key for \'%s\'', text)) + keyEditWindow.keyCombo:setText(Keybind.getHotkeyKeys(hotkeyId, preset, getChatMode()).secondary) + + editHotkeyKey(text) + + keyEditWindow.buttons.ok.onClick = function() + local keyCombo = keyEditWindow.keyCombo:getText() + + column:setText(keyEditWindow.keyCombo:getText()) + + if changedHotkeys[hotkeyId] then + if not changedHotkeys[hotkeyId].primary then + changedHotkeys[hotkeyId].primary = Keybind.getHotkeyKeys(hotkeyId, preset, getChatMode()).primary + end + changedHotkeys[hotkeyId].secondary = keyCombo + changedHotkeys[hotkeyId].editKey = true + else + table.insert(changedHotkeys, { + hotkeyId = hotkeyId, + primary = Keybind.getHotkeyKeys(hotkeyId, preset, getChatMode()).primary, + secondary = keyCombo, + editKey = true + }) + end + + disconnect(keyEditWindow, { + onKeyDown = editKeybindKeyDown + }) + keyEditWindow:hide() + keyEditWindow:ungrabKeyboard() + show() + end + + keyEditWindow.buttons.clear.onClick = function() + column:setText('') + + if changedHotkeys[hotkeyId] then + if not changedHotkeys[hotkeyId].primary then + changedHotkeys[hotkeyId].primary = Keybind.getHotkeyKeys(hotkeyId, preset, getChatMode()).primary + end + changedHotkeys[hotkeyId].secondary = nil + changedHotkeys[hotkeyId].editKey = true + else + table.insert(changedHotkeys, { + hotkeyId = hotkeyId, + primary = Keybind.getHotkeyKeys(hotkeyId, preset, getChatMode()).primary, + editKey = true + }) + end + + disconnect(keyEditWindow, { + onKeyDown = editKeybindKeyDown + }) + keyEditWindow:hide() + keyEditWindow:ungrabKeyboard() + show() + end +end + +function searchActions(field, text, oldText) + if actionSearchEvent then + removeEvent(actionSearchEvent) + end + + actionSearchEvent = scheduleEvent(performeSearchActions, 200) +end + +function performeSearchActions() + local searchText = panels.keybindsPanel.search.field:getText():trim():lower() + + local rows = panels.keybindsPanel.tablePanel.keybinds.dataSpace:getChildren() + if searchText:len() > 0 then + for _, row in ipairs(rows) do + row:hide() + end + + for _, row in ipairs(rows) do + local actionText = row:getChildByIndex(1):getText():lower() + local primaryText = row:getChildByIndex(3):getText():lower() + local secondaryText = row:getChildByIndex(5):getText():lower() + if actionText:find(searchText) or primaryText:find(searchText) or secondaryText:find(searchText) then + row:show() + end + end + else + for _, row in ipairs(rows) do + row:show() + end + end + + removeEvent(actionSearchEvent) + actionSearchEvent = nil +end + +function chatModeChange() + changedHotkeys = {} + changedKeybinds = {} + + panels.keybindsPanel.search.field:clearText() + + updateKeybinds() +end + +function getChatMode() + if chatModeGroup:getSelectedWidget() == panels.keybindsPanel.panel.chatMode.on then + return CHAT_MODE.ON + end + + return CHAT_MODE.OFF +end + +function applyChangedOptions() + local needKeybindsUpdate = false + local needHotkeysUpdate = false + + for key, option in pairs(changedOptions) do + if key == 'resetKeybinds' then + Keybind.resetKeybindsToDefault(option.value, option.chatMode) + needKeybindsUpdate = true + end + end + changedOptions = {} + + for preset, keybinds in pairs(changedKeybinds) do + for index, keybind in pairs(keybinds) do + if keybind.primary then + if Keybind.setPrimaryActionKey(keybind.primary.category, keybind.primary.action, preset, + keybind.primary.keyCombo, getChatMode()) then + needKeybindsUpdate = true + end + elseif keybind.secondary then + if Keybind.setSecondaryActionKey(keybind.secondary.category, keybind.secondary.action, preset, + keybind.secondary.keyCombo, getChatMode()) then + needKeybindsUpdate = true + end + end + end + end + changedKeybinds = {} + + if needKeybindsUpdate then + updateKeybinds() + end + g_settings.save() +end + +function presetOption(widget, key, value, force) + if not controller.ui:isVisible() then + return + end + + changedOptions[key] = { widget = widget, value = value, force = force } + if key == "currentPreset" then + Keybind.selectPreset(value) + panels.keybindsPanel.presets.list:setCurrentOption(value, true) + end +end + +function init_binds() + chatModeGroup = UIRadioGroup.create() + chatModeGroup:addWidget(panels.keybindsPanel.panel.chatMode.on) + chatModeGroup:addWidget(panels.keybindsPanel.panel.chatMode.off) + chatModeGroup.onSelectionChange = chatModeChange + chatModeGroup:selectWidget(panels.keybindsPanel.panel.chatMode.on) + + keyEditWindow = g_ui.displayUI("styles/controls/key_edit") + keyEditWindow:hide() + presetWindow = g_ui.displayUI("styles/controls/preset") + presetWindow:hide() + panels.keybindsPanel.presets.add.onClick = addNewPreset + panels.keybindsPanel.presets.copy.onClick = copyPreset + panels.keybindsPanel.presets.rename.onClick = renamePreset + panels.keybindsPanel.presets.remove.onClick = removePreset + panels.keybindsPanel.buttons.newAction:disable() + panels.keybindsPanel.buttons.newAction.onClick = newHotkeyAction + panels.keybindsPanel.buttons.reset.onClick = resetActions + panels.keybindsPanel.search.field.onTextChange = searchActions + panels.keybindsPanel.search.clear.onClick = function() panels.keybindsPanel.search.field:clearText() end + presetWindow.onEnter = okPresetWindow + presetWindow.onEscape = cancelPresetWindow + presetWindow.buttons.ok.onClick = okPresetWindow + presetWindow.buttons.cancel.onClick = cancelPresetWindow +end + +function terminate_binds() + if presetWindow then + presetWindow:destroy() + presetWindow = nil + end + + if chatModeGroup then + chatModeGroup:destroy() + chatModeGroup = nil + end + + if keyEditWindow then + if keyEditWindow:isVisible() then + keyEditWindow:ungrabKeyboard() + disconnect(keyEditWindow, { onKeyDown = editKeybindKeyDown }) + end + keyEditWindow:destroy() + keyEditWindow = nil + end + + actionSearchEvent = nil +end + +function listKeybindsComboBox(value) + local widget = panels.keybindsPanel.presets.list + presetOption(widget, 'currentPreset', value, false) + changedKeybinds = {} + changedHotkeys = {} + applyChangedOptions() + updateKeybinds() +end + +function debug() + local currentOptionText = Keybind.currentPreset + local chatMode = Keybind.chatMode + local chatModeText = (chatMode == 1) and "Chat mode ON" or (chatMode == 2) and "Chat mode OFF" or "Unknown chat mode" + print(string.format("The current configuration is: %s, and the mode is: %s", currentOptionText, chatModeText)) +end diff --git a/modules/client_options/options.lua b/modules/client_options/options.lua index 53190cb64f..d89f726e7f 100644 --- a/modules/client_options/options.lua +++ b/modules/client_options/options.lua @@ -1,6 +1,5 @@ local options = dofile("data_options") - -local panels = { +panels = { generalPanel = nil, graphicsPanel = nil, soundPanel = nil, @@ -9,24 +8,19 @@ local panels = { interfaceHUD = nil, interface = nil, misc = nil, - miscHelp = nil + miscHelp = nil, + keybindsPanel = nil } -- LuaFormatter off local buttons = {{ text = "Controls", icon = "/images/icons/icon_controls", - open = "generalPanel" - --[[ subCategories = {{ + open = "generalPanel", + subCategories = {{ text = "General Hotkeys", - open = "generalPanel" - }, { - text = "Action Bar Hotkeys", - open = "Action_Bar_Hotkeys" - }, { - text = "Custom Hotkeys", - open = "Custom_Hotkeys" - }} ]] + open = "keybindsPanel" + }} }, { text = "Interface", icon = "/images/icons/icon_interface", @@ -105,6 +99,9 @@ local function setupComboBox() local crosshairCombo = panels.interface:recursiveGetChildById('crosshair') local antialiasingModeCombobox = panels.graphicsPanel:recursiveGetChildById('antialiasingMode') local floorViewModeCombobox = panels.graphicsEffectsPanel:recursiveGetChildById('floorViewMode') + local framesRarityCombobox = panels.interface:recursiveGetChildById('frames') + local vocationPresetsCombobox = panels.keybindsPanel:recursiveGetChildById('list') + local listKeybindsPanel = panels.keybindsPanel:recursiveGetChildById('list') for k, v in pairs({ { 'Disabled', 'disabled' }, { 'Default', 'default' }, { 'Full', 'full' } }) do crosshairCombo:addOption(v[1], v[2]) @@ -132,6 +129,14 @@ local function setupComboBox() setOption('floorViewMode', comboBox:getCurrentOption().data) end + for k, v in pairs({ { 'None', 'none' }, { 'Frames', 'frames' }, { 'Corners', 'corners' } }) do + framesRarityCombobox:addOption(v[1], v[2]) + end + + framesRarityCombobox.onOptionChange = function(comboBox, option) + setOption('framesRarity', comboBox:getCurrentOption().data) + end + if not g_game.isEnabledBotProtection() then local profileCombobox = panels.misc:recursiveGetChildById('profile') @@ -144,6 +149,13 @@ local function setupComboBox() end end + for _, preset in ipairs(Keybind.presets) do + listKeybindsPanel:addOption(preset) + end + listKeybindsPanel.onOptionChange = function(comboBox, option) + setOption('listKeybindsPanel', option) + end + panels.keybindsPanel.presets.list:setCurrentOption(Keybind.currentPreset) end local function setup() @@ -168,8 +180,6 @@ end controller = Controller:new() controller:setUI('options') -controller:bindKeyDown('Ctrl+Shift+F', function() toggleOption('fullscreen') end) -controller:bindKeyDown('Ctrl+N', toggleDisplays) function controller:onInit() for k, obj in pairs(options) do @@ -190,6 +200,7 @@ function controller:onInit() '/images/topbuttons/logout', toggle) panels.generalPanel = g_ui.loadUI('styles/controls/general',controller.ui.optionsTabContent) + panels.keybindsPanel = g_ui.loadUI('styles/controls/keybinds',controller.ui.optionsTabContent) panels.graphicsPanel = g_ui.loadUI('styles/graphics/graphics',controller.ui.optionsTabContent) panels.graphicsEffectsPanel = g_ui.loadUI('styles/graphics/effects',controller.ui.optionsTabContent) @@ -207,6 +218,39 @@ function controller:onInit() configureCharacterCategories() addEvent(setup) + init_binds() + + Keybind.new("UI", "Toggle Fullscreen", "Ctrl+Shift+F", "") + Keybind.bind("UI", "Toggle Fullscreen", { + { + type = KEY_DOWN, + callback = function() toggleOption('fullscreen') end, + } + }) + Keybind.new("UI", "Show/hide FPS / lag indicator", "", "") + Keybind.bind("UI", "Show/hide FPS / lag indicator", {{ + type = KEY_DOWN, + callback = function() + toggleOption('showPing') + toggleOption('showFps') + end + }}) + + Keybind.new("UI", "Show/hide Creature Names and Bars", "Ctrl+N", "") + Keybind.bind("UI", "Show/hide Creature Names and Bars", { + { + type = KEY_DOWN, + callback = toggleDisplays, + } + }) + + Keybind.new("Sound", "Mute/unmute", "", "") + Keybind.bind("Sound", "Mute/unmute", { + { + type = KEY_DOWN, + callback = function() toggleOption('enableAudio') end, + } + }) end function controller:onTerminate() @@ -215,6 +259,21 @@ function controller:onTerminate() panels = {} extraWidgets = {} buttons = {} + Keybind.delete("UI", "Toggle Full Screen") + Keybind.delete("UI", "Show/hide Creature Names and Bars") + Keybind.delete("Sound", "Mute/unmute") + + terminate_binds() +end + +function controller:onGameStart() + if g_settings.getBoolean("autoSwitchPreset") then + local name = g_game.getCharacterName() + if Keybind.selectPreset(name) then + panels.keybindsPanel.presets.list:setCurrentOption(name, true) + updateKeybinds() + end + end end function setOption(key, value, force) @@ -290,6 +349,7 @@ function toggle() end end show() + updateKeybinds() end function addTab(name, panel, icon) diff --git a/modules/client_options/options.otmod b/modules/client_options/options.otmod index 7671184cab..2b44193a17 100644 --- a/modules/client_options/options.otmod +++ b/modules/client_options/options.otmod @@ -4,6 +4,6 @@ Module author: edubart, BeniS website: https://github.com/edubart/otclient sandboxed: true - scripts: [ options ] + scripts: [ options, keybins ] @onLoad: controller:init() @onUnload: controller:terminate() diff --git a/modules/client_options/styles/controls/key_edit.otui b/modules/client_options/styles/controls/key_edit.otui new file mode 100644 index 0000000000..aeac99932a --- /dev/null +++ b/modules/client_options/styles/controls/key_edit.otui @@ -0,0 +1,66 @@ +MainWindow + size: 400 225 + layout: + type: verticalBox + spacing: 10 + fit-children: true + + Label + font: verdana-11px-monochrome + text-align: center + color: #c0c0c0 + text: Mode: "Chat On" + + FlatPanel + id: keyCombo + height: 33 + font: verdana-11px-monochrome + text-align: center + color: #c0c0c0 + + Label + id: info + font: verdana-11px-monochrome + color: #c0c0c0 + text-wrap: true + text-auto-resize: true + + Label + id: alone + font: verdana-11px-monochrome + color: #c0c0c0 + !text: tr("This action must be bound to a single key.") + visible: false + + Label + id: used + font: verdana-11px-monochrome + text-align: center + color: #f75f5f + !text: tr("This hotkey is already in use.") + visible: false + + HorizontalSeparator + + Panel + id: buttons + height: 20 + layout: + type: horizontalBox + align-right: true + spacing: -5 + + SmallButton + id: ok + width: 40 + !text: tr("Ok") + + SmallButton + id: clear + width: 45 + !text: tr("Clear") + SmallButton + id: cancel + width: 45 + !text: tr("Cancel") + diff --git a/modules/client_options/styles/controls/keybinds.otui b/modules/client_options/styles/controls/keybinds.otui new file mode 100644 index 0000000000..98ca8999c4 --- /dev/null +++ b/modules/client_options/styles/controls/keybinds.otui @@ -0,0 +1,285 @@ +RadioBox < CheckBox + image-source: /images/ui/outfits/checkbox_round + +OptionContainer < FlatPanel + height: 22 + padding: 3 +KeybindsTableRow < UITableRow + focusable: true + height: 20 + background-color: alpha + even-background-color: alpha + odd-background-color: #484848 + text-align: left + @onFocusChange: for _, child in ipairs(self:getChildren()) do child:setChecked(self:isFocused()) end + layout: horizontalBox + + $focus: + background-color: #585858 + +KeybindsTableColumn < Label + color: #c0c0c0 + text-align: left + focusable: false + text-offset: 2 0 + font: verdana-11px-monochrome + +EditableKeybindsTableColumn < Label + color: #c0c0c0 + text-align: left + focusable: false + text-offset: 2 0 + font: verdana-11px-monochrome + @onCheckChange: self.edit:setVisible(self:isChecked()) + + Button + id: edit + anchors.verticalCenter: parent.verticalCenter + anchors.right: parent.right + size: 13 13 + margin-right: 2 + icon: /images/ui/icon-edit + visible: false + +EditableHotkeysTableColumn < Label + color: #c0c0c0 + text-align: left + focusable: false + text-offset: 18 0 + font: verdana-11px-monochrome + @onCheckChange: self.edit:setVisible(self:isChecked()) + + UIItem + id: item + anchors.verticalCenter: parent.verticalCenter + anchors.left: parent.left + size: 16 16 + virtual: true + phantom: true + + Button + id: edit + anchors.verticalCenter: parent.verticalCenter + anchors.right: parent.right + size: 13 13 + margin-right: 2 + icon: /images/options/icon-edit + visible: false + +KeybindsTableHeaderRow < TableHeaderRow + padding: 0 + height: 18 + +KeybindsTableHeaderColumn < UITableHeaderColumn + font: verdana-11px-monochrome + text-offset: 2 0 + text-align: left + height: 14 + color: #c0c0c0 + background: #363636 + +UIWidget + anchors.fill: parent + visible: false + Panel + anchors.left: parent.left + anchors.right: parent.right + anchors.top: parent.top + id: presets + height: 20 + layout: + type: horizontalBox + spacing: 5 + + QtComboBox + id: list + width: 320 + + SmallButton + id: add + width: 30 + !text: tr("Add") + @onClick: addNewPreset() + + SmallButton + id: copy + width: 35 + !text: tr("Copy") + @onClick: copyPreset() + + SmallButton + id: rename + width: 45 + !text: tr("Rename") + @onClick : renamePreset() + + SmallButton + id: remove + width: 45 + !text: tr("Remove") + @onClick : removePreset() + + SmallReversedQtPanel + anchors.left: parent.left + anchors.right: parent.right + anchors.top: prev.bottom + height: 22 + margin-top: 7 + + OptionCheckBoxMarked + id: autoSwitchPreset + !text: tr('Auto-Switch Hotkey Preset') + !tooltip: tr('If you have named your hotkey presets the same like your\ncharacters and have checked this option, the preset with the same\nname as the corresponding character will be activated upon login\nautomatically.') + + SmallReversedQtPanel + anchors.left: parent.left + anchors.right: parent.right + anchors.top: prev.bottom + height: 22 + margin-top: 7 + id: panel + OptionContainer + anchors.left: parent.left + anchors.right: parent.right + image-source: "" + !tooltip: tr('There are two chat modes for each hotkey preset: Chat On and Chat\n Off.You can find a small button that tells you which chat mode is\n currently active on the right side of the entry line of the chat console.Press this button to switch between the two chat modes.\nOf course, you can also set a hotkey to toggle between Chat On and Off.\n- Chat On\nIn this mode, you will be able to write text in the entry line of the chat console.\nHowever, if you have assigned an action to a letter key, the action will be triggered.\n- Chat On*\nThis is the temporary Chat On mode.\nIn the default hotkey preset, the Return key switches between Chat Off and this mode.\nIf the chat mode is off and you press this hotkey, it temporarily activates the chat mode so that you can write one message in the console.\nAs soon as you press Return to send the message, your chat mode will be set to Chat Off again so that you can continue walking with WASD, for example.\n- Chat Off\nIn this mode, you will not be able to write any text in the entry line of the console, but you can use your predefined hotkeys to walk or cast spells, for example.\nYou can assign functions to all keys of your keyboard, e.g. walk with WASD.') + + id: chatMode + $!first: + margin-left:40 + layout: + type: horizontalBox + spacing: 127 + + RadioBox + id: on + text-horizontal-auto-resize: true + !text: tr("Chat Mode On") + margin-bottom: -5 + text-offset: 20 -3 + RadioBox + id: off + text-horizontal-auto-resize: true + !text: tr("Chat Mode Off") + margin-bottom: -5 + text-offset: 20 -3 + UIWidget + id: toolTipWidget + image-source: /images/icons/show_gui_help_grey + size: 12 12 + anchors.right: parent.right + margin-right: 3 + !tooltip: tr('There are two chat modes for each hotkey preset: Chat On and Chat \nOff. You can find a small button that tells you which chat mode is \ncurrently active on the right side of the entry line of the chat \nconsole. Press this button to switch between the two chat modes. Of \ncourse, you can also set a hotkey to toggle between Chat On and Off.\n\tChat On\n\t\tIn this mode, you will be able to write text in the entry line of\n the chat console. However, if you have assigned an action to \na letter key, the action will be \t\ttriggered.\n\n\n\tChat On\n\t\tThis is the temporary Chat On mode. In the default hotkey \npreset, the Return key switches between Chat Off and this\n mode. If the chat mode is off and you press \t\tthis hotkey, it \ntemporarily activates the chat mode so that you can write \none message in the console. As soon as you press Return to \nsend the message, your chat \t\tmode will be set to \nChat Off again so that you can continue walking with WASD, for\n example.\n\n\tChat Off\n\t\tIn this mode, you will not be able to write any text in the entry line of the\n console, but you can use your predefined\n hotkeys to walk or cast spells, for \t\texample. You can assign\n functions to all keys of your keyboard, e.g. walk with WASD') + + Panel + anchors.left: parent.left + anchors.right: parent.right + anchors.top: prev.bottom + id: search + height: 20 + margin-top: 5 + layout: + type: horizontalBox + spacing: 6 + + Label + text-offset: 0 3 + font: verdana-11px-monochrome + !text: tr('Type to search for a hotkey:') + + TextEdit + id: field + width: 300 + @onTextChange: searchActions() + + UIButton + id: clear + image-source: /images/ui/button-clear-18x18-up + image-clip: 0 0 20 20 + width: 20 + + $pressed: + image-source: /images/ui/button-clear-18x18-down + @onClick : self:getParent().field:clearText() + + Panel + id: tablePanel + anchors.left: parent.left + anchors.right: parent.right + anchors.top: prev.bottom + height: 305 + margin-top: 5 + image-source: /images/game/actionbar/1pixel-down-frame + image-border: 1 + background: #404040 + + Table + id: keybinds + anchors.fill: parent + margin: 1 + table-data: keybindsData + row-style: KeybindsTableRow + column-style: KeybindsTableColumn + header-row-style: KeybindsTableHeaderRow + header-column-style: KeybindsTableHeaderColumn + + KeybindsTableHeaderRow + id: header + + KeybindsTableHeaderColumn + !text: tr("Action") + width: 286 + + VerticalSeparator + + KeybindsTableHeaderColumn + !text: tr("Primary Key") + width: 100 + + VerticalSeparator + + KeybindsTableHeaderColumn + !text: tr("Secondary Key") + width: 100 + + HorizontalSeparator + + TableData + id: keybindsData + anchors.fill: keybinds + margin-top: 20 + padding-bottom: 1 + vertical-scrollbar: scrollBar + + VerticalQtScrollBar + id: scrollBar + anchors.top: parent.top + anchors.bottom: parent.bottom + anchors.right: parent.right + step: 16 + pixels-scroll: true + + Panel + id: buttons + height: 20 + anchors.left: parent.left + anchors.right: parent.right + anchors.top: prev.bottom + + SmallButton + id: newAction + anchors.top: parent.top + anchors.left: parent.left + width: 75 + !text: tr('New Action') + visible: false + @onClick : newHotkeyAction() + + SmallButton + id: reset + anchors.top: parent.top + anchors.right: parent.right + width: 45 + margin-top: 8 + !text: tr('Reset') + @onClick : resetActions() diff --git a/modules/client_options/styles/controls/preset.otui b/modules/client_options/styles/controls/preset.otui new file mode 100644 index 0000000000..9b3d4ab223 --- /dev/null +++ b/modules/client_options/styles/controls/preset.otui @@ -0,0 +1,43 @@ +MainWindow + width: 360 + text: Add hotkey preset + layout: + type: verticalBox + fit-children: true + + Label + id: info + font: verdana-11px-monochrome + color: #c0c0c0 + text: Enter a name for the new preset: + + TextEdit + id: field + margin-top: 3 + height: 16 + padding: 1 4 + font: verdana-11px-monochrome + color: #c0c0c0 + + HorizontalSeparator + margin-top: 10 + + Panel + id: buttons + margin-top: 10 + height: 20 + layout: + type: horizontalBox + align-right: true + spacing: -8 + + SmallButton + id: ok + width: 40 + !text: tr("Ok") + + SmallButton + id: cancel + width: 45 + !text: tr("Cancel") + diff --git a/modules/client_options/styles/interface/interface.otui b/modules/client_options/styles/interface/interface.otui index bddc74b729..58529dc3bc 100644 --- a/modules/client_options/styles/interface/interface.otui +++ b/modules/client_options/styles/interface/interface.otui @@ -11,7 +11,6 @@ UIWidget id: enableHighlightMouseTarget !text: tr('Highlight mouse target') - SmallReversedQtPanel anchors.left: parent.left anchors.right: parent.right @@ -77,4 +76,59 @@ UIWidget margin-left: 10 anchors.verticalCenter: prev.verticalCenter anchors.left: prev.right - mouse-scroll: false \ No newline at end of file + mouse-scroll: false + + SmallReversedQtPanel + anchors.left: parent.left + anchors.right: parent.right + anchors.top: prev.bottom + margin-top: 7 + height: 86 + + Label + !text: 'Colourise Loot Value: ' + anchors.left: parent.left + anchors.top: parent.top + margin-left: 10 + margin-top: -25 + color: #c0c0c0ff + anchors.verticalCenter: parent.verticalCenter + + QtComboBox + id: frames + width: 120 + margin-left: 10 + anchors.verticalCenter: prev.verticalCenter + anchors.left: prev.right + mouse-scroll: false + + + UIWidget + id: toolTipWidget + image-source: /images/icons/show_gui_help_grey + size: 12 12 + anchors.right: parent.right + margin-right: 3 + !tooltip: tr('If you select Frames or Corners, your loot will be marked with \ndifferent colours in loot messages, containers and the Bestiary.\n\nThe colour depends on the loot value, which can be determined in\n the Items Cyclopedia, either using the NPC buy value, the average\n Market price or your own preferred value.') + + OptionCheckBoxMarked + id: showExpiryInInvetory + anchors.top: frames.bottom + margin-top: 5 + !text: tr('Show Expiry In Invetory') + !tooltip: tr('Check this box to see how much time or how many charges are left \non your equipped items') + + OptionCheckBoxMarked + id: showExpiryInContainers + anchors.top: prev.bottom + margin-top: 5 + !text: tr('Show Expiry In Containers') + !tooltip: tr('Check this box to see how mmuch time or how many charges the \nitems in your open containers have left') + + OptionCheckBoxMarked + id: showExpiryOnUnusedItems + anchors.top: prev.bottom + margin-top: 5 + !text: tr('Show Expiry On Unused Items') + !tooltip: tr('Check this box to see how much time or how many charges are left\n on items that have not been used yet') + enabled: false diff --git a/modules/client_options/styles/misc/help.otui b/modules/client_options/styles/misc/help.otui index 784cefa5b3..a23a309d08 100644 --- a/modules/client_options/styles/misc/help.otui +++ b/modules/client_options/styles/misc/help.otui @@ -30,7 +30,7 @@ UIWidget anchors.left: parent.left anchors.right: parent.right anchors.top: prev.bottom - height: 33 + height: 55 margin-top: 5 QtButton @@ -40,5 +40,20 @@ UIWidget margin-right: 10 anchors.left: parent.left anchors.top: parent.top - @onClick: g_platform.openUrl("https://github.com/mehah/otclient/wiki") - + @onClick: | + g_settings.clear() + controller:scheduleEvent(function() + g_app.restart() + end, 1000) + QtButton + !text: tr('Change language') + size: 130 20 + margin-top: 5 + anchors.top: prev.bottom + anchors.left: parent.left + @onClick: | + if g_game.isOnline() then + g_logger.warning("To prevent errors, change the language while offline." ) + else + modules.client_locales.createWindow() + end diff --git a/modules/client_terminal/terminal.lua b/modules/client_terminal/terminal.lua index 97cb13ecc4..2bc613e1ff 100644 --- a/modules/client_terminal/terminal.lua +++ b/modules/client_terminal/terminal.lua @@ -150,7 +150,12 @@ function init() terminalButton = modules.client_topmenu.addTopRightToggleButton('terminalButton', tr('Terminal') .. ' (Ctrl + T)', '/images/topbuttons/terminal', toggle) - g_keyboard.bindKeyDown('Ctrl+T', toggle) + Keybind.new("Misc.", "Toggle Terminal", "Ctrl+T", "") + Keybind.bind("Misc.", "Toggle Terminal", {{ + type = KEY_DOWN, + callback = toggle + }}) + commandHistory = g_settings.getList('terminal-history') @@ -214,7 +219,7 @@ function terminate() } g_settings.setNode('terminal-window', settings) - g_keyboard.unbindKeyDown('Ctrl+T') + Keybind.delete("Misc.", "Toggle Terminal") g_logger.setOnLog(nil) terminalWindow:destroy() terminalButton:destroy() diff --git a/modules/client_topmenu/topmenu.lua b/modules/client_topmenu/topmenu.lua index f21fb6a6fe..40dab3f738 100644 --- a/modules/client_topmenu/topmenu.lua +++ b/modules/client_topmenu/topmenu.lua @@ -92,7 +92,13 @@ function init() topLeftYoutubeLink = topMenu:recursiveGetChildById('youtubeIcon') topLeftDiscordLink = topMenu:recursiveGetChildById('discordIcon') - g_keyboard.bindKeyDown('Ctrl+Shift+T', toggle) + Keybind.new("UI", "Toggle Top Menu", "Ctrl+Shift+T", "") + Keybind.bind("UI", "Toggle Top Menu", { + { + type = KEY_DOWN, + callback = toggle, + } + }) if Services.websites then managerAccountsButton = modules.client_topmenu.addTopRightRegularButton('hotkeysButton', tr('Manage Account'), nil, openManagerAccounts) @@ -113,7 +119,7 @@ function terminate() }) topMenu:destroy() - if PingWidget then + if PingWidget and not PingWidget:isDestroyed() then PingWidget:destroy() PingWidget = nil end @@ -121,7 +127,7 @@ function terminate() managerAccountsButton:destroy() managerAccountsButton = nil end - + Keybind.delete("UI", "Toggle Top Menu") end function hide() @@ -138,8 +144,23 @@ function online() showGameButtons() addEvent(function() - if modules.client_options.getOption('showPing') and - (g_game.getFeature(GameClientPing) or g_game.getFeature(GameExtendedClientPing)) then + local showPing = modules.client_options.getOption('showPing') + local pingFeatureAvailable = g_game.getFeature(GameClientPing) or g_game.getFeature(GameExtendedClientPing) + + if not PingWidget then + PingWidget = g_ui.loadUI("pingFps", modules.game_interface.getMapPanel()) + MainPingPanel = g_ui.createWidget("testPingPanel", PingWidget:getChildByIndex(1)) + MainPingPanel:setId("ping") + + pingImg = MainPingPanel:getChildByIndex(1) + pingPanel = MainPingPanel:getChildByIndex(2) + + mainFpsPanel = g_ui.createWidget("testPingPanel", PingWidget:getChildByIndex(2)) + mainFpsPanel:setId("fps") + fpsPanel2 = mainFpsPanel:getChildByIndex(2) + end + + if showPing and pingFeatureAvailable then pingLabel:show() if pingPanel then pingPanel:show() @@ -152,32 +173,13 @@ function online() pingImg:hide() end end - end) - if PingWidget then - return - end - PingWidget = g_ui.loadUI("pingFps", modules.game_interface.getMapPanel()) - - MainPingPanel = g_ui.createWidget("testPingPanel", PingWidget:getChildByIndex(1)) - MainPingPanel.setId(MainPingPanel, "ping") - pingImg = MainPingPanel.getChildByIndex(MainPingPanel, 1) - pingPanel = MainPingPanel.getChildByIndex(MainPingPanel, 2) - if modules.client_options.getOption('showPing') then - pingImg:setVisible(true) - pingPanel:setVisible(true) - else - pingImg:setVisible(false) - pingPanel:setVisible(true) - end - mainFpsPanel = g_ui.createWidget("testPingPanel", PingWidget:getChildByIndex(2)) - mainFpsPanel.setId(mainFpsPanel, "fps") - fpsPanel2 = mainFpsPanel.getChildByIndex(mainFpsPanel, 2) - if modules.client_options.getOption('showFps') then - fpsPanel2:setVisible(true) - else - fpsPanel2:setVisible(false) - end + pingImg:setVisible(showPing) + pingPanel:setVisible(showPing) + + local showFps = modules.client_options.getOption('showFps') + fpsPanel2:setVisible(showFps) + end) end function offline() diff --git a/modules/corelib/bitwise.lua b/modules/corelib/bitwise.lua index c9901c4e69..09d1471190 100644 --- a/modules/corelib/bitwise.lua +++ b/modules/corelib/bitwise.lua @@ -14,4 +14,4 @@ end function Bit.clearbit(x, p) return Bit.hasBit(x, p) and x - p or x -end +end \ No newline at end of file diff --git a/modules/corelib/corelib.otmod b/modules/corelib/corelib.otmod index 80c3359b77..7c665fb4f5 100644 --- a/modules/corelib/corelib.otmod +++ b/modules/corelib/corelib.otmod @@ -17,6 +17,7 @@ Module dofile 'globals' dofile 'config' dofile 'settings' + dofile 'keybind' dofile 'keyboard' dofile 'mouse' dofile 'net' @@ -28,4 +29,7 @@ Module dofile 'outputmessage' dofile 'json' - dofile 'http' \ No newline at end of file + dofile 'http' + Keybind.init() + + @onUnload: Keybind.terminate() diff --git a/modules/corelib/keybind.lua b/modules/corelib/keybind.lua new file mode 100644 index 0000000000..a61cfdf553 --- /dev/null +++ b/modules/corelib/keybind.lua @@ -0,0 +1,1036 @@ + +CHAT_MODE = { + ON = 1, + OFF = 2 +} + +Keybind = { + presets = {}, + presetToIndex = {}, + currentPreset = nil, + configs = { + keybinds = {}, + hotkeys = {} + }, + defaultKeys = { + [CHAT_MODE.ON] = {}, + [CHAT_MODE.OFF] = {} + }, + defaultKeybinds = {}, + hotkeys = { + [CHAT_MODE.ON] = {}, + [CHAT_MODE.OFF] = {} + }, + chatMode = CHAT_MODE.ON, + + reservedKeys = { + ["Up"] = true, + ["Down"] = true, + ["Left"] = true, + ["Right"] = true + } +} + +KEY_UP = 1 +KEY_DOWN = 2 +KEY_PRESS = 3 + +HOTKEY_ACTION = { + USE_YOURSELF = 1, + USE_CROSSHAIR = 2, + USE_TARGET = 3, + EQUIP = 4, + USE = 5, + TEXT = 6, + TEXT_AUTO = 7, + SPELL = 8 +} + +function Keybind.init() + connect(g_game, { onGameStart = Keybind.online, onGameEnd = Keybind.offline }) + + Keybind.presets = g_settings.getList("controls-presets") + + if #Keybind.presets == 0 then + Keybind.presets = { "Druid", "Knight", "Paladin", "Sorcerer" } + Keybind.currentPreset = "Druid" + else + Keybind.currentPreset = g_settings.getValue("controls-preset-current") + end + + for index, preset in ipairs(Keybind.presets) do + Keybind.presetToIndex[preset] = index + end + + if not g_resources.directoryExists("/controls") then + g_resources.makeDir("/controls") + end + + if not g_resources.directoryExists("/controls/keybinds") then + g_resources.makeDir("/controls/keybinds") + end + + if not g_resources.directoryExists("/controls/hotkeys") then + g_resources.makeDir("/controls/hotkeys") + end + + for _, preset in ipairs(Keybind.presets) do + Keybind.configs.keybinds[preset] = g_configs.create("/controls/keybinds/" .. preset .. ".otml") + Keybind.configs.hotkeys[preset] = g_configs.create("/controls/hotkeys/" .. preset .. ".otml") + end + + for preset, config in pairs(Keybind.configs.hotkeys) do + for chatMode = CHAT_MODE.ON, CHAT_MODE.OFF do + Keybind.hotkeys[chatMode][preset] = {} + local hotkeyId = 1 + local hotkeys = config:getNode(chatMode) + + if hotkeys then + local hotkey = hotkeys[tostring(hotkeyId)] + while hotkey do + if hotkey.data.parameter then + hotkey.data.parameter = "\"" .. hotkey.data.parameter .. "\"" -- forcing quotes cause OTML is not saving them, just wow + end + + table.insert(Keybind.hotkeys[chatMode][preset], hotkey) + hotkeyId = hotkeyId + 1 + + hotkey = hotkeys[tostring(hotkeyId)] + end + end + end + end +end + +function Keybind.terminate() + disconnect(g_game, { onGameStart = Keybind.online, onGameEnd = Keybind.offline }) + + for _, preset in ipairs(Keybind.presets) do + Keybind.configs.keybinds[preset]:save() + Keybind.configs.hotkeys[preset]:save() + end + + g_settings.setList("controls-presets", Keybind.presets) + g_settings.setValue("controls-preset-current", Keybind.currentPreset) + g_settings.save() +end + +function Keybind.online() + for _, hotkey in ipairs(Keybind.hotkeys[Keybind.chatMode][Keybind.currentPreset]) do + Keybind.bindHotkey(hotkey.hotkeyId, Keybind.chatMode) + end +end + +function Keybind.offline() + for _, hotkey in ipairs(Keybind.hotkeys[Keybind.chatMode][Keybind.currentPreset]) do + Keybind.unbindHotkey(hotkey.hotkeyId, Keybind.chatMode) + end +end + +function Keybind.new(category, action, primary, secondary, alone) + local index = category .. '_' .. action + if Keybind.defaultKeybinds[index] then + pwarning(string.format("Keybind for [%s: %s] is already in use", category, action)) + return + end + + local keys = {} + if type(primary) == "string" then + keys[CHAT_MODE.ON] = { primary = primary } + keys[CHAT_MODE.OFF] = { primary = primary } + else + keys[CHAT_MODE.ON] = { primary = primary[CHAT_MODE.ON] } + keys[CHAT_MODE.OFF] = { primary = primary[CHAT_MODE.OFF] } + end + + if type(secondary) == "string" then + keys[CHAT_MODE.ON].secondary = secondary + keys[CHAT_MODE.OFF].secondary = secondary + else + keys[CHAT_MODE.ON].secondary = secondary[CHAT_MODE.ON] + keys[CHAT_MODE.OFF].secondary = secondary[CHAT_MODE.OFF] + end + + keys[CHAT_MODE.ON].primary = retranslateKeyComboDesc(keys[CHAT_MODE.ON].primary) + + if keys[CHAT_MODE.ON].secondary then + keys[CHAT_MODE.ON].secondary = retranslateKeyComboDesc(keys[CHAT_MODE.ON].secondary) + end + + keys[CHAT_MODE.OFF].primary = retranslateKeyComboDesc(keys[CHAT_MODE.OFF].primary) + + if keys[CHAT_MODE.OFF].secondary then + keys[CHAT_MODE.OFF].secondary = retranslateKeyComboDesc(keys[CHAT_MODE.OFF].secondary) + end + + if Keybind.defaultKeys[CHAT_MODE.ON][keys[CHAT_MODE.ON].primary] then + local primaryIndex = Keybind.defaultKeys[CHAT_MODE.ON][keys[CHAT_MODE.ON].primary] + local primaryKeybind = Keybind.defaultKeybinds[primaryIndex] + perror(string.format("Default primary key (Chat Mode On) assigned to [%s: %s] is already in use by [%s: %s]", + category, action, primaryKeybind.category, primaryKeybind.action)) + return + end + + if Keybind.defaultKeys[CHAT_MODE.OFF][keys[CHAT_MODE.OFF].primary] then + local primaryIndex = Keybind.defaultKeys[CHAT_MODE.OFF][keys[CHAT_MODE.OFF].primary] + local primaryKeybind = Keybind.defaultKeybinds[primaryIndex] + perror(string.format("Default primary key (Chat Mode Off) assigned to [%s: %s] is already in use by [%s: %s]", + category, action, primaryKeybind.category, primaryKeybind.action)) + return + end + + if keys[CHAT_MODE.ON].secondary and Keybind.defaultKeys[CHAT_MODE.ON][keys[CHAT_MODE.ON].secondary] then + local secondaryIndex = Keybind.defaultKeys[CHAT_MODE.ON][keys[CHAT_MODE.ON].secondary] + local secondaryKeybind = Keybind.defaultKeybinds[secondaryIndex] + perror(string.format("Default secondary key (Chat Mode On) assigned to [%s: %s] is already in use by [%s: %s]", + category, action, secondaryKeybind.category, secondaryKeybind.action)) + return + end + + if keys[CHAT_MODE.OFF].secondary and Keybind.defaultKeys[CHAT_MODE.OFF][keys[CHAT_MODE.OFF].secondary] then + local secondaryIndex = Keybind.defaultKeys[CHAT_MODE.OFF][keys[CHAT_MODE.OFF].secondary] + local secondaryKeybind = Keybind.defaultKeybinds[secondaryIndex] + perror(string.format("Default secondary key (Chat Mode Off) assigned to [%s: %s] is already in use by [%s: %s]", + category, action, secondaryKeybind.category, secondaryKeybind.action)) + return + end + + if keys[CHAT_MODE.ON].primary then + Keybind.defaultKeys[CHAT_MODE.ON][keys[CHAT_MODE.ON].primary] = index + end + + if keys[CHAT_MODE.OFF].primary then + Keybind.defaultKeys[CHAT_MODE.OFF][keys[CHAT_MODE.OFF].primary] = index + end + + Keybind.defaultKeybinds[index] = { + category = category, + action = action, + keys = keys, + alone = alone + } + + if keys[CHAT_MODE.ON].secondary then + Keybind.defaultKeys[CHAT_MODE.ON][keys[CHAT_MODE.ON].secondary] = index + end + if keys[CHAT_MODE.OFF].secondary then + Keybind.defaultKeys[CHAT_MODE.OFF][keys[CHAT_MODE.OFF].secondary] = index + end +end + +function Keybind.delete(category, action) + local index = category .. '_' .. action + local keybind = Keybind.defaultKeybinds[index] + + if not keybind then + return + end + + Keybind.unbind(category, action) + + local keysOn = keybind.keys[CHAT_MODE.ON] + local keysOff = keybind.keys[CHAT_MODE.OFF] + + local primaryOn = keysOn.primary and tostring(keysOn.primary) or nil + local primaryOff = keysOff.primary and tostring(keysOff.primary) or nil + local secondaryOn = keysOn.secondary and tostring(keysOn.secondary) or nil + local secondaryOff = keysOff.secondary and tostring(keysOff.secondary) or nil + + if primaryOn and primaryOn:len() > 0 then + Keybind.defaultKeys[CHAT_MODE.ON][primaryOn] = nil + end + if secondaryOn and secondaryOn:len() > 0 then + Keybind.defaultKeys[CHAT_MODE.ON][secondaryOn] = nil + end + + if primaryOff and primaryOff:len() > 0 then + Keybind.defaultKeys[CHAT_MODE.OFF][primaryOff] = nil + end + if secondaryOff and secondaryOff:len() > 0 then + Keybind.defaultKeys[CHAT_MODE.OFF][secondaryOff] = nil + end + + Keybind.defaultKeybinds[index] = nil +end + +function Keybind.bind(category, action, callbacks, widget) + local index = category .. '_' .. action + local keybind = Keybind.defaultKeybinds[index] + + if not keybind then + return + end + + keybind.callbacks = callbacks + keybind.widget = widget + + local keys = Keybind.getKeybindKeys(category, action) + + for _, callback in ipairs(keybind.callbacks) do + if callback.type == KEY_UP then + if keys.primary then + keys.primary = tostring(keys.primary) + if keys.primary:len() > 0 then + g_keyboard.bindKeyUp(keys.primary, callback.callback, keybind.widget, callback.alone) + end + end + if keys.secondary then + keys.secondary = tostring(keys.secondary) + if keys.secondary:len() > 0 then + g_keyboard.bindKeyUp(keys.secondary, callback.callback, keybind.widget, callback.alone) + end + end + elseif callback.type == KEY_DOWN then + if keys.primary then + keys.primary = tostring(keys.primary) + if keys.primary:len() > 0 then + g_keyboard.bindKeyDown(keys.primary, callback.callback, keybind.widget, callback.alone) + end + end + if keys.secondary then + keys.secondary = tostring(keys.secondary) + if keys.secondary:len() > 0 then + g_keyboard.bindKeyDown(keys.secondary, callback.callback, keybind.widget, callback.alone) + end + end + elseif callback.type == KEY_PRESS then + if keys.primary then + keys.primary = tostring(keys.primary) + if keys.primary:len() > 0 then + g_keyboard.bindKeyPress(keys.primary, callback.callback, keybind.widget) + end + end + if keys.secondary then + keys.secondary = tostring(keys.secondary) + if keys.secondary:len() > 0 then + g_keyboard.bindKeyPress(keys.secondary, callback.callback, keybind.widget) + end + end + end + end +end + +function Keybind.unbind(category, action) + local index = category .. '_' .. action + local keybind = Keybind.defaultKeybinds[index] + + if not keybind or not keybind.callbacks then + return + end + + local keys = Keybind.getKeybindKeys(category, action) + + for _, callback in ipairs(keybind.callbacks) do + if callback.type == KEY_UP then + if keys.primary then + keys.primary = tostring(keys.primary) + if keys.primary:len() > 0 then + g_keyboard.unbindKeyUp(keys.primary, callback.callback, keybind.widget) + end + end + if keys.secondary then + keys.secondary = tostring(keys.secondary) + if keys.secondary:len() > 0 then + g_keyboard.unbindKeyUp(keys.secondary, callback.callback, keybind.widget) + end + end + elseif callback.type == KEY_DOWN then + if keys.primary then + keys.primary = tostring(keys.primary) + if keys.primary:len() > 0 then + g_keyboard.unbindKeyDown(keys.primary, callback.callback, keybind.widget) + end + end + if keys.secondary then + keys.secondary = tostring(keys.secondary) + if keys.secondary:len() > 0 then + g_keyboard.unbindKeyDown(keys.secondary, callback.callback, keybind.widget) + end + end + elseif callback.type == KEY_PRESS then + if keys.primary then + keys.primary = tostring(keys.primary) + if keys.primary:len() > 0 then + g_keyboard.unbindKeyPress(keys.primary, callback.callback, keybind.widget) + end + end + if keys.secondary then + keys.secondary = tostring(keys.secondary) + if keys.secondary:len() > 0 then + g_keyboard.unbindKeyPress(keys.secondary, callback.callback, keybind.widget) + end + end + end + end +end + +function Keybind.newPreset(presetName) + if Keybind.presetToIndex[presetName] then + return + end + + table.insert(Keybind.presets, presetName) + Keybind.presetToIndex[presetName] = #Keybind.presets + + Keybind.configs.keybinds[presetName] = g_configs.create("/controls/keybinds/" .. presetName .. ".otml") + Keybind.configs.hotkeys[presetName] = g_configs.create("/controls/hotkeys/" .. presetName .. ".otml") + + Keybind.hotkeys[CHAT_MODE.ON][presetName] = {} + Keybind.hotkeys[CHAT_MODE.OFF][presetName] = {} + + g_settings.setList("controls-presets", Keybind.presets) + g_settings.save() +end + +function Keybind.copyPreset(fromPreset, toPreset) + if Keybind.presetToIndex[toPreset] then + return false + end + + table.insert(Keybind.presets, toPreset) + Keybind.presetToIndex[toPreset] = #Keybind.presets + + Keybind.configs.keybinds[fromPreset]:save() + Keybind.configs.hotkeys[fromPreset]:save() + + local keybindsConfigPath = Keybind.configs.keybinds[fromPreset]:getFileName() + local keybindsConfigContent = g_resources.readFileContents(keybindsConfigPath) + g_resources.writeFileContents("/controls/keybinds/" .. toPreset .. ".otml", keybindsConfigContent) + Keybind.configs.keybinds[toPreset] = g_configs.create("/controls/keybinds/" .. toPreset .. ".otml") + + local hotkeysConfigPath = Keybind.configs.hotkeys[fromPreset]:getFileName() + local hotkeysConfigContent = g_resources.readFileContents(hotkeysConfigPath) + g_resources.writeFileContents("/controls/hotkeys/" .. toPreset .. ".otml", hotkeysConfigContent) + Keybind.configs.hotkeys[toPreset] = g_configs.create("/controls/hotkeys/" .. toPreset .. ".otml") + + for chatMode = CHAT_MODE.ON, CHAT_MODE.OFF do + Keybind.hotkeys[chatMode][toPreset] = {} + + local hotkeyId = 1 + local hotkeys = Keybind.configs.hotkeys[toPreset]:getNode(chatMode) + + if hotkeys then + local hotkey = hotkeys[tostring(hotkeyId)] + while hotkey do + if hotkey.data.parameter then + hotkey.data.parameter = "\"" .. hotkey.data.parameter .. "\"" -- forcing quotes cause OTML is not saving them, just wow + end + + table.insert(Keybind.hotkeys[chatMode][toPreset], hotkey) + hotkeyId = hotkeyId + 1 + + hotkey = hotkeys[tostring(hotkeyId)] + end + end + end + + g_settings.setList("controls-presets", Keybind.presets) + g_settings.save() + + return true +end + +function Keybind.renamePreset(oldPresetName, newPresetName) + if Keybind.currentPreset == oldPresetName then + Keybind.currentPreset = newPresetName + end + + local index = Keybind.presetToIndex[oldPresetName] + Keybind.presetToIndex[oldPresetName] = nil + Keybind.presetToIndex[newPresetName] = index + Keybind.presets[index] = newPresetName + + local keybindsConfigPath = Keybind.configs.keybinds[oldPresetName]:getFileName() + Keybind.configs.keybinds[oldPresetName]:save() + Keybind.configs.keybinds[oldPresetName] = nil + + local keybindsConfigContent = g_resources.readFileContents(keybindsConfigPath) + g_resources.deleteFile(keybindsConfigPath) + g_resources.writeFileContents("/controls/keybinds/" .. newPresetName .. ".otml", keybindsConfigContent) + Keybind.configs.keybinds[newPresetName] = g_configs.create("/controls/keybinds/" .. newPresetName .. ".otml") + + local hotkeysConfigPath = Keybind.configs.hotkeys[oldPresetName]:getFileName() + Keybind.configs.hotkeys[oldPresetName]:save() + Keybind.configs.hotkeys[oldPresetName] = nil + + local hotkeysConfigContent = g_resources.readFileContents(hotkeysConfigPath) + g_resources.deleteFile(hotkeysConfigPath) + g_resources.writeFileContents("/controls/hotkeys/" .. newPresetName .. ".otml", hotkeysConfigContent) + Keybind.configs.hotkeys[newPresetName] = g_configs.create("/controls/hotkeys/" .. newPresetName .. ".otml") + + Keybind.hotkeys[CHAT_MODE.ON][newPresetName] = Keybind.hotkeys[CHAT_MODE.ON][oldPresetName] + Keybind.hotkeys[CHAT_MODE.OFF][newPresetName] = Keybind.hotkeys[CHAT_MODE.OFF][oldPresetName] + + g_settings.setList("controls-presets", Keybind.presets) + g_settings.save() +end + +function Keybind.removePreset(presetName) + if #Keybind.presets == 1 then + return false + end + + table.remove(Keybind.presets, Keybind.presetToIndex[presetName]) + Keybind.presetToIndex[presetName] = nil + + Keybind.configs.keybinds[presetName] = nil + g_configs.unload("/controls/keybinds/" .. presetName .. ".otml") + g_resources.deleteFile("/controls/keybinds/" .. presetName .. ".otml") + + Keybind.configs.hotkeys[presetName] = nil + g_configs.unload("/controls/hotkeys/" .. presetName .. ".otml") + g_resources.deleteFile("/controls/hotkeys/" .. presetName .. ".otml") + + if Keybind.currentPreset == presetName then + Keybind.currentPreset = Keybind.presets[1] + end + + g_settings.setList("controls-presets", Keybind.presets) + g_settings.save() + + return true +end + +function Keybind.selectPreset(presetName) + if Keybind.currentPreset == presetName then + return false + end + + if not Keybind.presetToIndex[presetName] then + return false + end + + for _, keybind in pairs(Keybind.defaultKeybinds) do + if keybind.callbacks then + Keybind.unbind(keybind.category, keybind.action) + end + end + + for _, hotkey in ipairs(Keybind.hotkeys[Keybind.chatMode][Keybind.currentPreset]) do + Keybind.unbindHotkey(hotkey.hotkeyId, Keybind.chatMode) + end + + Keybind.currentPreset = presetName + + for _, keybind in pairs(Keybind.defaultKeybinds) do + if keybind.callbacks then + Keybind.bind(keybind.category, keybind.action, keybind.callbacks, keybind.widget) + end + end + + for _, hotkey in ipairs(Keybind.hotkeys[Keybind.chatMode][Keybind.currentPreset]) do + Keybind.bindHotkey(hotkey.hotkeyId, Keybind.chatMode) + end + + return true +end + +function Keybind.getAction(category, action) + local index = category .. '_' .. action + return Keybind.defaultKeybinds[index] +end + +function Keybind.setPrimaryActionKey(category, action, preset, keyCombo, chatMode) + local index = category .. '_' .. action + local keybind = Keybind.defaultKeybinds[index] + + local keys = Keybind.configs.keybinds[preset]:getNode(index) + if not keys then + keys = table.recursivecopy(keybind.keys) + else + chatMode = tostring(chatMode) + end + + if keybind.callbacks then + Keybind.unbind(category, action) + end + + if not keys[chatMode] then + keys[chatMode] = { primary = keyCombo, secondary = keybind.keys[tonumber(chatMode)].secondary } + end + + keys[chatMode].primary = keyCombo + + local ret = false + if keys[chatMode].secondary == keyCombo then + keys[chatMode].secondary = nil + ret = true + end + + Keybind.configs.keybinds[preset]:setNode(index, keys) + + if keybind.callbacks then + Keybind.bind(category, action, keybind.callbacks, keybind.widget) + end + + return ret +end + +function Keybind.setSecondaryActionKey(category, action, preset, keyCombo, chatMode) + local index = category .. '_' .. action + local keybind = Keybind.defaultKeybinds[index] + + local keys = Keybind.configs.keybinds[preset]:getNode(index) + if not keys then + keys = table.recursivecopy(keybind.keys) + else + chatMode = tostring(chatMode) + end + + if keybind.callbacks then + Keybind.unbind(category, action) + end + + if not keys[chatMode] then + keys[chatMode] = { primary = keybind.keys[tonumber(chatMode)].primary, secondary = keyCombo } + end + + keys[chatMode].secondary = keyCombo + + local ret = false + if keys[chatMode].primary == keyCombo then + keys[chatMode].primary = nil + ret = true + end + + Keybind.configs.keybinds[preset]:setNode(index, keys) + + if keybind.callbacks then + Keybind.bind(category, action, keybind.callbacks, keybind.widget) + end + + return ret +end + +function Keybind.resetKeybindsToDefault(presetName, chatMode) + if not chatMode then + chatMode = Keybind.chatMode + end + + for _, keybind in pairs(Keybind.defaultKeybinds) do + if keybind.callbacks then + Keybind.unbind(keybind.category, keybind.action) + end + end + + for _, keybind in pairs(Keybind.defaultKeybinds) do + local index = keybind.category .. '_' .. keybind.action + Keybind.configs.keybinds[presetName]:setNode(index, keybind.keys) + end + + for _, keybind in pairs(Keybind.defaultKeybinds) do + if keybind.callbacks then + Keybind.bind(keybind.category, keybind.action, keybind.callbacks, keybind.widget) + end + end +end + +function Keybind.getKeybindKeys(category, action, chatMode, preset, forceDefault) + if not chatMode then + chatMode = Keybind.chatMode + end + + local index = category .. '_' .. action + local keybind = Keybind.defaultKeybinds[index] + local keys = Keybind.configs.keybinds[preset or Keybind.currentPreset]:getNode(index) + + if not keys or forceDefault then + keys = { + primary = keybind.keys[chatMode].primary, + secondary = keybind.keys[chatMode].secondary + } + else + keys = keys[chatMode] or keys[tostring(chatMode)] + end + + if not keys then + keys = { + primary = "", + secondary = "" + } + end + + return keys +end + +function Keybind.isKeyComboUsed(keyCombo, category, action, chatMode) + if not chatMode then + chatMode = Keybind.chatMode + end + + if Keybind.reservedKeys[keyCombo] then + return true + end + + if category and action then + local targetKeys = Keybind.getKeybindKeys(category, action, chatMode, Keybind.currentPreset) + + for _, keybind in pairs(Keybind.defaultKeybinds) do + local keys = Keybind.getKeybindKeys(keybind.category, keybind.action, chatMode, Keybind.currentPreset) + if (keys.primary == keyCombo and targetKeys.primary ~= keyCombo) or (keys.secondary == keyCombo and targetKeys.secondary ~= keyCombo) then + return true + end + end + else + for _, keybind in pairs(Keybind.defaultKeybinds) do + local keys = Keybind.getKeybindKeys(keybind.category, keybind.action, chatMode, Keybind.currentPreset) + if keys.primary == keyCombo or keys.secondary == keyCombo then + return true + end + end + + if Keybind.hotkeys[chatMode][Keybind.currentPreset] then + for _, hotkey in ipairs(Keybind.hotkeys[chatMode][Keybind.currentPreset]) do + if hotkey.primary == keyCombo or hotkey.secondary == keyCombo then + return true + end + end + end + end + + return false +end + +function Keybind.newHotkey(action, data, primary, secondary, chatMode) + if not chatMode then + chatMode = Keybind.chatMode + end + + local hotkey = { + action = action, + data = data, + primary = primary or "", + secondary = secondary or "" + } + + if not Keybind.hotkeys[chatMode][Keybind.currentPreset] then + Keybind.hotkeys[chatMode][Keybind.currentPreset] = {} + end + + table.insert(Keybind.hotkeys[chatMode][Keybind.currentPreset], hotkey) + + local hotkeyId = #Keybind.hotkeys[chatMode][Keybind.currentPreset] + hotkey.hotkeyId = hotkeyId + Keybind.configs.hotkeys[Keybind.currentPreset]:setNode(chatMode, Keybind.hotkeys[chatMode][Keybind.currentPreset]) + Keybind.configs.hotkeys[Keybind.currentPreset]:save() + + Keybind.bindHotkey(hotkeyId, chatMode) +end + +function Keybind.removeHotkey(hotkeyId, chatMode) + if not chatMode then + chatMode = Keybind.chatMode + end + + if not Keybind.hotkeys[chatMode][Keybind.currentPreset] then + return + end + + Keybind.unbindHotkey(hotkeyId, chatMode) + + table.remove(Keybind.hotkeys[chatMode][Keybind.currentPreset], hotkeyId) + + Keybind.configs.hotkeys[Keybind.currentPreset]:clear() + + for id, hotkey in ipairs(Keybind.hotkeys[chatMode][Keybind.currentPreset]) do + hotkey.hotkeyId = id + Keybind.configs.hotkeys[Keybind.currentPreset]:setNode(id, hotkey) + end + + Keybind.configs.hotkeys[Keybind.currentPreset]:save() +end + +function Keybind.editHotkey(hotkeyId, action, data, chatMode) + if not chatMode then + chatMode = Keybind.chatMode + end + + Keybind.unbindHotkey(hotkeyId, chatMode) + + local hotkey = Keybind.hotkeys[chatMode][Keybind.currentPreset][hotkeyId] + hotkey.action = action + hotkey.data = data + Keybind.configs.hotkeys[Keybind.currentPreset]:setNode(chatMode, Keybind.hotkeys[chatMode][Keybind.currentPreset]) + Keybind.configs.hotkeys[Keybind.currentPreset]:save() + + Keybind.bindHotkey(hotkeyId, chatMode) +end + +function Keybind.editHotkeyKeys(hotkeyId, primary, secondary, chatMode) + if not chatMode then + chatMode = Keybind.chatMode + end + + Keybind.unbindHotkey(hotkeyId, chatMode) + + local hotkey = Keybind.hotkeys[chatMode][Keybind.currentPreset][hotkeyId] + hotkey.primary = primary or "" + hotkey.secondary = secondary or "" + Keybind.configs.hotkeys[Keybind.currentPreset]:setNode(chatMode, Keybind.hotkeys[chatMode][Keybind.currentPreset]) + Keybind.configs.hotkeys[Keybind.currentPreset]:save() + + Keybind.bindHotkey(hotkeyId, chatMode) +end + +function Keybind.removeAllHotkeys(chatMode) + if not chatMode then + chatMode = Keybind.chatMode + end + + for _, hotkey in ipairs(Keybind.hotkeys[chatMode][Keybind.currentPreset]) do + Keybind.unbindHotkey(hotkey.hotkeyId) + end + + Keybind.hotkeys[chatMode][Keybind.currentPreset] = {} + + Keybind.configs.hotkeys[Keybind.currentPreset]:remove(chatMode) + Keybind.configs.hotkeys[Keybind.currentPreset]:save() +end + +function Keybind.getHotkeyKeys(hotkeyId, preset, chatMode) + if not chatMode then + chatMode = Keybind.chatMode + end + if not preset then + preset = Keybind.currentPreset + end + + local keys = { primary = "", secondary = "" } + if not Keybind.hotkeys[chatMode][preset] then + return keys + end + + local hotkey = Keybind.hotkeys[chatMode][preset][hotkeyId] + if not hotkey then + return keys + end + + local config = Keybind.configs.hotkeys[preset]:getNode(chatMode) + if not config then + return keys + end + + return config[tostring(hotkeyId)] or keys +end + +function Keybind.hotkeyCallback(hotkeyId, chatMode) + if not chatMode then + chatMode = Keybind.chatMode + end + + local hotkey = Keybind.hotkeys[chatMode][Keybind.currentPreset][hotkeyId] + + if not hotkey then + return + end + + local action = hotkey.action + local data = hotkey.data + + if action == HOTKEY_ACTION.USE_YOURSELF then + if g_game.getClientVersion() < 780 then + local item = g_game.findPlayerItem(data.itemId, data.subType or -1) + + if item then + g_game.useWith(item, g_game.getLocalPlayer()) + end + else + g_game.useInventoryItemWith(data.itemId, g_game.getLocalPlayer(), data.subType or -1) + end + elseif action == HOTKEY_ACTION.USE_CROSSHAIR then + local item = Item.create(data.itemId) + + if g_game.getClientVersion() < 780 then + item = g_game.findPlayerItem(data.itemId, data.subType or -1) + end + + if item then + modules.game_interface.startUseWith(item, data.subType or -1) + end + elseif action == HOTKEY_ACTION.USE_TARGET then + local attackingCreature = g_game.getAttackingCreature() + if not attackingCreature then + local item = Item.create(data.itemId) + + if g_game.getClientVersion() < 780 then + item = g_game.findPlayerItem(data.itemId, data.subType or -1) + end + + if item then + modules.game_interface.startUseWith(item, data.subType or -1) + end + + return + end + + if attackingCreature:getTile() then + if g_game.getClientVersion() < 780 then + local item = g_game.findPlayerItem(data.itemId, data.subType or -1) + if item then + g_game.useWith(item, attackingCreature, data.subType or -1) + end + else + g_game.useInventoryItemWith(data.itemId, attackingCreature, data.subType or -1) + end + end + elseif action == HOTKEY_ACTION.EQUIP then + if g_game.getClientVersion() >= 910 then + local item = Item.create(data.itemId) + + g_game.equipItem(item) + end + elseif action == HOTKEY_ACTION.USE then + if g_game.getClientVersion() < 780 then + local item = g_game.findPlayerItem(data.itemId, data.subType or -1) + + if item then + g_game.use(item) + end + else + g_game.useInventoryItem(data.itemId) + end + elseif action == HOTKEY_ACTION.TEXT then + if modules.game_interface.isChatVisible() then + modules.game_console.setTextEditText(hotkey.data.text) + end + elseif action == HOTKEY_ACTION.TEXT_AUTO then + if modules.game_interface.isChatVisible() then + modules.game_console.sendMessage(hotkey.data.text) + else + g_game.talk(hotkey.data.text) + end + elseif action == HOTKEY_ACTION.SPELL then + local text = data.words + if data.parameter then + text = text .. " " .. data.parameter + end + + if modules.game_interface.isChatVisible() then + modules.game_console.sendMessage(text) + else + g_game.talk(text) + end + end +end + +function Keybind.bindHotkey(hotkeyId, chatMode) + if not chatMode or chatMode ~= Keybind.chatMode then + return + end + + if not modules.game_interface then + return + end + + local hotkey = Keybind.hotkeys[chatMode][Keybind.currentPreset][hotkeyId] + + if not hotkey then + return + end + + local keys = Keybind.getHotkeyKeys(hotkeyId, Keybind.currentPreset, chatMode) + local gameRootPanel = modules.game_interface.getRootPanel() + local action = hotkey.action + + hotkey.callback = function() Keybind.hotkeyCallback(hotkeyId, chatMode) end + + if keys.primary then + keys.primary = tostring(keys.primary) + if keys.primary:len() > 0 then + if action == HOTKEY_ACTION.EQUIP or action == HOTKEY_ACTION.USE or action == HOTKEY_ACTION.TEXT or action == HOTKEY_ACTION.TEXT_AUTO then + g_keyboard.bindKeyDown(keys.primary, hotkey.callback, gameRootPanel) + else + g_keyboard.bindKeyPress(keys.primary, hotkey.callback, gameRootPanel) + end + end + end + + if keys.secondary then + keys.secondary = tostring(keys.secondary) + if keys.secondary:len() > 0 then + if action == HOTKEY_ACTION.EQUIP or action == HOTKEY_ACTION.USE or action == HOTKEY_ACTION.TEXT or action == HOTKEY_ACTION.TEXT_AUTO then + g_keyboard.bindKeyDown(keys.secondary, hotkey.callback, gameRootPanel) + else + g_keyboard.bindKeyPress(keys.secondary, hotkey.callback, gameRootPanel) + end + end + end +end + +function Keybind.unbindHotkey(hotkeyId, chatMode) + if not chatMode or chatMode ~= Keybind.chatMode then + return + end + + if not modules.game_interface then + return + end + + local hotkey = Keybind.hotkeys[chatMode][Keybind.currentPreset][hotkeyId] + + if not hotkey then + return + end + + local keys = Keybind.getHotkeyKeys(hotkeyId, Keybind.currentPreset, chatMode) + local gameRootPanel = modules.game_interface.getRootPanel() + local action = hotkey.action + + if keys.primary then + keys.primary = tostring(keys.primary) + if keys.primary:len() > 0 then + if action == HOTKEY_ACTION.EQUIP or action == HOTKEY_ACTION.USE or action == HOTKEY_ACTION.TEXT or action == HOTKEY_ACTION.TEXT_AUTO then + g_keyboard.unbindKeyDown(keys.primary, hotkey.callback, gameRootPanel) + else + g_keyboard.unbindKeyPress(keys.primary, hotkey.callback, gameRootPanel) + end + end + end + + if keys.secondary then + keys.secondary = tostring(keys.secondary) + if keys.secondary:len() > 0 then + if action == HOTKEY_ACTION.EQUIP or action == HOTKEY_ACTION.USE or action == HOTKEY_ACTION.TEXT or action == HOTKEY_ACTION.TEXT_AUTO then + g_keyboard.unbindKeyDown(keys.secondary, hotkey.callback, gameRootPanel) + else + g_keyboard.unbindKeyPress(keys.secondary, hotkey.callback, gameRootPanel) + end + end + end +end + +function Keybind.setChatMode(chatMode) + if Keybind.chatMode == chatMode then + return + end + + for _, keybind in pairs(Keybind.defaultKeybinds) do + if keybind.callbacks then + Keybind.unbind(keybind.category, keybind.action) + end + end + + for _, hotkey in ipairs(Keybind.hotkeys[Keybind.chatMode][Keybind.currentPreset]) do + Keybind.unbindHotkey(hotkey.hotkeyId, Keybind.chatMode) + end + + if modules.game_walking then + modules.game_walking.unbindTurnKeys() + end + + Keybind.chatMode = chatMode + + for _, keybind in pairs(Keybind.defaultKeybinds) do + if keybind.callbacks then + Keybind.bind(keybind.category, keybind.action, keybind.callbacks, keybind.widget) + end + end + + for _, hotkey in ipairs(Keybind.hotkeys[chatMode][Keybind.currentPreset]) do + Keybind.bindHotkey(hotkey.hotkeyId, chatMode) + end + + if modules.game_walking then + modules.game_walking.bindTurnKeys() + end +end diff --git a/modules/corelib/ui/uicombobox.lua b/modules/corelib/ui/uicombobox.lua index feb856727c..d41dc122c7 100644 --- a/modules/corelib/ui/uicombobox.lua +++ b/modules/corelib/ui/uicombobox.lua @@ -199,3 +199,12 @@ function UIComboBox:HTML_onReadNodes(nodes) return false end + +function UIComboBox:getCurrentIndex() + return self.currentIndex +end + +function UIComboBox:updateCurrentOption(newText) + self.options[self.currentIndex].text = newText + self:setText(newText) +end diff --git a/modules/corelib/ui/uipopupmenu.lua b/modules/corelib/ui/uipopupmenu.lua index dd6e44f896..d02ae72bea 100644 --- a/modules/corelib/ui/uipopupmenu.lua +++ b/modules/corelib/ui/uipopupmenu.lua @@ -62,11 +62,11 @@ function UIPopupMenu:onGeometryChange(newRect, oldRect) self:bindRectToParent() end -function UIPopupMenu:addOption(optionName, optionCallback, shortcut) +function UIPopupMenu:addOption(optionName, optionCallback, shortcut, disabled) local optionWidget = g_ui.createWidget(self:getStyleName() .. 'Button', self) optionWidget.onClick = function(widget) self:destroy() - optionCallback() + optionCallback(self:getPosition()) end optionWidget:setText(optionName) local width = optionWidget:getTextSize().width + optionWidget:getMarginLeft() + optionWidget:getMarginRight() + 15 @@ -77,7 +77,7 @@ function UIPopupMenu:addOption(optionName, optionCallback, shortcut) width = width + shortcutLabel:getTextSize().width + shortcutLabel:getMarginLeft() + shortcutLabel:getMarginRight() end - + optionWidget:setEnabled(not disabled) self:setWidth(math.max(190, math.max(self:getWidth(), width))) end diff --git a/modules/corelib/ui/uitabbar.lua b/modules/corelib/ui/uitabbar.lua index 5a9722321b..5daf117a9c 100644 --- a/modules/corelib/ui/uitabbar.lua +++ b/modules/corelib/ui/uitabbar.lua @@ -48,7 +48,9 @@ function UITabBar:addTab(text, panel, icon) tab.onClick = onTabClick tab.onMouseRelease = onTabMouseRelease tab.onDestroy = function() - tab.tabPanel:destroy() + if not tab.tabPanel:isDestroyed() then + tab.tabPanel:destroy() + end end table.insert(self.tabs, tab) diff --git a/modules/corelib/ui/uitable.lua b/modules/corelib/ui/uitable.lua index a19e101f59..e1bae68fa5 100644 --- a/modules/corelib/ui/uitable.lua +++ b/modules/corelib/ui/uitable.lua @@ -223,7 +223,10 @@ function UITable:addRow(data, height) self.columns[rowId] = {} for colId, column in pairs(data) do - local col = g_ui.createWidget(self.columBaseStyle, row) + local col = g_ui.createWidget(column.style or self.columBaseStyle, row) + if column.id then + col:setId(column.id) + end if column.width then col:setWidth(column.width) else @@ -235,11 +238,29 @@ function UITable:addRow(data, height) if column.text then col:setText(column.text) end + if column.color then + col:setColor(column.color) + end + if column.coloredText then + col:parseColoredText(column.coloredText.text, column.coloredText.color) + end if column.sortvalue then col.sortvalue = column.sortvalue else col.sortvalue = column.text or 0 end + if column.marginTop then + col:setMarginTop(column.marginTop) + end + if column.marginBottom then + col:setMarginBottom(column.marginBottom) + end + if column.comboBox then + for _, comboValue in ipairs(column.comboBox) do + col:addOption(comboValue[1], comboValue[2]) + end + end + table.insert(self.columns[rowId], col) end diff --git a/modules/corelib/ui/uiwidget.lua b/modules/corelib/ui/uiwidget.lua index 85a26dbf53..9e6da7fbe2 100644 --- a/modules/corelib/ui/uiwidget.lua +++ b/modules/corelib/ui/uiwidget.lua @@ -18,3 +18,28 @@ function UIWidget:setMargin(...) self:setMarginLeft(params[4]) end end + +function UIWidget:parseColoredText(text, default_color) + local result = "" + local i = 1 + while i <= #text do + local start, stop = text:find("%[color=.-%]", i) + if start then + result = result .. text:sub(i, start - 1) + local closing_tag_start, closing_tag_stop = text:find("%[/color%]", stop + 1) + if closing_tag_start then + local content = text:sub(stop + 1, closing_tag_start - 1) + local color_start, color_stop = text:find("#%x+", start) + local color = text:sub(color_start, color_stop) or default_color + result = result .. "{" .. content .. ", " .. color .. "}" + i = closing_tag_stop + 1 + else + break + end + else + result = result .. text:sub(i) + break + end + end + self:setColoredText(result) +end diff --git a/modules/game_battle/battle.lua b/modules/game_battle/battle.lua index dda3268f5a..7f9e438c28 100644 --- a/modules/game_battle/battle.lua +++ b/modules/game_battle/battle.lua @@ -69,7 +69,13 @@ function init() -- Initiating the module (load) battleWindow = g_ui.loadUI('battle') -- Binding Ctrl + B shortcut - g_keyboard.bindKeyDown('Ctrl+B', toggle) + Keybind.new("Windows", "Show/hide battle list", "Ctrl+B", "") + Keybind.bind("Windows", "Show/hide battle list", { + { + type = KEY_DOWN, + callback = toggle, + } + }) -- Disabling scrollbar auto hiding local scrollbar = battleWindow:getChildById('miniwindowScrollBar') @@ -1087,7 +1093,7 @@ function terminate() -- Terminating the Module (unload) filterPanel = nil toggleFilterButton = nil - g_keyboard.unbindKeyDown('Ctrl+B') + Keybind.delete("Windows", "Show/hide battle list") disconnect(g_game, { onAttackingCreatureChange = onAttack, diff --git a/modules/game_bugreport/bugreport.lua b/modules/game_bugreport/bugreport.lua index 56b622f296..0cbc0a838d 100644 --- a/modules/game_bugreport/bugreport.lua +++ b/modules/game_bugreport/bugreport.lua @@ -12,11 +12,17 @@ function init() bugTextEdit = bugReportWindow:getChildById('bugTextEdit') - g_keyboard.bindKeyDown(HOTKEY, show) + Keybind.new("Dialogs", "Open Bugreport", HOTKEY, "") + Keybind.bind("Dialogs", "Open Bugreport", { + { + type = KEY_DOWN, + callback = show, + } + }, modules.game_interface.getRootPanel()) end function terminate() - g_keyboard.unbindKeyDown(HOTKEY) + Keybind.delete("Dialogs", "Open Bugreport") bugReportWindow:destroy() end diff --git a/modules/game_console/console.lua b/modules/game_console/console.lua index 3d92211f0e..3b07f6e6a6 100644 --- a/modules/game_console/console.lua +++ b/modules/game_console/console.lua @@ -222,14 +222,8 @@ function init() g_keyboard.bindKeyPress('Shift+Down', function() navigateMessageHistory(-1) end, consolePanel) - g_keyboard.bindKeyPress('Tab', function() - consoleTabBar:selectNextTab() - end, consolePanel) - g_keyboard.bindKeyPress('Shift+Tab', function() - consoleTabBar:selectPrevTab() - end, consolePanel) + g_keyboard.bindKeyDown('Enter', switchChatOnCall, consolePanel) - g_keyboard.bindKeyDown('Enter', sendCurrentMessage, consolePanel) g_keyboard.bindKeyDown('Escape', disableChatOnCall, consolePanel) g_keyboard.bindKeyPress('Ctrl+A', function() consoleTextEdit:clearText() @@ -241,9 +235,52 @@ function init() consoleTabBar.onTabChange = onTabChange -- tibia like hotkeys - g_keyboard.bindKeyDown('Ctrl+O', g_game.requestChannels) - g_keyboard.bindKeyDown('Ctrl+E', removeCurrentTab) - g_keyboard.bindKeyDown('Ctrl+H', openHelp) + local gameRootPanel = modules.game_interface.getRootPanel() + Keybind.new("Chat Channel", "Next Channel", "Tab", "") + Keybind.bind("Chat Channel", "Next Channel", { + { + type = KEY_PRESS, + callback = function() consoleTabBar:selectNextTab() end, + } + }, consolePanel) + + Keybind.new("Chat Channel", "Previous Channel", "Shift+Tab", "") + Keybind.bind("Chat Channel", "Previous Channel", { + { + type = KEY_PRESS, + callback = function() consoleTabBar:selectPrevTab() end, + } + }, consolePanel) + Keybind.new("Chat", "Send current chat line", { [CHAT_MODE.ON] = "Enter", [CHAT_MODE.OFF] = "" }, "") + Keybind.bind("Chat", "Send current chat line", { + { + type = KEY_DOWN, + callback = sendCurrentMessage, + } + }, consolePanel) + Keybind.new("Chat Channel", "Open Channel List", "Ctrl+O", "") + Keybind.bind("Chat Channel", "Open Channel List", { + { + type = KEY_DOWN, + callback = g_game.requestChannels, + } + }, gameRootPanel) + Keybind.new("Chat Channel", "Close Current Channel", "Ctrl+E", "") + + Keybind.bind("Chat Channel", "Close Current Channel", { + { + type = KEY_DOWN, + callback = removeCurrentTab, + } + }, gameRootPanel) + + Keybind.new("Chat Channel", "Open Help Channel", "Ctrl+H", "") + Keybind.bind("Chat Channel", "Open Help Channel", { + { + type = KEY_DOWN, + callback = openHelp, + } + }, consolePanel) -- toggle WASD consoleToggleChat = consolePanel:getChildById('toggleChat') @@ -340,9 +377,11 @@ function switchChat(enabled) if enabled then unbindMovingKeys() consoleToggleChat:setTooltip(tr('Disable chat mode, allow to walk using WASD')) + Keybind.setChatMode(CHAT_MODE.ON) else bindMovingKeys() consoleToggleChat:setTooltip(tr('Enable chat mode')) + Keybind.setChatMode(CHAT_MODE.OFF) end end @@ -401,10 +440,12 @@ function terminate() clear() end - g_keyboard.unbindKeyDown('Ctrl+O') - g_keyboard.unbindKeyDown('Ctrl+E') - g_keyboard.unbindKeyDown('Ctrl+H') - + Keybind.delete("Chat Channel", "Close Current Channel")-- + Keybind.delete("Chat Channel", "Next Channel")-- + Keybind.delete("Chat Channel", "Previous Channel")-- + Keybind.delete("Chat Channel", "Open Channel List")-- + Keybind.delete("Chat Channel", "Open Help Channel")-- + Keybind.delete("Chat", "Send current chat line") saveCommunicationSettings() if channelsWindow then @@ -1994,7 +2035,14 @@ function online() tab.npcChat = true end if g_game.getClientVersion() < 862 then - g_keyboard.bindKeyDown('Ctrl+R', openPlayerReportRuleViolationWindow) + Keybind.new("Dialogs", "Open Rule Violation", "Ctrl+R", "") + local gameRootPanel = modules.game_interface.getRootPanel() + Keybind.bind("Dialogs", "Open Rule Violation", { + { + type = KEY_DOWN, + callback = openPlayerReportRuleViolationWindow, + } + }, gameRootPanel) end -- open last channels local lastChannelsOpen = g_settings.getNode('lastChannelsOpen') @@ -2019,7 +2067,7 @@ end function offline() if g_game.getClientVersion() < 862 then - g_keyboard.unbindKeyDown('Ctrl+R') + Keybind.delete("Dialogs", "Open Rule Violation") end clear() end diff --git a/modules/game_containers/containers.lua b/modules/game_containers/containers.lua index d12357110d..a8f787e1ac 100644 --- a/modules/game_containers/containers.lua +++ b/modules/game_containers/containers.lua @@ -53,6 +53,10 @@ function refreshContainerItems(container) itemWidget:setItem(container:getItem(slot)) ItemsDatabase.setRarityItem(itemWidget, container:getItem(slot)) ItemsDatabase.setTier(itemWidget, container:getItem(slot)) + if modules.client_options.getOption('showExpiryInContainers') then + ItemsDatabase.setCharges(itemWidget, container:getItem(slot)) + ItemsDatabase.setDuration(itemWidget, container:getItem(slot)) + end end if container:hasPages() then @@ -140,6 +144,10 @@ function onContainerOpen(container, previousContainer) itemWidget:setItem(container:getItem(slot)) ItemsDatabase.setRarityItem(itemWidget, container:getItem(slot)) ItemsDatabase.setTier(itemWidget, container:getItem(slot)) + if modules.client_options.getOption('showExpiryInContainers') then + ItemsDatabase.setCharges(itemWidget, container:getItem(slot)) + ItemsDatabase.setDuration(itemWidget, container:getItem(slot)) + end itemWidget:setMargin(0) itemWidget.position = container:getSlotPosition(slot) @@ -191,4 +199,8 @@ function onContainerUpdateItem(container, slot, item, oldItem) end local itemWidget = container.itemsPanel:getChildById('item' .. slot) itemWidget:setItem(item) + if modules.client_options.getOption('showExpiryInContainers') then + ItemsDatabase.setCharges(itemWidget, container:getItem(slot)) + ItemsDatabase.setDuration(itemWidget, container:getItem(slot)) + end end diff --git a/modules/game_cooldown/cooldown.otui b/modules/game_cooldown/cooldown.otui index 51fdaf7baa..cc93530041 100644 --- a/modules/game_cooldown/cooldown.otui +++ b/modules/game_cooldown/cooldown.otui @@ -29,6 +29,8 @@ Panel anchors.top: parent.top anchors.left: parent.left anchors.right: parent.right + focusable: false + phantom: true Panel id:contentsPanel2 anchors.fill: parent diff --git a/modules/game_cyclopedia/game_cyclopedia.lua b/modules/game_cyclopedia/game_cyclopedia.lua index ad1c906491..535085edb0 100644 --- a/modules/game_cyclopedia/game_cyclopedia.lua +++ b/modules/game_cyclopedia/game_cyclopedia.lua @@ -33,7 +33,6 @@ controllerCyclopedia = Controller:new() controllerCyclopedia:setUI('game_cyclopedia') function controllerCyclopedia:onInit() - end function controllerCyclopedia:onGameStart() @@ -168,6 +167,19 @@ function controllerCyclopedia:onGameStart() trackerMiniWindow:setupOnStart() loadFilters() Cyclopedia.BossSlots.UnlockBosses = {} + Keybind.new("Windows", "Show/hide Bosstiary Tracker", "", "") + + Keybind.bind("Windows", "Show/hide Bosstiary Tracker", {{ + type = KEY_DOWN, + callback = Cyclopedia.toggleBosstiaryTracker + }}) + + Keybind.new("Windows", "Show/hide Bestiary Tracker", "", "") + Keybind.bind("Windows", "Show/hide Bestiary Tracker", {{ + type = KEY_DOWN, + callback = Cyclopedia.toggleBestiaryTracker + }}) + end end @@ -179,6 +191,8 @@ function controllerCyclopedia:onGameEnd() end hide() saveFilters() + Keybind.delete("Windows", "Show/hide Bosstiary Tracker") + Keybind.delete("Windows", "Show/hide Bestiary Tracker") end function controllerCyclopedia:onTerminate() diff --git a/modules/game_cyclopedia/images/bestiary/creatures/Construct.png b/modules/game_cyclopedia/images/bestiary/creatures/construct.png similarity index 100% rename from modules/game_cyclopedia/images/bestiary/creatures/Construct.png rename to modules/game_cyclopedia/images/bestiary/creatures/construct.png diff --git a/modules/game_cyclopedia/images/bestiary/creatures/Demon.png b/modules/game_cyclopedia/images/bestiary/creatures/demon.png similarity index 100% rename from modules/game_cyclopedia/images/bestiary/creatures/Demon.png rename to modules/game_cyclopedia/images/bestiary/creatures/demon.png diff --git a/modules/game_cyclopedia/images/bestiary/creatures/Dragon.png b/modules/game_cyclopedia/images/bestiary/creatures/dragon.png similarity index 100% rename from modules/game_cyclopedia/images/bestiary/creatures/Dragon.png rename to modules/game_cyclopedia/images/bestiary/creatures/dragon.png diff --git a/modules/game_cyclopedia/images/bestiary/creatures/Extra_Dimensional.png b/modules/game_cyclopedia/images/bestiary/creatures/extra_dimensional.png similarity index 100% rename from modules/game_cyclopedia/images/bestiary/creatures/Extra_Dimensional.png rename to modules/game_cyclopedia/images/bestiary/creatures/extra_dimensional.png diff --git a/modules/game_cyclopedia/images/bestiary/creatures/Fey.png b/modules/game_cyclopedia/images/bestiary/creatures/fey.png similarity index 100% rename from modules/game_cyclopedia/images/bestiary/creatures/Fey.png rename to modules/game_cyclopedia/images/bestiary/creatures/fey.png diff --git a/modules/game_cyclopedia/images/bestiary/creatures/Giant.png b/modules/game_cyclopedia/images/bestiary/creatures/giant.png similarity index 100% rename from modules/game_cyclopedia/images/bestiary/creatures/Giant.png rename to modules/game_cyclopedia/images/bestiary/creatures/giant.png diff --git a/modules/game_cyclopedia/images/bestiary/creatures/Human.png b/modules/game_cyclopedia/images/bestiary/creatures/human.png similarity index 100% rename from modules/game_cyclopedia/images/bestiary/creatures/Human.png rename to modules/game_cyclopedia/images/bestiary/creatures/human.png diff --git a/modules/game_cyclopedia/images/bestiary/creatures/Humanoid.png b/modules/game_cyclopedia/images/bestiary/creatures/humanoid.png similarity index 100% rename from modules/game_cyclopedia/images/bestiary/creatures/Humanoid.png rename to modules/game_cyclopedia/images/bestiary/creatures/humanoid.png diff --git a/modules/game_cyclopedia/images/bestiary/creatures/Lycanthrope.png b/modules/game_cyclopedia/images/bestiary/creatures/lycanthrope.png similarity index 100% rename from modules/game_cyclopedia/images/bestiary/creatures/Lycanthrope.png rename to modules/game_cyclopedia/images/bestiary/creatures/lycanthrope.png diff --git a/modules/game_cyclopedia/images/bestiary/creatures/Magical.png b/modules/game_cyclopedia/images/bestiary/creatures/magical.png similarity index 100% rename from modules/game_cyclopedia/images/bestiary/creatures/Magical.png rename to modules/game_cyclopedia/images/bestiary/creatures/magical.png diff --git a/modules/game_cyclopedia/images/bestiary/creatures/Mammal.png b/modules/game_cyclopedia/images/bestiary/creatures/mammal.png similarity index 100% rename from modules/game_cyclopedia/images/bestiary/creatures/Mammal.png rename to modules/game_cyclopedia/images/bestiary/creatures/mammal.png diff --git a/modules/game_cyclopedia/images/bestiary/creatures/Plant.png b/modules/game_cyclopedia/images/bestiary/creatures/plant.png similarity index 100% rename from modules/game_cyclopedia/images/bestiary/creatures/Plant.png rename to modules/game_cyclopedia/images/bestiary/creatures/plant.png diff --git a/modules/game_cyclopedia/images/bestiary/creatures/Reptile.png b/modules/game_cyclopedia/images/bestiary/creatures/reptile.png similarity index 100% rename from modules/game_cyclopedia/images/bestiary/creatures/Reptile.png rename to modules/game_cyclopedia/images/bestiary/creatures/reptile.png diff --git a/modules/game_cyclopedia/images/bestiary/creatures/Slime.png b/modules/game_cyclopedia/images/bestiary/creatures/slime.png similarity index 100% rename from modules/game_cyclopedia/images/bestiary/creatures/Slime.png rename to modules/game_cyclopedia/images/bestiary/creatures/slime.png diff --git a/modules/game_cyclopedia/images/bestiary/creatures/Undead.png b/modules/game_cyclopedia/images/bestiary/creatures/undead.png similarity index 100% rename from modules/game_cyclopedia/images/bestiary/creatures/Undead.png rename to modules/game_cyclopedia/images/bestiary/creatures/undead.png diff --git a/modules/game_cyclopedia/images/bestiary/creatures/Vermin.png b/modules/game_cyclopedia/images/bestiary/creatures/vermin.png similarity index 100% rename from modules/game_cyclopedia/images/bestiary/creatures/Vermin.png rename to modules/game_cyclopedia/images/bestiary/creatures/vermin.png diff --git a/modules/game_cyclopedia/tab/bestiary/bestiary.lua b/modules/game_cyclopedia/tab/bestiary/bestiary.lua index 5b34d7ddea..5baa514515 100644 --- a/modules/game_cyclopedia/tab/bestiary/bestiary.lua +++ b/modules/game_cyclopedia/tab/bestiary/bestiary.lua @@ -125,10 +125,7 @@ function Cyclopedia.CreateCreatureItems(data) end end - local price, rarity = ItemsDatabase.getSellValueAndColor(itemWidget.id) - if price > 0 then - itemWidget:setImageSource("/images/ui/rarity_" .. rarity) - end + ItemsDatabase.setRarityItem(itemWidget, itemWidget:getItem()) itemWidget.onMouseRelease = onAddLootClick end diff --git a/modules/game_cyclopedia/tab/boss_slots/boss_slots.lua b/modules/game_cyclopedia/tab/boss_slots/boss_slots.lua index 10bd8d68c8..27e28e6e71 100644 --- a/modules/game_cyclopedia/tab/boss_slots/boss_slots.lua +++ b/modules/game_cyclopedia/tab/boss_slots/boss_slots.lua @@ -1,4 +1,4 @@ -local UI = nil +local UI = nil function showBossSlot() UI = g_ui.loadUI("boss_slots", contentContainer) diff --git a/modules/game_cyclopedia/tab/bosstiary/bosstiary.lua b/modules/game_cyclopedia/tab/bosstiary/bosstiary.lua index cd51e198a2..7c89300e1b 100644 --- a/modules/game_cyclopedia/tab/bosstiary/bosstiary.lua +++ b/modules/game_cyclopedia/tab/bosstiary/bosstiary.lua @@ -1,4 +1,4 @@ -local UI = nil +local UI = nil function showBosstiary() UI = g_ui.loadUI("bosstiary", contentContainer) UI:show() diff --git a/modules/game_cyclopedia/tab/character/character.lua b/modules/game_cyclopedia/tab/character/character.lua index 9f3625ab55..0643baeb6f 100644 --- a/modules/game_cyclopedia/tab/character/character.lua +++ b/modules/game_cyclopedia/tab/character/character.lua @@ -641,7 +641,7 @@ function Cyclopedia.loadCharacterCombatStats(data, mitigation, additionalSkillsA -- Critical Chance local skillIndex = skillsIndexes[Skill.CriticalChance] local skill = additionalSkillsArray[skillIndex][2] - UI.CombatStats.criticalChance.value:setText(skill .. "%") + UI.CombatStats.criticalChance.value:setText(string.format("%.2f%%", skill / 100)) if skill > 0 then UI.CombatStats.criticalChance.value:setColor("#44AD25") else @@ -651,7 +651,7 @@ function Cyclopedia.loadCharacterCombatStats(data, mitigation, additionalSkillsA -- Critical Damage skillIndex = skillsIndexes[Skill.CriticalDamage] skill = additionalSkillsArray[skillIndex][2] - UI.CombatStats.criticalDamage.value:setText(skill .. "%") + UI.CombatStats.criticalDamage.value:setText(string.format("%.2f%%", skill / 100)) if skill > 0 then UI.CombatStats.criticalDamage.value:setColor("#44AD25") else @@ -727,13 +727,7 @@ function Cyclopedia.loadCharacterCombatStats(data, mitigation, additionalSkillsA value:setText(string.format("%.2f%%", percent / 100)) value:setColor("#C0C0C0") value:setMarginRight(2) - - if percent > 0 then - value:setColor("#44AD25") - else - value:setColor("#C0C0C0") - end - + value:setColor("#C0C0C0") firstSpecial = firstSpecial and false end end @@ -852,9 +846,7 @@ function Cyclopedia.loadCharacterGeneralStats(data, skills) Cyclopedia.setCharacterSkillBase("magiclevel", data.magicLevel, data.baseMagicLevel) for i = Skill.Fist + 1, Skill.Fishing + 1 do - local skillLevel = skills[i][1] - local baseSkill = skills[i][2] - local skillPercent = skills[i][3] + local skillLevel, baseSkill, skillPercent = unpack(skills[i]) Cyclopedia.onSkillChange(player, i - 1, skillLevel, skillPercent) Cyclopedia.onBaseCharacterSkillChange(player, i - 1, baseSkill) end diff --git a/modules/game_cyclopedia/tab/charms/charms.lua b/modules/game_cyclopedia/tab/charms/charms.lua index 5616136a54..eeaecd2b88 100644 --- a/modules/game_cyclopedia/tab/charms/charms.lua +++ b/modules/game_cyclopedia/tab/charms/charms.lua @@ -1,4 +1,4 @@ -local UI = nil +local UI = nil function showCharms() UI = g_ui.loadUI("charms", contentContainer) diff --git a/modules/game_cyclopedia/tab/house/house.lua b/modules/game_cyclopedia/tab/house/house.lua index dba48199d4..480e101c2a 100644 --- a/modules/game_cyclopedia/tab/house/house.lua +++ b/modules/game_cyclopedia/tab/house/house.lua @@ -1,4 +1,4 @@ -local UI = nil +local UI = nil function showHouse() UI = g_ui.loadUI("house", contentContainer) diff --git a/modules/game_cyclopedia/tab/items/items.lua b/modules/game_cyclopedia/tab/items/items.lua index 66903c842a..4d307385a5 100644 --- a/modules/game_cyclopedia/tab/items/items.lua +++ b/modules/game_cyclopedia/tab/items/items.lua @@ -219,28 +219,11 @@ function Cyclopedia.internalCreateItem(data) item:setId(data:getId()) item.Sprite:setItemId(data:getId()) item.Name:setText(marketData.name) - local function getColorForValue(value) - if value >= 1000000 then - return "yellow" - elseif value >= 100000 then - return "purple" - elseif value >= 10000 then - return "blue" - elseif value >= 1000 then - return "green" - elseif value >= 50 then - return "grey" - end - return "white" - end local price = data:getMeanPrice() - local rarity = getColorForValue(price) + item.Value = price item.Vocation = marketData.restrictVocation - - if price > 0 then - item.Rarity:setImageSource("/images/ui/rarity_" .. rarity) - end + ItemsDatabase.setRarityItem(item.Sprite, item.Sprite:getItem()) function item.onClick(widget) UI.InfoBase.SellBase.List:destroyChildren() @@ -267,8 +250,8 @@ function Cyclopedia.internalCreateItem(data) UI.SelectedItem.Sprite:setItemId(data:getId()) if price > 0 then - UI.InfoBase.ResultGoldBase.Rarity:setImageSource("/images/ui/rarity_" .. rarity) - UI.SelectedItem.Rarity:setImageSource("/images/ui/rarity_" .. rarity) + ItemsDatabase.setRarityItem(UI.SelectedItem.Rarity, price) + ItemsDatabase.setRarityItem(UI.InfoBase.ResultGoldBase.Rarity, price) else UI.InfoBase.ResultGoldBase.Rarity:setImageSource("") UI.SelectedItem.Rarity:setImageSource("") diff --git a/modules/game_cyclopedia/tab/items/items.otui b/modules/game_cyclopedia/tab/items/items.otui index 8123e295b9..0ecadcd88a 100644 --- a/modules/game_cyclopedia/tab/items/items.otui +++ b/modules/game_cyclopedia/tab/items/items.otui @@ -394,7 +394,7 @@ UIWidget UIWidget id: Rarity anchors.fill: parent - image-border: 5 + image-border: 8 margin: 1 UIWidget id: Icon diff --git a/modules/game_cyclopedia/tab/map/map.lua b/modules/game_cyclopedia/tab/map/map.lua index 93344cb589..46814ac14d 100644 --- a/modules/game_cyclopedia/tab/map/map.lua +++ b/modules/game_cyclopedia/tab/map/map.lua @@ -1,4 +1,4 @@ -local UI = nil +local UI = nil local virtualFloor = 7 function showMap() diff --git a/modules/game_cyclopedia/utils.lua b/modules/game_cyclopedia/utils.lua index 7684d10134..440ed01ef8 100644 --- a/modules/game_cyclopedia/utils.lua +++ b/modules/game_cyclopedia/utils.lua @@ -1,4 +1,4 @@ -RACE = { +RACE = { [-1] = {name = "unknow", type = 2}, [0] = {name = "unknow", type = 2}, [1] = {name = "unknow", type = 2}, @@ -1012,8 +1012,8 @@ ACHIEVEMENTS = { [80] = { name = "Party Animal", grade = 1, points = 1, secret = true, description = "Oh my god, it's a paaaaaaaaaaaarty! You're always in for fun, friends and booze and love being the center of attention. There's endless reasons to celebrate! Woohoo!" }, [81] = { name = "Fireworks in the Sky", grade = 1, points = 2, secret = true, description = "You love the moment right before your rocket takes off and explodes into beautiful colours - not only on new year's eve!" }, [82] = { name = "Quick as a Turtle", grade = 1, points = 2, secret = true, description = "There... is... simply... no... better... way - than to travel on the back of a turtle. At least you get to enjoy the beautiful surroundings of Laguna." }, - [83] = { name = "Polisher", grade = 2, points = 4, secret = true, description = "If you see a rusty item, you can't resist polishing it. There's always a little flask of rust remover in your inventory – who knows, there might be a golden armor beneath all that dirt!" }, - [84] = { name = "Ship's Kobold", grade = 2, points = 4, secret = true, description = "You’ve probably never gotten seasick in your life — you love spending your free time on the ocean and covered quite a lot of miles with ships. Aren’t you glad you didn’t have to swim all that?" }, + [83] = { name = "Polisher", grade = 2, points = 4, secret = true, description = "If you see a rusty item, you can't resist polishing it. There's always a little flask of rust remover in your inventory - who knows, there might be a golden armor beneath all that dirt!" }, + [84] = { name = "Ship's Kobold", grade = 2, points = 4, secret = true, description = "You've probably never gotten seasick in your life — you love spending your free time on the ocean and covered quite a lot of miles with ships. Aren't you glad you didn't have to swim all that?" }, [85] = { name = "Steampunked", grade = 1, points = 2, secret = true, description = "Travelling with the dwarven steamboats through the underground rivers is your preferred way of crossing the lands. No pesky seagulls, and good beer on board!" }, [86] = { name = "Vanity", grade = 1, points = 3, secret = true, description = "Aren't you just perfectly, wonderfully, beautifully gorgeous? You can't pass a mirror without admiring your looks. Or maybe doing a quick check whether something's stuck in your teeth, perhaps?" }, [87] = { name = "Superstitious", grade = 1, points = 2, secret = true, description = "Fortune tellers and horoscopes guide you through your life. And you probably wouldn't dare going on a big game hunt without your trusty voodoo skull giving you his approval for the day." }, @@ -1339,7 +1339,7 @@ ACHIEVEMENTS = { -- [407] = Unknown/non-existent [408] = { name = "Rift Warrior", grade = 1, points = 3, description = "You went through hell. Seven times. You defeated the demons. Countless times. You put an end to Ferumbras claims to ascendancy. Once and for all." }, -- [409] = Unknown/non-existent - [410] = { name = "Hat Hunter", grade = 2, points = 5, description = "You sucessfully fought against all odds to protect your world from an ascending god! – You weren't there for the hat only after all?" }, + [410] = { name = "Hat Hunter", grade = 2, points = 5, description = "You sucessfully fought against all odds to protect your world from an ascending god! - You weren't there for the hat only after all?" }, [411] = { name = "Ogre Chef", grade = 1, points = 1, description = "You didn't manage to become an ogre chief. But at least you are, beyond doubt, a worthy ogre chef." }, [412] = { name = "The Call of the Wild", grade = 1, points = 2, description = "You opposed man-eating ogres and clumsy clomps. You grappled with hungry chieftains, desperate goblins and angry spirits. So you truly overcame the wild vastness of Krailos." }, [413] = { name = "Ender of the End", grade = 2, points = 5, description = "You have entered the heart of destruction and valiantly defeated the world devourer. By your actions you have postponed the end of the world — at least for a while." }, diff --git a/modules/game_healthcircle/game_healthcircle.lua b/modules/game_healthcircle/game_healthcircle.lua index e0b4b2bacf..1a57dbb6d9 100644 --- a/modules/game_healthcircle/game_healthcircle.lua +++ b/modules/game_healthcircle/game_healthcircle.lua @@ -114,6 +114,7 @@ function terminate() disconnect(g_game, { onGameStart = setPlayerValues }) + statsBarMenuLoaded = false end ------------------------------------------------- diff --git a/modules/game_hotkeys/hotkeys_manager.lua b/modules/game_hotkeys/hotkeys_manager.lua index 941758480c..3bef1c9ef6 100644 --- a/modules/game_hotkeys/hotkeys_manager.lua +++ b/modules/game_hotkeys/hotkeys_manager.lua @@ -64,7 +64,13 @@ local hotkeysWindowButton = nil -- public functions function init() - g_keyboard.bindKeyDown('Ctrl+K', toggle) + Keybind.new("Windows", "Show/hide Hotkeys", "Ctrl+K", "") + Keybind.bind("Windows", "Show/hide Hotkeys", { + { + type = KEY_DOWN, + callback = toggle, + } + }) hotkeysWindow = g_ui.displayUI('hotkeys_manager') hotkeysWindow:setVisible(false) hotkeysWindowButton = modules.client_topmenu.addRightGameToggleButton('hotkeysWindowButton', tr('Hotkeys'), '/images/options/hotkeys', toggle) @@ -128,7 +134,7 @@ function terminate() onGameEnd = offline }) - g_keyboard.unbindKeyDown('Ctrl+K') + Keybind.delete("Windows", "Show/hide Hotkeys") unload() diff --git a/modules/game_interface/gameinterface.lua b/modules/game_interface/gameinterface.lua index 1f87592706..09f30763b1 100644 --- a/modules/game_interface/gameinterface.lua +++ b/modules/game_interface/gameinterface.lua @@ -154,25 +154,41 @@ function bindKeys() bindTurnKey('Ctrl+Numpad2', South) bindTurnKey('Ctrl+Numpad4', West) - g_keyboard.bindKeyPress('Escape', function() - g_game.cancelAttackAndFollow() - end, gameRootPanel) g_keyboard.bindKeyPress('Ctrl+=', function() gameMapPanel:zoomIn() end, gameRootPanel) g_keyboard.bindKeyPress('Ctrl+-', function() gameMapPanel:zoomOut() end, gameRootPanel) - g_keyboard.bindKeyDown('Ctrl+Q', function() - tryLogout(false) - end, gameRootPanel) - g_keyboard.bindKeyDown('Ctrl+L', function() - tryLogout(false) - end, gameRootPanel) - g_keyboard.bindKeyDown('Alt+W', function() - g_map.cleanTexts() - modules.game_textmessage.clearMessages() - end, gameRootPanel) + + Keybind.new("Movement", "Stop All Actions", "Esc", "", true) + Keybind.bind("Movement", "Stop All Actions", { + { + type = KEY_PRESS, + callback = function() + g_game.cancelAttackAndFollow() + end, + } + }, gameRootPanel) + + Keybind.new("Misc", "Logout", "Ctrl+L", "Ctrl+Q") + Keybind.bind("Misc", "Logout", { + { + type = KEY_PRESS, + callback = function() tryLogout(false) end, + } + }, gameRootPanel) + + Keybind.new("UI", "Clear All Texts", "Ctrl+W", "") + Keybind.bind("UI", "Clear All Texts", { + { + type = KEY_DOWN, + callback = function() + g_map.cleanTexts() + modules.game_textmessage.clearMessages() + end, + } + }, gameRootPanel) g_keyboard.bindKeyDown('Ctrl+.', nextViewMode, gameRootPanel) end @@ -251,6 +267,9 @@ function terminate() logoutButton:destroy() gameRootPanel:destroy() + Keybind.delete("Movement", "Stop All Actions") + Keybind.delete("Misc", "Logout") + Keybind.delete("UI", "Clear All Texts") end function onGameStart() diff --git a/modules/game_interface/widgets/statsbar.lua b/modules/game_interface/widgets/statsbar.lua index b66ed64a86..32e1b43f97 100644 --- a/modules/game_interface/widgets/statsbar.lua +++ b/modules/game_interface/widgets/statsbar.lua @@ -309,7 +309,6 @@ function StatsBar.reloadCurrentStatsBarQuickInfo_state(localPlayer, now, old) if now == old then return end - local bitsChanged = bit.bxor(now, old) for i = 1, 32 do local pow = math.pow(2, i - 1) diff --git a/modules/game_inventory/inventory.lua b/modules/game_inventory/inventory.lua index 9855c20697..b3a4dc02f2 100644 --- a/modules/game_inventory/inventory.lua +++ b/modules/game_inventory/inventory.lua @@ -43,6 +43,21 @@ local function updateSlotsDuration() end -- @ + if not modules.client_options.getOption('showExpiryInInvetory') then + stopEvent() + local ui = getInventoryUi() + for slot, itemDurationReg in pairs(itemSlotsWithDuration) do + local getSlotInfo = getSlotPanelBySlot[slot] + if getSlotInfo then + local slotPanel = getSlotInfo(ui) + if slotPanel and slotPanel.item then + slotPanel.item.duration:setText("") + end + end + end + return + end + local currTime = g_clock.seconds() local ui = getInventoryUi() local hasItemsWithDuration = false @@ -56,7 +71,7 @@ local function updateSlotsDuration() if getSlotInfo then local slotPanel = getSlotInfo(ui) if slotPanel and slotPanel.item then - slotPanel.item.Duration:setText(formatDuration(durationTimeLeft)) + slotPanel.item.duration:setText(formatDuration(durationTimeLeft)) end end end @@ -110,20 +125,29 @@ local function inventoryEvent(player, slot, item, oldItem) toggler:setEnabled(not item) slotPanel.item:setWidth(34) slotPanel.item:setHeight(34) + slotPanel.item.duration:setText("") + slotPanel.item.charges:setText("") if g_game.getFeature(GameThingClock) then if item and item:getDurationTime() > 0 then - itemSlotsWithDuration[slot] = { - item = item, - timeEnd = g_clock.seconds() + item:getDurationTime() - } - updateSlotsDuration() + if not itemSlotsWithDuration[slot] or itemSlotsWithDuration[slot].item ~= item then + itemSlotsWithDuration[slot] = { + item = item, + timeEnd = g_clock.seconds() + item:getDurationTime() + } + end + if modules.client_options.getOption('showExpiryInInvetory') then + if not updateSlotsDurationEvent then + updateSlotsDuration() + end + end else itemSlotsWithDuration[slot] = nil - if slotPanel and slotPanel.item then - slotPanel.item.Duration:setText("") - end end end + + if modules.client_options.getOption('showExpiryInInvetory') then + ItemsDatabase.setCharges(slotPanel.item, item) + end ItemsDatabase.setTier(slotPanel.item, item) end @@ -403,3 +427,20 @@ end function getSlot5() return inventoryController.ui.onPanel.shield end + +function reloadInventory() + if modules.client_options.getOption('showExpiryInInvetory') then + updateSlotsDuration() + end + + for slot, getSlotInfo in pairs(getSlotPanelBySlot) do + local ui = getInventoryUi() + local slotPanel, toggler = getSlotInfo(ui) + if slotPanel then + local player = g_game.getLocalPlayer() + if player then + inventoryEvent(player, slot, player:getInventoryItem(slot)) + end + end + end +end diff --git a/modules/game_outfit/outfit.lua b/modules/game_outfit/outfit.lua index ece28278b8..b13eac7425 100644 --- a/modules/game_outfit/outfit.lua +++ b/modules/game_outfit/outfit.lua @@ -512,6 +512,8 @@ function destroy() showTitleCheck = nil colorBoxes = {} currentColorBox = nil + previewCreature:destroy() + previewCreature = nil if appearanceGroup then appearanceGroup:destroy() appearanceGroup = nil diff --git a/modules/game_playerdeath/playerdeath.lua b/modules/game_playerdeath/playerdeath.lua index abb55968de..7a7ee08950 100644 --- a/modules/game_playerdeath/playerdeath.lua +++ b/modules/game_playerdeath/playerdeath.lua @@ -17,7 +17,7 @@ local deathTexts = { } deathController = Controller:new() -deathController:setUI('deathWindow') +deathController:setUI('deathwindow') function deathController:onInit() deathController:registerEvents(g_game, { onDeath = display, diff --git a/modules/game_playermount/playermount.lua b/modules/game_playermount/playermount.lua index d29596ff37..477c040851 100644 --- a/modules/game_playermount/playermount.lua +++ b/modules/game_playermount/playermount.lua @@ -18,13 +18,19 @@ end function online() if g_game.getFeature(GamePlayerMounts) then - g_keyboard.bindKeyDown('Ctrl+R', toggleMount) + Keybind.new("Movement", "Mount/dismount", "Ctrl+R", "") + Keybind.bind("Movement", "Mount/dismount", { + { + type = KEY_DOWN, + callback = toggleMount, + } + }) end end function offline() if g_game.getFeature(GamePlayerMounts) then - g_keyboard.unbindKeyDown('Ctrl+R') + Keybind.delete("Movement", "Mount/dismount") end end diff --git a/modules/game_questlog/questlog.lua b/modules/game_questlog/questlog.lua index 7a8012f5c5..a6dccf23ea 100644 --- a/modules/game_questlog/questlog.lua +++ b/modules/game_questlog/questlog.lua @@ -15,6 +15,16 @@ function init() onQuestLine = onGameQuestLine, onGameEnd = destroyWindows }) + + Keybind.new("Windows", "Show/hide quest Log", "", "") + Keybind.bind("Windows", "Show/hide quest Log", { + { + type = KEY_DOWN, + callback = function() + g_game.requestQuestLog() + end, + } + }) end function terminate() @@ -26,15 +36,19 @@ function terminate() destroyWindows() questLogButton:destroy() + questLogButton = nil + Keybind.delete("Windows", "Show/hide quest Log") end function destroyWindows() if questLogWindow then questLogWindow:destroy() + questLogWindow = nil end if questLineWindow then questLineWindow:destroy() + questLineWindow = nil end end @@ -69,6 +83,7 @@ function onGameQuestLine(questId, questMissions) end if questLineWindow then questLineWindow:destroy() + questLineWindow = nil end questLineWindow = g_ui.createWidget('QuestLineWindow', rootWidget) @@ -85,7 +100,7 @@ function onGameQuestLine(questId, questMissions) }) for i, questMission in pairs(questMissions) do - local name, description = unpack(questMission) + local name, description, missionId = unpack(questMission) local missionLabel = g_ui.createWidget('MissionLabel') missionLabel:setText(name) diff --git a/modules/game_quickloot/quickloot.lua b/modules/game_quickloot/quickloot.lua index 25f2ba6c90..9294eae918 100644 --- a/modules/game_quickloot/quickloot.lua +++ b/modules/game_quickloot/quickloot.lua @@ -1,4 +1,4 @@ -QuickLoot = {} +QuickLoot = {} local function getFilter(id) local filter = { @@ -219,9 +219,9 @@ function QuickLoot.Define() quickLootController.ui.fallbackPanel.checkbox:setChecked(fallback) -- LuaFormatter off local slotBags = { - { color = "#484848", name = "Unassigned", type = 1 }, + { color = "#484848", name = "Unassigned", type = 31 }, { color = "#414141", name = "Gold", type = 30 }, - { color = "#484848", name = "Armors", type = 31 }, + { color = "#484848", name = "Armors", type = 1 }, { color = "#414141", name = "Amulets", type = 2 }, { color = "#484848", name = "Boots", type = 3 }, { color = "#414141", name = "Containers", type = 4 }, @@ -259,8 +259,8 @@ function QuickLoot.Define() for _, container in pairs(lootContainers) do if container[1] == id then - local lootContainerId = container[2] - local obtainerContainerId = container[3] + local lootContainerId = container[3] + local obtainerContainerId = container[2] widget.item:setItemId(lootContainerId) widget.item2:setItemId(obtainerContainerId) diff --git a/modules/game_quickloot/quickloot.otui b/modules/game_quickloot/quickloot.otui index 97747eb8e8..16980637cc 100644 --- a/modules/game_quickloot/quickloot.otui +++ b/modules/game_quickloot/quickloot.otui @@ -49,9 +49,9 @@ QuicklootBagLabel < UIWidget margin-left: 2 SelectBagButton id: selectBag - &click: 6 - &Select:0 - &borrar:1 + &click: 2 + &Select:4 + &borrar:5 anchors.verticalCenter: parent.verticalCenter anchors.right: parent.right @@ -61,9 +61,9 @@ QuicklootBagLabel < UIWidget anchors.verticalCenter: parent.verticalCenter anchors.right: selectBag.left margin-right: 5 - &click: 6 - &Select:0 - &borrar:1 + &click: 2 + &Select:4 + &borrar:5 @onClick: modules.game_quickloot.QuickLoot.clearItem(self) Item id: item @@ -71,18 +71,18 @@ QuicklootBagLabel < UIWidget anchors.right: removeBag.left margin-right: 5 opacity: 1.0 - &click: 6 - &Select:0 - &borrar:1 + &click: 2 + &Select:4 + &borrar:5 @onClick: modules.game_quickloot.QuickLoot.openContainer(self) $pressed: opacity: 0.5 SelectBagButton id: selectBag2 - &click: 2 - &Select:4 - &borrar:5 + &click: 6 + &Select:0 + &borrar:1 anchors.verticalCenter: parent.verticalCenter anchors.right: item.left margin-right: 5 @@ -92,18 +92,18 @@ QuicklootBagLabel < UIWidget anchors.verticalCenter: parent.verticalCenter anchors.right: selectBag2.left margin-right: 5 - &click: 2 - &Select:4 - &borrar:5 + &click: 6 + &Select:0 + &borrar:1 @onClick: modules.game_quickloot.QuickLoot.clearItem(self) Item id: item2 anchors.verticalCenter: parent.verticalCenter anchors.right: removeBag2.left margin-right: 5 - &click: 2 - &Select:4 - &borrar:5 + &click: 6 + &Select:0 + &borrar:1 opacity: 1.0 @onClick: modules.game_quickloot.QuickLoot.openContainer(self) $pressed: diff --git a/modules/game_ruleviolation/ruleviolation.lua b/modules/game_ruleviolation/ruleviolation.lua index 61e4609fca..66e7935dc3 100644 --- a/modules/game_ruleviolation/ruleviolation.lua +++ b/modules/game_ruleviolation/ruleviolation.lua @@ -45,7 +45,7 @@ function init() reasonsTextList = ruleViolationWindow:getChildById('reasonList') actionsTextList = ruleViolationWindow:getChildById('actionList') - g_keyboard.bindKeyDown('Ctrl+Y', function() + g_keyboard.bindKeyDown('Ctrl+U', function() show() end) @@ -58,7 +58,7 @@ function terminate() disconnect(g_game, { onGMActions = loadReasons }) - g_keyboard.unbindKeyDown('Ctrl+Y') + g_keyboard.unbindKeyDown('Ctrl+U') ruleViolationWindow:destroy() end diff --git a/modules/game_shaders/shaders.lua b/modules/game_shaders/shaders.lua index 1418b29fca..0b75c66a25 100644 --- a/modules/game_shaders/shaders.lua +++ b/modules/game_shaders/shaders.lua @@ -124,19 +124,23 @@ function ShaderController:onInit() for _, opts in pairs(MOUNT_SHADERS) do registerShader(opts, 'setupMountShader') end + Keybind.new('Windows', 'show/hide Shader Windows', HOTKEY, '') + Keybind.bind('Windows', 'show/hide Shader Windows', { + { + type = KEY_DOWN, + callback = function() ShaderController.ui:setVisible(not ShaderController.ui:isVisible()) end, + } + }) end function ShaderController:onTerminate() g_shaders.clear() + Keybind.delete('Windows', 'show/hide Shader Windows') end function ShaderController:onGameStart() attachShaders() - self:bindKeyDown(HOTKEY, function() - ShaderController.ui:setVisible(not ShaderController.ui:isVisible()) - end) - self:loadHtml('shaders.html', modules.game_interface.getMapPanel()) for _, opts in pairs(MAP_SHADERS) do diff --git a/modules/game_shaders/shaders/fragment/bloom.frag b/modules/game_shaders/shaders/fragment/bloom.frag index 6571dd558c..acde4de9d6 100644 --- a/modules/game_shaders/shaders/fragment/bloom.frag +++ b/modules/game_shaders/shaders/fragment/bloom.frag @@ -5,11 +5,9 @@ varying vec2 v_TexCoord; void main() { vec4 color = texture2D(u_Tex0, v_TexCoord); - int j; - int i; - for (i = -4; i <= 4; i++) - for (j = -4; j <= 4; j++) + for (int i = -4; i <= 4; i++) + for (int j = -4; j <= 4; j++) color += texture2D(u_Tex0, v_TexCoord + vec2(i, j) * 0.003) * 0.008; gl_FragColor = color; diff --git a/modules/game_skills/skills.lua b/modules/game_skills/skills.lua index ea683ca775..7c9294b383 100644 --- a/modules/game_skills/skills.lua +++ b/modules/game_skills/skills.lua @@ -31,7 +31,13 @@ function init() skillsButton:setOn(true) skillsWindow = g_ui.loadUI('skills') - g_keyboard.bindKeyDown('Alt+S', toggle) + Keybind.new("Windows", "Show/hide skills windows", "Alt+S", "") + Keybind.bind("Windows", "Show/hide skills windows", { + { + type = KEY_DOWN, + callback = toggle, + } + }) skillSettings = g_settings.getNode('skills-hide') if not skillSettings then @@ -69,7 +75,7 @@ function terminate() onGameEnd = offline }) - g_keyboard.unbindKeyDown('Alt+S') + Keybind.delete("Windows", "Show/hide skills windows") skillsWindow:destroy() skillsButton:destroy() @@ -119,8 +125,10 @@ function setSkillValue(id, value) local skill = skillsWindow:recursiveGetChildById(id) if skill then local widget = skill:getChildById('value') - if id == "skillId7" or id == "skillId9" or id == "skillId11" or id == "skillId13" or id == "skillId14" or id == "skillId15" or id == "skillId16" then - local value = value / 100 + if id == "skillId7" or id == "skillId8" or id == "skillId9" or id == "skillId11" or id == "skillId13" or id == "skillId14" or id == "skillId15" or id == "skillId16" then + if g_game.getFeature(GameEnterGameShowAppearance) then + value = value / 100 + end widget:setText(value .. "%") else widget:setText(value) diff --git a/modules/game_skills/skills.otui b/modules/game_skills/skills.otui index ae13deb5da..eb66b77821 100644 --- a/modules/game_skills/skills.otui +++ b/modules/game_skills/skills.otui @@ -217,6 +217,10 @@ MiniWindow image-source: /images/icons/icon_fishing image-size: 9 9 SkillPercentPanel + + HorizontalSeparator + margin-top: 5 + margin-bottom: 5 SmallSkillButton id: skillId7 diff --git a/modules/game_spelllist/spelllist.lua b/modules/game_spelllist/spelllist.lua index 7d9f682a8f..787ed76548 100644 --- a/modules/game_spelllist/spelllist.lua +++ b/modules/game_spelllist/spelllist.lua @@ -176,6 +176,13 @@ function init() if g_game.isOnline() then online() end + Keybind.new("Windows", "Show/hide spell list", "Alt+L", "") + Keybind.bind("Windows", "Show/hide spell list", { + { + type = KEY_DOWN, + callback = toggle, + } + }) end function terminate() @@ -199,6 +206,7 @@ function terminate() vocationRadioGroup:destroy() groupRadioGroup:destroy() premiumRadioGroup:destroy() + Keybind.delete("Windows", "Show/hide spell list") end function initializeSpelllist() diff --git a/modules/game_tasks/tasks.lua b/modules/game_tasks/tasks.lua index 91679d3a18..bedf3401ab 100644 --- a/modules/game_tasks/tasks.lua +++ b/modules/game_tasks/tasks.lua @@ -12,7 +12,14 @@ function init() window = g_ui.displayUI('tasks') window:setVisible(false) - g_keyboard.bindKeyDown('Ctrl+A', toggleWindow) + Keybind.new('Windows', 'show/hide Tasks Windows', 'Ctrl+A', '') + Keybind.bind('Windows', 'show/hide Tasks Windows', { + { + type = KEY_DOWN, + callback = toggleWindow, + } + }) + g_keyboard.bindKeyDown('Escape', hideWindowzz) taskButton = modules.client_topmenu.addLeftGameButton('taskButton', tr('Tasks'), '/modules/game_tasks/images/taskIcon', toggleWindow) ProtocolGame.registerExtendedJSONOpcode(215, parseOpcode) @@ -25,6 +32,7 @@ function terminate() ProtocolGame.unregisterExtendedJSONOpcode(215, parseOpcode) taskButton:destroy() destroy() + Keybind.delete('Windows', 'show/hide Tasks Windows') end function onGameStart() diff --git a/modules/game_textmessage/textmessage.lua b/modules/game_textmessage/textmessage.lua index 50279e654f..4e4df247a4 100644 --- a/modules/game_textmessage/textmessage.lua +++ b/modules/game_textmessage/textmessage.lua @@ -159,9 +159,10 @@ function displayMessage(mode, text) if msgtype == MessageSettings.loot then local coloredText = ItemsDatabase.setColorLootMessage(text) label:setColoredText(coloredText) - local console = modules.game_console - local consoleBuffer = console.consoleTabBar:getTabPanel(console.getTab("Server Log")):getChildById('consoleBuffer') - consoleBuffer:getLastChild():setColoredText(coloredText) + local getTabServerLog = modules.game_console.consoleTabBar:getTabPanel(modules.game_console.getTab("Server Log")) + if getTabServerLog then + getTabServerLog:getChildById('consoleBuffer'):getLastChild():setColoredText(coloredText) + end else label:setText(text) label:setColor(msgtype.color) diff --git a/modules/game_viplist/addgroup.otui b/modules/game_viplist/addgroup.otui index 0cefe46c50..eeeb159771 100644 --- a/modules/game_viplist/addgroup.otui +++ b/modules/game_viplist/addgroup.otui @@ -4,7 +4,7 @@ MainWindow text-offset: 0 1 @onEnter: modules.game_viplist.addGroup() @onEscape: | - self:getParent():destroy() + self:destroy() modules.game_viplist.addGroupWindow = nil Label diff --git a/modules/game_viplist/viplist.lua b/modules/game_viplist/viplist.lua index 1c590d66b9..381ebe8b46 100644 --- a/modules/game_viplist/viplist.lua +++ b/modules/game_viplist/viplist.lua @@ -20,8 +20,13 @@ local globalSettings = { controllerVip = Controller:new() function controllerVip:onInit() - g_keyboard.bindKeyDown('Ctrl+P', toggle) - + Keybind.new("Windows", "Show/hide VIP list", "Ctrl+P", "") + Keybind.bind("Windows", "Show/hide VIP list", { + { + type = KEY_DOWN, + callback = toggle, + } + }) vipButton = modules.game_mainpanel.addToggleButton('vipListButton', tr('VIP List') .. ' (Ctrl+P)', '/images/options/button_vip', toggle, false, 3) vipWindow = g_ui.loadUI('viplist') @@ -50,7 +55,7 @@ function controllerVip:onInit() end function controllerVip:onTerminate() - g_keyboard.unbindKeyDown('Ctrl+P') + Keybind.delete("Windows", "Show/hide VIP list") local ArrayWidgets = {addVipWindow, editVipWindow, vipWindow, vipButton, addGroupWindow} for _, widget in ipairs(ArrayWidgets) do if widget ~= nil or widget then diff --git a/modules/gamelib/const.lua b/modules/gamelib/const.lua index 5323f505c1..5acb080ba6 100644 --- a/modules/gamelib/const.lua +++ b/modules/gamelib/const.lua @@ -74,6 +74,17 @@ SouthEast = Directions.SouthEast SouthWest = Directions.SouthWest NorthWest = Directions.NorthWest +DirectionString = { + [North] = "North", + [East] = "East", + [South] = "South", + [West] = "West", + [NorthEast] = "North East", + [SouthEast] = "South East", + [SouthWest] = "South West", + [NorthWest] = "North West" + } + FightOffensive = 1 FightBalanced = 2 FightDefensive = 3 diff --git a/modules/gamelib/items.lua b/modules/gamelib/items.lua index 47cc12f1cd..cea469c55b 100644 --- a/modules/gamelib/items.lua +++ b/modules/gamelib/items.lua @@ -24,6 +24,21 @@ local function getColorForValue(value) end end +local function clipfunction(value) + if value >= 1000000 then + return "128 0 32 32" + elseif value >= 100000 then + return "96 0 32 32" + elseif value >= 10000 then + return "64 0 32 32" + elseif value >= 1000 then + return "32 0 32 32" + elseif value >= 50 then + return "0 0 32 32" + end + return "" +end + function ItemsDatabase.setRarityItem(widget, item, style) if not g_game.getFeature(GameColorizedLootValue) then return @@ -33,14 +48,26 @@ function ItemsDatabase.setRarityItem(widget, item, style) return end + local frameOption = modules.client_options.getOption('framesRarity') + if frameOption == "none" then + return + end if item then local price = type(item) == "number" and item or (item and item:getMeanPrice()) or 0 local itemRarity = getColorForValue(price) - local imagePath = '/images/ui/item' - if itemRarity and itemRarity ~= "white" then -- necessary in setColorLootMessage - imagePath = '/images/ui/rarity_' .. itemRarity + if itemRarity then + local clip = clipfunction(price) + if clip ~= "" then + local imagePath = '/images/ui/item' + if frameOption == "frames" then + imagePath = "/images/ui/rarity_frames" + elseif frameOption == "corners" then + imagePath = "/images/ui/containerslot-coloredges" + end + widget:setImageClip(clip) + widget:setImageSource(imagePath) + end end - widget:setImageSource(imagePath) end if style then @@ -84,3 +111,37 @@ function ItemsDatabase.setTier(widget, item) widget.tier:setVisible(false) end end + +function ItemsDatabase.setCharges(widget, item, style) + if not g_game.getFeature(GameThingCounter) or not widget then + return + end + + if item and item:getCharges() > 0 then + widget.charges:setText(item:getCharges()) + else + widget.charges:setText("") + end + + if style then + widget:setStyle(style) + end +end + + +function ItemsDatabase.setDuration(widget, item, style) + if not g_game.getFeature(GameThingClock) or not widget then + return + end + + if item and item:getDurationTime() > 0 then + local durationTimeLeft = item:getDurationTime() + widget.duration:setText(string.format("%dm%02d", durationTimeLeft / 60, durationTimeLeft % 60)) + else + widget.duration:setText("") + end + + if style then + widget:setStyle(style) + end +end diff --git a/modules/modulelib/controller.lua b/modules/modulelib/controller.lua index cfedbd5a17..634bd633ab 100644 --- a/modules/modulelib/controller.lua +++ b/modules/modulelib/controller.lua @@ -59,6 +59,7 @@ Controller = { ui = nil, name = nil, attrs = nil, + extendedOpcodes = nil, opcodes = nil, events = nil, htmlRoot = nil, @@ -75,7 +76,8 @@ function Controller:new() scheduledEvents = {}, keyboardEvents = {}, attrs = {}, - opcodes = {} + extendedOpcodes = {}, + opcodes = {}, } setmetatable(obj, self) self.__index = self @@ -194,10 +196,6 @@ function Controller:setUI(name, parent) end function Controller:terminate() - if self.onTerminate then - self:onTerminate() - end - if self.onGameStart then disconnect(g_game, { onGameStart = self.onGameStart }) end @@ -207,14 +205,22 @@ function Controller:terminate() disconnect(g_game, { onGameEnd = self.onGameEnd }) end + if self.onTerminate then + self:onTerminate() + end + for i, event in pairs(self.keyboardEvents) do g_keyboard['unbind' .. event.name](event.args[1], event.args[2], event.args[3]) end - for i, opcode in pairs(self.opcodes) do + for i, opcode in pairs(self.extendedOpcodes) do ProtocolGame.unregisterExtendedOpcode(opcode) end + for _, opcode in ipairs(self.opcodes) do + ProtocolGame.unregisterOpcode(opcode) + end + for type, events in pairs(self.events) do if events ~= nil then for _, event in pairs(events) do @@ -239,6 +245,7 @@ function Controller:terminate() self.attrs = nil self.events = nil self.dataUI = nil + self.extendedOpcodes = nil self.opcodes = nil self.keyboardEvents = nil self.keyboardAnchor = nil @@ -267,6 +274,11 @@ end function Controller:registerExtendedOpcode(opcode, fnc) ProtocolGame.registerExtendedOpcode(opcode, fnc) + table.insert(self.extendedOpcodes, opcode) +end + +function Controller:registerOpcode(opcode, fnc) + ProtocolGame.registerOpcode(opcode, fnc) table.insert(self.opcodes, opcode) end diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index cdb1f8882b..c797894b25 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -4,6 +4,11 @@ project(otclient) # ***************************************************************************** # Options # ***************************************************************************** +if(CMAKE_BASE_NAME STREQUAL "em++") + set(WASM ON) + message(STATUS "WASM: ON") +endif() + option(TOGGLE_FRAMEWORK_GRAPHICS "Use Graphics " ON) option(TOGGLE_FRAMEWORK_SOUND "Use SOUND " ON) option(TOGGLE_FRAMEWORK_XML "Use XML " ON) @@ -67,7 +72,7 @@ endif() if (TOGGLE_FRAMEWORK_EDITOR) set(FRAMEWORK_DEFINITIONS ${FRAMEWORK_DEFINITIONS} -DFRAMEWORK_EDITOR) endif() -if (ANDROID) +if (ANDROID OR WASM) set(FRAMEWORK_DEFINITIONS ${FRAMEWORK_DEFINITIONS} -DOPENGL_ES=2) endif() @@ -207,7 +212,7 @@ if(APPLE) find_library(FOUNDATION Foundation REQUIRED) find_library(IOKIT IOKit REQUIRED) endif() -if(UNIX AND NOT ANDROID) +if(UNIX AND NOT ANDROID AND NOT WASM) find_package(X11 REQUIRED) endif() if(WIN32) @@ -220,7 +225,9 @@ if(TOGGLE_DIRECTX) find_package(DirectX REQUIRED) endif() if(TOGGLE_FRAMEWORK_SOUND) - find_package(OpenAL CONFIG REQUIRED) + if(NOT WASM) + find_package(OpenAL CONFIG REQUIRED) + endif() find_package(VorbisFile REQUIRED) find_package(Vorbis REQUIRED) find_package(Ogg REQUIRED) @@ -235,9 +242,14 @@ if(ANDROID) find_package(game-activity REQUIRED CONFIG) find_package(EGL REQUIRED) else() - find_package(OpenGL REQUIRED) - find_package(GLEW REQUIRED) - find_package(LuaJIT REQUIRED) + if(NOT WASM) + find_package(OpenGL REQUIRED) + find_package(GLEW REQUIRED) + find_package(LuaJIT REQUIRED) + else() + set(LUA_LIBRARY ${LUA_LIBRARY} ${CMAKE_SOURCE_DIR}/browser/include/lua51/liblua.a) + set(BROWSER_INCLUDE_DIR ${BROWSER_INCLUDE_DIR} ${CMAKE_SOURCE_DIR}/browser/include) + endif() endif() # ***************************************************************************** @@ -299,6 +311,8 @@ set(SOURCE_FILES framework/stdext/qrcodegen.cpp framework/util/color.cpp framework/util/crypt.cpp + framework/proxy/proxy.cpp + framework/proxy/proxy_client.cpp client/animatedtext.cpp client/animator.cpp @@ -420,7 +434,17 @@ if (TOGGLE_FRAMEWORK_SOUND) ) endif() +if (WASM) + set(SOURCE_FILES ${SOURCE_FILES} + framework/platform/browserplatform.cpp + framework/platform/browserwindow.cpp + framework/net/webconnection.cpp + ) +endif() + + target_sources(${PROJECT_NAME} PRIVATE ${SOURCE_FILES}) +target_link_options(${PROJECT_NAME} PUBLIC -flto=auto) # ***************************************************************************** # Includes and librarys @@ -543,6 +567,86 @@ elseif(ANDROID) log pugixml::pugixml ) + +elseif(WASM) + target_include_directories(${PROJECT_NAME} + PRIVATE + ${CMAKE_SOURCE_DIR}/src + ${CMAKE_THREAD_LIBS_INIT} + ${Protobuf_INCLUDE_DIRS} + ${GMP_INCLUDE_DIR} + ${PHYSFS_INCLUDE_DIR} + ${GLEW_INCLUDE_DIR} + ${PARALLEL_HASHMAP_INCLUDE_DIRS} + ${NLOHMANN_JSON_INCLUDE_DIR} + ${OPENSSL_INCLUDE_DIR} + ${BROWSER_INCLUDE_DIR} + ) + target_link_libraries(${PROJECT_NAME} + PRIVATE + ${LUA_LIBRARY} + ${PHYSFS_LIBRARY} + ${ZLIB_LIBRARY} + ${PROTOBUF_LIBRARY} + ${NLOHMANN_JSON_LIBRARY} + ${GLEW_LIBRARY} + ${OPENGL_LIBRARIES} + ${DirectX_LIBRARY} + ${DirectX_LIBRARIES} + ${OGG_LIBRARY} + ${VORBISFILE_LIBRARY} + ${VORBIS_LIBRARY} + ${GMP_LIBRARY} + ${STDUUID} + ${FOUNDATION} + ${IOKIT} + ${OPENSSL_LIBRARY} + ${OPENSSL_CRYPTO_LIBRARY} + ${HTTPLIB_LIBRARY} + + protobuf::libprotobuf protobuf + absl::log_internal_check_op + + Threads::Threads + asio::asio + # OpenAL::OpenAL (using emscripten openal api) + LibLZMA::LibLZMA + pugixml::pugixml + ZLIB::ZLIB + OpenSSL::SSL + OpenSSL::Crypto + httplib::httplib + ) + + + get_property(linkflags TARGET ${PROJECT_NAME} PROPERTY LINK_FLAGS) + + if(CMAKE_BUILD_TYPE STREQUAL "Debug") + target_compile_options(${PROJECT_NAME} + PRIVATE + -Wall -Wextra -Wpedantic + ) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g") + set(linkflags "${linkflags} -sASSERTIONS=1") + endif() + + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3 -ffast-math -frtti -pthread -fexceptions") + set(linkflags "${linkflags} + -sINVOKE_RUN=0 -sEXIT_RUNTIME=1 -sTEXTDECODER=0 -sCASE_INSENSITIVE_FS=1 + -lopenal -lidbfs.js -lwebsocket.js -sEXPORTED_RUNTIME_METHODS=ccall -sEXPORTED_FUNCTIONS=_main,_paste_return + -sINCOMING_MODULE_JS_API=[locateFile,preRun,postRun,print,printErr,canvas,setStatus,monitorRunDependencies] + -sFORCE_FILESYSTEM -sMALLOC=mimalloc -sWEBSOCKET_SUBPROTOCOL=binary -sOFFSCREENCANVAS_SUPPORT=1 + -sOFFSCREEN_FRAMEBUFFER -sENVIRONMENT=web,worker -sPROXY_TO_PTHREAD -sFULL_ES2=1 + -sMIN_WEBGL_VERSION=2 -sMAX_WEBGL_VERSION=2 -sUSE_PTHREADS=1 -sFETCH=1 + -sPTHREAD_POOL_SIZE=navigator.hardwareConcurrency -sALLOW_MEMORY_GROWTH=1 + --preload-file=../otclientrc.lua@otclientrc.lua --preload-file=../init.lua@init.lua + --preload-file=../data@data --preload-file=../mods@mods --preload-file=../modules@modules + --shell-file=../browser/shell.html --use-preload-cache") + set_target_properties(${PROJECT_NAME} PROPERTIES + LINK_FLAGS ${linkflags}) + set(CMAKE_EXECUTABLE_SUFFIX ".html") + set(VCPKG_TARGET_TRIPLET "wasm32-emscripten" CACHE STRING "") + else() # Linux target_include_directories(${PROJECT_NAME} PRIVATE diff --git a/src/client/animatedtext.cpp b/src/client/animatedtext.cpp index 27b394c932..d5632f776d 100644 --- a/src/client/animatedtext.cpp +++ b/src/client/animatedtext.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,11 +21,11 @@ */ #include "animatedtext.h" -#include -#include #include "game.h" -#include "map.h" #include "gameconfig.h" +#include "map.h" +#include +#include AnimatedText::AnimatedText() { diff --git a/src/client/animatedtext.h b/src/client/animatedtext.h index b6ff5af8d2..4ae90aa41c 100644 --- a/src/client/animatedtext.h +++ b/src/client/animatedtext.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -25,15 +25,14 @@ #include "declarations.h" #include #include -#include #include // @bindclass -class AnimatedText : public LuaObject +class AnimatedText final : public LuaObject { public: AnimatedText(); - AnimatedText(const std::string_view text, int color) : AnimatedText() { + AnimatedText(const std::string_view text, const int color) : AnimatedText() { setText(text); setColor(color); } @@ -42,7 +41,7 @@ class AnimatedText : public LuaObject void onAppear(); - void setColor(int color) { m_color = Color::from8bit(color); } + void setColor(const int color) { m_color = Color::from8bit(color); } void setText(const std::string_view text) { m_cachedText.setText(text); } void setOffset(const Point& offset) { m_offset = offset; } diff --git a/src/client/animator.cpp b/src/client/animator.cpp index 1c7d86be9c..a0363835e3 100644 --- a/src/client/animator.cpp +++ b/src/client/animator.cpp @@ -1,5 +1,5 @@ /* -* Copyright (c) 2010-2022 OTClient +* Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -43,7 +43,7 @@ void Animator::unserializeAppearance(const appearances::SpriteAnimation& animati assert(m_startPhase >= -1 && m_startPhase < m_animationPhases); } -void Animator::unserialize(int animationPhases, const FileStreamPtr& fin) +void Animator::unserialize(const int animationPhases, const FileStreamPtr& fin) { m_animationPhases = animationPhases; m_async = fin->getU8() == 0; @@ -77,7 +77,7 @@ void Animator::serialize(const FileStreamPtr& fin) const } } -void Animator::setPhase(int phase) +void Animator::setPhase(const int phase) { if (m_phase == phase) return; @@ -133,7 +133,7 @@ int Animator::getPhase() return m_phase; } -int Animator::getPhaseAt(Timer& timer, float durationFactor) const +int Animator::getPhaseAt(Timer& timer, const float durationFactor) const { const ticks_t time = timer.ticksElapsed(); @@ -195,7 +195,7 @@ int Animator::getLoopPhase() return m_phase; } -int Animator::getPhaseDuration(int phase) const +int Animator::getPhaseDuration(const int phase) const { assert(phase < static_cast(m_phaseDurations.size())); diff --git a/src/client/animator.h b/src/client/animator.h index 5a9d3baeec..cdc86b97f6 100644 --- a/src/client/animator.h +++ b/src/client/animator.h @@ -1,5 +1,5 @@ /* -* Copyright (c) 2010-2022 OTClient +* Copyright (c) 2010-2024 OTClient * * 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/src/client/attachableobject.cpp b/src/client/attachableobject.cpp index 8d796f87cf..7c972925db 100644 --- a/src/client/attachableobject.cpp +++ b/src/client/attachableobject.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,18 +21,18 @@ */ #include "attachableobject.h" -#include #include +#include -#include -#include #include #include +#include + +#include #include "client.h" #include "game.h" #include "map.h" -#include "tile.h" #include "uimap.h" extern ParticleManager g_particles; @@ -55,7 +55,7 @@ void AttachableObject::attachEffect(const AttachedEffectPtr& obj) ++m_ownerHidden; if (obj->getDuration() > 0) { - g_dispatcher.scheduleEvent([self = std::static_pointer_cast(shared_from_this()), effect = obj]() { + g_dispatcher.scheduleEvent([self = std::static_pointer_cast(shared_from_this()), effect = obj] { self->detachEffect(effect); }, obj->getDuration()); } @@ -95,7 +95,7 @@ bool AttachableObject::detachEffectById(uint16_t id) return true; } -void AttachableObject::onDetachEffect(const AttachedEffectPtr& effect, bool callEvent) +void AttachableObject::onDetachEffect(const AttachedEffectPtr& effect, const bool callEvent) { if (effect->isHidedOwner()) --m_ownerHidden; @@ -106,7 +106,7 @@ void AttachableObject::onDetachEffect(const AttachedEffectPtr& effect, bool call effect->callLuaField("onDetach", attachedObjectToLuaObject()); } -void AttachableObject::clearAttachedEffects(bool ignoreLuaEvent) +void AttachableObject::clearAttachedEffects(const bool ignoreLuaEvent) { if (!hasAttachedEffects()) return; for (const auto& e : m_data->attachedEffects) @@ -117,27 +117,27 @@ void AttachableObject::clearAttachedEffects(bool ignoreLuaEvent) void AttachableObject::clearTemporaryAttachedEffects() { if (!hasAttachedEffects()) return; - m_data->attachedEffects.erase(std::remove_if(m_data->attachedEffects.begin(), m_data->attachedEffects.end(), - [this](const AttachedEffectPtr& obj) { + std::erase_if(m_data->attachedEffects, + [this](const AttachedEffectPtr& obj) { if (!obj->isPermanent()) { onDetachEffect(obj); return true; } return false; - }), m_data->attachedEffects.end()); + }); } void AttachableObject::clearPermanentAttachedEffects() { if (!hasAttachedEffects()) return; - m_data->attachedEffects.erase(std::remove_if(m_data->attachedEffects.begin(), m_data->attachedEffects.end(), - [this](const AttachedEffectPtr& obj) { + std::erase_if(m_data->attachedEffects, + [this](const AttachedEffectPtr& obj) { if (obj->isPermanent()) { onDetachEffect(obj); return true; } return false; - }), m_data->attachedEffects.end()); + }); } AttachedEffectPtr AttachableObject::getAttachedEffectById(uint16_t id) @@ -152,13 +152,13 @@ AttachedEffectPtr AttachableObject::getAttachedEffectById(uint16_t id) return *it; } -void AttachableObject::drawAttachedEffect(const Point& dest, const LightViewPtr& lightView, bool isOnTop) +void AttachableObject::drawAttachedEffect(const Point& dest, const LightViewPtr& lightView, const bool isOnTop) { if (!hasAttachedEffects()) return; for (const auto& effect : m_data->attachedEffects) { effect->draw(dest, isOnTop, lightView); if (effect->getLoop() == 0) { - g_dispatcher.addEvent([self = std::static_pointer_cast(shared_from_this()), effect]() { + g_dispatcher.addEvent([self = std::static_pointer_cast(shared_from_this()), effect] { self->detachEffect(effect); }); } @@ -228,7 +228,7 @@ void AttachableObject::updateAndAttachParticlesEffects(std::vector& toRemove.reserve(m_data->attachedParticles.size()); for (const auto& effect : m_data->attachedParticles) { - auto findPos = std::find(newElements.begin(), newElements.end(), effect->getEffectType()->getName()); + auto findPos = std::ranges::find(newElements, effect->getEffectType()->getName()); if (findPos == newElements.end()) toRemove.emplace_back(effect->getEffectType()->getName()); else @@ -262,7 +262,7 @@ void AttachableObject::attachWidget(const UIWidgetPtr& widget) { getData()->attachedWidgets.emplace_back(widget); g_map.addAttachedWidgetToObject(widget, std::static_pointer_cast(shared_from_this())); widget->callLuaField("onAttached", asLuaObject()); - widget->addOnDestroyCallback("attached-widget-destroy", [this, widget]() { + widget->addOnDestroyCallback("attached-widget-destroy", [this, widget] { detachWidget(widget); }); } @@ -301,12 +301,12 @@ bool AttachableObject::detachWidget(const UIWidgetPtr widget) return true; } -void AttachableObject::clearAttachedWidgets(bool callEvent) +void AttachableObject::clearAttachedWidgets(const bool callEvent) { if (!hasAttachedWidgets()) return; // keep the same behavior as detachWidget - auto oldList = std::move(m_data->attachedWidgets); + const auto oldList = std::move(m_data->attachedWidgets); m_data->attachedWidgets.clear(); for (const auto& widget : oldList) { diff --git a/src/client/attachableobject.h b/src/client/attachableobject.h index 35c880ddc0..185ec03562 100644 --- a/src/client/attachableobject.h +++ b/src/client/attachableobject.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -31,7 +31,7 @@ class AttachableObject : public LuaObject { public: AttachableObject() = default; - virtual ~AttachableObject(); + ~AttachableObject() override; virtual LuaObjectPtr attachedObjectToLuaObject() = 0; virtual bool isTile() { return false; } @@ -45,9 +45,9 @@ class AttachableObject : public LuaObject bool detachEffect(const AttachedEffectPtr& obj); AttachedEffectPtr getAttachedEffectById(uint16_t id); - virtual void onStartAttachEffect(const AttachedEffectPtr& /*effect*/) { }; - virtual void onDispatcherAttachEffect(const AttachedEffectPtr& /*effect*/) { }; - virtual void onStartDetachEffect(const AttachedEffectPtr& /*effect*/) { }; + virtual void onStartAttachEffect(const AttachedEffectPtr& /*effect*/) {}; + virtual void onDispatcherAttachEffect(const AttachedEffectPtr& /*effect*/) {}; + virtual void onStartDetachEffect(const AttachedEffectPtr& /*effect*/) {}; bool isOwnerHidden() { return m_ownerHidden > 0; } @@ -67,7 +67,7 @@ class AttachableObject : public LuaObject void attachWidget(const UIWidgetPtr& widget); void clearAttachedWidgets(bool callEvent = true); bool detachWidgetById(const std::string& id); - bool detachWidget(const UIWidgetPtr widget); + bool detachWidget(UIWidgetPtr widget); UIWidgetPtr getAttachedWidgetById(const std::string& id); protected: @@ -84,7 +84,7 @@ class AttachableObject : public LuaObject void onDetachEffect(const AttachedEffectPtr& effect, bool callEvent = true); void drawAttachedParticlesEffect(const Point& dest); - inline auto getData() { + auto getData() { if (!m_data) m_data = std::make_shared(); return m_data; diff --git a/src/client/attachedeffect.cpp b/src/client/attachedeffect.cpp index ca65cab747..f39e709962 100644 --- a/src/client/attachedeffect.cpp +++ b/src/client/attachedeffect.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -25,11 +25,11 @@ #include "lightview.h" #include -#include #include #include +#include -AttachedEffectPtr AttachedEffect::create(uint16_t thingId, ThingCategory category) { +AttachedEffectPtr AttachedEffect::create(const uint16_t thingId, const ThingCategory category) { if (!g_things.isValidDatId(thingId, category)) { g_logger.error(stdext::format("AttachedEffectManager::getInstance(%d, %d): invalid thing with id or category.", thingId, static_cast(category))); return nullptr; @@ -71,7 +71,7 @@ int getBounce(const AttachedEffect::Bounce bounce, const ticks_t ticks) { return minHeight + (height - std::abs(height - static_cast(ticks / (bounce.speed / 100.f)) % static_cast(height * 2))); } -void AttachedEffect::draw(const Point& dest, bool isOnTop, const LightViewPtr& lightView, const bool drawThing) { +void AttachedEffect::draw(const Point& dest, const bool isOnTop, const LightViewPtr& lightView, const bool drawThing) { if (m_transform) return; diff --git a/src/client/attachedeffect.h b/src/client/attachedeffect.h index a2066d1763..d28035211d 100644 --- a/src/client/attachedeffect.h +++ b/src/client/attachedeffect.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -22,15 +22,15 @@ #pragma once -#include "thingtype.h" #include "outfit.h" +#include "thingtype.h" -class AttachedEffect : public LuaObject +class AttachedEffect final : public LuaObject { public: static AttachedEffectPtr create(uint16_t thingId, ThingCategory category); - void draw(const Point& /*dest*/, bool /*isOnTop*/, const LightViewPtr & = nullptr, const bool drawThing = true); + void draw(const Point& /*dest*/, bool /*isOnTop*/, const LightViewPtr & = nullptr, bool drawThing = true); void drawLight(const Point& /*dest*/, const LightViewPtr&); uint16_t getId() { return m_id; } @@ -38,31 +38,31 @@ class AttachedEffect : public LuaObject AttachedEffectPtr clone(); float getSpeed() { return m_speed / 100.f; } - void setSpeed(float speed) { m_speed = speed * 100u; } + void setSpeed(const float speed) { m_speed = speed * 100u; } float getOpacity() { return m_opacity / 100.f; } - void setOpacity(float opacity) { m_opacity = opacity * 100u; } + void setOpacity(const float opacity) { m_opacity = opacity * 100u; } Size getSize() { return m_size; } void setSize(const Size& s) { m_size = s; } bool isHidedOwner() { return m_hideOwner; } - void setHideOwner(bool v) { m_hideOwner = v; } + void setHideOwner(const bool v) { m_hideOwner = v; } bool isTransform() { return m_transform; } - void setTransform(bool v) { m_transform = v; } + void setTransform(const bool v) { m_transform = v; } bool isDisabledWalkAnimation() { return m_disableWalkAnimation; } - void setDisableWalkAnimation(bool v) { m_disableWalkAnimation = v; } + void setDisableWalkAnimation(const bool v) { m_disableWalkAnimation = v; } bool isPermanent() { return m_permanent; } - void setPermanent(bool permanent) { m_permanent = permanent; } + void setPermanent(const bool permanent) { m_permanent = permanent; } uint16_t getDuration() { return m_duration; } - void setDuration(uint16_t v) { m_duration = v; } + void setDuration(const uint16_t v) { m_duration = v; } int8_t getLoop() { return m_loop; } - void setLoop(int8_t v) { m_loop = v; } + void setLoop(const int8_t v) { m_loop = v; } void setName(std::string_view n) { m_name = { n.data() }; } std::string getName() { return m_name; } @@ -70,17 +70,37 @@ class AttachedEffect : public LuaObject Otc::Direction getDirection() { return m_direction; } void setDirection(const Otc::Direction dir) { m_direction = std::min(dir, Otc::NorthWest); } - void setBounce(uint8_t minHeight, uint8_t height, uint16_t speed) { m_bounce = { minHeight, height , speed }; } - void setPulse(uint8_t minHeight, uint8_t height, uint16_t speed) { m_pulse = { minHeight, height , speed }; } - void setFade(uint8_t start, uint8_t end, uint16_t speed) { m_fade = { start, end , speed }; } - - void setOnTop(bool onTop) { for (auto& control : m_offsetDirections) control.onTop = onTop; } + void setBounce(const uint8_t minHeight, const uint8_t height, const uint16_t speed) { + m_bounce = { .minHeight = +minHeight, +.height = height, .speed = speed + }; + } + void setPulse(const uint8_t minHeight, const uint8_t height, const uint16_t speed) { + m_pulse = { .minHeight = +minHeight, +.height = height, .speed = speed + }; + } + void setFade(const uint8_t start, const uint8_t end, const uint16_t speed) { + m_fade = { .minHeight = start, .height = +end, +.speed = speed + }; + } + + void setOnTop(const bool onTop) { for (auto& control : m_offsetDirections) control.onTop = onTop; } void setOffset(int16_t x, int16_t y) { for (auto& control : m_offsetDirections) control.offset = { x, y }; } - void setOnTopByDir(Otc::Direction direction, bool onTop) { m_offsetDirections[direction].onTop = onTop; } - - void setDirOffset(Otc::Direction direction, int8_t x, int8_t y, bool onTop = false) { m_offsetDirections[direction] = { onTop, {x, y} }; } - void setShader(const std::string_view name); - void setCanDrawOnUI(bool canDraw) { m_canDrawOnUI = canDraw; } + void setOnTopByDir(const Otc::Direction direction, const bool onTop) { m_offsetDirections[direction].onTop = onTop; } + + void setDirOffset(const Otc::Direction direction, int8_t x, int8_t y, const bool onTop = false) { + m_offsetDirections[direction] = { .onTop = +onTop, +.offset = {x, y} + }; + } + void setShader(std::string_view name); + void setCanDrawOnUI(const bool canDraw) { m_canDrawOnUI = canDraw; } bool canDrawOnUI() { return m_canDrawOnUI; } void move(const Position& fromPosition, const Position& toPosition); @@ -88,7 +108,7 @@ class AttachedEffect : public LuaObject void attachEffect(const AttachedEffectPtr& e) { m_effects.emplace_back(e); } DrawOrder getDrawOrder() { return m_drawOrder; } - void setDrawOrder(DrawOrder drawOrder) { m_drawOrder = drawOrder; } + void setDrawOrder(const DrawOrder drawOrder) { m_drawOrder = drawOrder; } const Light& getLight() const { return m_light; } void setLight(const Light& light) { m_light = light; } @@ -99,7 +119,7 @@ class AttachedEffect : public LuaObject uint8_t minHeight{ 0 }; uint8_t height{ 0 }; uint16_t speed{ 0 }; - Timer timer; + Timer timer{}; }; private: @@ -116,7 +136,7 @@ class AttachedEffect : public LuaObject uint8_t m_speed{ 100 }; uint8_t m_opacity{ 100 }; uint8_t m_lastAnimation{ 0 }; - DrawOrder m_drawOrder{ DrawOrder::FIRST }; + DrawOrder m_drawOrder{ FIRST }; uint16_t m_id{ 0 }; uint16_t m_duration{ 0 }; diff --git a/src/client/attachedeffectmanager.cpp b/src/client/attachedeffectmanager.cpp index 3449e563e2..af88cc16e1 100644 --- a/src/client/attachedeffectmanager.cpp +++ b/src/client/attachedeffectmanager.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -23,19 +23,18 @@ #include "attachedeffectmanager.h" #include "attachedeffect.h" #include "thingtypemanager.h" -#include "spritemanager.h" #include AttachedEffectManager g_attachedEffects; -AttachedEffectPtr AttachedEffectManager::getById(uint16_t id) { +AttachedEffectPtr AttachedEffectManager::getById(const uint16_t id) { const auto it = m_effects.find(id); if (it == m_effects.end()) { g_logger.error(stdext::format("AttachedEffectManager::getById(%d): not found.", id)); return nullptr; } - const auto& obj = (*it).second; + const auto& obj = it->second; if (obj->m_thingId > 0 && !g_things.isValidDatId(obj->m_thingId, obj->m_thingCategory)) { g_logger.error(stdext::format("AttachedEffectManager::getById(%d): invalid thing with id %d.", id, obj->m_thingId)); return nullptr; @@ -44,7 +43,7 @@ AttachedEffectPtr AttachedEffectManager::getById(uint16_t id) { return obj->clone(); } -AttachedEffectPtr AttachedEffectManager::registerByThing(uint16_t id, const std::string_view name, uint16_t thingId, ThingCategory category) { +AttachedEffectPtr AttachedEffectManager::registerByThing(uint16_t id, const std::string_view name, const uint16_t thingId, const ThingCategory category) { const auto it = m_effects.find(id); if (it != m_effects.end()) { g_logger.error(stdext::format("AttachedEffectManager::registerByThing(%d, %s): has already been registered.", id, name)); @@ -62,7 +61,7 @@ AttachedEffectPtr AttachedEffectManager::registerByThing(uint16_t id, const std: return obj; } -AttachedEffectPtr AttachedEffectManager::registerByImage(uint16_t id, const std::string_view name, const std::string_view path, bool smooth) { +AttachedEffectPtr AttachedEffectManager::registerByImage(uint16_t id, const std::string_view name, const std::string_view path, const bool smooth) { const auto it = m_effects.find(id); if (it != m_effects.end()) { g_logger.error(stdext::format("AttachedEffectManager::registerByImage(%d, %s): has already been registered.", id, name)); diff --git a/src/client/attachedeffectmanager.h b/src/client/attachedeffectmanager.h index 000d8a81b5..b910d3c80e 100644 --- a/src/client/attachedeffectmanager.h +++ b/src/client/attachedeffectmanager.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -28,11 +28,11 @@ class AttachedEffectManager { public: - AttachedEffectPtr registerByThing(uint16_t id, const std::string_view name, uint16_t thingId, ThingCategory category); - AttachedEffectPtr registerByImage(uint16_t id, const std::string_view name, const std::string_view path, bool smooth); + AttachedEffectPtr registerByThing(uint16_t id, std::string_view name, uint16_t thingId, ThingCategory category); + AttachedEffectPtr registerByImage(uint16_t id, std::string_view name, std::string_view path, bool smooth); AttachedEffectPtr getById(uint16_t id); - void remove(uint16_t id) { m_effects.erase(id); } + void remove(const uint16_t id) { m_effects.erase(id); } void clear() { m_effects.clear(); } private: diff --git a/src/client/client.cpp b/src/client/client.cpp index 20b6776ca8..2503240b3d 100644 --- a/src/client/client.cpp +++ b/src/client/client.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -22,19 +22,17 @@ #include "client.h" #include "game.h" +#include "gameconfig.h" #include "map.h" -#include "uimap.h" #include "minimap.h" #include "spriteappearances.h" #include "spritemanager.h" -#include "gameconfig.h" +#include "uimap.h" -#include -#include #include -#include +#include #include -#include +#include Client g_client; @@ -77,7 +75,7 @@ void Client::preLoad() { } } -void Client::draw(DrawPoolType type) +void Client::draw(const DrawPoolType type) { if (!g_game.isOnline()) { m_mapWidget = nullptr; @@ -96,7 +94,7 @@ void Client::draw(DrawPoolType type) m_mapWidget->draw(type); } -bool Client::canDraw(DrawPoolType type) const +bool Client::canDraw(const DrawPoolType type) const { switch (type) { case DrawPoolType::FOREGROUND: diff --git a/src/client/client.h b/src/client/client.h index 210aafb73d..bdfd0cf20b 100644 --- a/src/client/client.h +++ b/src/client/client.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -26,7 +26,6 @@ #include "uimap.h" -#include #include class Client : public ApplicationDrawEvents @@ -49,10 +48,10 @@ class Client : public ApplicationDrawEvents UIMapPtr getMapWidget() { return m_mapWidget; } float getEffectAlpha() const { return m_effectAlpha; } - void setEffectAlpha(float v) { m_effectAlpha = v; } + void setEffectAlpha(const float v) { m_effectAlpha = v; } float getMissileAlpha() const { return m_missileAlpha; } - void setMissileAlpha(float v) { m_missileAlpha = v; } + void setMissileAlpha(const float v) { m_missileAlpha = v; } private: UIMapPtr m_mapWidget; diff --git a/src/client/const.h b/src/client/const.h index 66a82f1821..7fce38ee29 100644 --- a/src/client/const.h +++ b/src/client/const.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -761,8 +761,8 @@ namespace Otc INSPECT_NPCTRADE = 1, INSPECT_PLAYERTRADE = 2, INSPECT_CYCLOPEDIA = 3 - }; - + }; + enum GameStoreInfoType_t : uint8_t { SHOW_NONE = 0, diff --git a/src/client/container.cpp b/src/client/container.cpp index 7295816690..31fc994de4 100644 --- a/src/client/container.cpp +++ b/src/client/container.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -23,7 +23,7 @@ #include "container.h" #include "item.h" -ItemPtr Container::getItem(int slot) +ItemPtr Container::getItem(const int slot) { if (slot < 0 || slot >= static_cast(m_items.size())) return nullptr; @@ -62,7 +62,7 @@ void Container::onAddItem(const ItemPtr& item, int slot) callLuaField("onAddItem", slot, item); } -ItemPtr Container::findItemById(uint32_t itemId, int subType) const +ItemPtr Container::findItemById(const uint32_t itemId, const int subType) const { for (const auto& item : m_items) if (item->getId() == itemId && (subType == -1 || item->getSubType() == subType)) diff --git a/src/client/container.h b/src/client/container.h index d99eb1000d..5bd51e2207 100644 --- a/src/client/container.h +++ b/src/client/container.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -28,14 +28,14 @@ #include // @bindclass -class Container : public LuaObject +class Container final : public LuaObject { public: ItemPtr getItem(int slot); std::deque getItems() { return m_items; } int getItemsCount() { return m_items.size(); } - Position getSlotPosition(int slot) { return { 0xffff, m_id | 0x40, static_cast(slot) }; } + Position getSlotPosition(const int slot) { return { 0xffff, m_id | 0x40, static_cast(slot) }; } int getId() { return m_id; } int getCapacity() { return m_capacity; } ItemPtr getContainerItem() { return m_containerItem; } @@ -49,9 +49,10 @@ class Container : public LuaObject ItemPtr findItemById(uint32_t itemId, int subType) const; protected: - Container(uint8_t id, uint8_t capacity, const std::string_view name, const ItemPtr& containerItem, bool hasParent, bool isUnlocked, bool hasPages, uint16_t containerSize, uint16_t firstIndex) - :m_id(id), m_capacity(capacity), m_containerItem(containerItem), m_name(name), m_hasParent(hasParent), m_unlocked(isUnlocked), m_hasPages(hasPages), m_size(containerSize), m_firstIndex(firstIndex) - {} + Container(const uint8_t id, const uint8_t capacity, const std::string_view name, ItemPtr containerItem, const bool hasParent, const bool isUnlocked, const bool hasPages, const uint16_t containerSize, const uint16_t firstIndex) + :m_id(id), m_capacity(capacity), m_containerItem(std::move(containerItem)), m_name(name), m_hasParent(hasParent), m_unlocked(isUnlocked), m_hasPages(hasPages), m_size(containerSize), m_firstIndex(firstIndex) + { + } void onOpen(const ContainerPtr& previousContainer); void onClose(); diff --git a/src/client/creature.cpp b/src/client/creature.cpp index c6bc9ae447..404ca37262 100644 --- a/src/client/creature.cpp +++ b/src/client/creature.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -28,15 +28,13 @@ #include "map.h" #include "thingtypemanager.h" #include "tile.h" -#include "statictext.h" #include #include #include #include -#include -#include #include +#include #include double Creature::speedA = 0; @@ -58,7 +56,7 @@ void Creature::onCreate() { callLuaField("onCreate"); } -void Creature::draw(const Point& dest, bool drawThings, const LightViewPtr& /*lightView*/) +void Creature::draw(const Point& dest, const bool drawThings, const LightViewPtr& /*lightView*/) { if (!canBeSeen() || !canDraw()) return; @@ -105,7 +103,7 @@ void Creature::drawLight(const Point& dest, const LightViewPtr& lightView) { drawAttachedLightEffect(dest + m_walkOffset * g_drawPool.getScaleFactor(), lightView); } -void Creature::draw(const Rect& destRect, uint8_t size, bool center) +void Creature::draw(const Rect& destRect, const uint8_t size, const bool center) { if (!getThingType()) return; @@ -127,7 +125,7 @@ void Creature::draw(const Rect& destRect, uint8_t size, bool center) } g_drawPool.releaseFrameBuffer(destRect); } -void Creature::drawInformation(const MapPosInfo& mapRect, const Point& dest, int drawFlags) +void Creature::drawInformation(const MapPosInfo& mapRect, const Point& dest, const int drawFlags) { static const Color DEFAULT_COLOR(96, 96, 96), @@ -168,7 +166,7 @@ void Creature::drawInformation(const MapPosInfo& mapRect, const Point& dest, int const int cropSizeText = g_gameConfig.isAdjustCreatureInformationBasedCropSize() ? getExactSize() : 12; const int cropSizeBackGround = g_gameConfig.isAdjustCreatureInformationBasedCropSize() ? cropSizeText - nameSize.height() : 0; - bool isScaled = g_app.getCreatureInformationScale() != PlatformWindow::DEFAULT_DISPLAY_DENSITY; + const bool isScaled = g_app.getCreatureInformationScale() != PlatformWindow::DEFAULT_DISPLAY_DENSITY; if (isScaled) { p.scale(g_app.getCreatureInformationScale()); } @@ -255,7 +253,7 @@ void Creature::internalDraw(Point dest, const Color& color) m_shader->setUniformValue(ShaderManager::OUTFIT_ID_UNIFORM, id); };*/ - bool replaceColorShader = color != Color::white; + const bool replaceColorShader = color != Color::white; if (replaceColorShader) g_drawPool.setShaderProgram(g_painter->getReplaceColorShader()); else @@ -362,7 +360,7 @@ void Creature::internalDraw(Point dest, const Color& color) } } -void Creature::turn(Otc::Direction direction) +void Creature::turn(const Otc::Direction direction) { // schedules to set the new direction when walk ends if (m_walking) { @@ -392,9 +390,6 @@ void Creature::walk(const Position& oldPos, const Position& newPos) m_walkTimer.restart(); m_walkedPixels = 0; - if (++m_walkSteps == 0) - m_walkSteps = 1; - // no direction need to be changed when the walk ends m_walkTurnDirection = Otc::InvalidDirection; @@ -416,7 +411,7 @@ void Creature::stopWalk() terminateWalk(); } -void Creature::jump(int height, int duration) +void Creature::jump(const int height, const int duration) { if (!m_jumpOffset.isNull()) return; @@ -561,7 +556,7 @@ void Creature::updateWalkAnimation() return; int minFootDelay = 20; - int maxFootDelay = footAnimPhases > 2 ? 80 : 205; + const int maxFootDelay = footAnimPhases > 2 ? 80 : 205; int footAnimDelay = footAnimPhases; if (g_game.getFeature(Otc::GameEnhancedAnimations) && footAnimPhases > 2) { @@ -581,7 +576,7 @@ void Creature::updateWalkAnimation() } } -void Creature::updateWalkOffset(uint8_t totalPixelsWalked) +void Creature::updateWalkOffset(const uint8_t totalPixelsWalked) { m_walkOffset = {}; if (m_direction == Otc::North || m_direction == Otc::NorthEast || m_direction == Otc::NorthWest) @@ -701,13 +696,12 @@ void Creature::terminateWalk() const auto self = static_self_cast(); m_walkFinishAnimEvent = g_dispatcher.scheduleEvent([self] { - self->m_walkSteps = 0; self->m_walkAnimationPhase = 0; self->m_walkFinishAnimEvent = nullptr; }, g_game.getServerBeat()); } -void Creature::setHealthPercent(uint8_t healthPercent) +void Creature::setHealthPercent(const uint8_t healthPercent) { static const Color COLOR1(0x00, 0xBC, 0x00), @@ -741,7 +735,7 @@ void Creature::setHealthPercent(uint8_t healthPercent) onDeath(); } -void Creature::setDirection(Otc::Direction direction) +void Creature::setDirection(const Otc::Direction direction) { if (direction == Otc::InvalidDirection) return; @@ -817,7 +811,7 @@ void Creature::setSpeed(uint16_t speed) callLuaField("onSpeedChange", m_speed, oldSpeed); } -void Creature::setBaseSpeed(uint16_t baseSpeed) +void Creature::setBaseSpeed(const uint16_t baseSpeed) { if (m_baseSpeed == baseSpeed) return; @@ -828,18 +822,18 @@ void Creature::setBaseSpeed(uint16_t baseSpeed) callLuaField("onBaseSpeedChange", baseSpeed, oldBaseSpeed); } -void Creature::setType(uint8_t v) { if (m_type != v) callLuaField("onTypeChange", m_type = v); } -void Creature::setIcon(uint8_t v) { if (m_icon != v) callLuaField("onIconChange", m_icon = v); } -void Creature::setSkull(uint8_t v) { if (m_skull != v) callLuaField("onSkullChange", m_skull = v); } -void Creature::setShield(uint8_t v) { if (m_shield != v) callLuaField("onShieldChange", m_shield = v); } -void Creature::setEmblem(uint8_t v) { if (m_emblem != v) callLuaField("onEmblemChange", m_emblem = v); } +void Creature::setType(const uint8_t v) { if (m_type != v) callLuaField("onTypeChange", m_type = v); } +void Creature::setIcon(const uint8_t v) { if (m_icon != v) callLuaField("onIconChange", m_icon = v); } +void Creature::setSkull(const uint8_t v) { if (m_skull != v) callLuaField("onSkullChange", m_skull = v); } +void Creature::setShield(const uint8_t v) { if (m_shield != v) callLuaField("onShieldChange", m_shield = v); } +void Creature::setEmblem(const uint8_t v) { if (m_emblem != v) callLuaField("onEmblemChange", m_emblem = v); } void Creature::setTypeTexture(const std::string& filename) { m_typeTexture = g_textures.getTexture(filename); } void Creature::setIconTexture(const std::string& filename) { m_iconTexture = g_textures.getTexture(filename); } void Creature::setSkullTexture(const std::string& filename) { m_skullTexture = g_textures.getTexture(filename); } void Creature::setEmblemTexture(const std::string& filename) { m_emblemTexture = g_textures.getTexture(filename); } -void Creature::setShieldTexture(const std::string& filename, bool blink) +void Creature::setShieldTexture(const std::string& filename, const bool blink) { m_shieldTexture = g_textures.getTexture(filename); m_showShieldTexture = true; @@ -854,7 +848,7 @@ void Creature::setShieldTexture(const std::string& filename, bool blink) m_shieldBlink = blink; } -void Creature::addTimedSquare(uint8_t color) +void Creature::addTimedSquare(const uint8_t color) { m_showTimedSquare = true; m_timedSquareColor = Color::from8bit(color != 0 ? color : 1); @@ -879,7 +873,7 @@ void Creature::updateShield() m_showShieldTexture = true; } -int getSmoothedElevation(const Creature* creature, int currentElevation, float factor) { +int getSmoothedElevation(const Creature* creature, const int currentElevation, const float factor) { const auto& fromPos = creature->getLastStepFromPosition(); const auto& toPos = creature->getLastStepToPosition(); const auto& fromTile = g_map.getTile(fromPos); @@ -912,7 +906,7 @@ int Creature::getDrawElevation() { bool Creature::hasSpeedFormula() { return g_game.getFeature(Otc::GameNewSpeedLaw) && speedA != 0 && speedB != 0 && speedC != 0; } -uint16_t Creature::getStepDuration(bool ignoreDiagonal, Otc::Direction dir) +uint16_t Creature::getStepDuration(const bool ignoreDiagonal, const Otc::Direction dir) { if (m_speed < 1) return 0; @@ -1064,7 +1058,7 @@ void Creature::setTypingIconTexture(const std::string& filename) m_typingIconTexture = g_textures.getTexture(filename); } -void Creature::setTyping(bool typing) +void Creature::setTyping(const bool typing) { m_typing = typing; } @@ -1111,7 +1105,7 @@ void Creature::onStartDetachEffect(const AttachedEffectPtr& effect) { } } -void Creature::setStaticWalking(uint16_t v) { +void Creature::setStaticWalking(const uint16_t v) { if (m_walkUpdateEvent) { m_walkUpdateEvent->cancel(); m_walkUpdateEvent = nullptr; diff --git a/src/client/creature.h b/src/client/creature.h index 195be8a168..c1feb01661 100644 --- a/src/client/creature.h +++ b/src/client/creature.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -22,16 +22,15 @@ #pragma once -#include -#include -#include #include "mapview.h" #include "outfit.h" #include "thing.h" +#include +#include +#include struct PreyMonster { -public: std::string name; Outfit outfit; }; @@ -45,7 +44,7 @@ class Creature : public Thing static double speedC; Creature(); - ~Creature(); + ~Creature() override; static bool hasSpeedFormula(); @@ -61,9 +60,9 @@ class Creature : public Thing void internalDraw(Point dest, const Color& color = Color::white); void drawInformation(const MapPosInfo& mapRect, const Point& dest, int drawFlags); - void setId(uint32_t id) override { m_id = id; } - void setMasterId(uint32_t id) { m_masterId = id; } - void setName(const std::string_view name); + void setId(const uint32_t id) override { m_id = id; } + void setMasterId(const uint32_t id) { m_masterId = id; } + void setName(std::string_view name); void setHealthPercent(uint8_t healthPercent); void setDirection(Otc::Direction direction); void setOutfit(const Outfit& outfit); @@ -80,8 +79,8 @@ class Creature : public Thing void setEmblemTexture(const std::string& filename); void setTypeTexture(const std::string& filename); void setIconTexture(const std::string& filename); - void setPassable(bool passable) { m_passable = passable; } - void setMountShader(const std::string_view name); + void setPassable(const bool passable) { m_passable = passable; } + void setMountShader(std::string_view name); void setStaticWalking(uint16_t v); void onStartAttachEffect(const AttachedEffectPtr& effect) override; @@ -94,8 +93,6 @@ class Creature : public Thing void hideStaticSquare() { m_showStaticSquare = false; } // walk related - int getWalkSteps() const { return m_walkSteps; } - void setWalkSteps(uint8_t step) { m_walkSteps = step; } void turn(Otc::Direction direction); void jump(int height, int duration); void allowAppearWalk() { m_allowAppearWalk = true; } @@ -162,7 +159,7 @@ class Creature : public Thing void setCovered(bool covered); bool isDisabledWalkAnimation() { return m_disableWalkAnimation > 0; } - void setDisableWalkAnimation(bool v) { + void setDisableWalkAnimation(const bool v) { if (v) ++m_disableWalkAnimation; else { if (m_disableWalkAnimation <= 1) m_disableWalkAnimation = 0; else --m_disableWalkAnimation; @@ -173,7 +170,12 @@ class Creature : public Thing void sendTyping(); bool getTyping() { return m_typing; } void setTypingIconTexture(const std::string& filename); - void setBounce(uint8_t minHeight, uint8_t height, uint16_t speed) { m_bounce = { minHeight, height , speed }; } + void setBounce(const uint8_t minHeight, const uint8_t height, const uint16_t speed) { + m_bounce = { .minHeight = +minHeight, +.height = height, .speed = speed + }; + } void setWidgetInformation(const UIWidgetPtr& info); UIWidgetPtr getWidgetInformation() { return m_widgetInformation; } @@ -221,7 +223,7 @@ class Creature : public Thing uint16_t walkDuration{ 0 }; uint16_t diagonalDuration{ 0 }; - uint16_t getDuration(Otc::Direction dir) const { return Position::isDiagonal(dir) ? diagonalDuration : duration; } + uint16_t getDuration(const Otc::Direction dir) const { return Position::isDiagonal(dir) ? diagonalDuration : duration; } }; UIWidgetPtr m_widgetInformation; @@ -294,8 +296,6 @@ class Creature : public Thing uint8_t m_disableWalkAnimation{ 0 }; - uint8_t m_walkSteps{ 0 }; - // Mount Shader uint8_t m_mountShaderId{ 0 }; @@ -320,14 +320,14 @@ class Creature : public Thing }; // @bindclass -class Npc : public Creature +class Npc final : public Creature { public: bool isNpc() override { return true; } }; // @bindclass -class Monster : public Creature +class Monster final : public Creature { public: bool isMonster() override { return true; } diff --git a/src/client/creatures.cpp b/src/client/creatures.cpp index fbbca0a689..46d2b31532 100644 --- a/src/client/creatures.cpp +++ b/src/client/creatures.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * 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/src/client/creatures.h b/src/client/creatures.h index b23802dc17..e9aacdae5c 100644 --- a/src/client/creatures.h +++ b/src/client/creatures.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * 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/src/client/declarations.h b/src/client/declarations.h index 755a029fae..b5061e033f 100644 --- a/src/client/declarations.h +++ b/src/client/declarations.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -22,9 +22,9 @@ #pragma once +#include "global.h" #include #include -#include "global.h" // core class Map; diff --git a/src/client/effect.cpp b/src/client/effect.cpp index 54ddcf2154..517f7474bc 100644 --- a/src/client/effect.cpp +++ b/src/client/effect.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,13 +21,13 @@ */ #include "effect.h" -#include -#include #include "game.h" #include "map.h" #include +#include +#include -void Effect::draw(const Point& dest, bool drawThings, const LightViewPtr& lightView) +void Effect::draw(const Point& dest, const bool drawThings, const LightViewPtr& lightView) { if (!canDraw() || isHided()) return; @@ -57,11 +57,11 @@ void Effect::draw(const Point& dest, bool drawThings, const LightViewPtr& lightV const int offsetX = m_position.x - g_map.getCentralPosition().x; const int offsetY = m_position.y - g_map.getCentralPosition().y; - int xPattern = unsigned(offsetX) % getNumPatternX(); + int xPattern = static_cast(offsetX) % getNumPatternX(); xPattern = 1 - xPattern - getNumPatternX(); if (xPattern < 0) xPattern += getNumPatternX(); - int yPattern = unsigned(offsetY) % getNumPatternY(); + int yPattern = static_cast(offsetY) % getNumPatternY(); if (g_game.getFeature(Otc::GameMapOldEffectRendering)) { xPattern = offsetX % getNumPatternX(); @@ -76,7 +76,7 @@ void Effect::draw(const Point& dest, bool drawThings, const LightViewPtr& lightV if (g_drawPool.getCurrentType() == DrawPoolType::MAP) { if (g_app.isDrawingEffectsOnTop() && !m_drawConductor.agroup) { m_drawConductor.agroup = true; - m_drawConductor.order = DrawOrder::FOURTH; + m_drawConductor.order = FOURTH; } if (drawThings && g_client.getEffectAlpha() < 1.f) @@ -126,7 +126,7 @@ bool Effect::waitFor(const EffectPtr& effect) return true; } -void Effect::setId(uint32_t id) +void Effect::setId(const uint32_t id) { if (!g_things.isValidDatId(id, ThingCategoryEffect)) return; @@ -134,7 +134,7 @@ void Effect::setId(uint32_t id) m_clientId = id; } -void Effect::setPosition(const Position& position, uint8_t stackPos, bool hasElevation) +void Effect::setPosition(const Position& position, const uint8_t stackPos, const bool hasElevation) { if (m_clientId == 0) return; diff --git a/src/client/effect.h b/src/client/effect.h index afb1850759..ab991149d3 100644 --- a/src/client/effect.h +++ b/src/client/effect.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -22,12 +22,11 @@ #pragma once -#include -#include #include "thing.h" +#include - // @bindclass -class Effect : public Thing +// @bindclass +class Effect final : public Thing { public: void draw(const Point& /*dest*/, bool drawThings = true, const LightViewPtr & = nullptr) override; diff --git a/src/client/game.cpp b/src/client/game.cpp index 28cad81b75..7f7ac58c48 100644 --- a/src/client/game.cpp +++ b/src/client/game.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,8 +21,6 @@ */ #include "game.h" -#include -#include #include "container.h" #include "creature.h" #include "localplayer.h" @@ -30,9 +28,11 @@ #include "map.h" #include "protocolcodes.h" #include "protocolgame.h" +#include +#include -#include "tile.h" #include "framework/core/graphicalapplication.h" +#include "tile.h" Game g_game; @@ -384,7 +384,7 @@ void Game::processVipStateChange(const uint32_t id, const uint32_t status) g_lua.callGlobalField("g_game", "onVipStateChange", id, status, groupID); } -void Game::processVipGroupChange(const std::vector>& vipGroups, uint8_t groupsAmountLeft) +void Game::processVipGroupChange(const std::vector>& vipGroups, const uint8_t groupsAmountLeft) { g_lua.callGlobalField("g_game", "onVipGroupChange", vipGroups, groupsAmountLeft); } @@ -478,7 +478,7 @@ void Game::processQuestLog(const std::vector>& questMissions) +void Game::processQuestLine(const uint16_t questId, const std::vector>& questMissions) { g_lua.callGlobalField("g_game", "onQuestLine", questId, questMissions); } @@ -525,7 +525,7 @@ void Game::processCyclopediaCharacterItemSummary(const CyclopediaCharacterItemSu } void Game::processCyclopediaCharacterAppearances(const OutfitColorStruct& currentOutfit, const std::vector& outfits, - const std::vector& mounts, std::vector& familiars) + const std::vector& mounts, const std::vector& familiars) { g_lua.callGlobalField("g_game", "onParseCyclopediaCharacterAppearances", currentOutfit, outfits, mounts, familiars); } @@ -581,7 +581,7 @@ void Game::processWalkCancel(const Otc::Direction direction) m_localPlayer->cancelWalk(direction); } -void Game::loginWorld(const std::string_view account, const std::string_view password, const std::string_view worldName, const std::string_view worldHost, int worldPort, const std::string_view characterName, const std::string_view authenticatorToken, const std::string_view sessionKey) +void Game::loginWorld(const std::string_view account, const std::string_view password, const std::string_view worldName, const std::string_view worldHost, const int worldPort, const std::string_view characterName, const std::string_view authenticatorToken, const std::string_view sessionKey) { if (m_protocolGame || isOnline()) throw Exception("Unable to login into a world while already online or logging."); @@ -630,19 +630,9 @@ void Game::safeLogout() m_protocolGame->sendLogout(); } -bool Game::walk(const Otc::Direction direction, bool force) +bool Game::walk(const Otc::Direction direction) { - static ScheduledEventPtr nextWalkSchedule = nullptr; - - if (direction == Otc::InvalidDirection) { - if (nextWalkSchedule) { - nextWalkSchedule->cancel(); - nextWalkSchedule = nullptr; - } - return false; - } - - if (!canPerformGameAction()) + if (!canPerformGameAction() || direction == Otc::InvalidDirection) return false; // must cancel auto walking, and wait next try @@ -652,39 +642,32 @@ bool Game::walk(const Otc::Direction direction, bool force) return false; } - if (!force) { - if (nextWalkSchedule) - return false; + static ScheduledEventPtr nextWalkSchedule = nullptr; + static uint16_t steps = 0; + static Timer timer; - if (m_localPlayer->getWalkSteps() > 0) { - uint16_t delay = 0; - if (m_localPlayer->getWalkSteps() == 1) { - if (m_localPlayer->isWalking()) - return false; - - delay = m_walkFirstStepDelay; - } else if (direction != m_localPlayer->getDirection()) - delay = m_walkTurnDelay; - - if (delay > 0) { - nextWalkSchedule = g_dispatcher.scheduleEvent([this, direction] { - if (m_localPlayer) { - m_localPlayer->setWalkSteps(1); - walk(direction, true); - } - - nextWalkSchedule = nullptr; - }, delay); - return false; - } - } - } + if (nextWalkSchedule) nextWalkSchedule->cancel(); + nextWalkSchedule = g_dispatcher.scheduleEvent([this] { + nextWalkSchedule = nullptr; + steps = 0; + }, 150); // check we can walk and add new walk event if false if (!m_localPlayer->canWalk(direction)) { return false; } + if (steps == 1) { + if (timer.ticksElapsed() <= m_walkFirstStepDelay) + return false; + } else if (direction != m_localPlayer->getDirection()) { + if (timer.ticksElapsed() <= m_walkTurnDelay) + return false; + } + + ++steps; + timer.restart(); + const auto& toPos = m_localPlayer->getPosition().translatedToDirection(direction); // only do prewalks to walkable tiles (like grounds and not walls) diff --git a/src/client/game.h b/src/client/game.h index ae4c25b231..64ba1ee92a 100644 --- a/src/client/game.h +++ b/src/client/game.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -22,15 +22,13 @@ #pragma once -#include -#include -#include "animatedtext.h" #include "container.h" #include "creature.h" #include "declarations.h" -#include "item.h" #include "outfit.h" #include "protocolgame.h" +#include +#include struct UnjustifiedPoints { @@ -419,60 +417,60 @@ class Game void processPing(); void processPingBack(); - static void processUpdateNeeded(const std::string_view signature); - static void processLoginError(const std::string_view error); - static void processLoginAdvice(const std::string_view message); - static void processLoginWait(const std::string_view message, const uint8_t time); - static void processSessionEnd(const uint8_t reason); + static void processUpdateNeeded(std::string_view signature); + static void processLoginError(std::string_view error); + static void processLoginAdvice(std::string_view message); + static void processLoginWait(std::string_view message, uint8_t time); + static void processSessionEnd(uint8_t reason); static void processLogin(); void processPendingGame(); void processEnterGame(); void processGameStart(); void processGameEnd(); - void processDeath(const uint8_t deathType, const uint8_t penality); + void processDeath(uint8_t deathType, uint8_t penality); void processGMActions(const std::vector& actions); - void processInventoryChange(const uint8_t slot, const ItemPtr& item); - void processAttackCancel(const uint32_t seq); - void processWalkCancel(const Otc::Direction direction); + void processInventoryChange(uint8_t slot, const ItemPtr& item); + void processAttackCancel(uint32_t seq); + void processWalkCancel(Otc::Direction direction); - static void processPlayerHelpers(const uint16_t helpers); - void processPlayerModes(const Otc::FightModes fightMode, const Otc::ChaseModes chaseMode, const bool safeMode, const Otc::PVPModes pvpMode); + static void processPlayerHelpers(uint16_t helpers); + void processPlayerModes(Otc::FightModes fightMode, Otc::ChaseModes chaseMode, bool safeMode, Otc::PVPModes pvpMode); // message related - static void processTextMessage(const Otc::MessageMode mode, const std::string_view text); - static void processTalk(const std::string_view name, const uint16_t level, const Otc::MessageMode mode, const std::string_view text, const uint16_t channelId, const Position& pos); + static void processTextMessage(Otc::MessageMode mode, std::string_view text); + static void processTalk(std::string_view name, uint16_t level, Otc::MessageMode mode, std::string_view text, uint16_t channelId, const Position& pos); // container related - void processOpenContainer(const uint8_t containerId, const ItemPtr& containerItem, const std::string_view name, const uint8_t capacity, const bool hasParent, const std::vector& items, const bool isUnlocked, const bool hasPages, const uint16_t containerSize, const uint16_t firstIndex); - void processCloseContainer(const uint8_t containerId); - void processContainerAddItem(const uint8_t containerId, const ItemPtr& item, const uint16_t slot); - void processContainerUpdateItem(const uint8_t containerId, const uint16_t slot, const ItemPtr& item); - void processContainerRemoveItem(const uint8_t containerId, const uint16_t slot, const ItemPtr& lastItem); + void processOpenContainer(uint8_t containerId, const ItemPtr& containerItem, std::string_view name, uint8_t capacity, bool hasParent, const std::vector& items, bool isUnlocked, bool hasPages, uint16_t containerSize, uint16_t firstIndex); + void processCloseContainer(uint8_t containerId); + void processContainerAddItem(uint8_t containerId, const ItemPtr& item, uint16_t slot); + void processContainerUpdateItem(uint8_t containerId, uint16_t slot, const ItemPtr& item); + void processContainerRemoveItem(uint8_t containerId, uint16_t slot, const ItemPtr& lastItem); // channel related static void processChannelList(const std::vector>& channelList); - static void processOpenChannel(const uint16_t channelId, const std::string_view name); - static void processOpenPrivateChannel(const std::string_view name); - static void processOpenOwnPrivateChannel(const uint16_t channelId, const std::string_view name); - static void processCloseChannel(const uint16_t channelId); + static void processOpenChannel(uint16_t channelId, std::string_view name); + static void processOpenPrivateChannel(std::string_view name); + static void processOpenOwnPrivateChannel(uint16_t channelId, std::string_view name); + static void processCloseChannel(uint16_t channelId); // rule violations - static void processRuleViolationChannel(const uint16_t channelId); - static void processRuleViolationRemove(const std::string_view name); - static void processRuleViolationCancel(const std::string_view name); + static void processRuleViolationChannel(uint16_t channelId); + static void processRuleViolationRemove(std::string_view name); + static void processRuleViolationCancel(std::string_view name); static void processRuleViolationLock(); // vip related - void processVipAdd(const uint32_t id, const std::string_view name, const uint32_t status, const std::string_view description, const uint32_t iconId, const bool notifyLogin, const std::vector& groupID); - void processVipStateChange(const uint32_t id, const uint32_t status); + void processVipAdd(uint32_t id, std::string_view name, uint32_t status, std::string_view description, uint32_t iconId, bool notifyLogin, const std::vector& groupID); + void processVipStateChange(uint32_t id, uint32_t status); void processVipGroupChange(const std::vector>& vipGroups, uint8_t groupsAmountLeft); // tutorial hint - static void processTutorialHint(const uint8_t id); - static void processAddAutomapFlag(const Position& pos, const uint8_t icon, const std::string_view message); - static void processRemoveAutomapFlag(const Position& pos, const uint8_t icon, const std::string_view message); + static void processTutorialHint(uint8_t id); + static void processAddAutomapFlag(const Position& pos, uint8_t icon, std::string_view message); + static void processRemoveAutomapFlag(const Position& pos, uint8_t icon, std::string_view message); // outfit void processOpenOutfitWindow(const Outfit& currentOutfit, const std::vector>& outfitList, @@ -484,47 +482,47 @@ class Game // npc trade static void processOpenNpcTrade(const std::vector>& items); - static void processPlayerGoods(const uint64_t money, const std::vector>& goods); + static void processPlayerGoods(uint64_t money, const std::vector>& goods); static void processCloseNpcTrade(); // player trade - static void processOwnTrade(const std::string_view name, const std::vector& items); - static void processCounterTrade(const std::string_view name, const std::vector& items); + static void processOwnTrade(std::string_view name, const std::vector& items); + static void processCounterTrade(std::string_view name, const std::vector& items); static void processCloseTrade(); // edit text/list - static void processEditText(const uint32_t id, const uint32_t itemId, const uint16_t maxLength, const std::string_view text, const std::string_view writer, const std::string_view date); - static void processEditList(const uint32_t id, const uint8_t doorId, const std::string_view text); + static void processEditText(uint32_t id, uint32_t itemId, uint16_t maxLength, std::string_view text, std::string_view writer, std::string_view date); + static void processEditList(uint32_t id, uint8_t doorId, std::string_view text); // questlog static void processQuestLog(const std::vector>& questList); - static void processQuestLine(const uint16_t questId, const std::vector>& questMissions); + static void processQuestLine(uint16_t questId, const std::vector>& questMissions); // modal dialogs >= 970 - static void processModalDialog(const uint32_t id, const std::string_view title, const std::string_view message, const std::vector> - & buttonList, const uint8_t enterButton, const uint8_t escapeButton, const std::vector> - & choiceList, const bool priority); + static void processModalDialog(uint32_t id, std::string_view title, std::string_view message, const std::vector> + & buttonList, uint8_t enterButton, uint8_t escapeButton, const std::vector> + & choiceList, bool priority); // cyclopedia - static void processItemDetail(const uint32_t itemId, const std::vector>& descriptions); + static void processItemDetail(uint32_t itemId, const std::vector>& descriptions); static void processBestiaryRaces(const std::vector& bestiaryRaces); static void processCyclopediaCharacterGeneralStats(const CyclopediaCharacterGeneralStats& stats, const std::vector>& skills, const std::vector>& combats); - static void processCyclopediaCharacterCombatStats(const CyclopediaCharacterCombatStats& data, const double mitigation, + static void processCyclopediaCharacterCombatStats(const CyclopediaCharacterCombatStats& data, double mitigation, const std::vector>& additionalSkillsArray, const std::vector>& forgeSkillsArray, const std::vector& perfectShotDamageRangesArray, const std::vector>& combatsArray, const std::vector>& concoctionsArray); - static void processCyclopediaCharacterGeneralStatsBadge(const uint8_t showAccountInformation, const uint8_t playerOnline, const uint8_t playerPremium, - const std::string_view loyaltyTitle, - const std::vector>& badgesVector); + static void processCyclopediaCharacterGeneralStatsBadge(uint8_t showAccountInformation, uint8_t playerOnline, uint8_t playerPremium, + std::string_view loyaltyTitle, + const std::vector>& badgesVector); static void processCyclopediaCharacterItemSummary(const CyclopediaCharacterItemSummary& data); static void processCyclopediaCharacterAppearances(const OutfitColorStruct& currentOutfit, const std::vector& outfits, - const std::vector& mounts, std::vector& familiars); + const std::vector& mounts, const std::vector& familiars); static void processCyclopediaCharacterRecentDeaths(const CyclopediaCharacterRecentDeaths& data); static void processCyclopediaCharacterRecentPvpKills(const CyclopediaCharacterRecentPvPKills& data); static void processParseBestiaryRaces(const std::vector& bestiaryData); - static void processParseBestiaryOverview(const std::string_view raceName, const std::vector& data, const uint16_t animusMasteryPoints); + static void processParseBestiaryOverview(std::string_view raceName, const std::vector& data, uint16_t animusMasteryPoints); static void processUpdateBestiaryMonsterData(const BestiaryMonsterData& data); static void processUpdateBestiaryCharmsData(const BestiaryCharmsData& charmData); static void processBosstiaryInfo(const std::vector& boss); @@ -535,29 +533,29 @@ class Game public: // login related - void loginWorld(const std::string_view account, const std::string_view password, const std::string_view worldName, const std::string_view worldHost, int worldPort, const std::string_view characterName, const std::string_view authenticatorToken, const std::string_view sessionKey); + void loginWorld(std::string_view account, std::string_view password, std::string_view worldName, std::string_view worldHost, int worldPort, std::string_view characterName, std::string_view authenticatorToken, std::string_view sessionKey); void cancelLogin(); void forceLogout(); void safeLogout(); // walk related - bool walk(const Otc::Direction direction, bool force = false); + bool walk(Otc::Direction direction); void autoWalk(const std::vector& dirs, const Position& startPos); - void forceWalk(const Otc::Direction direction); - void turn(const Otc::Direction direction); + void forceWalk(Otc::Direction direction); + void turn(Otc::Direction direction); void stop(); // item related - void look(const ThingPtr& thing, const bool isBattleList = false); + void look(const ThingPtr& thing, bool isBattleList = false); void move(const ThingPtr& thing, const Position& toPos, int count); - void moveToParentContainer(const ThingPtr& thing, const int count); + void moveToParentContainer(const ThingPtr& thing, int count); void rotate(const ThingPtr& thing); void wrap(const ThingPtr& thing); void use(const ThingPtr& thing); void useWith(const ItemPtr& item, const ThingPtr& toThing); - void useInventoryItem(const uint16_t itemId); - void useInventoryItemWith(const uint16_t itemId, const ThingPtr& toThing); - ItemPtr findItemInContainers(const uint32_t itemId, const int subType); + void useInventoryItem(uint16_t itemId); + void useInventoryItemWith(uint16_t itemId, const ThingPtr& toThing); + ItemPtr findItemInContainers(uint32_t itemId, int subType); // container related int open(const ItemPtr& item, const ContainerPtr& previousContainer); @@ -573,27 +571,27 @@ class Game void cancelAttackAndFollow(); // talk related - void talk(const std::string_view message); - void talkChannel(const Otc::MessageMode mode, const uint16_t channelId, const std::string_view message); - void talkPrivate(const Otc::MessageMode mode, const std::string_view receiver, const std::string_view message); + void talk(std::string_view message); + void talkChannel(Otc::MessageMode mode, uint16_t channelId, std::string_view message); + void talkPrivate(Otc::MessageMode mode, std::string_view receiver, std::string_view message); // channel related - void openPrivateChannel(const std::string_view receiver); + void openPrivateChannel(std::string_view receiver); void requestChannels(); - void joinChannel(const uint16_t channelId); - void leaveChannel(const uint16_t channelId); + void joinChannel(uint16_t channelId); + void leaveChannel(uint16_t channelId); void closeNpcChannel(); void openOwnChannel(); - void inviteToOwnChannel(const std::string_view name); - void excludeFromOwnChannel(const std::string_view name); + void inviteToOwnChannel(std::string_view name); + void excludeFromOwnChannel(std::string_view name); // party related - void partyInvite(const uint32_t creatureId); - void partyJoin(const uint32_t creatureId); - void partyRevokeInvitation(const uint32_t creatureId); - void partyPassLeadership(const uint32_t creatureId); + void partyInvite(uint32_t creatureId); + void partyJoin(uint32_t creatureId); + void partyRevokeInvitation(uint32_t creatureId); + void partyPassLeadership(uint32_t creatureId); void partyLeave(); - void partyShareExperience(const bool active); + void partyShareExperience(bool active); // outfit related void requestOutfit(); @@ -602,104 +600,104 @@ class Game void sendTyping(bool typing); // vip related - void addVip(const std::string_view name); - void removeVip(const uint32_t playerId); - void editVip(const uint32_t playerId, const std::string_view description, const uint32_t iconId, const bool notifyLogin, const std::vector& groupID = {}); - void editVipGroups(const Otc::GroupsEditInfoType_t action, const uint8_t groupId, const std::string_view groupName); + void addVip(std::string_view name); + void removeVip(uint32_t playerId); + void editVip(uint32_t playerId, std::string_view description, uint32_t iconId, bool notifyLogin, const std::vector& groupID = {}); + void editVipGroups(Otc::GroupsEditInfoType_t action, uint8_t groupId, std::string_view groupName); // fight modes related - void setChaseMode(const Otc::ChaseModes chaseMode); - void setFightMode(const Otc::FightModes fightMode); - void setSafeFight(const bool on); - void setPVPMode(const Otc::PVPModes pvpMode); + void setChaseMode(Otc::ChaseModes chaseMode); + void setFightMode(Otc::FightModes fightMode); + void setSafeFight(bool on); + void setPVPMode(Otc::PVPModes pvpMode); Otc::ChaseModes getChaseMode() { return m_chaseMode; } Otc::FightModes getFightMode() { return m_fightMode; } bool isSafeFight() { return m_safeFight; } Otc::PVPModes getPVPMode() { return m_pvpMode; } // pvp related - void setUnjustifiedPoints(const UnjustifiedPoints unjustifiedPoints); + void setUnjustifiedPoints(UnjustifiedPoints unjustifiedPoints); UnjustifiedPoints getUnjustifiedPoints() { return m_unjustifiedPoints; }; - void setOpenPvpSituations(const uint8_t openPvpSituations); + void setOpenPvpSituations(uint8_t openPvpSituations); int getOpenPvpSituations() { return m_openPvpSituations; } // npc trade related void inspectNpcTrade(const ItemPtr& item); - void buyItem(const ItemPtr& item, const uint16_t amount, const bool ignoreCapacity, const bool buyWithBackpack); - void sellItem(const ItemPtr& item, const uint16_t amount, const bool ignoreEquipped); + void buyItem(const ItemPtr& item, uint16_t amount, bool ignoreCapacity, bool buyWithBackpack); + void sellItem(const ItemPtr& item, uint16_t amount, bool ignoreEquipped); void closeNpcTrade(); // player trade related void requestTrade(const ItemPtr& item, const CreaturePtr& creature); - void inspectTrade(const bool counterOffer, const uint8_t index); + void inspectTrade(bool counterOffer, uint8_t index); void acceptTrade(); void rejectTrade(); // house window and editable items related - void editText(const uint32_t id, const std::string_view text); - void editList(const uint32_t id, const uint8_t doorId, const std::string_view text); + void editText(uint32_t id, std::string_view text); + void editList(uint32_t id, uint8_t doorId, std::string_view text); // rule violations (only gms) - void openRuleViolation(const std::string_view reporter); - void closeRuleViolation(const std::string_view reporter); + void openRuleViolation(std::string_view reporter); + void closeRuleViolation(std::string_view reporter); void cancelRuleViolation(); // reports - void reportBug(const std::string_view comment); - void reportRuleViolation(const std::string_view target, const uint8_t reason, const uint8_t action, const std::string_view comment, const std::string_view statement, const uint16_t statementId, const bool ipBanishment); - void debugReport(const std::string_view a, const std::string_view b, const std::string_view c, const std::string_view d); + void reportBug(std::string_view comment); + void reportRuleViolation(std::string_view target, uint8_t reason, uint8_t action, std::string_view comment, std::string_view statement, uint16_t statementId, bool ipBanishment); + void debugReport(std::string_view a, std::string_view b, std::string_view c, std::string_view d); // questlog related void requestQuestLog(); - void requestQuestLine(const uint16_t questId); + void requestQuestLine(uint16_t questId); // 870 only void equipItem(const ItemPtr& item); - void mount(const bool mount); + void mount(bool mount); // 910 only - void requestItemInfo(const ItemPtr& item, const uint8_t index); + void requestItemInfo(const ItemPtr& item, uint8_t index); // >= 970 modal dialog - void answerModalDialog(const uint32_t dialog, const uint8_t button, const uint8_t choice); + void answerModalDialog(uint32_t dialog, uint8_t button, uint8_t choice); // >= 984 browse field void browseField(const Position& position); - void seekInContainer(const uint8_t containerId, const uint16_t index); + void seekInContainer(uint8_t containerId, uint16_t index); // >= 1080 ingame store - void buyStoreOffer(const uint32_t offerId, const uint8_t productType, const std::string_view name = ""); - void requestTransactionHistory(const uint32_t page, const uint32_t entriesPerPage); - void requestStoreOffers(const std::string_view categoryName, const uint8_t serviceType = 0); - void openStore(const uint8_t serviceType = 0, const std::string_view category = ""); - void transferCoins(const std::string_view recipient, const uint16_t amount); - void openTransactionHistory(const uint8_t entriesPerPage); + void buyStoreOffer(uint32_t offerId, uint8_t productType, std::string_view name = ""); + void requestTransactionHistory(uint32_t page, uint32_t entriesPerPage); + void requestStoreOffers(std::string_view categoryName, uint8_t serviceType = 0); + void openStore(uint8_t serviceType = 0, std::string_view category = ""); + void transferCoins(std::string_view recipient, uint16_t amount); + void openTransactionHistory(uint8_t entriesPerPage); //void reportRuleViolation2(); void ping(); void setPingDelay(const int delay) { m_pingDelay = delay; } // otclient only - void changeMapAwareRange(const uint8_t xrange, const uint8_t yrange); + void changeMapAwareRange(uint8_t xrange, uint8_t yrange); // dynamic support for game features void enableFeature(const Otc::GameFeature feature) { m_features.set(feature, true); } void disableFeature(const Otc::GameFeature feature) { m_features.set(feature, false); } - void setFeature(const Otc::GameFeature feature, bool enabled) { m_features.set(feature, enabled); } + void setFeature(const Otc::GameFeature feature, const bool enabled) { m_features.set(feature, enabled); } bool getFeature(const Otc::GameFeature feature) { return m_features.test(feature); } - void setProtocolVersion(const uint16_t version); + void setProtocolVersion(uint16_t version); int getProtocolVersion() { return m_protocolVersion; } bool isUsingProtobuf() { return getProtocolVersion() >= 1281 && !getFeature(Otc::GameLoadSprInsteadProtobuf); } - void setClientVersion(const uint16_t version); + void setClientVersion(uint16_t version); int getClientVersion() { return m_clientVersion; } void setCustomOs(const Otc::OperatingSystem_t os) { m_clientCustomOs = os; } Otc::OperatingSystem_t getOs(); - void setWalkTurnDelay(uint16_t v) { m_walkTurnDelay = v; } - void setWalkFirstStepDelay(uint16_t v) { m_walkFirstStepDelay = v; } + void setWalkTurnDelay(const uint16_t v) { m_walkTurnDelay = v; } + void setWalkFirstStepDelay(const uint16_t v) { m_walkFirstStepDelay = v; } uint16_t getWalkTurnDelay() { return m_walkTurnDelay; } uint16_t getWalkFirstStepDelay() { return m_walkFirstStepDelay; } @@ -722,16 +720,16 @@ class Game bool isConnectionOk() { return m_protocolGame && m_protocolGame->getElapsedTicksSinceLastRead() < 5000; } int getPing() { return m_ping; } - ContainerPtr getContainer(int index) { return m_containers[index]; } + ContainerPtr getContainer(const int index) { return m_containers[index]; } stdext::map getContainers() { return m_containers; } stdext::map getVips() { return m_vips; } CreaturePtr getAttackingCreature() { return m_attackingCreature; } CreaturePtr getFollowingCreature() { return m_followingCreature; } - void setServerBeat(int beat) { m_serverBeat = beat; } + void setServerBeat(const int beat) { m_serverBeat = beat; } int getServerBeat() { return m_serverBeat; } - void setCanReportBugs(bool enable) { m_canReportBugs = enable; } + void setCanReportBugs(const bool enable) { m_canReportBugs = enable; } bool canReportBugs() { return m_canReportBugs; } - void setExpertPvpMode(bool enable) { m_expertPvpMode = enable; } + void setExpertPvpMode(const bool enable) { m_expertPvpMode = enable; } bool getExpertPvpMode() { return m_expertPvpMode; } LocalPlayerPtr getLocalPlayer() { return m_localPlayer; } ProtocolGamePtr getProtocolGame() { return m_protocolGame; } @@ -740,56 +738,56 @@ class Game std::vector getGMActions() { return m_gmActions; } bool isGM() { return !m_gmActions.empty(); } - std::string formatCreatureName(const std::string_view name); + std::string formatCreatureName(std::string_view name); int findEmptyContainerId(); // market related void leaveMarket(); - void browseMarket(const uint8_t browseId, const uint8_t browseType); - void createMarketOffer(const uint8_t type, const uint16_t itemId, const uint8_t itemTier, const uint16_t amount, const uint64_t price, const uint8_t anonymous); - void cancelMarketOffer(const uint32_t timestamp, const uint16_t counter); - void acceptMarketOffer(const uint32_t timestamp, const uint16_t counter, const uint16_t amount); + void browseMarket(uint8_t browseId, uint8_t browseType); + void createMarketOffer(uint8_t type, uint16_t itemId, uint8_t itemTier, uint16_t amount, uint64_t price, uint8_t anonymous); + void cancelMarketOffer(uint32_t timestamp, uint16_t counter); + void acceptMarketOffer(uint32_t timestamp, uint16_t counter, uint16_t amount); // prey related - void preyAction(const uint8_t slot, const uint8_t actionType, const uint16_t index); + void preyAction(uint8_t slot, uint8_t actionType, uint16_t index); void preyRequest(); // imbuing related - void applyImbuement(const uint8_t slot, const uint32_t imbuementId, const bool protectionCharm); - void clearImbuement(const uint8_t slot); + void applyImbuement(uint8_t slot, uint32_t imbuementId, bool protectionCharm); + void clearImbuement(uint8_t slot); void closeImbuingWindow(); void imbuementDurations(bool isOpen = false); - void enableTileThingLuaCallback(bool value) { m_tileThingsLuaCallback = value; } + void enableTileThingLuaCallback(const bool value) { m_tileThingsLuaCallback = value; } bool isTileThingLuaCallbackEnabled() { return m_tileThingsLuaCallback; } - void stashWithdraw(const uint16_t itemId, const uint32_t count, const uint8_t stackpos); + void stashWithdraw(uint16_t itemId, uint32_t count, uint8_t stackpos); // highscore related - void requestHighscore(const uint8_t action, const uint8_t category, const uint32_t vocation, const std::string_view world, const uint8_t worldType, const uint8_t battlEye, const uint16_t page, const uint8_t totalPages); - void processHighscore(const std::string_view serverName, const std::string_view world, const uint8_t worldType, const uint8_t battlEye, - const std::vector>& vocations, - const std::vector>& categories, - const uint16_t page, const uint16_t totalPages, - const std::vector>& highscores, const uint32_t entriesTs); + void requestHighscore(uint8_t action, uint8_t category, uint32_t vocation, std::string_view world, uint8_t worldType, uint8_t battlEye, uint16_t page, uint8_t totalPages); + void processHighscore(std::string_view serverName, std::string_view world, uint8_t worldType, uint8_t battlEye, + const std::vector>& vocations, + const std::vector>& categories, + uint16_t page, uint16_t totalPages, + const std::vector>& highscores, uint32_t entriesTs); void requestBless(); - void requestQuickLootBlackWhiteList(const uint8_t filter, const uint16_t size, const std::vector& listedItems); - void openContainerQuickLoot(const uint8_t action, const uint8_t category, const Position& pos, const uint16_t itemId, const uint8_t stackpos, const bool useMainAsFallback); + void requestQuickLootBlackWhiteList(uint8_t filter, uint16_t size, const std::vector& listedItems); + void openContainerQuickLoot(uint8_t action, uint8_t category, const Position& pos, uint16_t itemId, uint8_t stackpos, bool useMainAsFallback); void sendGmTeleport(const Position& pos); // cyclopedia related void inspectionNormalObject(const Position& position); - void inspectionObject(const Otc::InspectObjectTypes inspectionType, const uint16_t itemId, const uint8_t itemCount); + void inspectionObject(Otc::InspectObjectTypes inspectionType, uint16_t itemId, uint8_t itemCount); void requestBestiary(); - void requestBestiaryOverview(const std::string_view catName); - void requestBestiarySearch(const uint16_t raceId); - void requestSendBuyCharmRune(const uint8_t runeId, const uint8_t action, const uint16_t raceId); - void requestSendCharacterInfo(const uint32_t playerId, const Otc::CyclopediaCharacterInfoType_t characterInfoType, const uint16_t entriesPerPage = 0, const uint16_t page = 0); + void requestBestiaryOverview(std::string_view catName); + void requestBestiarySearch(uint16_t raceId); + void requestSendBuyCharmRune(uint8_t runeId, uint8_t action, uint16_t raceId); + void requestSendCharacterInfo(uint32_t playerId, Otc::CyclopediaCharacterInfoType_t characterInfoType, uint16_t entriesPerPage = 0, uint16_t page = 0); void requestBosstiaryInfo(); void requestBossSlootInfo(); - void requestBossSlotAction(const uint8_t action, const uint32_t raceId); - void sendStatusTrackerBestiary(const uint16_t raceId, const bool status); + void requestBossSlotAction(uint8_t action, uint32_t raceId); + void sendStatusTrackerBestiary(uint16_t raceId, bool status); protected: void enableBotCall() { m_denyBotCall = false; } void disableBotCall() { m_denyBotCall = true; } diff --git a/src/client/gameconfig.cpp b/src/client/gameconfig.cpp index 41cf818d52..f295088946 100644 --- a/src/client/gameconfig.cpp +++ b/src/client/gameconfig.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,9 +21,9 @@ */ #include "gameconfig.h" -#include -#include #include +#include +#include GameConfig g_gameConfig; @@ -31,9 +31,6 @@ static constexpr bool LOAD_SETUP = true; void GameConfig::init() { - if (!LOAD_SETUP) - return; - const std::string& fileName = "/data/setup"; try { diff --git a/src/client/gameconfig.h b/src/client/gameconfig.h index 37240e9f15..ec97279370 100644 --- a/src/client/gameconfig.h +++ b/src/client/gameconfig.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -24,8 +24,8 @@ #include "declarations.h" -#include #include +#include // @bindclass class GameConfig diff --git a/src/client/global.h b/src/client/global.h index f47de87298..101f42e430 100644 --- a/src/client/global.h +++ b/src/client/global.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * 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/src/client/houses.cpp b/src/client/houses.cpp index 756e8e7368..8db725edc5 100644 --- a/src/client/houses.cpp +++ b/src/client/houses.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * 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/src/client/houses.h b/src/client/houses.h index d9b7b2657d..a208e90a73 100644 --- a/src/client/houses.h +++ b/src/client/houses.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * 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/src/client/item.cpp b/src/client/item.cpp index b0fab796b3..39f7657026 100644 --- a/src/client/item.cpp +++ b/src/client/item.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -23,20 +23,16 @@ #include "item.h" #include "container.h" #include "game.h" -#include "map.h" #include "spritemanager.h" #include "thing.h" #include "thingtypemanager.h" #include "tile.h" -#include #include -#include #include -#include #include -ItemPtr Item::create(int id) +ItemPtr Item::create(const int id) { const auto& item = std::make_shared(); item->setId(id); @@ -44,7 +40,7 @@ ItemPtr Item::create(int id) return item; } -void Item::draw(const Point& dest, bool drawThings, const LightViewPtr& lightView) +void Item::draw(const Point& dest, const bool drawThings, const LightViewPtr& lightView) { if (!canDraw(m_color) || isHided()) return; @@ -60,7 +56,7 @@ void Item::draw(const Point& dest, bool drawThings, const LightViewPtr& lightVie internalDraw(animationPhase, dest, getHighlightColor(), drawThings, true); } -void Item::internalDraw(int animationPhase, const Point& dest, const Color& color, bool drawThings, bool replaceColorShader, const LightViewPtr& lightView) +void Item::internalDraw(const int animationPhase, const Point& dest, const Color& color, const bool drawThings, const bool replaceColorShader, const LightViewPtr& lightView) { if (replaceColorShader) g_drawPool.setShaderProgram(g_painter->getReplaceColorShader(), true); @@ -95,14 +91,14 @@ void Item::setConductor() { if (isSingleGround()) { m_drawConductor.agroup = true; - m_drawConductor.order = DrawOrder::FIRST; + m_drawConductor.order = FIRST; } else if (isSingleGroundBorder() && !hasElevation()) { m_drawConductor.agroup = true; - m_drawConductor.order = DrawOrder::SECOND; + m_drawConductor.order = SECOND; } } -void Item::setPosition(const Position& position, uint8_t stackPos, bool hasElevation) +void Item::setPosition(const Position& position, const uint8_t stackPos, const bool hasElevation) { Thing::setPosition(position, stackPos); diff --git a/src/client/item.h b/src/client/item.h index 10f1f40a22..374e10d729 100644 --- a/src/client/item.h +++ b/src/client/item.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -22,9 +22,8 @@ #pragma once -#include -#include "effect.h" #include "thing.h" +#include enum ItemAttr : uint8_t { @@ -71,7 +70,7 @@ enum ItemAttr : uint8_t // @bindclass #pragma pack(push,1) // disable memory alignment -class Item : public Thing +class Item final : public Thing { public: static ItemPtr create(int id); @@ -81,13 +80,14 @@ class Item : public Thing void setId(uint32_t id) override; - void setCountOrSubType(int value) { m_countOrSubType = value; updatePatterns(); } - void setCount(int count) { m_countOrSubType = count; updatePatterns(); } - void setSubType(int subType) { m_countOrSubType = subType; updatePatterns(); } + void setCountOrSubType(const int value) { m_countOrSubType = value; updatePatterns(); } + void setCount(const int count) { m_countOrSubType = count; updatePatterns(); } + void setSubType(const int subType) { m_countOrSubType = subType; updatePatterns(); } void setColor(const Color& c) { if (m_color != c) m_color = c; } void setPosition(const Position& position, uint8_t stackPos = 0, bool hasElevation = false) override; void setTooltip(const std::string& str) { m_tooltip = str; } void setDurationTime(const uint32_t durationTime) { m_durationTime = durationTime; } + void setCharges(const uint32_t charges) { m_charges = charges; } void setTier(const uint8_t tier) { m_tier = tier; } int getCountOrSubType() { return m_countOrSubType; } @@ -95,11 +95,12 @@ class Item : public Thing int getCount() { return isStackable() ? m_countOrSubType : 1; } std::string getTooltip() { return m_tooltip; } uint32_t getDurationTime() { return m_durationTime; } + uint32_t getCharges() { return m_charges; } uint8_t getTier() { return m_tier; } bool isValid() { return getThingType() != nullptr; } - void setAsync(bool enable) { m_async = enable; } + void setAsync(const bool enable) { m_async = enable; } ItemPtr clone(); ItemPtr asItem() { return static_self_cast(); } @@ -107,7 +108,7 @@ class Item : public Thing void updatePatterns(); int calculateAnimationPhase(); - int getExactSize(int layer = 0, int /*xPattern*/ = 0, int /*yPattern*/ = 0, int /*zPattern*/ = 0, int /*animationPhase*/ = 0) override { + int getExactSize(const int layer = 0, int /*xPattern*/ = 0, int /*yPattern*/ = 0, int /*zPattern*/ = 0, int /*animationPhase*/ = 0) override { return Thing::getExactSize(layer, m_numPatternX, m_numPatternY, m_numPatternZ, calculateAnimationPhase()); } @@ -162,11 +163,12 @@ class Item : public Thing uint16_t m_countOrSubType{ 0 }; uint32_t m_durationTime{ 0 }; + uint32_t m_charges{ 0 }; uint8_t m_tier{ 0 }; + uint8_t m_phase{ 0 }; Color m_color{ Color::white }; - uint8_t m_phase{ 0 }; ticks_t m_lastPhase{ 0 }; bool m_async{ true }; diff --git a/src/client/itemtype.cpp b/src/client/itemtype.cpp index 0c7de00a5c..9c3cd2fdb8 100644 --- a/src/client/itemtype.cpp +++ b/src/client/itemtype.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * 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/src/client/itemtype.h b/src/client/itemtype.h index 74d25541dd..d111880046 100644 --- a/src/client/itemtype.h +++ b/src/client/itemtype.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * 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/src/client/lightview.cpp b/src/client/lightview.cpp index ce93428a07..eb72aa3c4d 100644 --- a/src/client/lightview.cpp +++ b/src/client/lightview.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -22,11 +22,9 @@ #include "lightview.h" #include "map.h" -#include "mapview.h" -#include "spritemanager.h" -#include #include +#include #include LightView::LightView(const Size& size) : m_pool(g_drawPool.get(DrawPoolType::LIGHT)) { @@ -54,10 +52,9 @@ void LightView::resize(const Size& size, const uint16_t tileSize) { m_texture->setupSize(m_mapSize); } -void LightView::addLightSource(const Point& pos, const Light& light, float brightness) +void LightView::addLightSource(const Point& pos, const Light& light, const float brightness) { - if (!isDark() || light.intensity == 0) - return; + if (!isDark() || light.intensity == 0) return; if (!m_lightData.lights.empty()) { auto& prevLight = m_lightData.lights.back(); @@ -67,22 +64,22 @@ void LightView::addLightSource(const Point& pos, const Light& light, float brigh } } - size_t hash = 0; - - stdext::hash_union(hash, pos.hash()); + size_t hash = pos.hash(); stdext::hash_combine(hash, light.intensity); stdext::hash_combine(hash, light.color); if (g_drawPool.getOpacity() < 1.f) stdext::hash_combine(hash, g_drawPool.getOpacity()); - if (m_pool->getHashController().put(hash)) - m_lightData.lights.emplace_back(pos, light.intensity, light.color, std::min(brightness, g_drawPool.getOpacity())); + if (m_pool->getHashController().put(hash)) { + const float effectiveBrightness = std::min(brightness, g_drawPool.getOpacity()); + m_lightData.lights.emplace_back(pos, light.intensity, light.color, effectiveBrightness); + } } void LightView::resetShade(const Point& pos) { - size_t index = (pos.y / m_tileSize) * m_mapSize.width() + (pos.x / m_tileSize); + const size_t index = (pos.y / m_tileSize) * m_mapSize.width() + (pos.x / m_tileSize); if (index >= m_lightData.tiles.size()) return; m_lightData.tiles[index] = m_lightData.lights.size(); } @@ -135,35 +132,55 @@ void LightView::updateCoords(const Rect& dest, const Rect& src) { static_cast(size.width()) / m_tileSize, static_cast(size.height()) / m_tileSize)); } -void LightView::updatePixels() { - const size_t lightSize = m_lightData.lights.size(); - - const int mapWidth = m_mapSize.width(); - const int mapHeight = m_mapSize.height(); - - for (int x = -1; ++x < mapWidth;) { - for (int y = -1; ++y < mapHeight;) { - const Point pos(x * m_tileSize + m_tileSize / 2, y * m_tileSize + m_tileSize / 2); - const int index = (y * mapWidth + x); - const int colorIndex = index * 4; - m_pixels[colorIndex] = m_globalLightColor.r(); - m_pixels[colorIndex + 1] = m_globalLightColor.g(); - m_pixels[colorIndex + 2] = m_globalLightColor.b(); - m_pixels[colorIndex + 3] = 255; // alpha channel - for (size_t i = m_lightData.tiles[index]; i < lightSize; ++i) { +void LightView::updatePixels() +{ + const auto lightSize = m_lightData.lights.size(); + const auto mapWidth = m_mapSize.width(); + const auto mapHeight = m_mapSize.height(); + const auto tileCenterOffset = m_tileSize / 2; + const auto invTileSize = 1.0f / m_tileSize; + + auto* pixelData = m_pixels.data(); + + for (int y = 0; y < mapHeight; ++y) { + for (int x = 0; x < mapWidth; ++x) { + const auto centerX = x * m_tileSize + tileCenterOffset; + const auto centerY = y * m_tileSize + tileCenterOffset; + const auto index = y * mapWidth + x; + + auto r = m_globalLightColor.r(); + auto g = m_globalLightColor.g(); + auto b = m_globalLightColor.b(); + + for (auto i = m_lightData.tiles[index]; i < lightSize; ++i) { const auto& light = m_lightData.lights[i]; - const float distance = (std::sqrt((pos.x - light.pos.x) * (pos.x - light.pos.x) + - (pos.y - light.pos.y) * (pos.y - light.pos.y))) / m_tileSize; - float intensity = (-distance + light.intensity) * 0.2f; + const auto dx = centerX - light.pos.x; + const auto dy = centerY - light.pos.y; + const auto distanceSq = dx * dx + dy * dy; + + const auto lightRadiusSq = (light.intensity * m_tileSize) * (light.intensity * m_tileSize); + if (distanceSq > lightRadiusSq) continue; + + const auto distanceNorm = std::sqrt(distanceSq) * invTileSize; + float intensity = (-distanceNorm + light.intensity) * 0.2f; if (intensity < 0.01f) continue; - if (intensity > 1.0f) intensity = 1.0f; + + intensity = std::min(intensity, 1.0f); const auto& lightColor = Color::from8bit(light.color) * intensity; - m_pixels[colorIndex] = std::max(m_pixels[colorIndex], lightColor.r()); - m_pixels[colorIndex + 1] = std::max(m_pixels[colorIndex + 1], lightColor.g()); - m_pixels[colorIndex + 2] = std::max(m_pixels[colorIndex + 2], lightColor.b()); + + r = std::max(r, lightColor.r()); + g = std::max(g, lightColor.g()); + b = std::max(b, lightColor.b()); } + + const auto colorIndex = index * 4; + + pixelData[colorIndex] = r; + pixelData[colorIndex + 1] = g; + pixelData[colorIndex + 2] = b; + pixelData[colorIndex + 3] = 255; } } } \ No newline at end of file diff --git a/src/client/lightview.h b/src/client/lightview.h index 79b11c0f08..e365e75377 100644 --- a/src/client/lightview.h +++ b/src/client/lightview.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -22,16 +22,16 @@ #pragma once -#include -#include #include "declarations.h" #include "thingtype.h" +#include +#include -class LightView : public LuaObject +class LightView final : public LuaObject { public: LightView(const Size& size); - ~LightView() { m_texture = nullptr; } + ~LightView() override { m_texture = nullptr; } void resize(const Size& size, uint16_t tileSize); void draw(const Rect& dest, const Rect& src); @@ -48,15 +48,15 @@ class LightView : public LuaObject bool isDark() const { return m_isDark; } bool isEnabled() const { return m_pool->isEnabled(); } - void setEnabled(bool v) { m_pool->setEnable(v); } + void setEnabled(const bool v) { m_pool->setEnable(v); } private: - struct TileLight : public Light + struct TileLight : Light { Point pos; float brightness{ 1.f }; - TileLight(const Point& pos, uint8_t intensity, uint8_t color, float brightness) : Light(intensity, color), pos(pos), brightness(brightness) {} + TileLight(const Point& pos, const uint8_t intensity, const uint8_t color, const float brightness) : Light(intensity, color), pos(pos), brightness(brightness) {} }; struct LightData diff --git a/src/client/localplayer.cpp b/src/client/localplayer.cpp index c01dccde50..5b6e1962c5 100644 --- a/src/client/localplayer.cpp +++ b/src/client/localplayer.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,17 +21,17 @@ */ #include "localplayer.h" -#include #include "game.h" #include "map.h" #include "tile.h" +#include -void LocalPlayer::lockWalk(uint16_t millis) +void LocalPlayer::lockWalk(const uint16_t millis) { m_walkLockExpiration = std::max(m_walkLockExpiration, g_clock.millis() + millis); } -bool LocalPlayer::canWalk(Otc::Direction dir, bool ignoreLock) +bool LocalPlayer::canWalk(const Otc::Direction dir, const bool ignoreLock) { // paralyzed if (isDead()) @@ -59,7 +59,7 @@ void LocalPlayer::walk(const Position& oldPos, const Position& newPos) Creature::walk(oldPos, newPos); } -void LocalPlayer::preWalk(Otc::Direction direction) +void LocalPlayer::preWalk(const Otc::Direction direction) { // avoid reanimating prewalks if (m_preWalking) @@ -96,7 +96,7 @@ bool LocalPlayer::retryAutoWalk() return false; } -void LocalPlayer::cancelWalk(Otc::Direction direction) +void LocalPlayer::cancelWalk(const Otc::Direction direction) { // only cancel client side walks if (m_walking && m_preWalking) @@ -114,7 +114,7 @@ void LocalPlayer::cancelWalk(Otc::Direction direction) callLuaField("onCancelWalk", direction); } -bool LocalPlayer::autoWalk(const Position& destination, bool retry) +bool LocalPlayer::autoWalk(const Position& destination, const bool retry) { // reset state m_autoWalkDestination = {}; @@ -184,7 +184,7 @@ void LocalPlayer::stopWalk() m_lastPrewalkDestination = {}; } -void LocalPlayer::updateWalkOffset(uint8_t totalPixelsWalked) +void LocalPlayer::updateWalkOffset(const uint8_t totalPixelsWalked) { if (!m_preWalking) { Creature::updateWalkOffset(totalPixelsWalked); @@ -220,7 +220,7 @@ void LocalPlayer::onPositionChange(const Position& newPos, const Position& oldPo autoWalk(m_autoWalkDestination); } -void LocalPlayer::setStates(uint32_t states) +void LocalPlayer::setStates(const uint32_t states) { if (m_states == states) return; @@ -234,7 +234,7 @@ void LocalPlayer::setStates(uint32_t states) callLuaField("onStatesChange", states, oldStates); } -void LocalPlayer::setSkill(Otc::Skill skillId, uint16_t level, uint16_t levelPercent) +void LocalPlayer::setSkill(const Otc::Skill skillId, const uint16_t level, const uint16_t levelPercent) { if (skillId >= Otc::LastSkill) { g_logger.traceError("invalid skill"); @@ -255,7 +255,7 @@ void LocalPlayer::setSkill(Otc::Skill skillId, uint16_t level, uint16_t levelPer callLuaField("onSkillChange", skillId, level, levelPercent, oldLevel, oldLevelPercent); } -void LocalPlayer::setBaseSkill(Otc::Skill skill, uint16_t baseLevel) +void LocalPlayer::setBaseSkill(const Otc::Skill skill, const uint16_t baseLevel) { if (skill >= Otc::LastSkill) { g_logger.traceError("invalid skill"); @@ -271,7 +271,7 @@ void LocalPlayer::setBaseSkill(Otc::Skill skill, uint16_t baseLevel) callLuaField("onBaseSkillChange", skill, baseLevel, oldBaseLevel); } -void LocalPlayer::setHealth(uint32_t health, uint32_t maxHealth) +void LocalPlayer::setHealth(const uint32_t health, const uint32_t maxHealth) { if (m_health != health || m_maxHealth != maxHealth) { const uint32_t oldHealth = m_health; @@ -289,7 +289,7 @@ void LocalPlayer::setHealth(uint32_t health, uint32_t maxHealth) } } -void LocalPlayer::setFreeCapacity(uint32_t freeCapacity) +void LocalPlayer::setFreeCapacity(const uint32_t freeCapacity) { if (m_freeCapacity == freeCapacity) return; @@ -300,7 +300,7 @@ void LocalPlayer::setFreeCapacity(uint32_t freeCapacity) callLuaField("onFreeCapacityChange", freeCapacity, oldFreeCapacity); } -void LocalPlayer::setTotalCapacity(uint32_t totalCapacity) +void LocalPlayer::setTotalCapacity(const uint32_t totalCapacity) { if (m_totalCapacity == totalCapacity) return; @@ -311,7 +311,7 @@ void LocalPlayer::setTotalCapacity(uint32_t totalCapacity) callLuaField("onTotalCapacityChange", totalCapacity, oldTotalCapacity); } -void LocalPlayer::setExperience(uint64_t experience) +void LocalPlayer::setExperience(const uint64_t experience) { if (m_experience == experience) return; @@ -322,7 +322,7 @@ void LocalPlayer::setExperience(uint64_t experience) callLuaField("onExperienceChange", experience, oldExperience); } -void LocalPlayer::setLevel(uint16_t level, uint8_t levelPercent) +void LocalPlayer::setLevel(const uint16_t level, const uint8_t levelPercent) { if (m_level == level && m_levelPercent == levelPercent) return; @@ -336,7 +336,7 @@ void LocalPlayer::setLevel(uint16_t level, uint8_t levelPercent) callLuaField("onLevelChange", level, levelPercent, oldLevel, oldLevelPercent); } -void LocalPlayer::setMana(uint32_t mana, uint32_t maxMana) +void LocalPlayer::setMana(const uint32_t mana, const uint32_t maxMana) { if (m_mana == mana && m_maxMana == maxMana) return; @@ -349,13 +349,13 @@ void LocalPlayer::setMana(uint32_t mana, uint32_t maxMana) callLuaField("onManaChange", mana, maxMana, oldMana, oldMaxMana); } -void LocalPlayer::setMagicLevel(uint8_t magicLevel, uint8_t magicLevelPercent) +void LocalPlayer::setMagicLevel(const uint16_t magicLevel, const uint16_t magicLevelPercent) { if (m_magicLevel == magicLevel && m_magicLevelPercent == magicLevelPercent) return; - const uint8_t oldMagicLevel = m_magicLevel; - const uint8_t oldMagicLevelPercent = m_magicLevelPercent; + const uint16_t oldMagicLevel = m_magicLevel; + const uint16_t oldMagicLevelPercent = m_magicLevelPercent; m_magicLevel = magicLevel; m_magicLevelPercent = magicLevelPercent; @@ -363,18 +363,18 @@ void LocalPlayer::setMagicLevel(uint8_t magicLevel, uint8_t magicLevelPercent) callLuaField("onMagicLevelChange", magicLevel, magicLevelPercent, oldMagicLevel, oldMagicLevelPercent); } -void LocalPlayer::setBaseMagicLevel(uint8_t baseMagicLevel) +void LocalPlayer::setBaseMagicLevel(const uint16_t baseMagicLevel) { if (m_baseMagicLevel == baseMagicLevel) return; - const uint8_t oldBaseMagicLevel = m_baseMagicLevel; + const uint16_t oldBaseMagicLevel = m_baseMagicLevel; m_baseMagicLevel = baseMagicLevel; callLuaField("onBaseMagicLevelChange", baseMagicLevel, oldBaseMagicLevel); } -void LocalPlayer::setSoul(uint8_t soul) +void LocalPlayer::setSoul(const uint8_t soul) { if (m_soul == soul) return; @@ -385,7 +385,7 @@ void LocalPlayer::setSoul(uint8_t soul) callLuaField("onSoulChange", soul, oldSoul); } -void LocalPlayer::setStamina(uint16_t stamina) +void LocalPlayer::setStamina(const uint16_t stamina) { if (m_stamina == stamina) return; @@ -396,7 +396,7 @@ void LocalPlayer::setStamina(uint16_t stamina) callLuaField("onStaminaChange", stamina, oldStamina); } -void LocalPlayer::setInventoryItem(Otc::InventorySlot inventory, const ItemPtr& item) +void LocalPlayer::setInventoryItem(const Otc::InventorySlot inventory, const ItemPtr& item) { if (inventory >= Otc::LastInventorySlot) { g_logger.traceError("invalid slot"); @@ -412,7 +412,7 @@ void LocalPlayer::setInventoryItem(Otc::InventorySlot inventory, const ItemPtr& callLuaField("onInventoryChange", inventory, item, oldItem); } -void LocalPlayer::setVocation(uint8_t vocation) +void LocalPlayer::setVocation(const uint8_t vocation) { if (m_vocation == vocation) return; @@ -423,7 +423,7 @@ void LocalPlayer::setVocation(uint8_t vocation) callLuaField("onVocationChange", vocation, oldVocation); } -void LocalPlayer::setPremium(bool premium) +void LocalPlayer::setPremium(const bool premium) { if (m_premium == premium) return; @@ -433,7 +433,7 @@ void LocalPlayer::setPremium(bool premium) callLuaField("onPremiumChange", premium); } -void LocalPlayer::setRegenerationTime(uint16_t regenerationTime) +void LocalPlayer::setRegenerationTime(const uint16_t regenerationTime) { if (m_regenerationTime == regenerationTime) return; @@ -444,7 +444,7 @@ void LocalPlayer::setRegenerationTime(uint16_t regenerationTime) callLuaField("onRegenerationChange", regenerationTime, oldRegenerationTime); } -void LocalPlayer::setOfflineTrainingTime(uint16_t offlineTrainingTime) +void LocalPlayer::setOfflineTrainingTime(const uint16_t offlineTrainingTime) { if (m_offlineTrainingTime == offlineTrainingTime) return; @@ -466,7 +466,7 @@ void LocalPlayer::setSpells(const std::vector& spells) callLuaField("onSpellsChange", spells, oldSpells); } -void LocalPlayer::setBlessings(uint16_t blessings) +void LocalPlayer::setBlessings(const uint16_t blessings) { if (blessings == m_blessings) return; @@ -477,12 +477,12 @@ void LocalPlayer::setBlessings(uint16_t blessings) callLuaField("onBlessingsChange", blessings, oldBlessings); } -void LocalPlayer::takeScreenshot(uint8_t type) +void LocalPlayer::takeScreenshot(const uint8_t type) { g_lua.callGlobalField("LocalPlayer", "onTakeScreenshot", type); } -void LocalPlayer::setResourceBalance(Otc::ResourceTypes_t type, uint64_t value) +void LocalPlayer::setResourceBalance(const Otc::ResourceTypes_t type, const uint64_t value) { const uint64_t oldBalance = getResourceBalance(type); if (value == oldBalance) diff --git a/src/client/localplayer.h b/src/client/localplayer.h index eaf37ab5c9..d048e572d0 100644 --- a/src/client/localplayer.h +++ b/src/client/localplayer.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -25,7 +25,7 @@ #include "player.h" // @bindclass -class LocalPlayer : public Player +class LocalPlayer final : public Player { public: void unlockWalk() { m_walkLockExpiration = 0; } @@ -45,12 +45,12 @@ class LocalPlayer : public Player void setExperience(uint64_t experience); void setLevel(uint16_t level, uint8_t levelPercent); void setMana(uint32_t mana, uint32_t maxMana); - void setMagicLevel(uint8_t magicLevel, uint8_t magicLevelPercent); - void setBaseMagicLevel(uint8_t baseMagicLevel); + void setMagicLevel(uint16_t magicLevel, uint16_t magicLevelPercent); + void setBaseMagicLevel(uint16_t baseMagicLevel); void setSoul(uint8_t soul); void setStamina(uint16_t stamina); - void setKnown(bool known) { m_known = known; } - void setPendingGame(bool pending) { m_pending = pending; } + void setKnown(const bool known) { m_known = known; } + void setPendingGame(const bool pending) { m_pending = pending; } void setInventoryItem(Otc::InventorySlot inventory, const ItemPtr& item); void setVocation(uint8_t vocation); void setPremium(bool premium); @@ -65,16 +65,16 @@ class LocalPlayer : public Player uint32_t getTotalCapacity() { return m_totalCapacity; } uint8_t getVocation() { return m_vocation; } - uint8_t getMagicLevel() { return m_magicLevel; } - uint8_t getMagicLevelPercent() { return m_magicLevelPercent; } - uint8_t getBaseMagicLevel() { return m_baseMagicLevel; } + uint16_t getMagicLevel() { return m_magicLevel; } + uint16_t getMagicLevelPercent() { return m_magicLevelPercent; } + uint16_t getBaseMagicLevel() { return m_baseMagicLevel; } uint8_t getSoul() { return m_soul; } uint8_t getLevelPercent() { return m_levelPercent; } uint16_t getLevel() { return m_level; } - uint16_t getSkillLevel(Otc::Skill skill) { return m_skills[skill].level; } - uint16_t getSkillBaseLevel(Otc::Skill skill) { return m_skills[skill].baseLevel; } - uint16_t getSkillLevelPercent(Otc::Skill skill) { return m_skills[skill].levelPercent; } + uint16_t getSkillLevel(const Otc::Skill skill) { return m_skills[skill].level; } + uint16_t getSkillBaseLevel(const Otc::Skill skill) { return m_skills[skill].baseLevel; } + uint16_t getSkillLevelPercent(const Otc::Skill skill) { return m_skills[skill].levelPercent; } uint16_t getStamina() { return m_stamina; } uint16_t getBlessings() { return m_blessings; } uint16_t getRegenerationTime() { return m_regenerationTime; } @@ -88,9 +88,9 @@ class LocalPlayer : public Player uint64_t getExperience() { return m_experience; } const std::vector& getSpells() { return m_spells; } - ItemPtr getInventoryItem(Otc::InventorySlot inventory) { return m_inventoryItems[inventory]; } + ItemPtr getInventoryItem(const Otc::InventorySlot inventory) { return m_inventoryItems[inventory]; } - uint64_t getResourceBalance(Otc::ResourceTypes_t type) + uint64_t getResourceBalance(const Otc::ResourceTypes_t type) { const auto it = m_resourcesBalance.find(type); return it != m_resourcesBalance.end() ? it->second : 0; @@ -175,9 +175,9 @@ class LocalPlayer : public Player uint8_t m_levelPercent{ 0 }; uint32_t m_mana{ 0 }; uint32_t m_maxMana{ 0 }; - uint8_t m_magicLevel{ 0 }; - uint8_t m_magicLevelPercent{ 0 }; - uint8_t m_baseMagicLevel{ 0 }; + uint16_t m_magicLevel{ 0 }; + uint16_t m_magicLevelPercent{ 0 }; + uint16_t m_baseMagicLevel{ 0 }; uint8_t m_soul{ 0 }; uint16_t m_stamina{ 0 }; uint16_t m_regenerationTime{ 0 }; diff --git a/src/client/luafunctions.cpp b/src/client/luafunctions.cpp index abe843ad15..30fa5a0674 100644 --- a/src/client/luafunctions.cpp +++ b/src/client/luafunctions.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -22,6 +22,7 @@ #include "animatedtext.h" #include "attachedeffect.h" +#include "attachedeffectmanager.h" #include "client.h" #include "container.h" #include "creature.h" @@ -37,7 +38,6 @@ #include "outfit.h" #include "player.h" #include "protocolgame.h" -#include "attachedeffectmanager.h" #include "spriteappearances.h" #include "spritemanager.h" #include "statictext.h" @@ -45,17 +45,17 @@ #include "tile.h" #include "towns.h" #include "uicreature.h" -#include "uiitem.h" #include "uieffect.h" +#include "uiitem.h" #include "uimissile.h" +#include "attachableobject.h" +#include "uigraph.h" #include "uimap.h" #include "uimapanchorlayout.h" #include "uiminimap.h" #include "uiprogressrect.h" #include "uisprite.h" -#include "uigraph.h" -#include "attachableobject.h" #ifdef FRAMEWORK_EDITOR #include "houses.h" @@ -714,6 +714,7 @@ void Client::registerLuaFunctions() g_lua.bindClassMemberFunction("getTooltip", &Item::getTooltip); g_lua.bindClassMemberFunction("getDurationTime", &Item::getDurationTime); g_lua.bindClassMemberFunction("getTier", &Item::getTier); + g_lua.bindClassMemberFunction("getCharges", &Item::getCharges); g_lua.bindClassMemberFunction("isStackable", &Item::isStackable); g_lua.bindClassMemberFunction("isMarketable", &Item::isMarketable); @@ -1062,13 +1063,21 @@ void Client::registerLuaFunctions() g_lua.bindClassMemberFunction("getPercent", &UIProgressRect::getPercent); g_lua.registerClass(); - g_lua.bindClassStaticFunction("create", [] { return UIGraphPtr(new UIGraph); }); - g_lua.bindClassMemberFunction("addValue", &UIGraph::addValue); + g_lua.bindClassStaticFunction("create", [] { return std::make_shared(); }); g_lua.bindClassMemberFunction("clear", &UIGraph::clear); - g_lua.bindClassMemberFunction("setLineWidth", &UIGraph::setLineWidth); + g_lua.bindClassMemberFunction("createGraph", &UIGraph::createGraph); + g_lua.bindClassMemberFunction("getGraphsCount", &UIGraph::getGraphsCount); + g_lua.bindClassMemberFunction("addValue", &UIGraph::addValue); g_lua.bindClassMemberFunction("setCapacity", &UIGraph::setCapacity); g_lua.bindClassMemberFunction("setTitle", &UIGraph::setTitle); g_lua.bindClassMemberFunction("setShowLabels", &UIGraph::setShowLabels); + g_lua.bindClassMemberFunction("setShowInfo", &UIGraph::setShowInfo); + g_lua.bindClassMemberFunction("setLineWidth", &UIGraph::setLineWidth); + g_lua.bindClassMemberFunction("setLineColor", &UIGraph::setLineColor); + g_lua.bindClassMemberFunction("setInfoText", &UIGraph::setInfoText); + g_lua.bindClassMemberFunction("setInfoLineColor", &UIGraph::setInfoLineColor); + g_lua.bindClassMemberFunction("setTextBackground", &UIGraph::setTextBackground); + g_lua.bindClassMemberFunction("setGraphVisible", &UIGraph::setGraphVisible); g_lua.registerClass(); } \ No newline at end of file diff --git a/src/client/luavaluecasts_client.cpp b/src/client/luavaluecasts_client.cpp index dda6fb325a..9d8fc04f81 100644 --- a/src/client/luavaluecasts_client.cpp +++ b/src/client/luavaluecasts_client.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -49,7 +49,7 @@ int push_luavalue(const Outfit& outfit) return 1; } -bool luavalue_cast(int index, Outfit& outfit) +bool luavalue_cast(const int index, Outfit& outfit) { if (!g_lua.isTable(index)) return false; @@ -104,7 +104,7 @@ int push_luavalue(const Position& pos) return 1; } -bool luavalue_cast(int index, Position& pos) +bool luavalue_cast(const int index, Position& pos) { if (!g_lua.isTable(index)) return false; @@ -140,7 +140,7 @@ int push_luavalue(const std::vector& data) { return 1; } -bool luavalue_cast(int index, std::vector& data) +bool luavalue_cast(const int index, std::vector& data) { if (!g_lua.isTable(index)) return false; @@ -187,7 +187,7 @@ int push_luavalue(const MarketData& data) return 1; } -bool luavalue_cast(int index, MarketData& data) +bool luavalue_cast(const int index, MarketData& data) { if (!g_lua.isTable(index)) return false; @@ -219,7 +219,7 @@ int push_luavalue(const Light& light) return 1; } -bool luavalue_cast(int index, Light& light) +bool luavalue_cast(const int index, Light& light) { if (!g_lua.isTable(index)) return false; @@ -315,7 +315,7 @@ int push_luavalue(const ImbuementTrackerItem& i) return 1; } -bool luavalue_cast(int index, UnjustifiedPoints& unjustifiedPoints) +bool luavalue_cast(const int index, UnjustifiedPoints& unjustifiedPoints) { if (!g_lua.isTable(index)) return false; @@ -396,7 +396,7 @@ int push_luavalue(const BlessDialogData& data) { g_lua.rawSeti(i + 1); } g_lua.setField("logs"); - + return 1; } @@ -749,7 +749,7 @@ int push_luavalue(const BestiaryMonsterData& data) { } return 1; -} +} int push_luavalue(const CharmData& charm) { g_lua.createTable(0, 7); @@ -971,7 +971,7 @@ int push_luavalue(const BosstiarySlotsData& data) { g_lua.rawSeti(i + 1); } g_lua.setField("bossesUnlockedData"); - return 1; + return 1; } int push_luavalue(const ItemSummary& item) { @@ -1124,4 +1124,4 @@ int push_luavalue(const CharacterInfoFamiliar& familiar) { g_lua.pushInteger(familiar.isCurrent); g_lua.setField("isCurrent"); return 1; -} +} \ No newline at end of file diff --git a/src/client/luavaluecasts_client.h b/src/client/luavaluecasts_client.h index 31ef9f188e..a26eb1986a 100644 --- a/src/client/luavaluecasts_client.h +++ b/src/client/luavaluecasts_client.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * 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/src/client/map.cpp b/src/client/map.cpp index a3fa720c65..9d8e98ede4 100644 --- a/src/client/map.cpp +++ b/src/client/map.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -30,9 +30,10 @@ #include "statictext.h" #include "tile.h" +#include #include -#include #include +#include #include #include @@ -69,7 +70,7 @@ void Map::addMapView(const MapViewPtr& mapView) { m_mapViews.push_back(mapView); void Map::removeMapView(const MapViewPtr& mapView) { - const auto it = std::find(m_mapViews.begin(), m_mapViews.end(), mapView); + const auto it = std::ranges::find(m_mapViews, mapView); if (it != m_mapViews.end()) m_mapViews.erase(it); } @@ -109,7 +110,7 @@ void Map::clean() { cleanDynamicThings(); - for (int_fast8_t i = -1; ++i <= g_gameConfig.getMapMaxZ();) + for (auto i = -1; ++i <= g_gameConfig.getMapMaxZ();) m_floors[i].tileBlocks.clear(); #ifdef FRAMEWORK_EDITOR @@ -141,13 +142,13 @@ void Map::cleanDynamicThings() m_knownCreatures.clear(); - for (int_fast8_t i = -1; ++i <= g_gameConfig.getMapMaxZ();) + for (auto i = -1; ++i <= g_gameConfig.getMapMaxZ();) m_floors[i].missiles.clear(); cleanTexts(); } -void Map::addThing(const ThingPtr& thing, const Position& pos, int16_t stackPos) +void Map::addThing(const ThingPtr& thing, const Position& pos, const int16_t stackPos) { if (!thing) return; @@ -225,7 +226,7 @@ void Map::addAnimatedText(const AnimatedTextPtr& txt, const Position& pos) { }); } -ThingPtr Map::getThing(const Position& pos, int16_t stackPos) +ThingPtr Map::getThing(const Position& pos, const int16_t stackPos) { if (const auto& tile = getTile(pos)) return tile->getThing(stackPos); @@ -240,7 +241,7 @@ bool Map::removeThing(const ThingPtr& thing) if (thing->isMissile()) { auto& missiles = m_floors[thing->getPosition().z].missiles; - const auto it = std::find(missiles.begin(), missiles.end(), thing->static_self_cast()); + const auto it = std::ranges::find(missiles, thing->static_self_cast()); if (it == missiles.end()) return false; @@ -258,7 +259,7 @@ bool Map::removeThing(const ThingPtr& thing) return false; } -bool Map::removeThingByPos(const Position& pos, int16_t stackPos) +bool Map::removeThingByPos(const Position& pos, const int16_t stackPos) { if (const auto& tile = getTile(pos)) return removeThing(tile->getThing(stackPos)); @@ -267,7 +268,7 @@ bool Map::removeThingByPos(const Position& pos, int16_t stackPos) } bool Map::removeStaticText(const StaticTextPtr& txt) { - const auto it = std::find(m_staticTexts.begin(), m_staticTexts.end(), txt); + const auto it = std::ranges::find(m_staticTexts, txt); if (it == m_staticTexts.end()) return false; @@ -276,7 +277,7 @@ bool Map::removeStaticText(const StaticTextPtr& txt) { } bool Map::removeAnimatedText(const AnimatedTextPtr& txt) { - const auto it = std::find(m_animatedTexts.begin(), m_animatedTexts.end(), txt); + const auto it = std::ranges::find(m_animatedTexts, txt); if (it == m_animatedTexts.end()) return false; @@ -361,7 +362,7 @@ const TilePtr& Map::getTile(const Position& pos) return m_nulltile; } -TileList Map::getTiles(int8_t floor/* = -1*/) +TileList Map::getTiles(const int8_t floor/* = -1*/) { TileList tiles; if (floor > g_gameConfig.getMapMaxZ()) @@ -369,7 +370,7 @@ TileList Map::getTiles(int8_t floor/* = -1*/) if (floor < 0) { // Search all floors - for (int_fast8_t z = -1; ++z <= g_gameConfig.getMapMaxZ();) { + for (auto z = -1; ++z <= g_gameConfig.getMapMaxZ();) { for (const auto& [key, block] : m_floors[z].tileBlocks) { for (const auto& tile : block.getTiles()) { if (tile != nullptr) @@ -472,10 +473,10 @@ void Map::setShowAnimations(bool show) } #endif -void Map::beginGhostMode(float opacity) { g_painter->setOpacity(opacity); } +void Map::beginGhostMode(const float opacity) { g_painter->setOpacity(opacity); } void Map::endGhostMode() { g_painter->resetOpacity(); } -stdext::map Map::findItemsById(uint16_t clientId, uint32_t max) +stdext::map Map::findItemsById(const uint16_t clientId, const uint32_t max) { stdext::map ret; uint32_t count = 0; @@ -498,14 +499,14 @@ stdext::map Map::findItemsById(uint16_t cli return ret; } -CreaturePtr Map::getCreatureById(uint32_t id) +CreaturePtr Map::getCreatureById(const uint32_t id) { const auto it = m_knownCreatures.find(id); return it != m_knownCreatures.end() ? it->second : nullptr; } void Map::addCreature(const CreaturePtr& creature) { m_knownCreatures[creature->getId()] = creature; } -void Map::removeCreatureById(uint32_t id) +void Map::removeCreatureById(const uint32_t id) { if (id == 0) return; @@ -536,10 +537,10 @@ void Map::removeUnawareThings() if (!g_game.getFeature(Otc::GameKeepUnawareTiles)) { // remove tiles that we are not aware anymore - for (int_fast8_t z = -1; ++z <= g_gameConfig.getMapMaxZ();) { + for (auto z = -1; ++z <= g_gameConfig.getMapMaxZ();) { auto& tileBlocks = m_floors[z].tileBlocks; for (auto it = tileBlocks.begin(); it != tileBlocks.end();) { - auto& block = (*it).second; + auto& block = it->second; bool blockEmpty = true; for (const auto& tile : block.getTiles()) { if (!tile) continue; @@ -610,7 +611,7 @@ void Map::setLight(const Light& light) mapView->onGlobalLightChange(m_light); } -std::vector Map::getSpectatorsInRangeEx(const Position& centerPos, bool multiFloor, int32_t minXRange, int32_t maxXRange, int32_t minYRange, int32_t maxYRange) +std::vector Map::getSpectatorsInRangeEx(const Position& centerPos, const bool multiFloor, const int32_t minXRange, const int32_t maxXRange, const int32_t minYRange, const int32_t maxYRange) { std::vector creatures; uint8_t minZRange = 0; @@ -623,9 +624,9 @@ std::vector Map::getSpectatorsInRangeEx(const Position& centerPos, //TODO: optimize //TODO: delivery creatures in distance order - for (int_fast8_t iz = -minZRange; iz <= maxZRange; ++iz) { - for (int_fast32_t iy = -minYRange; iy <= maxYRange; ++iy) { - for (int_fast32_t ix = -minXRange; ix <= maxXRange; ++ix) { + for (int iz = -minZRange; iz <= maxZRange; ++iz) { + for (int iy = -minYRange; iy <= maxYRange; ++iy) { + for (int ix = -minXRange; ix <= maxXRange; ++ix) { if (const auto& tile = getTile(centerPos.translated(ix, iy, iz))) { const auto& tileCreatures = tile->getCreatures(); creatures.insert(creatures.end(), tileCreatures.rbegin(), tileCreatures.rend()); @@ -643,7 +644,7 @@ bool Map::isLookPossible(const Position& pos) return tile && tile->isLookPossible(); } -bool Map::isCovered(const Position& pos, uint8_t firstFloor) +bool Map::isCovered(const Position& pos, const uint8_t firstFloor) { // check for tiles on top of the postion Position tilePos = pos; @@ -663,7 +664,7 @@ bool Map::isCovered(const Position& pos, uint8_t firstFloor) return false; } -bool Map::isCompletelyCovered(const Position& pos, uint8_t firstFloor) +bool Map::isCompletelyCovered(const Position& pos, const uint8_t firstFloor) { const auto& checkTile = getTile(pos); Position tilePos = pos; @@ -672,8 +673,8 @@ bool Map::isCompletelyCovered(const Position& pos, uint8_t firstFloor) bool done = false; // Check is Top Ground - for (int_fast8_t x = -1; ++x < 2 && !done;) { - for (int_fast8_t y = -1; ++y < 2 && !done;) { + for (auto x = -1; ++x < 2 && !done;) { + for (auto y = -1; ++y < 2 && !done;) { const auto& tile = getTile(tilePos.translated(x, x)); if (!tile || !tile->hasTopGround()) { covered = false; @@ -691,8 +692,8 @@ bool Map::isCompletelyCovered(const Position& pos, uint8_t firstFloor) done = false; // check in 2x2 range tiles that has no transparent pixels - for (int_fast8_t x = -1; ++x < 2 && !done;) { - for (int_fast8_t y = -1; ++y < 2 && !done;) { + for (auto x = -1; ++x < 2 && !done;) { + for (auto y = -1; ++y < 2 && !done;) { const auto& tile = getTile(tilePos.translated(-x, -y)); if (!tile || !tile->isFullyOpaque()) { covered = false; @@ -741,10 +742,10 @@ void Map::setAwareRange(const AwareRange& range) void Map::resetAwareRange() { setAwareRange({ - static_cast(g_gameConfig.getMapViewPort().width()) , - static_cast(g_gameConfig.getMapViewPort().height()), - static_cast(g_gameConfig.getMapViewPort().width() + 1), - static_cast(g_gameConfig.getMapViewPort().height() + 1) + .left = static_cast(g_gameConfig.getMapViewPort().width()) , + .top = static_cast(g_gameConfig.getMapViewPort().height()), + .right = static_cast(g_gameConfig.getMapViewPort().width() + 1), + .bottom = static_cast(g_gameConfig.getMapViewPort().height() + 1) }); } @@ -764,23 +765,24 @@ uint8_t Map::getLastAwareFloor() const return std::min(m_centralPosition.z + g_gameConfig.getMapAwareUndergroundFloorRange(), g_gameConfig.getMapMaxZ()); } -std::tuple, Otc::PathFindResult> Map::findPath(const Position& startPos, const Position& goalPos, int maxComplexity, int flags) +std::tuple, Otc::PathFindResult> Map::findPath(const Position& startPos, const Position& goalPos, const int maxComplexity, const int flags) { // pathfinding using dijkstra search algorithm struct SNode { - SNode(const Position& pos) : cost(0), totalCost(0), pos(pos), prev(nullptr), dir(Otc::InvalidDirection) {} - float cost; - float totalCost; + SNode(const Position& pos) : + pos(pos) {} + float cost{ 0 }; + float totalCost{ 0 }; Position pos; - SNode* prev; - Otc::Direction dir; + SNode* prev{ nullptr }; + Otc::Direction dir{ Otc::InvalidDirection }; }; struct LessNode { - bool operator()(std::pair a, std::pair b) const + bool operator()(const std::pair a, const std::pair b) const { return b.second < a.second; } @@ -910,7 +912,7 @@ std::tuple, Otc::PathFindResult> Map::findPath(const neighborNode->cost = cost; neighborNode->totalCost = neighborNode->cost + neighborPos.distance(goalPos); neighborNode->dir = walkDir; - searchList.push(std::make_pair(neighborNode, neighborNode->totalCost)); + searchList.emplace(neighborNode, neighborNode->totalCost); } } @@ -928,7 +930,7 @@ std::tuple, Otc::PathFindResult> Map::findPath(const currentNode = currentNode->prev; } dirs.pop_back(); - std::reverse(dirs.begin(), dirs.end()); + std::ranges::reverse(dirs); result = Otc::PathFindResultOk; } @@ -975,7 +977,7 @@ PathFindResult_ptr Map::newFindPath(const Position& start, const Position& goal, struct LessNode { - bool operator()(Node const* a, Node const* b) const + bool operator()(const Node* a, const Node* b) const { return b->totalCost < a->totalCost; } @@ -989,14 +991,14 @@ PathFindResult_ptr Map::newFindPath(const Position& start, const Position& goal, nodes.emplace(node->pos, node); } - const auto& initNode = new Node{ 1, 0, start, nullptr, 0, 0 }; + const auto& initNode = new Node{ .cost = 1, .totalCost = 0, .pos = start, .prev = nullptr, .distance = 0, .unseen = 0 }; nodes[start] = initNode; searchList.push(initNode); int limit = 50000; const float distance = start.distance(goal); - Node* dstNode = nullptr; + const Node* dstNode = nullptr; while (!searchList.empty() && --limit) { Node* node = searchList.top(); searchList.pop(); @@ -1025,7 +1027,9 @@ PathFindResult_ptr Map::newFindPath(const Position& start, const Position& goal, } else { if (!wasSeen) speed = 2000; - it = nodes.emplace(neighbor, new Node{ speed, 10000000.0f, neighbor, node, node->distance + 1, wasSeen ? 0 : 1 }).first; + it = nodes.emplace(neighbor, new Node{ .cost = speed, .totalCost = 10000000.0f, .pos = neighbor, .prev = + node, + .distance = node->distance + 1, .unseen = wasSeen ? 0 : 1 }).first; } } if (!it->second) // no way @@ -1081,9 +1085,14 @@ void Map::findPathAsync(const Position& start, const Position& goal, const std:: const bool isNotPathable = !tile->isPathable(); const float speed = tile->getGroundSpeed(); if ((isNotWalkable || isNotPathable) && tile->getPosition() != goal) { - visibleNodes->push_back(new Node{ speed, 0, tile->getPosition(), nullptr, 0, 0 }); + visibleNodes->push_back(new Node{ .cost = speed, .totalCost = 0, .pos = tile->getPosition(), .prev = nullptr, .distance = + 0, + .unseen = 0 + }); } else { - visibleNodes->push_back(new Node{ speed, 10000000.0f, tile->getPosition(), nullptr, 0, 0 }); + visibleNodes->push_back(new Node{ .cost = speed, .totalCost = 10000000.0f, .pos = tile->getPosition(), .prev = + nullptr, .distance = 0, .unseen = 0 + }); } } @@ -1113,19 +1122,19 @@ bool Map::isSightClear(const Position& fromPos, const Position& toPos) } Position start(fromPos.z > toPos.z ? toPos : fromPos); - Position destination(fromPos.z > toPos.z ? fromPos : toPos); + const Position destination(fromPos.z > toPos.z ? fromPos : toPos); const int8_t mx = start.x < destination.x ? 1 : start.x == destination.x ? 0 : -1; const int8_t my = start.y < destination.y ? 1 : start.y == destination.y ? 0 : -1; - int32_t A = destination.y - start.y; - int32_t B = start.x - destination.x; - int32_t C = -(A * destination.x + B * destination.y); + const int32_t A = destination.y - start.y; + const int32_t B = start.x - destination.x; + const int32_t C = -(A * destination.x + B * destination.y); while (start.x != destination.x || start.y != destination.y) { - int32_t move_hor = std::abs(A * (start.x + mx) + B * (start.y) + C); - int32_t move_ver = std::abs(A * (start.x) + B * (start.y + my) + C); - int32_t move_cross = std::abs(A * (start.x + mx) + B * (start.y + my) + C); + const int32_t move_hor = std::abs(A * (start.x + mx) + B * (start.y) + C); + const int32_t move_ver = std::abs(A * (start.x) + B * (start.y + my) + C); + const int32_t move_cross = std::abs(A * (start.x + mx) + B * (start.y + my) + C); if (start.y != destination.y && (start.x == destination.x || move_hor > move_ver || move_hor > move_cross)) { start.y += my; @@ -1135,14 +1144,14 @@ bool Map::isSightClear(const Position& fromPos, const Position& toPos) start.x += mx; } - auto tile = getTile(Position(start.x, start.y, start.z)); + const auto tile = getTile(Position(start.x, start.y, start.z)); if (tile && !tile->isLookPossible()) { return false; } } while (start.z != destination.z) { - auto tile = getTile(Position(start.x, start.y, start.z)); + const auto tile = getTile(Position(start.x, start.y, start.z)); if (tile && tile->getThingCount() > 0) { return false; } @@ -1153,7 +1162,7 @@ bool Map::isSightClear(const Position& fromPos, const Position& toPos) } bool Map::isWidgetAttached(const UIWidgetPtr& widget) const { - return m_attachedObjectWidgetMap.find(widget) != m_attachedObjectWidgetMap.end(); + return m_attachedObjectWidgetMap.contains(widget); } void Map::addAttachedWidgetToObject(const UIWidgetPtr& widget, const AttachableObjectPtr& object) { diff --git a/src/client/map.h b/src/client/map.h index e51255aaa8..0cfafca23f 100644 --- a/src/client/map.h +++ b/src/client/map.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -155,7 +155,7 @@ class Map void addMapView(const MapViewPtr& mapView); void removeMapView(const MapViewPtr& mapView); - MapViewPtr getMapView(size_t i) { return i < m_mapViews.size() ? m_mapViews[i] : nullptr; } + MapViewPtr getMapView(const size_t i) { return i < m_mapViews.size() ? m_mapViews[i] : nullptr; } void notificateTileUpdate(const Position& pos, const ThingPtr& thing, Otc::Operation operation); void notificateCameraMove(const Point& offset) const; @@ -197,8 +197,8 @@ class Map void setShowAnimations(bool show); #endif - void setWidth(uint16_t w) { m_width = w; } - void setHeight(uint16_t h) { m_height = h; } + void setWidth(const uint16_t w) { m_width = w; } + void setHeight(const uint16_t h) { m_height = h; } Size getSize() { return { m_width, m_height }; } void clean(); @@ -245,17 +245,17 @@ class Map void addCreature(const CreaturePtr& creature); void removeCreatureById(uint32_t id); - std::vector getSpectators(const Position& centerPos, bool multiFloor) + std::vector getSpectators(const Position& centerPos, const bool multiFloor) { return getSpectatorsInRangeEx(centerPos, multiFloor, m_awareRange.left, m_awareRange.right, m_awareRange.top, m_awareRange.bottom); } - std::vector getSightSpectators(const Position& centerPos, bool multiFloor) + std::vector getSightSpectators(const Position& centerPos, const bool multiFloor) { return getSpectatorsInRangeEx(centerPos, multiFloor, m_awareRange.left - 1, m_awareRange.right - 2, m_awareRange.top - 1, m_awareRange.bottom - 2); } - std::vector getSpectatorsInRange(const Position& centerPos, bool multiFloor, int32_t xRange, int32_t yRange) + std::vector getSpectatorsInRange(const Position& centerPos, const bool multiFloor, const int32_t xRange, const int32_t yRange) { return getSpectatorsInRangeEx(centerPos, multiFloor, xRange, xRange, yRange, yRange); } @@ -281,7 +281,7 @@ class Map Position getCentralPosition() { return m_centralPosition; } uint8_t getFirstAwareFloor() const; uint8_t getLastAwareFloor() const; - const std::vector& getFloorMissiles(uint8_t z) { return m_floors[z].missiles; } + const std::vector& getFloorMissiles(const uint8_t z) { return m_floors[z].missiles; } std::vector getAnimatedTexts() { return m_animatedTexts; } std::vector getStaticTexts() { return m_staticTexts; } @@ -292,7 +292,7 @@ class Map void findPathAsync(const Position& start, const Position& goal, const std::function& callback); - void setFloatingEffect(bool enable) { m_floatingEffect = enable; } + void setFloatingEffect(const bool enable) { m_floatingEffect = enable; } bool isDrawingFloatingEffects() { return m_floatingEffect; } #ifndef BOT_PROTECTION diff --git a/src/client/mapio.cpp b/src/client/mapio.cpp index 9f0f363a3d..ea4f601f6b 100644 --- a/src/client/mapio.cpp +++ b/src/client/mapio.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * 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/src/client/mapview.cpp b/src/client/mapview.cpp index 2e5f29c1ec..2ea07325ae 100644 --- a/src/client/mapview.cpp +++ b/src/client/mapview.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -23,6 +23,7 @@ #include "mapview.h" #include "animatedtext.h" +#include "client.h" #include "creature.h" #include "game.h" #include "lightview.h" @@ -30,17 +31,17 @@ #include "missile.h" #include "statictext.h" #include "tile.h" -#include "client.h" -#include +#include "framework/graphics/texturemanager.h" #include #include #include #include -#include "framework/graphics/texturemanager.h" #include #include +#include + MapView::MapView() : m_lightView(std::make_unique(Size())), m_pool(g_drawPool.get(DrawPoolType::MAP)) { m_floors.resize(g_gameConfig.getMapMaxZ() + 1); @@ -120,7 +121,7 @@ void MapView::drawFloor() { const auto& cameraPosition = m_posInfo.camera; - uint32_t flags = Otc::DrawThings; + const uint32_t flags = Otc::DrawThings; for (int_fast8_t z = m_floorMax; z >= m_floorMin; --z) { const float fadeLevel = getFadeLevel(z); @@ -315,20 +316,20 @@ void MapView::updateVisibleTiles() if (!m_lastCameraPosition.isValid() || m_lastCameraPosition.z != m_posInfo.camera.z || m_lastCameraPosition.distance(m_posInfo.camera) >= 3) { m_fadeType = FadeType::NONE$; for (int iz = m_cachedLastVisibleFloor; iz >= cachedFirstVisibleFloor; --iz) { - m_floors[iz].fadingTimers.restart(m_floorFading * 1000); + m_floors[iz].fadingTimers.restart(m_floorFading); } } else if (prevFirstVisibleFloor < m_cachedFirstVisibleFloor) { // hiding new floor m_fadeType = FadeType::OUT$; for (int iz = prevFirstVisibleFloor; iz < m_cachedFirstVisibleFloor; ++iz) { - const int shift = std::max(0, m_floorFading - m_floors[iz].fadingTimers.elapsed_millis()); - m_floors[iz].fadingTimers.restart(shift * 1000); + const int shift = std::max(0, m_floorFading - m_floors[iz].fadingTimers.ticksElapsed()); + m_floors[iz].fadingTimers.restart(shift); } } else if (prevFirstVisibleFloor > m_cachedFirstVisibleFloor) { // showing floor m_fadeType = FadeType::IN$; m_fadeFinish = false; for (int iz = m_cachedFirstVisibleFloor; iz < prevFirstVisibleFloor; ++iz) { - const int shift = std::max(0, m_floorFading - m_floors[iz].fadingTimers.elapsed_millis()); - m_floors[iz].fadingTimers.restart(shift * 1000); + const int shift = std::max(0, m_floorFading - m_floors[iz].fadingTimers.ticksElapsed()); + m_floors[iz].fadingTimers.restart(shift); } } @@ -450,16 +451,16 @@ void MapView::updateGeometry(const Size& visibleDimension) m_lightView->resize(lightSize, tileSize); } - g_mainDispatcher.addEvent([this, bufferSize]() { + g_mainDispatcher.addEvent([this, bufferSize] { m_pool->getFrameBuffer()->resize(bufferSize); }); const uint8_t left = std::min(g_map.getAwareRange().left, (m_drawDimension.width() / 2) - 1); const uint8_t top = std::min(g_map.getAwareRange().top, (m_drawDimension.height() / 2) - 1); - const uint8_t right = static_cast(left + 1); - const uint8_t bottom = static_cast(top + 1); + const auto right = static_cast(left + 1); + const auto bottom = static_cast(top + 1); - m_posInfo.awareRange = { left, top, right, bottom }; + m_posInfo.awareRange = { .left = left, .top = top, .right = right, .bottom = bottom }; updateViewportDirectionCache(); updateViewport(); @@ -536,7 +537,7 @@ void MapView::onMapCenterChange(const Position& /*newPos*/, const Position& /*ol requestUpdateVisibleTiles(); } -void MapView::lockFirstVisibleFloor(uint8_t firstVisibleFloor) +void MapView::lockFirstVisibleFloor(const uint8_t firstVisibleFloor) { m_lockedFirstVisibleFloor = firstVisibleFloor; requestUpdateVisibleTiles(); @@ -575,7 +576,7 @@ void MapView::setVisibleDimension(const Size& visibleDimension) updateGeometry(visibleDimension); } -void MapView::setFloorViewMode(FloorViewMode floorViewMode) +void MapView::setFloorViewMode(const FloorViewMode floorViewMode) { m_floorViewMode = floorViewMode; @@ -587,7 +588,7 @@ void MapView::setAntiAliasingMode(const AntialiasingMode mode) { m_antiAliasingMode = mode; - g_mainDispatcher.addEvent([=, this]() { + g_mainDispatcher.addEvent([=, this] { m_pool->getFrameBuffer()->setSmooth(mode != ANTIALIASING_DISABLED); }); @@ -612,7 +613,7 @@ void MapView::setCameraPosition(const Position& pos) Position MapView::getPosition(const Point& mousePos) { - auto newMousePos = mousePos * g_window.getDisplayDensity(); + const auto newMousePos = mousePos * g_window.getDisplayDensity(); if (!m_posInfo.rect.contains(newMousePos)) return {}; @@ -647,7 +648,7 @@ Position MapView::getPosition(const Point& point, const Size& mapSize) return position; } -void MapView::move(int32_t x, int32_t y) +void MapView::move(const int32_t x, const int32_t y) { m_moveOffset.x += x; m_moveOffset.y += y; @@ -693,7 +694,7 @@ Rect MapView::calcFramebufferSource(const Size& destSize) return Rect(drawOffset, srcSize); } -uint8_t MapView::calcFirstVisibleFloor(bool checkLimitsFloorsView) const +uint8_t MapView::calcFirstVisibleFloor(const bool checkLimitsFloorsView) const { uint8_t z = g_gameConfig.getMapSeaFloor(); // return forced first visible floor @@ -792,7 +793,7 @@ TilePtr MapView::getTopTile(Position tilePos) const return nullptr; } -void MapView::setShader(const std::string_view name, float fadein, float fadeout) +void MapView::setShader(const std::string_view name, const float fadein, const float fadeout) { const auto& shader = g_shaders.getShader(name); @@ -817,7 +818,7 @@ void MapView::setShader(const std::string_view name, float fadein, float fadeout }); } -void MapView::setDrawLights(bool enable) +void MapView::setDrawLights(const bool enable) { m_drawingLight = enable; @@ -877,12 +878,12 @@ void MapView::updateViewportDirectionCache() } Position MapView::getCameraPosition() { return isFollowingCreature() ? m_followingCreature->getPosition() : m_customCameraPosition; } -std::vector MapView::getSightSpectators(bool multiFloor) +std::vector MapView::getSightSpectators(const bool multiFloor) { return g_map.getSpectatorsInRangeEx(getCameraPosition(), multiFloor, m_posInfo.awareRange.left - 1, m_posInfo.awareRange.right - 2, m_posInfo.awareRange.top - 1, m_posInfo.awareRange.bottom - 2); } -std::vector MapView::getSpectators(bool multiFloor) +std::vector MapView::getSpectators(const bool multiFloor) { return g_map.getSpectatorsInRangeEx(getCameraPosition(), multiFloor, m_posInfo.awareRange.left, m_posInfo.awareRange.right, m_posInfo.awareRange.top, m_posInfo.awareRange.bottom); } @@ -909,12 +910,12 @@ void MapView::destroyHighlightTile() { void MapView::addForegroundTile(const TilePtr& tile) { std::scoped_lock l(g_drawPool.get(DrawPoolType::FOREGROUND_MAP)->getMutex()); - if (std::find(m_foregroundTiles.begin(), m_foregroundTiles.end(), tile) == m_foregroundTiles.end()) + if (std::ranges::find(m_foregroundTiles, tile) == m_foregroundTiles.end()) m_foregroundTiles.emplace_back(tile); } void MapView::removeForegroundTile(const TilePtr& tile) { std::scoped_lock l(g_drawPool.get(DrawPoolType::FOREGROUND_MAP)->getMutex()); - const auto it = std::find(m_foregroundTiles.begin(), m_foregroundTiles.end(), tile); + const auto it = std::ranges::find(m_foregroundTiles, tile); if (it == m_foregroundTiles.end()) return; diff --git a/src/client/mapview.h b/src/client/mapview.h index 8105e47248..1fc512ab01 100644 --- a/src/client/mapview.h +++ b/src/client/mapview.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -22,11 +22,10 @@ #pragma once +#include "lightview.h" #include #include -#include #include -#include "lightview.h" struct AwareRange { @@ -50,12 +49,12 @@ struct MapPosInfo float verticalStretchFactor; float scaleFactor; - bool isInRange(const Position& pos, bool ignoreZ = false) const + bool isInRange(const Position& pos, const bool ignoreZ = false) const { return camera.isInRange(pos, awareRange.left - 1, awareRange.right - 2, awareRange.top - 1, awareRange.bottom - 2, ignoreZ); } - bool isInRangeEx(const Position& pos, bool ignoreZ = false) const + bool isInRangeEx(const Position& pos, const bool ignoreZ = false) const { return camera.isInRange(pos, awareRange.left, awareRange.right, awareRange.top, awareRange.bottom, ignoreZ); } @@ -68,7 +67,7 @@ struct MapPosInfo }; // @bindclass -class MapView : public LuaObject +class MapView final : public LuaObject { public: enum FloorViewMode @@ -118,30 +117,30 @@ class MapView : public LuaObject Position getCameraPosition(); void setCameraPosition(const Position& pos); - void setMinimumAmbientLight(float intensity) { m_minimumAmbientLight = intensity; updateLight(); } + void setMinimumAmbientLight(const float intensity) { m_minimumAmbientLight = intensity; updateLight(); } float getMinimumAmbientLight() const { return m_minimumAmbientLight; } - void setShadowFloorIntensity(float intensity) { m_shadowFloorIntensity = intensity; updateLight(); } + void setShadowFloorIntensity(const float intensity) { m_shadowFloorIntensity = intensity; updateLight(); } float getShadowFloorIntensity() const { return m_shadowFloorIntensity; } - void setDrawNames(bool enable) { m_drawNames = enable; } + void setDrawNames(const bool enable) { m_drawNames = enable; } bool isDrawingNames() const { return m_drawNames; } - void setDrawHealthBars(bool enable) { m_drawHealthBars = enable; } + void setDrawHealthBars(const bool enable) { m_drawHealthBars = enable; } bool isDrawingHealthBars() const { return m_drawHealthBars; } void setDrawLights(bool enable); bool isDrawingLights() const { return m_drawingLight && m_lightView->isDark(); } - void setLimitVisibleDimension(bool v) { m_limitVisibleDimension = v; } + void setLimitVisibleDimension(const bool v) { m_limitVisibleDimension = v; } bool isLimitedVisibleDimension() const { return m_limitVisibleDimension; } - void setDrawManaBar(bool enable) { m_drawManaBar = enable; } + void setDrawManaBar(const bool enable) { m_drawManaBar = enable; } bool isDrawingManaBar() const { return m_drawManaBar; } void move(int32_t x, int32_t y); - void setShader(const std::string_view name, float fadein, float fadeout); + void setShader(std::string_view name, float fadein, float fadeout); PainterShaderProgramPtr getShader() { return m_shader; } Position getPosition(const Point& point, const Size& mapSize); @@ -155,12 +154,12 @@ class MapView : public LuaObject std::vector getSpectators(bool multiFloor = false); std::vector getSightSpectators(bool multiFloor = false); - bool isInRange(const Position& pos, bool ignoreZ = false) + bool isInRange(const Position& pos, const bool ignoreZ = false) { return getCameraPosition().isInRange(pos, m_posInfo.awareRange.left - 1, m_posInfo.awareRange.right - 2, m_posInfo.awareRange.top - 1, m_posInfo.awareRange.bottom - 2, ignoreZ); } - bool isInRangeEx(const Position& pos, bool ignoreZ = false) + bool isInRangeEx(const Position& pos, const bool ignoreZ = false) { return getCameraPosition().isInRange(pos, m_posInfo.awareRange.left, m_posInfo.awareRange.right, m_posInfo.awareRange.top, m_posInfo.awareRange.bottom, ignoreZ); } @@ -178,7 +177,7 @@ class MapView : public LuaObject void setDrawHighlightTarget(const bool enable) { m_drawHighlightTarget = enable; } - void setFloorFading(uint16_t value) { m_floorFading = value; } + void setFloorFading(const uint16_t value) { m_floorFading = value; } PainterShaderProgramPtr getNextShader() { return m_nextShader; } bool isSwitchingShader() { return !m_shaderSwitchDone; } @@ -215,7 +214,7 @@ class MapView : public LuaObject struct FloorData { MapObject cachedVisibleTiles; - stdext::timer fadingTimers; + Timer fadingTimers; }; struct Crosshair @@ -247,11 +246,11 @@ class MapView : public LuaObject bool canFloorFade() const { return m_floorViewMode == FADE && m_floorFading; } - float getFadeLevel(uint8_t z) const + float getFadeLevel(const uint8_t z) const { if (!canFloorFade()) return 1.f; - float fading = std::clamp(static_cast(m_floors[z].fadingTimers.elapsed_millis()) / static_cast(m_floorFading), 0.f, 1.f); + float fading = std::clamp(static_cast(m_floors[z].fadingTimers.ticksElapsed()) / static_cast(m_floorFading), 0.f, 1.f); if (z < m_cachedFirstVisibleFloor) fading = 1.0 - fading; return fading; @@ -322,7 +321,7 @@ class MapView : public LuaObject FadeType m_fadeType{ FadeType::NONE$ }; - AntialiasingMode m_antiAliasingMode{ AntialiasingMode::ANTIALIASING_DISABLED }; + AntialiasingMode m_antiAliasingMode{ ANTIALIASING_DISABLED }; std::vector m_floors; std::vector m_foregroundTiles; @@ -340,6 +339,6 @@ class MapView : public LuaObject TilePtr m_lastHighlightTile; TexturePtr m_crosshairTexture; - DrawConductor m_shadowConductor{ false, DrawOrder::FIFTH }; + DrawConductor m_shadowConductor{ .agroup = false, .order = FIFTH }; DrawPool* m_pool; }; diff --git a/src/client/minimap.cpp b/src/client/minimap.cpp index 5e083da567..66db001a44 100644 --- a/src/client/minimap.cpp +++ b/src/client/minimap.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -23,13 +23,12 @@ #include "minimap.h" #include "tile.h" -#include #include #include -#include #include #include #include +#include Minimap g_minimap; static MinimapTile nulltile; @@ -71,7 +70,7 @@ void MinimapBlock::update() m_mustUpdate = false; } -void MinimapBlock::updateTile(int x, int y, const MinimapTile& tile) +void MinimapBlock::updateTile(const int x, const int y, const MinimapTile& tile) { if (m_tiles[getTileIndex(x, y)].color != tile.color) m_mustUpdate = true; @@ -92,7 +91,7 @@ void Minimap::clean() m_tileBlocks[i].clear(); } -void Minimap::draw(const Rect& screenRect, const Position& mapCenter, float scale, const Color& color) +void Minimap::draw(const Rect& screenRect, const Position& mapCenter, const float scale, const Color& color) { if (screenRect.isEmpty()) return; @@ -137,7 +136,7 @@ void Minimap::draw(const Rect& screenRect, const Position& mapCenter, float scal g_drawPool.setClipRect(oldClipRect); } -Point Minimap::getTilePoint(const Position& pos, const Rect& screenRect, const Position& mapCenter, float scale) +Point Minimap::getTilePoint(const Position& pos, const Rect& screenRect, const Position& mapCenter, const float scale) { if (screenRect.isEmpty() || pos.z != mapCenter.z) return { -1 }; @@ -148,7 +147,7 @@ Point Minimap::getTilePoint(const Position& pos, const Rect& screenRect, const P return posoff + screenRect.topLeft() - off + (Point(1) * scale) / 2; } -Position Minimap::getTilePosition(const Point& point, const Rect& screenRect, const Position& mapCenter, float scale) +Position Minimap::getTilePosition(const Point& point, const Rect& screenRect, const Position& mapCenter, const float scale) { if (screenRect.isEmpty()) return {}; @@ -159,7 +158,7 @@ Position Minimap::getTilePosition(const Point& point, const Rect& screenRect, co return { pos2d.x, pos2d.y, mapCenter.z }; } -Rect Minimap::getTileRect(const Position& pos, const Rect& screenRect, const Position& mapCenter, float scale) +Rect Minimap::getTileRect(const Position& pos, const Rect& screenRect, const Position& mapCenter, const float scale) { if (screenRect.isEmpty() || pos.z != mapCenter.z) return {}; @@ -171,7 +170,7 @@ Rect Minimap::getTileRect(const Position& pos, const Rect& screenRect, const Pos return tileRect; } -Rect Minimap::calcMapRect(const Rect& screenRect, const Position& mapCenter, float scale) const +Rect Minimap::calcMapRect(const Rect& screenRect, const Position& mapCenter, const float scale) const { const int w = screenRect.width() / scale; const int h = std::ceil(screenRect.height() / scale); @@ -362,7 +361,7 @@ bool Minimap::loadOtmm(const std::string& fileName) if (ret != Z_OK || destLen != blockSize) break; - memcpy(reinterpret_cast(&block.getTiles()), decompressBuffer.data(), blockSize); + memcpy(&block.getTiles(), decompressBuffer.data(), blockSize); block.mustUpdate(); block.justSaw(); } @@ -405,7 +404,7 @@ void Minimap::saveOtmm(const std::string& fileName) for (uint_fast8_t z = 0; z <= g_gameConfig.getMapMaxZ(); ++z) { for (const auto& [index, block] : m_tileBlocks[z]) { - if (!(*block).wasSeen()) + if (!block->wasSeen()) continue; const auto& pos = getIndexPosition(index, z); @@ -414,14 +413,14 @@ void Minimap::saveOtmm(const std::string& fileName) fin->addU8(pos.z); unsigned long len = blockSize; - compress2(compressBuffer.data(), &len, (uint8_t*)&(*block).getTiles(), blockSize, COMPRESS_LEVEL); + compress2(compressBuffer.data(), &len, (uint8_t*)&block->getTiles(), blockSize, COMPRESS_LEVEL); fin->addU16(len); fin->write(compressBuffer.data(), len); } } // end of file - const Position invalidPos; + constexpr Position invalidPos; fin->addU16(invalidPos.x); fin->addU16(invalidPos.y); fin->addU8(invalidPos.z); diff --git a/src/client/minimap.h b/src/client/minimap.h index dbd2c3340a..7da9b8c290 100644 --- a/src/client/minimap.h +++ b/src/client/minimap.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -22,9 +22,9 @@ #pragma once -#include #include "declarations.h" #include "gameconfig.h" +#include constexpr uint8_t MMBLOCK_SIZE = 64; constexpr uint8_t OTMM_VERSION = 1; @@ -44,7 +44,7 @@ struct MinimapTile uint8_t flags{ 0 }; uint8_t color{ 255 }; uint8_t speed{ 10 }; - bool hasFlag(MinimapTileFlags flag) const { return flags & flag; } + bool hasFlag(const MinimapTileFlags flag) const { return flags & flag; } int getSpeed() const { return speed * 10; } bool operator==(const MinimapTile& other) const { return color == other.color && flags == other.flags && speed == other.speed; } bool operator!=(const MinimapTile& other) const { return !(*this == other); } @@ -56,9 +56,9 @@ class MinimapBlock void clean(); void update(); void updateTile(int x, int y, const MinimapTile& tile); - MinimapTile& getTile(int x, int y) { return m_tiles[getTileIndex(x, y)]; } - void resetTile(int x, int y) { m_tiles[getTileIndex(x, y)] = MinimapTile(); } - uint32_t getTileIndex(int x, int y) { return ((y % MMBLOCK_SIZE) * MMBLOCK_SIZE) + (x % MMBLOCK_SIZE); } + MinimapTile& getTile(const int x, const int y) { return m_tiles[getTileIndex(x, y)]; } + void resetTile(const int x, const int y) { m_tiles[getTileIndex(x, y)] = MinimapTile(); } + uint32_t getTileIndex(const int x, const int y) { return ((y % MMBLOCK_SIZE) * MMBLOCK_SIZE) + (x % MMBLOCK_SIZE); } const TexturePtr& getTexture() { return m_texture; } std::array& getTiles() { return m_tiles; } void mustUpdate() { m_mustUpdate = true; } @@ -120,7 +120,7 @@ class Minimap pos.y - pos.y % MMBLOCK_SIZE }; } - Position getIndexPosition(int index, int z) + Position getIndexPosition(const int index, const int z) { return { (index % (65536 / MMBLOCK_SIZE)) * MMBLOCK_SIZE, diff --git a/src/client/missile.cpp b/src/client/missile.cpp index 388c7e96a9..589a947ce9 100644 --- a/src/client/missile.cpp +++ b/src/client/missile.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,13 +21,13 @@ */ #include "missile.h" -#include #include "map.h" #include "thingtypemanager.h" #include "tile.h" #include +#include -void Missile::draw(const Point& dest, bool drawThings, const LightViewPtr& lightView) +void Missile::draw(const Point& dest, const bool drawThings, const LightViewPtr& lightView) { if (!canDraw() || isHided()) return; @@ -69,7 +69,7 @@ void Missile::setPath(const Position& fromPosition, const Position& toPosition) g_dispatcher.scheduleEvent([self = asMissile()] { g_map.removeThing(self); }, m_duration); } -void Missile::setDirection(Otc::Direction dir) { +void Missile::setDirection(const Otc::Direction dir) { m_direction = dir; if (m_direction == Otc::NorthWest) { diff --git a/src/client/missile.h b/src/client/missile.h index 68ff3e482e..4a1732f354 100644 --- a/src/client/missile.h +++ b/src/client/missile.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -22,16 +22,15 @@ #pragma once -#include -#include #include "thing.h" +#include - // @bindclass -class Missile : public Thing +// @bindclass +class Missile final : public Thing { public: - Missile() { m_drawConductor = { true, DrawOrder::FIFTH }; }; - void draw(const Point& dest, bool drawThings = true, const LightViewPtr& lightView = nullptr); + Missile() { m_drawConductor = { .agroup = true, .order = FIFTH }; }; + void draw(const Point& dest, bool drawThings = true, const LightViewPtr& lightView = nullptr) override; void setId(uint32_t id) override; void setPath(const Position& fromPosition, const Position& toPosition); diff --git a/src/client/outfit.cpp b/src/client/outfit.cpp index 5f190f941f..f62bd5359a 100644 --- a/src/client/outfit.cpp +++ b/src/client/outfit.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -122,31 +122,30 @@ void Outfit::resetClothes() setAura(0); setEffect(0); setShader("Outfit - Default"); - } -void Outfit::setHead(uint8_t head) { +void Outfit::setHead(const uint8_t head) { if (m_head == head) return; m_head = head; m_headColor = getColor(head); } -void Outfit::setBody(uint8_t body) { +void Outfit::setBody(const uint8_t body) { if (m_body == body) return; m_body = body; m_bodyColor = getColor(body); } -void Outfit::setLegs(uint8_t legs) { +void Outfit::setLegs(const uint8_t legs) { if (m_legs == legs) return; m_legs = legs; m_legsColor = getColor(legs); } -void Outfit::setFeet(uint8_t feet) { +void Outfit::setFeet(const uint8_t feet) { if (m_feet == feet) return; diff --git a/src/client/outfit.h b/src/client/outfit.h index ad7e6c1e29..eadef3104e 100644 --- a/src/client/outfit.h +++ b/src/client/outfit.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -22,8 +22,8 @@ #pragma once -#include #include "thingtypemanager.h" +#include class Outfit { @@ -36,22 +36,22 @@ class Outfit public: static Color getColor(int color); - void setId(uint16_t id) { m_id = id; } - void setAuxId(uint16_t id) { m_auxId = id; } - void setMount(uint16_t mount) { m_mount = mount; } - void setWing(uint16_t Wing) { m_wing = Wing; } - void setAura(uint16_t Aura) { m_aura = Aura; } - void setEffect(uint16_t Effect) { m_effect = Effect; } + void setId(const uint16_t id) { m_id = id; } + void setAuxId(const uint16_t id) { m_auxId = id; } + void setMount(const uint16_t mount) { m_mount = mount; } + void setWing(const uint16_t Wing) { m_wing = Wing; } + void setAura(const uint16_t Aura) { m_aura = Aura; } + void setEffect(const uint16_t Effect) { m_effect = Effect; } void setShader(const std::string& shader) { m_shader = shader; } void setHead(uint8_t head); void setBody(uint8_t body); void setLegs(uint8_t legs); void setFeet(uint8_t feet); - void setAddons(uint8_t addons) { m_addons = addons; } - void setTemp(bool temp) { m_temp = temp; } + void setAddons(const uint8_t addons) { m_addons = addons; } + void setTemp(const bool temp) { m_temp = temp; } - void setCategory(ThingCategory category) { m_category = category; } + void setCategory(const ThingCategory category) { m_category = category; } void resetClothes(); diff --git a/src/client/player.cpp b/src/client/player.cpp index 6cbbe5f0a7..dcdd3f0bf7 100644 --- a/src/client/player.cpp +++ b/src/client/player.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * 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/src/client/player.h b/src/client/player.h index f3e50251ce..1741d0dfe3 100644 --- a/src/client/player.h +++ b/src/client/player.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * 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/src/client/position.cpp b/src/client/position.cpp index fd45cf8a1c..25cbfb5a51 100644 --- a/src/client/position.cpp +++ b/src/client/position.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -25,7 +25,7 @@ bool Position::isMapPosition() const { return ((x >= 0) && (y >= 0) && (x < UINT16_MAX) && (y < UINT16_MAX) && (z <= g_gameConfig.getMapMaxZ())); } -bool Position::up(int8_t n) +bool Position::up(const int8_t n) { const int8_t nz = z - n; if (nz >= 0 && nz <= g_gameConfig.getMapMaxZ()) { @@ -35,7 +35,7 @@ bool Position::up(int8_t n) return false; } -bool Position::down(int8_t n) +bool Position::down(const int8_t n) { const int8_t nz = z + n; if (nz >= 0 && nz <= g_gameConfig.getMapMaxZ()) { @@ -46,7 +46,7 @@ bool Position::down(int8_t n) return false; } -bool Position::coveredUp(int8_t n) +bool Position::coveredUp(const int8_t n) { const int32_t nx = x + n, ny = y + n; const int8_t nz = z - n; @@ -58,7 +58,7 @@ bool Position::coveredUp(int8_t n) return false; } -bool Position::coveredDown(int8_t n) +bool Position::coveredDown(const int8_t n) { const int32_t nx = x - n, ny = y - n; const int8_t nz = z + n; diff --git a/src/client/position.h b/src/client/position.h index 50274310bb..541bf79484 100644 --- a/src/client/position.h +++ b/src/client/position.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -22,10 +22,9 @@ #pragma once +#include "const.h" #include -#include #include -#include "const.h" #include #include @@ -38,10 +37,10 @@ class Position { public: Position() = default; - Position(int32_t x, int32_t y, uint8_t z) : x(x), y(y), z(z) {} + Position(const int32_t x, const int32_t y, const uint8_t z) : x(x), y(y), z(z) {} Position(const Position& position) = default; - Position translatedToDirection(Otc::Direction direction) const + Position translatedToDirection(const Otc::Direction direction) const { Position pos = *this; switch (direction) { @@ -79,7 +78,7 @@ class Position return pos; } - Position translatedToReverseDirection(Otc::Direction direction) const + Position translatedToReverseDirection(const Otc::Direction direction) const { Position pos = *this; switch (direction) { @@ -194,8 +193,8 @@ class Position double distance(const Position& pos) const { return sqrt(pow(pos.x - x, 2) + pow(pos.y - y, 2)); } uint16_t manhattanDistance(const Position& pos) const { return static_cast(std::abs(pos.x - x) + std::abs(pos.y - y)); } - void translate(int32_t dx, int32_t dy, int8_t dz = 0) { x += dx; y += dy; z += dz; } - Position translated(int32_t dx, int32_t dy, int8_t dz = 0) const { Position pos = *this; pos.x += dx; pos.y += dy; pos.z += dz; return pos; } + void translate(const int32_t dx, const int32_t dy, const int8_t dz = 0) { x += dx; y += dy; z += dz; } + Position translated(const int32_t dx, const int32_t dy, const int8_t dz = 0) const { Position pos = *this; pos.x += dx; pos.y += dy; pos.z += dz; return pos; } std::array getPositionsAround() const { @@ -226,7 +225,7 @@ class Position bool operator==(const Position& other) const { return other.x == x && other.y == y && other.z == z; } bool operator!=(const Position& other) const { return other.x != x || other.y != y || other.z != z; } - bool isInRange(const Position& pos, uint16_t xRange, uint16_t yRange, const bool ignoreZ = false) const + bool isInRange(const Position& pos, const uint16_t xRange, const uint16_t yRange, const bool ignoreZ = false) const { auto _pos = pos; if (pos.z != z) { @@ -237,7 +236,7 @@ class Position return std::abs(x - _pos.x) <= xRange && std::abs(y - _pos.y) <= yRange && z == pos.z; } - bool isInRange(const Position& pos, uint16_t minXRange, uint16_t maxXRange, uint16_t minYRange, uint16_t maxYRange, const bool ignoreZ = false) const + bool isInRange(const Position& pos, const uint16_t minXRange, const uint16_t maxXRange, const uint16_t minYRange, const uint16_t maxYRange, const bool ignoreZ = false) const { auto _pos = pos; if (pos.z != z) { diff --git a/src/client/protocolcodes.cpp b/src/client/protocolcodes.cpp index fc0b4ed36d..36550a8276 100644 --- a/src/client/protocolcodes.cpp +++ b/src/client/protocolcodes.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -26,7 +26,7 @@ namespace Proto { stdext::map messageModesMap; - void buildMessageModesMap(int version) + void buildMessageModesMap(const int version) { messageModesMap.clear(); @@ -224,15 +224,15 @@ namespace Proto } } - Otc::MessageMode translateMessageModeFromServer(uint8_t mode) + Otc::MessageMode translateMessageModeFromServer(const uint8_t mode) { - const auto it = std::find_if(messageModesMap.begin(), messageModesMap.end(), [=](const std::pair& p) { return p.second == mode; }); + const auto it = std::ranges::find_if(messageModesMap, [=](const std::pair& p) { return p.second == mode; }); if (it != messageModesMap.end()) return static_cast(it->first); return Otc::MessageInvalid; } - uint8_t translateMessageModeToServer(Otc::MessageMode mode) + uint8_t translateMessageModeToServer(const Otc::MessageMode mode) { if (mode >= Otc::LastMessage) return Otc::MessageInvalid; diff --git a/src/client/protocolcodes.h b/src/client/protocolcodes.h index 957a07ffc3..a6c2c1492d 100644 --- a/src/client/protocolcodes.h +++ b/src/client/protocolcodes.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -117,6 +117,7 @@ namespace Proto GameServerMissleEffect = 133, // Anthem on 13.x GameServerItemClasses = 134, GameServerTrappers = 135, + GameServerCloseForgeWindow = 137, GameServerCreatureData = 139, GameServerCreatureHealth = 140, GameServerCreatureLight = 141, diff --git a/src/client/protocolgame.cpp b/src/client/protocolgame.cpp index bcde3cde11..2e1bef2853 100644 --- a/src/client/protocolgame.cpp +++ b/src/client/protocolgame.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,8 +21,8 @@ */ #include "protocolgame.h" -#include "game.h" #include "framework/net/inputmessage.h" +#include "game.h" void ProtocolGame::login(const std::string_view accountName, const std::string_view accountPassword, const std::string_view host, uint16_t port, const std::string_view characterName, const std::string_view authenticatorToken, const std::string_view sessionKey) @@ -33,7 +33,13 @@ void ProtocolGame::login(const std::string_view accountName, const std::string_v m_sessionKey = sessionKey; m_characterName = characterName; +#ifndef __EMSCRIPTEN__ connect(host, port); +#else + if (port == 7172) + port = 443; + connect(host, port, true); +#endif } void ProtocolGame::onConnect() diff --git a/src/client/protocolgame.h b/src/client/protocolgame.h index 3549e9bc2c..cd266d4f39 100644 --- a/src/client/protocolgame.h +++ b/src/client/protocolgame.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -22,19 +22,19 @@ #pragma once -#include #include "creature.h" #include "declarations.h" #include "protocolcodes.h" +#include -class ProtocolGame : public Protocol +class ProtocolGame final : public Protocol { public: - void login(const std::string_view accountName, const std::string_view accountPassword, const std::string_view host, uint16_t port, const std::string_view characterName, const std::string_view authenticatorToken, const std::string_view sessionKey); + void login(std::string_view accountName, std::string_view accountPassword, std::string_view host, uint16_t port, std::string_view characterName, std::string_view authenticatorToken, std::string_view sessionKey); void send(const OutputMessagePtr& outputMessage) override; - void sendExtendedOpcode(const uint8_t opcode, const std::string& buffer); - void sendLoginPacket(const uint32_t challengeTimestamp, const uint8_t challengeRandom); + void sendExtendedOpcode(uint8_t opcode, const std::string& buffer); + void sendLoginPacket(uint32_t challengeTimestamp, uint8_t challengeRandom); void sendEnterGame(); void sendLogout(); void sendPing(); @@ -54,104 +54,104 @@ class ProtocolGame : public Protocol void sendTurnSouth(); void sendTurnWest(); void sendGmTeleport(const Position& pos); - void sendEquipItem(const uint16_t itemId, const uint16_t countOrSubType); - void sendMove(const Position& fromPos, const uint16_t thingId, const uint8_t stackpos, const Position& toPos, const uint16_t count); - void sendInspectNpcTrade(const uint16_t itemId, const uint16_t count); - void sendBuyItem(const uint16_t itemId, const uint8_t subType, const uint16_t amount, const bool ignoreCapacity, const bool buyWithBackpack); - void sendSellItem(const uint16_t itemId, const uint8_t subType, const uint16_t amount, const bool ignoreEquipped); + void sendEquipItem(uint16_t itemId, uint16_t countOrSubType); + void sendMove(const Position& fromPos, uint16_t thingId, uint8_t stackpos, const Position& toPos, uint16_t count); + void sendInspectNpcTrade(uint16_t itemId, uint16_t count); + void sendBuyItem(uint16_t itemId, uint8_t subType, uint16_t amount, bool ignoreCapacity, bool buyWithBackpack); + void sendSellItem(uint16_t itemId, uint8_t subType, uint16_t amount, bool ignoreEquipped); void sendCloseNpcTrade(); - void sendRequestTrade(const Position& pos, const uint16_t thingId, const uint8_t stackpos, const uint32_t creatureId); - void sendInspectTrade(const bool counterOffer, const uint8_t index); + void sendRequestTrade(const Position& pos, uint16_t thingId, uint8_t stackpos, uint32_t creatureId); + void sendInspectTrade(bool counterOffer, uint8_t index); void sendAcceptTrade(); void sendRejectTrade(); - void sendUseItem(const Position& position, const uint16_t itemId, const uint8_t stackpos, const uint8_t index); - void sendUseItemWith(const Position& fromPos, const uint16_t itemId, const uint8_t fromStackPos, const Position& toPos, const uint16_t toThingId, const uint8_t toStackPos); - void sendUseOnCreature(const Position& pos, const uint16_t thingId, const uint8_t stackpos, const uint32_t creatureId); - void sendRotateItem(const Position& pos, const uint16_t thingId, const uint8_t stackpos); - void sendOnWrapItem(const Position& pos, const uint16_t thingId, const uint8_t stackpos); - void sendCloseContainer(const uint8_t containerId); - void sendUpContainer(const uint8_t containerId); - void sendEditText(const uint32_t id, const std::string_view text); - void sendEditList(const uint32_t id, const uint8_t doorId, const std::string_view text); - void sendLook(const Position& position, const uint16_t itemId, const uint8_t stackpos); - void sendLookCreature(const uint32_t creatureId); - void sendTalk(const Otc::MessageMode mode, const uint16_t channelId, const std::string_view receiver, const std::string_view message); + void sendUseItem(const Position& position, uint16_t itemId, uint8_t stackpos, uint8_t index); + void sendUseItemWith(const Position& fromPos, uint16_t itemId, uint8_t fromStackPos, const Position& toPos, uint16_t toThingId, uint8_t toStackPos); + void sendUseOnCreature(const Position& pos, uint16_t thingId, uint8_t stackpos, uint32_t creatureId); + void sendRotateItem(const Position& pos, uint16_t thingId, uint8_t stackpos); + void sendOnWrapItem(const Position& pos, uint16_t thingId, uint8_t stackpos); + void sendCloseContainer(uint8_t containerId); + void sendUpContainer(uint8_t containerId); + void sendEditText(uint32_t id, std::string_view text); + void sendEditList(uint32_t id, uint8_t doorId, std::string_view text); + void sendLook(const Position& position, uint16_t itemId, uint8_t stackpos); + void sendLookCreature(uint32_t creatureId); + void sendTalk(Otc::MessageMode mode, uint16_t channelId, std::string_view receiver, std::string_view message); void sendRequestChannels(); - void sendJoinChannel(const uint16_t channelId); - void sendLeaveChannel(const uint16_t channelId); - void sendOpenPrivateChannel(const std::string_view receiver); - void sendOpenRuleViolation(const std::string_view reporter); - void sendCloseRuleViolation(const std::string_view reporter); + void sendJoinChannel(uint16_t channelId); + void sendLeaveChannel(uint16_t channelId); + void sendOpenPrivateChannel(std::string_view receiver); + void sendOpenRuleViolation(std::string_view reporter); + void sendCloseRuleViolation(std::string_view reporter); void sendCancelRuleViolation(); void sendCloseNpcChannel(); - void sendChangeFightModes(const Otc::FightModes fightMode, const Otc::ChaseModes chaseMode, const bool safeFight, const Otc::PVPModes pvpMode); - void sendAttack(const uint32_t creatureId, const uint32_t seq); - void sendFollow(const uint32_t creatureId, const uint32_t seq); - void sendInviteToParty(const uint32_t creatureId); - void sendJoinParty(const uint32_t creatureId); - void sendRevokeInvitation(const uint32_t creatureId); - void sendPassLeadership(const uint32_t creatureId); + void sendChangeFightModes(Otc::FightModes fightMode, Otc::ChaseModes chaseMode, bool safeFight, Otc::PVPModes pvpMode); + void sendAttack(uint32_t creatureId, uint32_t seq); + void sendFollow(uint32_t creatureId, uint32_t seq); + void sendInviteToParty(uint32_t creatureId); + void sendJoinParty(uint32_t creatureId); + void sendRevokeInvitation(uint32_t creatureId); + void sendPassLeadership(uint32_t creatureId); void sendLeaveParty(); - void sendShareExperience(const bool active); + void sendShareExperience(bool active); void sendOpenOwnChannel(); - void sendInviteToOwnChannel(const std::string_view name); - void sendExcludeFromOwnChannel(const std::string_view name); + void sendInviteToOwnChannel(std::string_view name); + void sendExcludeFromOwnChannel(std::string_view name); void sendCancelAttackAndFollow(); - void sendRefreshContainer(const uint8_t containerId); + void sendRefreshContainer(uint8_t containerId); void sendRequestBless(); void sendRequestOutfit(); - void sendTyping(const bool typing); + void sendTyping(bool typing); void sendChangeOutfit(const Outfit& outfit); - void sendMountStatus(const bool mount); - void sendAddVip(const std::string_view name); - void sendRemoveVip(const uint32_t playerId); - void sendEditVip(const uint32_t playerId, const std::string_view description, const uint32_t iconId, const bool notifyLogin, const std::vector& groupIDs = {}); - void sendEditVipGroups(const Otc::GroupsEditInfoType_t action, const uint8_t groupId, const std::string_view groupName); - void sendBugReport(const std::string_view comment); - void sendRuleViolation(const std::string_view target, const uint8_t reason, const uint8_t action, const std::string_view comment, const std::string_view statement, const uint16_t statementId, const bool ipBanishment); - void sendDebugReport(const std::string_view a, const std::string_view b, const std::string_view c, const std::string_view d); + void sendMountStatus(bool mount); + void sendAddVip(std::string_view name); + void sendRemoveVip(uint32_t playerId); + void sendEditVip(uint32_t playerId, std::string_view description, uint32_t iconId, bool notifyLogin, const std::vector& groupIDs = {}); + void sendEditVipGroups(Otc::GroupsEditInfoType_t action, uint8_t groupId, std::string_view groupName); + void sendBugReport(std::string_view comment); + void sendRuleViolation(std::string_view target, uint8_t reason, uint8_t action, std::string_view comment, std::string_view statement, uint16_t statementId, bool ipBanishment); + void sendDebugReport(std::string_view a, std::string_view b, std::string_view c, std::string_view d); void sendRequestQuestLog(); - void sendRequestQuestLine(const uint16_t questId); - void sendNewNewRuleViolation(const uint8_t reason, const uint8_t action, const std::string_view characterName, const std::string_view comment, const std::string_view translation); - void sendRequestItemInfo(const uint16_t itemId, const uint8_t subType, const uint8_t index); - void sendAnswerModalDialog(const uint32_t dialog, const uint8_t button, const uint8_t choice); + void sendRequestQuestLine(uint16_t questId); + void sendNewNewRuleViolation(uint8_t reason, uint8_t action, std::string_view characterName, std::string_view comment, std::string_view translation); + void sendRequestItemInfo(uint16_t itemId, uint8_t subType, uint8_t index); + void sendAnswerModalDialog(uint32_t dialog, uint8_t button, uint8_t choice); void sendBrowseField(const Position& position); - void sendSeekInContainer(const uint8_t containerId, const uint16_t index); - void sendBuyStoreOffer(const uint32_t offerId, const uint8_t productType, const std::string_view name); - void sendRequestTransactionHistory(const uint32_t page, const uint32_t entriesPerPage); - void sendRequestStoreOffers(const std::string_view categoryName, const uint8_t serviceType); - void sendOpenStore(const uint8_t serviceType, const std::string_view category); - void sendTransferCoins(const std::string_view recipient, const uint16_t amount); - void sendOpenTransactionHistory(const uint8_t entriesPerPage); + void sendSeekInContainer(uint8_t containerId, uint16_t index); + void sendBuyStoreOffer(uint32_t offerId, uint8_t productType, std::string_view name); + void sendRequestTransactionHistory(uint32_t page, uint32_t entriesPerPage); + void sendRequestStoreOffers(std::string_view categoryName, uint8_t serviceType); + void sendOpenStore(uint8_t serviceType, std::string_view category); + void sendTransferCoins(std::string_view recipient, uint16_t amount); + void sendOpenTransactionHistory(uint8_t entriesPerPage); void sendMarketLeave(); - void sendMarketBrowse(const uint8_t browseId, const uint16_t browseType); - void sendMarketCreateOffer(const uint8_t type, const uint16_t itemId, const uint8_t itemTier, const uint16_t amount, const uint64_t price, const uint8_t anonymous); - void sendMarketCancelOffer(const uint32_t timestamp, const uint16_t counter); - void sendMarketAcceptOffer(const uint32_t timestamp, const uint16_t counter, const uint16_t amount); - void sendPreyAction(const uint8_t slot, const uint8_t actionType, const uint16_t index); + void sendMarketBrowse(uint8_t browseId, uint16_t browseType); + void sendMarketCreateOffer(uint8_t type, uint16_t itemId, uint8_t itemTier, uint16_t amount, uint64_t price, uint8_t anonymous); + void sendMarketCancelOffer(uint32_t timestamp, uint16_t counter); + void sendMarketAcceptOffer(uint32_t timestamp, uint16_t counter, uint16_t amount); + void sendPreyAction(uint8_t slot, uint8_t actionType, uint16_t index); void sendPreyRequest(); - void sendApplyImbuement(const uint8_t slot, const uint32_t imbuementId, const bool protectionCharm); - void sendClearImbuement(const uint8_t slot); + void sendApplyImbuement(uint8_t slot, uint32_t imbuementId, bool protectionCharm); + void sendClearImbuement(uint8_t slot); void sendCloseImbuingWindow(); - void sendStashWithdraw(const uint16_t itemId, const uint32_t count, const uint8_t stackpos); - void sendHighscoreInfo(const uint8_t action, const uint8_t category, const uint32_t vocation, const std::string_view world, const uint8_t worldType, const uint8_t battlEye, const uint16_t page, const uint8_t totalPages); + void sendStashWithdraw(uint16_t itemId, uint32_t count, uint8_t stackpos); + void sendHighscoreInfo(uint8_t action, uint8_t category, uint32_t vocation, std::string_view world, uint8_t worldType, uint8_t battlEye, uint16_t page, uint8_t totalPages); void sendImbuementDurations(bool isOpen = false); void sendRequestBestiary(); - void sendRequestBestiaryOverview(const std::string_view catName); - void sendRequestBestiarySearch(const uint16_t raceId); - void sendBuyCharmRune(const uint8_t runeId, const uint8_t action, const uint16_t raceId); - void sendCyclopediaRequestCharacterInfo(const uint32_t playerId, const Otc::CyclopediaCharacterInfoType_t characterInfoType, const uint16_t entriesPerPage, const uint16_t page); + void sendRequestBestiaryOverview(std::string_view catName); + void sendRequestBestiarySearch(uint16_t raceId); + void sendBuyCharmRune(uint8_t runeId, uint8_t action, uint16_t raceId); + void sendCyclopediaRequestCharacterInfo(uint32_t playerId, Otc::CyclopediaCharacterInfoType_t characterInfoType, uint16_t entriesPerPage, uint16_t page); void sendRequestBosstiaryInfo(); void sendRequestBossSlootInfo(); - void sendRequestBossSlotAction(const uint8_t action, const uint32_t raceId); - void sendStatusTrackerBestiary(const uint16_t raceId, const bool status); - void requestQuickLootBlackWhiteList(const uint8_t filter, const uint16_t size, const std::vector& listedItems); - void openContainerQuickLoot(const uint8_t action, const uint8_t category, const Position& pos, const uint16_t itemId, const uint8_t stackpos, const bool useMainAsFallback); + void sendRequestBossSlotAction(uint8_t action, uint32_t raceId); + void sendStatusTrackerBestiary(uint16_t raceId, bool status); + void requestQuickLootBlackWhiteList(uint8_t filter, uint16_t size, const std::vector& listedItems); + void openContainerQuickLoot(uint8_t action, uint8_t category, const Position& pos, uint16_t itemId, uint8_t stackpos, bool useMainAsFallback); void sendInspectionNormalObject(const Position& position); - void sendInspectionObject(const Otc::InspectObjectTypes inspectionType, const uint16_t itemId, const uint8_t itemCount); + void sendInspectionObject(Otc::InspectObjectTypes inspectionType, uint16_t itemId, uint8_t itemCount); // otclient only - void sendChangeMapAwareRange(const uint8_t xrange, const uint8_t yrange); + void sendChangeMapAwareRange(uint8_t xrange, uint8_t yrange); protected: void onConnect() override; @@ -230,7 +230,8 @@ class ProtocolGame : public Protocol void parseItemClasses(const InputMessagePtr& msg); void parseCreatureMark(const InputMessagePtr& msg); void parseTrappers(const InputMessagePtr& msg); - void addCreatureIcon(const InputMessagePtr& msg); + void addCreatureIcon(const InputMessagePtr& msg) const; + void parseCloseForgeWindow(const InputMessagePtr& msg); void parseCreatureData(const InputMessagePtr& msg); void parseCreatureHealth(const InputMessagePtr& msg); void parseCreatureLight(const InputMessagePtr& msg); @@ -333,14 +334,13 @@ class ProtocolGame : public Protocol void parseBestiaryMonsterData(const InputMessagePtr& msg); void parseBestiaryCharmsData(const InputMessagePtr& msg); - void parseHighscores(const InputMessagePtr& msg); void parseAttachedEffect(const InputMessagePtr& msg); void parseDetachEffect(const InputMessagePtr& msg); void parseCreatureShader(const InputMessagePtr& msg); void parseMapShader(const InputMessagePtr& msg); - MarketOffer readMarketOffer(const InputMessagePtr& msg, const uint8_t action, const uint16_t var); + MarketOffer readMarketOffer(const InputMessagePtr& msg, uint8_t action, uint16_t var); Imbuement getImbuementInfo(const InputMessagePtr& msg); PreyMonster getPreyMonster(const InputMessagePtr& msg) const; @@ -351,7 +351,7 @@ class ProtocolGame : public Protocol int setFloorDescription(const InputMessagePtr& msg, int x, int y, int z, int width, int height, int offset, int skip); int setTileDescription(const InputMessagePtr& msg, Position position); - Outfit getOutfit(const InputMessagePtr& msg, const bool parseMount = true) const; + Outfit getOutfit(const InputMessagePtr& msg, bool parseMount = true) const; ThingPtr getThing(const InputMessagePtr& msg); ThingPtr getMappedThing(const InputMessagePtr& msg) const; CreaturePtr getCreature(const InputMessagePtr& msg, int type = 0) const; diff --git a/src/client/protocolgameparse.cpp b/src/client/protocolgameparse.cpp index 6d9705b279..61c6384abc 100644 --- a/src/client/protocolgameparse.cpp +++ b/src/client/protocolgameparse.cpp @@ -1,5 +1,5 @@ /* -* Copyright (c) 2010-2022 OTClient +* Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -25,17 +25,16 @@ #include "effect.h" #include "framework/net/inputmessage.h" -#include +#include "attachedeffectmanager.h" #include "item.h" #include "localplayer.h" #include "luavaluecasts_client.h" #include "map.h" #include "missile.h" -#include "statictext.h" #include "thingtypemanager.h" -#include "attachedeffectmanager.h" #include "tile.h" -#include "time.h" +#include +#include void ProtocolGame::parseMessage(const InputMessagePtr& msg) { @@ -267,6 +266,9 @@ void ProtocolGame::parseMessage(const InputMessagePtr& msg) case Proto::GameServerTrappers: parseTrappers(msg); break; + case Proto::GameServerCloseForgeWindow: + parseCloseForgeWindow(msg); + break; case Proto::GameServerCreatureData: parseCreatureData(msg); break; @@ -582,7 +584,6 @@ void ProtocolGame::parseMessage(const InputMessagePtr& msg) break; default: throw Exception("unhandled opcode %d", opcode); - break; } prevOpcode = opcode; } @@ -858,7 +859,7 @@ void ProtocolGame::parseStoreTransactionHistory(const InputMessagePtr& msg) cons msg->getU32(); // 0 const uint32_t time = msg->getU32(); const uint8_t mode = msg->getU8(); //0 = normal, 1 = gift, 2 = refund - uint32_t rawAmount = msg->getU32(); + const uint32_t rawAmount = msg->getU32(); int32_t amount; if (rawAmount > INT32_MAX) { amount = -static_cast(UINT32_MAX - rawAmount + 1); @@ -1072,7 +1073,7 @@ void ProtocolGame::parseStoreError(const InputMessagePtr& msg) const const uint8_t errorType = msg->getU8(); const auto& message = msg->getString(); - g_lua.callGlobalField("g_game", "onParseStoreError", message); + g_lua.callGlobalField("g_game", "onParseStoreError", message, errorType); } void ProtocolGame::parseUnjustifiedStats(const InputMessagePtr& msg) @@ -1085,7 +1086,10 @@ void ProtocolGame::parseUnjustifiedStats(const InputMessagePtr& msg) const uint8_t killsMonthRemaining = msg->getU8(); const uint8_t skullTime = msg->getU8(); - g_game.setUnjustifiedPoints({ killsDay, killsDayRemaining, killsWeek, killsWeekRemaining, killsMonth, killsMonthRemaining, skullTime }); + g_game.setUnjustifiedPoints({ .killsDay = killsDay, .killsDayRemaining = killsDayRemaining, .killsWeek = killsWeek, .killsWeekRemaining = + killsWeekRemaining, + .killsMonth = killsMonth, .killsMonthRemaining = killsMonthRemaining, .skullTime = skullTime + }); } void ProtocolGame::parsePvpSituations(const InputMessagePtr& msg) @@ -1616,8 +1620,8 @@ void ProtocolGame::parseMagicEffect(const InputMessagePtr& msg) case Otc::MAGIC_EFFECTS_CREATE_DISTANCEEFFECT: case Otc::MAGIC_EFFECTS_CREATE_DISTANCEEFFECT_REVERSED: { const uint16_t shotId = g_game.getFeature(Otc::GameEffectU16) ? msg->getU16() : msg->getU8(); - const int8_t offsetX = static_cast(msg->getU8()); - const int8_t offsetY = static_cast(msg->getU8()); + const auto offsetX = static_cast(msg->getU8()); + const auto offsetY = static_cast(msg->getU8()); if (!g_things.isValidDatId(shotId, ThingCategoryMissile)) { g_logger.traceError(stdext::format("invalid missile id %d", shotId)); return; @@ -1825,14 +1829,13 @@ void ProtocolGame::parseTrappers(const InputMessagePtr& msg) const auto& creature = g_map.getCreatureById(creatureId); if (!creature) { g_logger.traceError(stdext::format("ProtocolGame::parseTrappers: could not get creature with id %d", creatureId)); - continue; } //TODO: set creature as trapper } } -void ProtocolGame::addCreatureIcon(const InputMessagePtr& msg) +void ProtocolGame::addCreatureIcon(const InputMessagePtr& msg) const { const uint8_t sizeIcons = msg->getU8(); for (auto i = 0; i < sizeIcons; ++i) { @@ -1844,6 +1847,11 @@ void ProtocolGame::addCreatureIcon(const InputMessagePtr& msg) // TODO: implement creature icons usage } +void ProtocolGame::parseCloseForgeWindow(const InputMessagePtr& /*msg*/) +{ + g_lua.callGlobalField("g_game", "onCloseForgeCloseWindows"); +} + void ProtocolGame::parseCreatureData(const InputMessagePtr& msg) { const uint32_t creatureId = msg->getU32(); @@ -2314,7 +2322,6 @@ void ProtocolGame::parseTalk(const InputMessagePtr& msg) break; default: throw Exception("ProtocolGame::parseTalk: unknown message mode %d", mode); - break; } const auto& text = msg->getString(); @@ -2468,7 +2475,6 @@ void ProtocolGame::parseTextMessage(const InputMessagePtr& msg) } case Otc::MessageInvalid: throw Exception("ProtocolGame::parseTextMessage: unknown message mode %d", mode); - break; default: break; } @@ -2863,7 +2869,7 @@ void ProtocolGame::parseBestiaryCharmsData(const InputMessagePtr& msg) charm.description = msg->getString(); msg->getU8(); charm.unlockPrice = msg->getU16(); - charm.unlocked = static_cast(msg->getU8() == 1); + charm.unlocked = msg->getU8() == 1; charm.asignedStatus = false; charm.raceId = 0; charm.removeRuneCost = 0; @@ -2933,12 +2939,16 @@ void ProtocolGame::parseQuestLine(const InputMessagePtr& msg) const uint16_t questId = msg->getU16(); const uint8_t missionCount = msg->getU8(); - std::vector> questMissions; + std::vector> questMissions; for (auto i = 0; i < missionCount; ++i) { + auto missionId = 0; + if (g_game.getClientVersion() >= 1200) { + missionId = msg->getU16(); + } const auto& missionName = msg->getString(); const auto& missionDescrition = msg->getString(); - questMissions.emplace_back(missionName, missionDescrition); + questMissions.emplace_back(missionName, missionDescrition, missionId); } g_game.processQuestLine(questId, questMissions); @@ -3084,7 +3094,7 @@ void ProtocolGame::parseCreatureType(const InputMessagePtr& msg) creature->setType(type); } -void ProtocolGame::setMapDescription(const InputMessagePtr& msg, int x, int y, int z, int width, int height) +void ProtocolGame::setMapDescription(const InputMessagePtr& msg, const int x, const int y, const int z, const int width, const int height) { int startz; int endz; @@ -3106,7 +3116,7 @@ void ProtocolGame::setMapDescription(const InputMessagePtr& msg, int x, int y, i } } -int ProtocolGame::setFloorDescription(const InputMessagePtr& msg, int x, int y, int z, int width, int height, int offset, int skip) +int ProtocolGame::setFloorDescription(const InputMessagePtr& msg, const int x, const int y, const int z, const int width, const int height, const int offset, int skip) { for (auto nx = 0; nx < width; ++nx) { for (auto ny = 0; ny < height; ++ny) { @@ -3122,7 +3132,7 @@ int ProtocolGame::setFloorDescription(const InputMessagePtr& msg, int x, int y, return skip; } -int ProtocolGame::setTileDescription(const InputMessagePtr& msg, Position position) +int ProtocolGame::setTileDescription(const InputMessagePtr& msg, const Position position) { g_map.cleanTile(position); @@ -3288,8 +3298,6 @@ CreaturePtr ProtocolGame::getCreature(const InputMessagePtr& msg, int type) cons creatureType = msg->getU8(); } else if (id >= Proto::PlayerStartId && id < Proto::PlayerEndId) { creatureType = Proto::CreatureTypePlayer; - } else if (id >= Proto::MonsterStartId && id < Proto::MonsterEndId) { - creatureType = Proto::CreatureTypeMonster; } else { creatureType = Proto::CreatureTypeNpc; } @@ -3356,12 +3364,7 @@ CreaturePtr ProtocolGame::getCreature(const InputMessagePtr& msg, int type) cons const uint16_t speed = msg->getU16(); if (g_game.getClientVersion() >= 1281) { - const uint8_t iconDebuff = msg->getU8(); // creature debuffs - if (iconDebuff != 0) { - msg->getU8(); // Icon - msg->getU8(); // Update (?) - msg->getU16(); // Counter text - } + addCreatureIcon(msg); } const uint8_t skull = msg->getU8(); @@ -3628,7 +3631,7 @@ ItemPtr ProtocolGame::getItem(const InputMessagePtr& msg, int id) if (g_game.getFeature(Otc::GameThingCounter)) { if (item->hasWearOut()) { - msg->getU32(); // Item charge (UI) + item->setCharges(msg->getU32()); msg->getU8(); // Is brand-new } } @@ -3669,7 +3672,7 @@ void ProtocolGame::parseShowDescription(const InputMessagePtr& msg) void ProtocolGame::parseBestiaryTracker(const InputMessagePtr& msg) { - uint8_t trackerType = msg->getU8(); // 0x00 para bestiary, 0x01 para boss + const uint8_t trackerType = msg->getU8(); // 0x00 para bestiary, 0x01 para boss const uint8_t size = msg->getU8(); std::vector> trackerData; @@ -4071,7 +4074,7 @@ void ProtocolGame::parseCyclopediaCharacterInfo(const InputMessagePtr& msg) const uint16_t baseSkill = msg->getU16(); msg->getU16(); // base + loyalty bonus(?) const uint16_t skillPercent = msg->getU16() / 100; - skills.push_back({ skillLevel, skillPercent, baseSkill }); + skills.push_back({ skillLevel, baseSkill, skillPercent }); } const uint8_t combatCount = msg->getU8(); @@ -4564,7 +4567,7 @@ PreyMonster ProtocolGame::getPreyMonster(const InputMessagePtr& msg) const { const auto& name = msg->getString(); const auto& outfit = getOutfit(msg, false); - return { name , outfit }; + return { .name = name, .outfit = outfit }; } std::vector ProtocolGame::getPreyMonsters(const InputMessagePtr& msg) @@ -4976,7 +4979,9 @@ MarketOffer ProtocolGame::readMarketOffer(const InputMessagePtr& msg, const uint } g_lua.callGlobalField("g_game", "onMarketReadOffer", action, amount, counter, itemId, playerName, price, state, timestamp, var); - return { timestamp, counter, action, itemId, amount, price, playerName, state, var }; + return { .timestamp = timestamp, .counter = counter, .action = action, .itemId = itemId, .amount = amount, .price = price, + .playerName = playerName, .state = state, .var = var + }; } void ProtocolGame::parseMarketBrowse(const InputMessagePtr& msg) @@ -4997,7 +5002,6 @@ void ProtocolGame::parseMarketBrowse(const InputMessagePtr& msg) const uint32_t buyOfferCount = msg->getU32(); - std::vector offers; for (uint32_t i = 0; i < buyOfferCount; ++i) { @@ -5253,4 +5257,4 @@ void ProtocolGame::parseHighscores(const InputMessagePtr& msg) const uint32_t entriesTs = msg->getU32(); // last update g_game.processHighscore(serverName, world, worldType, battlEye, vocations, categories, page, totalPages, highscores, entriesTs); -} +} \ No newline at end of file diff --git a/src/client/protocolgamesend.cpp b/src/client/protocolgamesend.cpp index 4e39e106c9..8cea01e1a4 100644 --- a/src/client/protocolgamesend.cpp +++ b/src/client/protocolgamesend.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -20,12 +20,10 @@ * THE SOFTWARE. */ -#include -#include -#include +#include "framework/net/outputmessage.h" #include "game.h" #include "protocolgame.h" -#include "framework/net/outputmessage.h" +#include void ProtocolGame::send(const OutputMessagePtr& outputMessage) { @@ -323,7 +321,7 @@ void ProtocolGame::sendMove(const Position& fromPos, const uint16_t thingId, con msg->addU16(thingId); msg->addU8(stackpos); addPosition(msg, toPos); - if(g_game.getFeature(Otc::GameCountU16)) + if (g_game.getFeature(Otc::GameCountU16)) msg->addU16(count); else msg->addU8(static_cast(count)); @@ -352,8 +350,8 @@ void ProtocolGame::sendBuyItem(const uint16_t itemId, const uint8_t subType, con msg->addU16(amount); else msg->addU8(static_cast(amount)); - msg->addU8(static_cast(ignoreCapacity)); - msg->addU8(static_cast(buyWithBackpack)); + msg->addU8(ignoreCapacity); + msg->addU8(buyWithBackpack); send(msg); } @@ -367,7 +365,7 @@ void ProtocolGame::sendSellItem(const uint16_t itemId, const uint8_t subType, co msg->addU16(amount); else msg->addU8(static_cast(amount)); - msg->addU8(static_cast(ignoreEquipped)); + msg->addU8(ignoreEquipped); send(msg); } @@ -393,7 +391,7 @@ void ProtocolGame::sendInspectTrade(const bool counterOffer, const uint8_t index { const auto& msg = std::make_shared(); msg->addU8(Proto::ClientInspectTrade); - msg->addU8(static_cast(counterOffer)); + msg->addU8(counterOffer); msg->addU8(index); send(msg); } @@ -621,7 +619,7 @@ void ProtocolGame::sendChangeFightModes(const Otc::FightModes fightMode, const O msg->addU8(Proto::ClientChangeFightModes); msg->addU8(fightMode); msg->addU8(chaseMode); - msg->addU8(static_cast(safeFight)); + msg->addU8(safeFight); if (g_game.getFeature(Otc::GamePVPMode)) msg->addU8(pvpMode); send(msg); @@ -690,7 +688,7 @@ void ProtocolGame::sendShareExperience(const bool active) { const auto& msg = std::make_shared(); msg->addU8(Proto::ClientShareExperience); - msg->addU8(static_cast(active)); + msg->addU8(active); if (g_game.getClientVersion() < 910) msg->addU8(0); send(msg); @@ -752,7 +750,7 @@ void ProtocolGame::sendTyping(const bool typing) { const auto& msg = std::make_shared(); msg->addU8(Proto::GameServerCreatureTyping); - msg->addU8(static_cast(typing)); + msg->addU8(typing); send(msg); } @@ -788,6 +786,10 @@ void ProtocolGame::sendChangeOutfit(const Outfit& outfit) } } + if (g_game.getClientVersion() >= 1334) { + msg->addU8(outfit.hasMount()); + } + if (g_game.getClientVersion() >= 1281) { msg->addU16(0x00); //familiars msg->addU8(0x00); //randomizeMount @@ -807,7 +809,7 @@ void ProtocolGame::sendMountStatus(const bool mount) if (g_game.getFeature(Otc::GamePlayerMounts)) { const auto& msg = std::make_shared(); msg->addU8(Proto::ClientMount); - msg->addU8(static_cast(mount)); + msg->addU8(mount); send(msg); } else { g_logger.error("ProtocolGame::sendMountStatus does not support the current protocol."); @@ -837,10 +839,10 @@ void ProtocolGame::sendEditVip(const uint32_t playerId, const std::string_view d msg->addU32(playerId); msg->addString(description); msg->addU32(iconId); - msg->addU8(static_cast(notifyLogin)); + msg->addU8(notifyLogin); if (g_game.getFeature(Otc::GameVipGroups)) { msg->addU8(static_cast(groupIDs.size())); - for (uint8_t groupID : groupIDs) { + for (const uint8_t groupID : groupIDs) { msg->addU8(groupID); } } @@ -851,19 +853,19 @@ void ProtocolGame::sendEditVipGroups(const Otc::GroupsEditInfoType_t action, con { const auto& msg = std::make_shared(); msg->addU8(Proto::ClientEditVipGroups); - msg->addU8(static_cast(action)); + msg->addU8(action); switch (action) { - case Otc::VIP_GROUP_ADD: { - msg->addString(groupName); + case Otc::VIP_GROUP_ADD: { + msg->addString(groupName); break; } - case Otc::VIP_GROUP_EDIT: { + case Otc::VIP_GROUP_EDIT: { msg->addU8(groupId); msg->addString(groupName); break; } case Otc::VIP_GROUP_REMOVE: { - msg->addU8(groupId); + msg->addU8(groupId); break; } default: { @@ -894,7 +896,7 @@ void ProtocolGame::sendRuleViolation(const std::string_view target, const uint8_ msg->addString(comment); msg->addString(statement); msg->addU16(statementId); - msg->addU8(static_cast(ipBanishment)); + msg->addU8(ipBanishment); send(msg); } @@ -1082,7 +1084,7 @@ void ProtocolGame::sendStatusTrackerBestiary(const uint16_t raceId, const bool s const auto& msg = std::make_shared(); msg->addU8(Proto::ClientBestiaryTrackerStatus); msg->addU16(raceId); - msg->addU8(static_cast(status)); + msg->addU8(status); send(msg); } @@ -1262,7 +1264,7 @@ void ProtocolGame::sendApplyImbuement(const uint8_t slot, const uint32_t imbueme msg->addU8(Proto::ClientApplyImbuement); msg->addU8(slot); msg->addU32(imbuementId); - msg->addU8(static_cast(protectionCharm)); + msg->addU8(protectionCharm); send(msg); } @@ -1307,17 +1309,17 @@ void ProtocolGame::sendHighscoreInfo(const uint8_t action, const uint8_t categor send(msg); } -void ProtocolGame::sendImbuementDurations(bool isOpen) +void ProtocolGame::sendImbuementDurations(const bool isOpen) { const auto& msg = std::make_shared(); msg->addU8(Proto::ClientImbuementDurations); - msg->addU8(static_cast(isOpen)); + msg->addU8(isOpen); send(msg); } void ProtocolGame::requestQuickLootBlackWhiteList(const uint8_t filter, const uint16_t size, const std::vector& listedItems) { - auto msg = std::make_shared(); + const auto msg = std::make_shared(); msg->addU8(0x91); msg->addU8(filter); msg->addU16(size); @@ -1330,7 +1332,7 @@ void ProtocolGame::requestQuickLootBlackWhiteList(const uint8_t filter, const ui void ProtocolGame::openContainerQuickLoot(const uint8_t action, const uint8_t category, const Position& pos, const uint16_t itemId, const uint8_t stackpos, const bool useMainAsFallback) { - auto msg = std::make_shared(); + const auto msg = std::make_shared(); msg->addU8(0x90); msg->addU8(action); @@ -1340,9 +1342,9 @@ void ProtocolGame::openContainerQuickLoot(const uint8_t action, const uint8_t ca msg->addU16(itemId); msg->addU8(stackpos); } else if (action == 3) { - msg->addU8(static_cast(useMainAsFallback)); + msg->addU8(useMainAsFallback); } else if (action == 1 || action == 2 || action == 5 || action == 6) { msg->addU8(category); } send(msg); -} +} \ No newline at end of file diff --git a/src/client/spriteappearances.cpp b/src/client/spriteappearances.cpp index d94b012f5b..e77a74d2c9 100644 --- a/src/client/spriteappearances.cpp +++ b/src/client/spriteappearances.cpp @@ -21,12 +21,12 @@ */ #include "spriteappearances.h" +#include "game.h" #include #include -#include #include -#include "game.h" +#include #include #include @@ -167,14 +167,14 @@ void SpriteAppearances::unload() m_sheets.clear(); } -SpriteSheetPtr SpriteAppearances::getSheetBySpriteId(int id, bool load /* = true */) +SpriteSheetPtr SpriteAppearances::getSheetBySpriteId(const int id, const bool load /* = true */) { if (id == 0) { return nullptr; } // find sheet - const auto sheetIt = std::find_if(m_sheets.begin(), m_sheets.end(), [=](const SpriteSheetPtr& sheet) { + const auto sheetIt = std::ranges::find_if(m_sheets, [=](const SpriteSheetPtr& sheet) { return id >= sheet->firstId && id <= sheet->lastId; }); @@ -189,7 +189,7 @@ SpriteSheetPtr SpriteAppearances::getSheetBySpriteId(int id, bool load /* = true return sheet; } -ImagePtr SpriteAppearances::getSpriteImage(int id) +ImagePtr SpriteAppearances::getSpriteImage(const int id) { try { const auto& sheet = getSheetBySpriteId(id); @@ -231,14 +231,14 @@ ImagePtr SpriteAppearances::getSpriteImage(int id) } } -void SpriteAppearances::saveSpriteToFile(int id, const std::string& file) +void SpriteAppearances::saveSpriteToFile(const int id, const std::string& file) { if (const auto& sprite = getSpriteImage(id)) { sprite->savePNG(file); } } -void SpriteAppearances::saveSheetToFileBySprite(int id, const std::string& file) +void SpriteAppearances::saveSheetToFileBySprite(const int id, const std::string& file) { if (const auto& sheet = getSheetBySpriteId(id)) { Image image({ SpriteSheet::SIZE }, 4, sheet->data.get()); @@ -250,4 +250,4 @@ void SpriteAppearances::saveSheetToFile(const SpriteSheetPtr& sheet, const std:: { Image image({ SpriteSheet::SIZE }, 4, sheet->data.get()); image.savePNG(file); -} +} \ No newline at end of file diff --git a/src/client/spriteappearances.h b/src/client/spriteappearances.h index 416a1724ca..1676ebd546 100644 --- a/src/client/spriteappearances.h +++ b/src/client/spriteappearances.h @@ -40,7 +40,10 @@ class SpriteSheet public: static constexpr uint16_t SIZE = 384; - SpriteSheet(int firstId, int lastId, SpriteLayout spriteLayout, const std::string& file) : firstId(firstId), lastId(lastId), spriteLayout(spriteLayout), file(file) {} + SpriteSheet(const int firstId, const int lastId, const SpriteLayout spriteLayout, std::string file) : firstId(firstId), lastId(lastId), spriteLayout(spriteLayout), file(std::move( + file)) + { + } Size getSpriteSize() const { @@ -78,7 +81,7 @@ class SpriteAppearances void unload(); - void setSpritesCount(int count) { m_spritesCount = count; } + void setSpritesCount(const int count) { m_spritesCount = count; } int getSpritesCount() const { return m_spritesCount; } void setPath(const std::string& path) { m_path = path; } diff --git a/src/client/spritemanager.cpp b/src/client/spritemanager.cpp index ecfcb45203..d64de1fda3 100644 --- a/src/client/spritemanager.cpp +++ b/src/client/spritemanager.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,15 +21,14 @@ */ #include "spritemanager.h" -#include -#include -#include -#include -#include #include "game.h" +#include "gameconfig.h" #include "spriteappearances.h" +#include +#include #include -#include "gameconfig.h" +#include +#include SpriteManager g_sprites; @@ -61,13 +60,13 @@ bool SpriteManager::loadSpr(std::string file) m_loaded = false; m_spritesHd = false; - auto cwmFile = g_resources.guessFilePath(file, "cwm"); + const auto cwmFile = g_resources.guessFilePath(file, "cwm"); if (g_resources.fileExists(cwmFile)) { m_spritesHd = true; return loadCwmSpr(cwmFile); } - auto sprFile = g_resources.guessFilePath(file, "spr"); + const auto sprFile = g_resources.guessFilePath(file, "spr"); if (g_resources.fileExists(sprFile)) { return loadRegularSpr(sprFile); } @@ -109,7 +108,7 @@ bool SpriteManager::loadCwmSpr(std::string file) const auto& spritesFile = getSpriteFile(); - uint8_t version = spritesFile->getU8(); + const uint8_t version = spritesFile->getU8(); if (version != 0x01) { g_logger.error(stdext::format("Invalid CWM file version - %s", file)); return false; @@ -117,7 +116,7 @@ bool SpriteManager::loadCwmSpr(std::string file) m_spritesCount = spritesFile->getU16(); - uint32_t entries = spritesFile->getU32(); + const uint32_t entries = spritesFile->getU32(); m_cwmSpritesMetadata.reserve(entries); for (uint32_t i = 0; i < entries; ++i) { FileMetadata spriteMetadata{ spritesFile }; @@ -138,8 +137,6 @@ bool SpriteManager::loadCwmSpr(std::string file) g_logger.error(stdext::format("Failed to load sprites from '%s': %s", file, e.what())); return false; } - - return false; } #ifdef FRAMEWORK_EDITOR @@ -208,7 +205,7 @@ void SpriteManager::unload() m_spritesFiles.clear(); } -ImagePtr SpriteManager::getSpriteImage(int id) +ImagePtr SpriteManager::getSpriteImage(const int id) { if (g_game.getClientVersion() >= 1281 && !g_game.getFeature(Otc::GameLoadSprInsteadProtobuf)) { return g_spriteAppearances.getSpriteImage(id); @@ -223,9 +220,9 @@ ImagePtr SpriteManager::getSpriteImage(int id) return nullptr; } -ImagePtr SpriteManager::getSpriteImageHd(int id, const FileStreamPtr& file) +ImagePtr SpriteManager::getSpriteImageHd(const int id, const FileStreamPtr& file) { - auto it = m_cwmSpritesMetadata.find(id); + const auto it = m_cwmSpritesMetadata.find(id); if (it == m_cwmSpritesMetadata.end()) return nullptr; @@ -239,7 +236,7 @@ ImagePtr SpriteManager::getSpriteImageHd(int id, const FileStreamPtr& file) return Image::loadPNG(buffer.data(), buffer.size()); } -ImagePtr SpriteManager::getSpriteImage(int id, const FileStreamPtr& file) +ImagePtr SpriteManager::getSpriteImage(const int id, const FileStreamPtr& file) { if (id == 0 || !file) return nullptr; diff --git a/src/client/spritemanager.h b/src/client/spritemanager.h index ace02d13eb..91262ccb00 100644 --- a/src/client/spritemanager.h +++ b/src/client/spritemanager.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -22,10 +22,10 @@ #pragma once -#include -#include #include "gameconfig.h" +#include #include +#include class FileMetadata { @@ -49,7 +49,7 @@ class FileMetadata uint32_t spriteId = 0; }; - //@bindsingleton g_sprites +//@bindsingleton g_sprites class SpriteManager { public: diff --git a/src/client/statictext.cpp b/src/client/statictext.cpp index 83d4026bd9..3b1268261b 100644 --- a/src/client/statictext.cpp +++ b/src/client/statictext.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,11 +21,11 @@ */ #include "statictext.h" +#include "framework/core/graphicalapplication.h" +#include "map.h" #include #include #include -#include "map.h" -#include "framework/core/graphicalapplication.h" StaticText::StaticText() { @@ -50,7 +50,7 @@ void StaticText::drawText(const Point& dest, const Rect& parentRect) void StaticText::setText(const std::string_view text) { m_cachedText.setText(text); } void StaticText::setFont(const std::string_view fontName) { m_cachedText.setFont(g_fonts.getFont(fontName)); } -bool StaticText::addMessage(const std::string_view name, Otc::MessageMode mode, const std::string_view text) +bool StaticText::addMessage(const std::string_view name, const Otc::MessageMode mode, const std::string_view text) { //TODO: this could be moved to lua // first message diff --git a/src/client/statictext.h b/src/client/statictext.h index cf0759d1f5..89344e5b8b 100644 --- a/src/client/statictext.h +++ b/src/client/statictext.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -22,11 +22,11 @@ #pragma once -#include #include "thing.h" +#include // @bindclass -class StaticText : public LuaObject +class StaticText final : public LuaObject { public: StaticText(); @@ -43,9 +43,9 @@ class StaticText : public LuaObject bool isYell() const { return m_mode == Otc::MessageYell || m_mode == Otc::MessageMonsterYell || m_mode == Otc::MessageBarkLoud; } - void setText(const std::string_view text); - void setFont(const std::string_view fontName); - bool addMessage(const std::string_view name, Otc::MessageMode mode, const std::string_view text); + void setText(std::string_view text); + void setFont(std::string_view fontName); + bool addMessage(std::string_view name, Otc::MessageMode mode, std::string_view text); StaticTextPtr asStaticText() { return static_self_cast(); } diff --git a/src/client/thing.cpp b/src/client/thing.cpp index a002d1cf08..f58ac8873a 100644 --- a/src/client/thing.cpp +++ b/src/client/thing.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -23,11 +23,7 @@ #include "thing.h" #include "game.h" #include "map.h" -#include "thingtypemanager.h" -#include "tile.h" -#include -#include #include void Thing::setPosition(const Position& position, uint8_t /*stackPos*/, bool /*hasElevation*/) @@ -44,25 +40,25 @@ int Thing::getStackPriority() { // Bug fix for old versions if (g_game.getClientVersion() <= 800 && isSplash()) - return STACK_PRIORITY::GROUND; + return GROUND; if (isGround()) - return STACK_PRIORITY::GROUND; + return GROUND; if (isGroundBorder()) - return STACK_PRIORITY::GROUND_BORDER; + return GROUND_BORDER; if (isOnBottom()) - return STACK_PRIORITY::ON_BOTTOM; + return ON_BOTTOM; if (isOnTop()) - return STACK_PRIORITY::ON_TOP; + return ON_TOP; if (isCreature()) - return STACK_PRIORITY::CREATURE; + return CREATURE; // common items - return STACK_PRIORITY::COMMON_ITEMS; + return COMMON_ITEMS; } const TilePtr& Thing::getTile() diff --git a/src/client/thing.h b/src/client/thing.h index e25723c558..cd97da2237 100644 --- a/src/client/thing.h +++ b/src/client/thing.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -22,14 +22,14 @@ #pragma once -#include -#include -#include +#include "attachableobject.h" #include "declarations.h" #include "spritemanager.h" #include "thingtype.h" #include "thingtypemanager.h" -#include "attachableobject.h" +#include +#include +#include // @bindclass #pragma pack(push,1) // disable memory alignment @@ -72,14 +72,14 @@ class Thing : public AttachableObject virtual Point getDisplacement() const { return getThingType()->getDisplacement(); } virtual int getDisplacementX() const { return getThingType()->getDisplacementX(); } virtual int getDisplacementY() const { return getThingType()->getDisplacementY(); } - virtual int getExactSize(int layer = 0, int xPattern = 0, int yPattern = 0, int zPattern = 0, int animationPhase = 0) { return getThingType()->getExactSize(layer, xPattern, yPattern, zPattern, animationPhase); } + virtual int getExactSize(const int layer = 0, const int xPattern = 0, const int yPattern = 0, const int zPattern = 0, const int animationPhase = 0) { return getThingType()->getExactSize(layer, xPattern, yPattern, zPattern, animationPhase); } virtual const Light& getLight() const { return getThingType()->getLight(); } virtual bool hasLight() const { return getThingType()->hasLight(); } const MarketData& getMarketData() { return getThingType()->getMarketData(); } const std::vector& getNpcSaleData() { return getThingType()->getNpcSaleData(); } - int getMeanPrice() { return getThingType()->getMeanPrice(); } + int getMeanPrice() { return getThingType()->getMeanPrice(); } const Size& getSize() const { return getThingType()->getSize(); } int getWidth() const { return getThingType()->getWidth(); } @@ -163,12 +163,13 @@ class Thing : public AttachableObject uint16_t getClassification() { return getThingType()->getClassification(); } - void canDraw(bool canDraw) { m_canDraw = canDraw; } - inline bool canDraw(const Color& color = Color::white) const { + void canDraw(const bool canDraw) { m_canDraw = canDraw; } + + bool canDraw(const Color& color = Color::white) const { return m_canDraw && m_clientId > 0 && color.aF() > Fw::MIN_ALPHA && getThingType() && getThingType()->getOpacity() > Fw::MIN_ALPHA; } - void setShader(const std::string_view name); + void setShader(std::string_view name); uint8_t getShaderId() const { return m_shaderId; } PainterShaderProgramPtr getShader() const; @@ -210,7 +211,7 @@ class Thing : public AttachableObject protected: virtual ThingType* getThingType() const = 0; - void setAttachedEffectDirection(Otc::Direction dir) const + void setAttachedEffectDirection(const Otc::Direction dir) const { if (!hasAttachedEffects()) return; @@ -224,7 +225,7 @@ class Thing : public AttachableObject Color m_highlightColor{ Color::white }; Position m_position; - DrawConductor m_drawConductor{ false, DrawOrder::THIRD }; + DrawConductor m_drawConductor{ .agroup = false, .order = THIRD }; uint16_t m_clientId{ 0 }; @@ -237,8 +238,8 @@ class Thing : public AttachableObject uint8_t m_shaderId{ 0 }; private: - void lua_setMarked(std::string_view color) { setMarked(Color(color)); } - void lua_setHighlight(std::string_view color) { setHighlight(Color(color)); } + void lua_setMarked(const std::string_view color) { setMarked(Color(color)); } + void lua_setHighlight(const std::string_view color) { setHighlight(Color(color)); } bool m_canDraw{ true }; diff --git a/src/client/thingtype.cpp b/src/client/thingtype.cpp index c0759b5c13..a73b64ce09 100644 --- a/src/client/thingtype.cpp +++ b/src/client/thingtype.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -23,15 +23,15 @@ #include "thingtype.h" #include "game.h" #include "lightview.h" +#include "localplayer.h" #include "map.h" #include "spriteappearances.h" #include "spritemanager.h" -#include "localplayer.h" -#include #include -#include +#include #include +#include #include #include #include @@ -39,7 +39,7 @@ const static TexturePtr m_textureNull; -void ThingType::unserializeAppearance(uint16_t clientId, ThingCategory category, const appearances::Appearance& appearance) +void ThingType::unserializeAppearance(const uint16_t clientId, const ThingCategory category, const appearances::Appearance& appearance) { m_null = false; m_id = clientId; @@ -371,7 +371,7 @@ void ThingType::unserializeAppearance(uint16_t clientId, ThingCategory category, prepareTextureLoad(sizes, total_sprites); } -void ThingType::unserialize(uint16_t clientId, ThingCategory category, const FileStreamPtr& fin) +void ThingType::unserialize(const uint16_t clientId, const ThingCategory category, const FileStreamPtr& fin) { m_null = false; m_id = clientId; @@ -639,7 +639,7 @@ void ThingType::drawWithFrameBuffer(const TexturePtr& texture, const Rect& scree g_drawPool.resetShaderProgram(); } -void ThingType::draw(const Point& dest, int layer, int xPattern, int yPattern, int zPattern, int animationPhase, const Color& color, bool drawThings, const LightViewPtr& lightView, const DrawConductor& conductor) +void ThingType::draw(const Point& dest, const int layer, const int xPattern, const int yPattern, const int zPattern, const int animationPhase, const Color& color, const bool drawThings, const LightViewPtr& lightView, const DrawConductor& conductor) { if (m_null) return; @@ -676,7 +676,7 @@ void ThingType::draw(const Point& dest, int layer, int xPattern, int yPattern, i } } -TexturePtr ThingType::getTexture(int animationPhase) +TexturePtr ThingType::getTexture(const int animationPhase) { if (m_null) return m_textureNull; @@ -714,7 +714,7 @@ TexturePtr ThingType::getTexture(int animationPhase) return nullptr; } -void ThingType::loadTexture(int animationPhase) +void ThingType::loadTexture(const int animationPhase) { auto& textureData = m_textureData[animationPhase]; if (textureData.source) @@ -821,7 +821,7 @@ void ThingType::loadTexture(int animationPhase) textureData.source = std::make_shared(fullImage, true, false); } -Size ThingType::getBestTextureDimension(int w, int h, int count) +Size ThingType::getBestTextureDimension(int w, int h, const int count) { int k = 1; while (k < w) @@ -853,7 +853,7 @@ Size ThingType::getBestTextureDimension(int w, int h, int count) return bestDimension; } -uint32_t ThingType::getSpriteIndex(int w, int h, int l, int x, int y, int z, int a) const +uint32_t ThingType::getSpriteIndex(const int w, const int h, const int l, const int x, const int y, const int z, const int a) const { uint32_t index = ((((((a % m_animationPhases) * m_numPatternZ + z) @@ -875,14 +875,14 @@ uint32_t ThingType::getSpriteIndex(int w, int h, int l, int x, int y, int z, int return index; } -uint32_t ThingType::getTextureIndex(int l, int x, int y, int z) const +uint32_t ThingType::getTextureIndex(const int l, const int x, const int y, const int z) const { return ((l * m_numPatternZ + z) * m_numPatternY + y) * m_numPatternX + x; } -int ThingType::getExactSize(int layer, int xPattern, int yPattern, int zPattern, int animationPhase) +int ThingType::getExactSize(const int layer, const int xPattern, const int yPattern, const int zPattern, const int animationPhase) { if (m_null) return 0; @@ -898,7 +898,7 @@ int ThingType::getExactSize(int layer, int xPattern, int yPattern, int zPattern, return std::max(size.width(), size.height()); } -void ThingType::setPathable(bool var) +void ThingType::setPathable(const bool var) { if (var == true) m_flags &= ~ThingFlagAttrNotPathable; @@ -922,7 +922,7 @@ int ThingType::getExactHeight() return m_exactHeight = size.height(); } -ThingFlagAttr ThingType::thingAttrToThingFlagAttr(ThingAttr attr) { +ThingFlagAttr ThingType::thingAttrToThingFlagAttr(const ThingAttr attr) { switch (attr) { case ThingAttrDisplacement: return ThingFlagAttrDisplacement; case ThingAttrLight: return ThingFlagAttrLight; diff --git a/src/client/thingtype.h b/src/client/thingtype.h index f5b5242451..0fc41ad8cc 100644 --- a/src/client/thingtype.h +++ b/src/client/thingtype.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -24,15 +24,12 @@ #include "animator.h" #include "declarations.h" -#include "gameconfig.h" -#include #include #include -#include #include -#include #include +#include using namespace otclient::protobuf; @@ -244,7 +241,7 @@ struct Imbuement struct ImbuementSlot { - ImbuementSlot(uint8_t id) : id(id) { } + ImbuementSlot(const uint8_t id) : id(id) {} uint8_t id; std::string name; @@ -255,8 +252,8 @@ struct ImbuementSlot struct ImbuementTrackerItem { - ImbuementTrackerItem() : slot(0) { } - ImbuementTrackerItem(uint8_t slot) : slot(slot) { } + ImbuementTrackerItem() : slot(0) {} + ImbuementTrackerItem(const uint8_t slot) : slot(slot) {} uint8_t slot; ItemPtr item; @@ -299,12 +296,12 @@ struct MarketOffer struct Light { Light() = default; - Light(uint8_t intensity, uint8_t color) : intensity(intensity), color(color) {} + Light(const uint8_t intensity, const uint8_t color) : intensity(intensity), color(color) {} uint8_t intensity = 0; uint8_t color = 215; }; -class ThingType : public LuaObject +class ThingType final : public LuaObject { public: void unserializeAppearance(uint16_t clientId, ThingCategory category, const appearances::Appearance& appearance); @@ -322,7 +319,7 @@ class ThingType : public LuaObject uint16_t getId() { return m_id; } ThingCategory getCategory() { return m_category; } bool isNull() { return m_null; } - bool hasAttr(ThingAttr attr) { return (m_flags & thingAttrToThingFlagAttr(attr)); } + bool hasAttr(const ThingAttr attr) { return (m_flags & thingAttrToThingFlagAttr(attr)); } int getWidth() { return m_size.width(); } int getHeight() { return m_size.height(); } @@ -346,13 +343,11 @@ class ThingType : public LuaObject {3043, 10000}, {3031, 50}, {3035, 50 } - } }; const uint32_t itemId = getId(); - const auto it = std::find_if(forcedPrices.begin(), forcedPrices.end(), - [itemId](const auto& pair) { return pair.first == itemId; }); + const auto it = std::ranges::find_if(forcedPrices, [itemId](const auto& pair) { return pair.first == itemId; }); if (it != forcedPrices.end()) { return it->second; @@ -384,7 +379,7 @@ class ThingType : public LuaObject bool isTopGroundBorder() { return isGroundBorder() && m_size.dimension() == 4; } bool isSingleGround() { return isGround() && isSingleDimension(); } bool isSingleGroundBorder() { return isGroundBorder() && isSingleDimension(); } - bool isTall(const bool useRealSize = false); + bool isTall(bool useRealSize = false); bool isSingleDimension() { return m_size.area() == 1; } bool isGround() { return (m_flags & ThingFlagAttrGround); } diff --git a/src/client/thingtypemanager.cpp b/src/client/thingtypemanager.cpp index ff657a46d1..e39132681c 100644 --- a/src/client/thingtypemanager.cpp +++ b/src/client/thingtypemanager.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -30,14 +30,11 @@ #include "creatures.h" #endif -#include -#include #include #include #include #include -#include #include @@ -100,16 +97,16 @@ bool ThingTypeManager::loadDat(std::string file) const auto& type = std::make_shared(); type->unserialize(id, static_cast(category), fin); m_thingTypes[category][id] = type; + } } - } m_datLoaded = true; g_lua.callGlobalField("g_things", "onLoadDat", file); return true; -} catch (const stdext::exception& e) { - g_logger.error(stdext::format("Failed to read dat '%s': %s'", file, e.what())); - return false; -} + } catch (const stdext::exception& e) { + g_logger.error(stdext::format("Failed to read dat '%s': %s'", file, e.what())); + return false; + } } bool ThingTypeManager::loadOtml(std::string file) @@ -141,10 +138,10 @@ bool ThingTypeManager::loadOtml(std::string file) } } return true; -} catch (const std::exception& e) { - g_logger.error(stdext::format("Failed to read dat otml '%s': %s'", file, e.what())); - return false; -} + } catch (const std::exception& e) { + g_logger.error(stdext::format("Failed to read dat otml '%s': %s'", file, e.what())); + return false; + } } bool ThingTypeManager::loadAppearances(const std::string& file) @@ -214,7 +211,7 @@ bool ThingTypeManager::loadAppearances(const std::string& file) } } -const ThingTypeList& ThingTypeManager::getThingTypes(ThingCategory category) +const ThingTypeList& ThingTypeManager::getThingTypes(const ThingCategory category) { if (category < ThingLastCategory) return m_thingTypes[category]; @@ -222,7 +219,7 @@ const ThingTypeList& ThingTypeManager::getThingTypes(ThingCategory category) throw Exception("invalid thing type category %d", category); } -const ThingTypePtr& ThingTypeManager::getThingType(uint16_t id, ThingCategory category) +const ThingTypePtr& ThingTypeManager::getThingType(const uint16_t id, const ThingCategory category) { if (category >= ThingLastCategory || id >= m_thingTypes[category].size()) { g_logger.error(stdext::format("invalid thing type client id %d in category %d", id, category)); @@ -231,7 +228,7 @@ const ThingTypePtr& ThingTypeManager::getThingType(uint16_t id, ThingCategory ca return m_thingTypes[category][id]; } -ThingTypeList ThingTypeManager::findThingTypeByAttr(ThingAttr attr, ThingCategory category) +ThingTypeList ThingTypeManager::findThingTypeByAttr(const ThingAttr attr, const ThingCategory category) { ThingTypeList ret; for (const auto& type : m_thingTypes[category]) @@ -493,4 +490,4 @@ void ThingTypeManager::loadXml(const std::string& file) #endif -/* vim: set ts=4 sw=4 et: */ +/* vim: set ts=4 sw=4 et: */ \ No newline at end of file diff --git a/src/client/thingtypemanager.h b/src/client/thingtypemanager.h index a44cf795c3..a8b9a7ca7c 100644 --- a/src/client/thingtypemanager.h +++ b/src/client/thingtypemanager.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -22,8 +22,8 @@ #pragma once -#include #include "thingtype.h" +#include #ifdef FRAMEWORK_EDITOR #include "itemtype.h" @@ -73,7 +73,7 @@ class ThingTypeManager uint16_t getContentRevision() { return m_contentRevision; } bool isDatLoaded() { return m_datLoaded; } - bool isValidDatId(uint16_t id, ThingCategory category) const { return id >= 1 && id < m_thingTypes[category].size(); } + bool isValidDatId(const uint16_t id, const ThingCategory category) const { return id >= 1 && id < m_thingTypes[category].size(); } private: ThingTypeList m_thingTypes[ThingLastCategory]; diff --git a/src/client/tile.cpp b/src/client/tile.cpp index 5030789f9e..3881c50922 100644 --- a/src/client/tile.cpp +++ b/src/client/tile.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -24,18 +24,18 @@ #include #include #include -#include #include + +#include + #include "client.h" #include "effect.h" #include "game.h" #include "item.h" -#include "lightview.h" #include "map.h" -#include "uimap.h" #include "protocolgame.h" -#include "statictext.h" -#include "localplayer.h" +#include "uimap.h" +#include Tile::Tile(const Position& position) : m_position(position) {} @@ -44,13 +44,13 @@ void updateElevation(const ThingPtr& thing, uint8_t& drawElevation) { drawElevation = std::min(drawElevation + thing->getElevation(), g_gameConfig.getTileMaxElevation()); } -void drawThing(const ThingPtr& thing, const Point& dest, int flags, uint8_t& drawElevation, const LightViewPtr& lightView = nullptr) +void drawThing(const ThingPtr& thing, const Point& dest, const int flags, uint8_t& drawElevation, const LightViewPtr& lightView = nullptr) { thing->draw(dest - drawElevation * g_drawPool.getScaleFactor(), flags & Otc::DrawThings, lightView); updateElevation(thing, drawElevation); } -void Tile::draw(const Point& dest, int flags, const LightViewPtr& lightView) +void Tile::draw(const Point& dest, const int flags, const LightViewPtr& lightView) { m_lastDrawDest = dest; @@ -73,8 +73,7 @@ void Tile::draw(const Point& dest, int flags, const LightViewPtr& lightView) drawAttachedEffect(dest, lightView, false); if (hasCommonItem()) { - for (auto it = m_things.rbegin(); it != m_things.rend(); ++it) { - const auto& item = *it; + for (auto& item : std::ranges::reverse_view(m_things)) { if (!item->isCommon()) continue; drawThing(item, dest, flags, drawElevation); } @@ -110,7 +109,7 @@ void Tile::drawLight(const Point& dest, const LightViewPtr& lightView) { drawAttachedLightEffect(dest, lightView); } -void Tile::drawCreature(const Point& dest, int flags, bool forceDraw, uint8_t drawElevation) +void Tile::drawCreature(const Point& dest, const int flags, const bool forceDraw, uint8_t drawElevation) { if (!forceDraw && !m_drawTopAndCreature) return; @@ -133,7 +132,7 @@ void Tile::drawCreature(const Point& dest, int flags, bool forceDraw, uint8_t dr } } -void Tile::drawTop(const Point& dest, int flags, bool forceDraw, uint8_t drawElevation) +void Tile::drawTop(const Point& dest, const int flags, const bool forceDraw, uint8_t drawElevation) { if (!forceDraw && !m_drawTopAndCreature) return; @@ -189,7 +188,7 @@ void Tile::addWalkingCreature(const CreaturePtr& creature) void Tile::removeWalkingCreature(const CreaturePtr& creature) { - const auto it = std::find(m_walkingCreatures.begin(), m_walkingCreatures.end(), creature); + const auto it = std::ranges::find(m_walkingCreatures, creature); if (it == m_walkingCreatures.end()) return; @@ -325,7 +324,7 @@ bool Tile::removeThing(const ThingPtr thing) return true; } - const auto it = std::find(m_things.begin(), m_things.end(), thing); + const auto it = std::ranges::find(m_things, thing); if (it == m_things.end()) return false; @@ -358,7 +357,7 @@ bool Tile::removeThing(const ThingPtr thing) return true; } -ThingPtr Tile::getThing(int stackPos) +ThingPtr Tile::getThing(const int stackPos) { if (stackPos >= 0 && stackPos < static_cast(m_things.size())) return m_things[stackPos]; @@ -412,7 +411,7 @@ std::vector Tile::getItems() return items; } -EffectPtr Tile::getEffect(uint16_t id) const +EffectPtr Tile::getEffect(const uint16_t id) const { if (m_effects) { for (const auto& effect : *m_effects) @@ -436,8 +435,7 @@ uint8_t Tile::getMinimapColorByte() if (m_minimapColor != 0) return m_minimapColor; - for (auto it = m_things.rbegin(); it != m_things.rend(); ++it) { - const auto& thing = *it; + for (auto& thing : std::ranges::reverse_view(m_things)) { if (thing->isCreature() || thing->isCommon()) continue; @@ -569,9 +567,9 @@ ThingPtr Tile::getTopMultiUseThing() return m_things[0]; } -bool Tile::isWalkable(bool ignoreCreatures) +bool Tile::isWalkable(const bool ignoreCreatures) { - if (m_thingTypeFlag & TileThingType::NOT_WALKABLE || !getGround()) { + if (m_thingTypeFlag & NOT_WALKABLE || !getGround()) { return false; } @@ -588,7 +586,7 @@ bool Tile::isWalkable(bool ignoreCreatures) return true; } -bool Tile::isCompletelyCovered(uint8_t firstFloor, bool resetCache) +bool Tile::isCompletelyCovered(const uint8_t firstFloor, const bool resetCache) { if (m_position.z == 0 || m_position.z == firstFloor) return false; @@ -613,7 +611,7 @@ bool Tile::isCompletelyCovered(uint8_t firstFloor, bool resetCache) return (m_isCompletelyCovered & idState) == idState; } -bool Tile::isCovered(int8_t firstFloor) +bool Tile::isCovered(const int8_t firstFloor) { if (m_position.z == 0 || m_position.z == firstFloor) return false; @@ -656,7 +654,7 @@ void Tile::onAddInMapView() if (m_tilesRedraw) m_tilesRedraw->clear(); - if (m_thingTypeFlag & TileThingType::CORRECT_CORPSE) { + if (m_thingTypeFlag & CORRECT_CORPSE) { if (!m_tilesRedraw) m_tilesRedraw = std::make_unique>(); @@ -692,7 +690,7 @@ bool Tile::hasBlockingCreature() const return false; } -bool Tile::limitsFloorsView(bool isFreeView) +bool Tile::limitsFloorsView(const bool isFreeView) { // ground and walls limits the view for (const auto& thing : m_things) { @@ -741,8 +739,7 @@ bool Tile::checkForDetachableThing(const TileSelectType selectType) } if (hasBottomItem()) { - for (auto it = m_things.rbegin(); it != m_things.rend(); ++it) { - const auto& item = *it; + for (auto& item : std::ranges::reverse_view(m_things)) { if (!item->isOnBottom() || !item->canDraw()) continue; if (isFiltered && (item->isIgnoreLook() || item->isFluidContainer())) @@ -755,8 +752,7 @@ bool Tile::checkForDetachableThing(const TileSelectType selectType) } if (hasTopItem()) { - for (auto it = m_things.rbegin(); it != m_things.rend(); ++it) { - const auto& item = *it; + for (auto& item : std::ranges::reverse_view(m_things)) { if (!item->isOnTop()) break; if (!item->canDraw()) continue; @@ -781,93 +777,93 @@ bool Tile::checkForDetachableThing(const TileSelectType selectType) void Tile::setThingFlag(const ThingPtr& thing) { if (thing->hasLight()) - m_thingTypeFlag |= TileThingType::HAS_LIGHT; + m_thingTypeFlag |= HAS_LIGHT; if (thing->hasDisplacement()) - m_thingTypeFlag |= TileThingType::HAS_DISPLACEMENT; + m_thingTypeFlag |= HAS_DISPLACEMENT; if (thing->isEffect()) return; if (thing->isCommon()) - m_thingTypeFlag |= TileThingType::HAS_COMMON_ITEM; + m_thingTypeFlag |= HAS_COMMON_ITEM; if (thing->isOnTop()) - m_thingTypeFlag |= TileThingType::HAS_TOP_ITEM; + m_thingTypeFlag |= HAS_TOP_ITEM; if (thing->isCreature()) - m_thingTypeFlag |= TileThingType::HAS_CREATURE; + m_thingTypeFlag |= HAS_CREATURE; if (thing->isSingleGroundBorder()) - m_thingTypeFlag |= TileThingType::HAS_GROUND_BORDER; + m_thingTypeFlag |= HAS_GROUND_BORDER; if (thing->isTopGroundBorder()) - m_thingTypeFlag |= TileThingType::HAS_TOP_GROUND_BORDER; + m_thingTypeFlag |= HAS_TOP_GROUND_BORDER; if (thing->isLyingCorpse() && !g_game.getFeature(Otc::GameMapDontCorrectCorpse)) - m_thingTypeFlag |= TileThingType::CORRECT_CORPSE; + m_thingTypeFlag |= CORRECT_CORPSE; // Creatures and items if (thing->isOnBottom()) { - m_thingTypeFlag |= TileThingType::HAS_BOTTOM_ITEM; + m_thingTypeFlag |= HAS_BOTTOM_ITEM; if (thing->isHookSouth()) - m_thingTypeFlag |= TileThingType::HAS_HOOK_SOUTH; + m_thingTypeFlag |= HAS_HOOK_SOUTH; if (thing->isHookEast()) - m_thingTypeFlag |= TileThingType::HAS_HOOK_EAST; + m_thingTypeFlag |= HAS_HOOK_EAST; } if (hasElevation()) - m_thingTypeFlag |= TileThingType::HAS_THING_WITH_ELEVATION; + m_thingTypeFlag |= HAS_THING_WITH_ELEVATION; if (thing->isIgnoreLook()) - m_thingTypeFlag |= TileThingType::IGNORE_LOOK; + m_thingTypeFlag |= IGNORE_LOOK; // best option to have something more real, but in some cases as a custom project, // the developers are not defining crop size //if(thing->getRealSize() > g_gameConfig.getSpriteSize()) if (!thing->isSingleDimension() || thing->hasElevation() || thing->hasDisplacement()) - m_thingTypeFlag |= TileThingType::NOT_SINGLE_DIMENSION; + m_thingTypeFlag |= NOT_SINGLE_DIMENSION; if (thing->getHeight() > 1) { - m_thingTypeFlag |= TileThingType::HAS_TALL_THINGS; + m_thingTypeFlag |= HAS_TALL_THINGS; if (thing->getHeight() > 2) - m_thingTypeFlag |= TileThingType::HAS_TALL_THINGS_2; + m_thingTypeFlag |= HAS_TALL_THINGS_2; } if (thing->getWidth() > 1) { - m_thingTypeFlag |= TileThingType::HAS_WIDE_THINGS; + m_thingTypeFlag |= HAS_WIDE_THINGS; if (thing->getWidth() > 2) - m_thingTypeFlag |= TileThingType::HAS_WIDE_THINGS_2; + m_thingTypeFlag |= HAS_WIDE_THINGS_2; } if (!thing->isItem()) return; if (thing->getWidth() > 1 && thing->getHeight() > 1) - m_thingTypeFlag |= TileThingType::HAS_WALL; + m_thingTypeFlag |= HAS_WALL; if (thing->isNotWalkable()) - m_thingTypeFlag |= TileThingType::NOT_WALKABLE; + m_thingTypeFlag |= NOT_WALKABLE; if (thing->isNotPathable()) - m_thingTypeFlag |= TileThingType::NOT_PATHABLE; + m_thingTypeFlag |= NOT_PATHABLE; if (thing->blockProjectile()) - m_thingTypeFlag |= TileThingType::BLOCK_PROJECTTILE; + m_thingTypeFlag |= BLOCK_PROJECTTILE; if (thing->isFullGround()) - m_thingTypeFlag |= TileThingType::FULL_GROUND; + m_thingTypeFlag |= FULL_GROUND; if (thing->isOpaque()) - m_thingTypeFlag |= TileThingType::IS_OPAQUE; + m_thingTypeFlag |= IS_OPAQUE; if (thing->hasElevation()) ++m_elevation; } -void Tile::select(TileSelectType selectType) +void Tile::select(const TileSelectType selectType) { m_selectType = selectType; diff --git a/src/client/tile.h b/src/client/tile.h index ba738bd37b..9129b3d5f3 100644 --- a/src/client/tile.h +++ b/src/client/tile.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -23,12 +23,11 @@ #pragma once #include + +#include "attachableobject.h" #include "declarations.h" -#include "effect.h" #include "item.h" #include "mapview.h" -#include "attachableobject.h" -#include "statictext.h" #ifdef FRAMEWORK_EDITOR enum tileflags_t : uint32_t @@ -90,7 +89,7 @@ enum TileThingType : uint32_t CORRECT_CORPSE = 1 << 25 }; -class Tile : public AttachableObject +class Tile final : public AttachableObject { public: Tile(const Position& position); @@ -111,7 +110,7 @@ class Tile : public AttachableObject bool removeThing(ThingPtr thing); ThingPtr getThing(int stackPos); EffectPtr getEffect(uint16_t id) const; - bool hasThing(const ThingPtr& thing) { return std::find(m_things.begin(), m_things.end(), thing) != m_things.end(); } + bool hasThing(const ThingPtr& thing) { return std::ranges::find(m_things, thing) != m_things.end(); } int getThingStackPos(const ThingPtr& thing); ThingPtr getTopThing(); @@ -135,11 +134,11 @@ class Tile : public AttachableObject bool isWalkable(bool ignoreCreatures = false); bool isClickable(); - bool isPathable() { return (m_thingTypeFlag & TileThingType::NOT_PATHABLE) == 0; } - bool isFullGround() { return m_thingTypeFlag & TileThingType::FULL_GROUND; } - bool isFullyOpaque() { return m_thingTypeFlag & TileThingType::IS_OPAQUE; } - bool isSingleDimension() { return (m_thingTypeFlag & TileThingType::NOT_SINGLE_DIMENSION) == 0 && m_walkingCreatures.empty(); } - bool isLookPossible() { return (m_thingTypeFlag & TileThingType::BLOCK_PROJECTTILE) == 0; } + bool isPathable() { return (m_thingTypeFlag & NOT_PATHABLE) == 0; } + bool isFullGround() { return m_thingTypeFlag & FULL_GROUND; } + bool isFullyOpaque() { return m_thingTypeFlag & IS_OPAQUE; } + bool isSingleDimension() { return (m_thingTypeFlag & NOT_SINGLE_DIMENSION) == 0 && m_walkingCreatures.empty(); } + bool isLookPossible() { return (m_thingTypeFlag & BLOCK_PROJECTTILE) == 0; } bool isEmpty() { return m_things.empty(); } bool isDrawable() { return !isEmpty() || !m_walkingCreatures.empty() || hasEffect() || hasAttachedEffects(); } bool isCovered(int8_t firstFloor); @@ -148,25 +147,25 @@ class Tile : public AttachableObject bool hasBlockingCreature() const; bool hasEffect() const { return m_effects && !m_effects->empty(); } - bool hasGround() { return (getGround() && getGround()->isSingleGround()) || m_thingTypeFlag & TileThingType::HAS_GROUND_BORDER; }; - bool hasTopGround(bool ignoreBorder = false) { return (getGround() && getGround()->isTopGround()) || (!ignoreBorder && m_thingTypeFlag & TileThingType::HAS_TOP_GROUND_BORDER); } - - bool hasCreature() { return m_thingTypeFlag & TileThingType::HAS_CREATURE; } - bool hasTopItem() const { return m_thingTypeFlag & TileThingType::HAS_TOP_ITEM; } - bool hasCommonItem() const { return m_thingTypeFlag & TileThingType::HAS_COMMON_ITEM; } - bool hasBottomItem() const { return m_thingTypeFlag & TileThingType::HAS_BOTTOM_ITEM; } - - bool hasIgnoreLook() { return m_thingTypeFlag & TileThingType::IGNORE_LOOK; } - bool hasDisplacement() const { return m_thingTypeFlag & TileThingType::HAS_DISPLACEMENT; } - bool hasLight() const { return m_thingTypeFlag & TileThingType::HAS_LIGHT; } - bool hasTallThings() const { return m_thingTypeFlag & TileThingType::HAS_TALL_THINGS; } - bool hasWideThings() const { return m_thingTypeFlag & TileThingType::HAS_WIDE_THINGS; } - bool hasTallThings2() const { return m_thingTypeFlag & TileThingType::HAS_TALL_THINGS_2; } - bool hasWideThings2() const { return m_thingTypeFlag & TileThingType::HAS_WIDE_THINGS_2; } - bool hasWall() const { return m_thingTypeFlag & TileThingType::HAS_WALL; } - - bool mustHookSouth() const { return m_thingTypeFlag & TileThingType::HAS_HOOK_SOUTH; } - bool mustHookEast() const { return m_thingTypeFlag & TileThingType::HAS_HOOK_EAST; } + bool hasGround() { return (getGround() && getGround()->isSingleGround()) || m_thingTypeFlag & HAS_GROUND_BORDER; }; + bool hasTopGround(const bool ignoreBorder = false) { return (getGround() && getGround()->isTopGround()) || (!ignoreBorder && m_thingTypeFlag & HAS_TOP_GROUND_BORDER); } + + bool hasCreature() { return m_thingTypeFlag & HAS_CREATURE; } + bool hasTopItem() const { return m_thingTypeFlag & HAS_TOP_ITEM; } + bool hasCommonItem() const { return m_thingTypeFlag & HAS_COMMON_ITEM; } + bool hasBottomItem() const { return m_thingTypeFlag & HAS_BOTTOM_ITEM; } + + bool hasIgnoreLook() { return m_thingTypeFlag & IGNORE_LOOK; } + bool hasDisplacement() const { return m_thingTypeFlag & HAS_DISPLACEMENT; } + bool hasLight() const { return m_thingTypeFlag & HAS_LIGHT; } + bool hasTallThings() const { return m_thingTypeFlag & HAS_TALL_THINGS; } + bool hasWideThings() const { return m_thingTypeFlag & HAS_WIDE_THINGS; } + bool hasTallThings2() const { return m_thingTypeFlag & HAS_TALL_THINGS_2; } + bool hasWideThings2() const { return m_thingTypeFlag & HAS_WIDE_THINGS_2; } + bool hasWall() const { return m_thingTypeFlag & HAS_WALL; } + + bool mustHookSouth() const { return m_thingTypeFlag & HAS_HOOK_SOUTH; } + bool mustHookEast() const { return m_thingTypeFlag & HAS_HOOK_EAST; } bool limitsFloorsView(bool isFreeView = false); @@ -181,7 +180,7 @@ class Tile : public AttachableObject ; } - bool hasElevation(int elevation = 1) const { return m_elevation >= elevation; } + bool hasElevation(const int elevation = 1) const { return m_elevation >= elevation; } #ifdef FRAMEWORK_EDITOR void overwriteMinimapColor(uint8_t color) { m_minimapColor = color; } @@ -203,7 +202,7 @@ class Tile : public AttachableObject TilePtr asTile() { return static_self_cast(); } - bool checkForDetachableThing(const TileSelectType selectType = TileSelectType::FILTERED); + bool checkForDetachableThing(TileSelectType selectType = TileSelectType::FILTERED); #ifndef BOT_PROTECTION void drawTexts(Point dest); @@ -229,7 +228,7 @@ class Tile : public AttachableObject setThingFlag(thing); } - bool hasThingWithElevation() const { return hasElevation() && m_thingTypeFlag & TileThingType::HAS_THING_WITH_ELEVATION; } + bool hasThingWithElevation() const { return hasElevation() && m_thingTypeFlag & HAS_THING_WITH_ELEVATION; } void markHighlightedThing(const Color& color) { if (m_highlightThingStackPos > -1 && m_highlightThingStackPos < static_cast(m_things.size())) { m_things[m_highlightThingStackPos]->setMarked(color); diff --git a/src/client/towns.cpp b/src/client/towns.cpp index 4929be1566..40a2b177b2 100644 --- a/src/client/towns.cpp +++ b/src/client/towns.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * 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/src/client/towns.h b/src/client/towns.h index f1e39abbbc..3e823c86d6 100644 --- a/src/client/towns.h +++ b/src/client/towns.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * 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/src/client/uicreature.cpp b/src/client/uicreature.cpp index da1934cd47..9f049acd8f 100644 --- a/src/client/uicreature.cpp +++ b/src/client/uicreature.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -22,7 +22,7 @@ #include "uicreature.h" -void UICreature::drawSelf(DrawPoolType drawPane) +void UICreature::drawSelf(const DrawPoolType drawPane) { if (drawPane != DrawPoolType::FOREGROUND) return; diff --git a/src/client/uicreature.h b/src/client/uicreature.h index 512ed630ea..0e300fe0b0 100644 --- a/src/client/uicreature.h +++ b/src/client/uicreature.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -22,11 +22,11 @@ #pragma once -#include #include "creature.h" #include "declarations.h" +#include -class UICreature : public UIWidget +class UICreature final : public UIWidget { public: void drawSelf(DrawPoolType drawPane) override; @@ -36,9 +36,9 @@ class UICreature : public UIWidget CreaturePtr getCreature() { return m_creature; } uint8_t getCreatureSize() { return m_creatureSize; } - void setCreatureSize(uint8_t size) { m_creatureSize = size; } + void setCreatureSize(const uint8_t size) { m_creatureSize = size; } - void setCenter(bool v) { m_center = v; } + void setCenter(const bool v) { m_center = v; } bool isCentered() { return m_center; } /* @@ -55,13 +55,12 @@ class UICreature : public UIWidget Otc::Direction getDirection() { if (m_creature != nullptr) { return m_creature->getDirection(); - } else { - return Otc::InvalidDirection; } + return Otc::InvalidDirection; } // @ protected: - void onStyleApply(const std::string_view styleName, const OTMLNodePtr& styleNode) override; + void onStyleApply(std::string_view styleName, const OTMLNodePtr& styleNode) override; Outfit getOutfit() { if (!m_creature) setOutfit({}); return m_creature->getOutfit(); } CreaturePtr m_creature; uint8_t m_creatureSize{ 0 }; diff --git a/src/client/uieffect.cpp b/src/client/uieffect.cpp index ffc59d986b..1e972ba7cd 100644 --- a/src/client/uieffect.cpp +++ b/src/client/uieffect.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -25,7 +25,7 @@ UIEffect::UIEffect() { setProp(PropDraggable, true, false); } -void UIEffect::drawSelf(DrawPoolType drawPane) +void UIEffect::drawSelf(const DrawPoolType drawPane) { if (drawPane != DrawPoolType::FOREGROUND) return; @@ -52,7 +52,7 @@ void UIEffect::drawSelf(DrawPoolType drawPane) drawText(m_rect); } -void UIEffect::setEffectId(int id) +void UIEffect::setEffectId(const int id) { if (id == 0) m_effect = nullptr; diff --git a/src/client/uieffect.h b/src/client/uieffect.h index 7d6f4c40d7..5cb40a8e18 100644 --- a/src/client/uieffect.h +++ b/src/client/uieffect.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -22,20 +22,20 @@ #pragma once -#include #include "declarations.h" #include "effect.h" +#include -class UIEffect : public UIWidget +class UIEffect final : public UIWidget { public: UIEffect(); void drawSelf(DrawPoolType drawPane) override; void setEffectId(int id); - void setEffectVisible(bool visible) { m_effectVisible = visible; } + void setEffectVisible(const bool visible) { m_effectVisible = visible; } void setEffect(const EffectPtr& effect); - void setVirtual(bool virt) { m_virtual = virt; } + void setVirtual(const bool virt) { m_virtual = virt; } void clearEffect() { setEffectId(0); } int getEffectId() { return m_effect ? m_effect->getId() : 0; } @@ -44,7 +44,7 @@ class UIEffect : public UIWidget bool isEffectVisible() { return m_effectVisible; } protected: - void onStyleApply(const std::string_view styleName, const OTMLNodePtr& styleNode) override; + void onStyleApply(std::string_view styleName, const OTMLNodePtr& styleNode) override; EffectPtr m_effect; bool m_virtual{ false }; diff --git a/src/client/uigraph.cpp b/src/client/uigraph.cpp index 3afe1d0813..7aa9d2f820 100644 --- a/src/client/uigraph.cpp +++ b/src/client/uigraph.cpp @@ -1,79 +1,398 @@ #include "uigraph.h" -#include -#include #include +#include -void UIGraph::drawSelf(DrawPoolType drawPane) +#include + +void UIGraph::drawSelf(const DrawPoolType drawPane) { if (drawPane != DrawPoolType::FOREGROUND) return; - UIWidget::drawSelf(drawPane); + if (m_backgroundColor.aF() > Fw::MIN_ALPHA) { + Rect backgroundDestRect = m_rect; + backgroundDestRect.expand(-m_borderWidth.top, -m_borderWidth.right, -m_borderWidth.bottom, -m_borderWidth.left); + drawBackground(m_rect); + } - Rect dest = getPaddingRect(); + drawImage(m_rect); - float offsetX = dest.left(); - float offsetY = dest.top(); - size_t elements = std::min(m_values.size(), dest.width() / (m_width * 2) - 1); - size_t start = m_values.size() - elements; - int minVal = 0xFFFFFF, maxVal = -0xFFFFFF; - for (size_t i = start; i < m_values.size(); ++i) { - if (minVal > m_values[i]) - minVal = m_values[i]; - if (maxVal < m_values[i]) - maxVal = m_values[i]; - } - // round - maxVal = (1 + maxVal / 10) * 10; - minVal = (minVal / 10) * 10; - float step = (float)(dest.height()) / std::max(1, (maxVal - minVal)); - std::vector points; - for (size_t i = start, j = 0; i < m_values.size(); ++i) { - points.push_back(Point(offsetX + j * m_width, offsetY + 1 + (maxVal - m_values[i]) * step)); - j += 2; + if (m_needsUpdate) { + cacheGraphs(); } - if (elements > 0) { - g_drawPool.addAction([points = std::move(points), width = m_width, color = m_color] { - static std::vector vertices(1024, 0); - if (vertices.size() < points.size()) - vertices.resize(points.size()); + if (!m_graphs.empty()) { + const Rect dest = getPaddingRect(); - int i = 0; - for (const auto& point : points) { - vertices[i++] = point.x; - vertices[i++] = point.y; + // draw graph first + for (auto& graph : m_graphs) { + if (!graph.visible) continue; + + g_drawPool.addAction([points = graph.points, width = graph.width, color = graph.lineColor] { + static std::vector vertices; + vertices.resize(points.size() * 2); + int i = 0; + for (const auto& point : points) { + vertices[i++] = static_cast(point.x); + vertices[i++] = static_cast(point.y); + } + g_painter->setColor(color); + g_painter->drawLine(vertices, points.size(), width); + }); + } + + // then update if needed and draw vertical line if hovered + bool updated = false; + for (auto& graph : m_graphs) { + if (!graph.visible) continue; + + if (m_showInfo && isHovered()) { + updateGraph(graph, updated); + g_drawPool.addAction([line = graph.infoLine, color = graph.infoLineColor] { + g_painter->setColor(color); + const std::vector vertices = { + static_cast(line[0].x), static_cast(line[0].y), + static_cast(line[1].x), static_cast(line[1].y) + }; + g_painter->drawLine(vertices, vertices.size() / 2, 1); + }); } + } - g_painter->setColor(color); - g_painter->drawLine(vertices, i / 2, width); - }); + // reposition intersecting rects and keep them within rect bounds + if (updated) { + updateInfoBoxes(); + } + + // now we draw indicators on the graph lines + for (auto& graph : m_graphs) { + if (!graph.visible) continue; + + if (m_showInfo && isHovered()) { + g_drawPool.addFilledRect(graph.infoIndicatorBg, Color::white); + g_drawPool.addFilledRect(graph.infoIndicator, graph.lineColor); + } + } + + // lastly we can draw info boxes with value + for (auto& graph : m_graphs) { + if (!graph.visible) continue; + + if (m_showInfo && isHovered()) { + g_drawPool.addFilledRect(graph.infoRectBg, graph.infoTextBg); + g_drawPool.addFilledRect(graph.infoRectIcon, graph.lineColor); + m_font->drawText(graph.infoValue, graph.infoRect, Color::black, Fw::AlignLeftCenter); + } + } if (!m_title.empty()) m_font->drawText(m_title, dest, Color::white, Fw::AlignTopCenter); if (m_showLabes) { - m_font->drawText(std::to_string(m_values.back()), dest, Color::white, Fw::AlignTopRight); - m_font->drawText(std::to_string(maxVal), dest, Color::white, Fw::AlignTopLeft); - m_font->drawText(std::to_string(minVal), dest, Color::white, Fw::AlignBottomLeft); + m_font->drawText(m_lastValue, dest, Color::white, Fw::AlignTopRight); + m_font->drawText(m_maxValue, dest, Color::white, Fw::AlignTopLeft); + m_font->drawText(m_minValue, dest, Color::white, Fw::AlignBottomLeft); } } + + drawBorder(m_rect); + drawIcon(m_rect); + drawText(m_rect); } void UIGraph::clear() { - m_values.clear(); + m_graphs.clear(); +} + +void UIGraph::setLineWidth(const size_t index, const int width) { + if (m_graphs.size() <= index - 1) { + g_logger.warning(stdext::format("[UIGraph::setLineWidth (%s)] Graph of index %d out of bounds.", getId(), index)); + return; + } + + auto& graph = m_graphs[index - 1]; + graph.width = width; + m_needsUpdate = true; } -void UIGraph::addValue(int value, bool ignoreSmallValues) +size_t UIGraph::createGraph() { + auto graph = Graph(); + + graph.points = {}; + graph.values = {}; + + graph.infoLine[0] = Point(); + graph.infoLine[1] = Point(); + + graph.originalInfoRect = Rect(); + graph.infoRect = Rect(); + graph.infoRectBg = Rect(); + graph.infoRectIcon = Rect(0, 0, 10, 10); + graph.infoIndicator = Rect(0, 0, 5, 5); + graph.infoIndicatorBg = Rect(0, 0, 7, 7); + + graph.infoText = "Value: "; + + graph.infoLineColor = Color::white; + graph.infoTextBg = Color(0, 0, 0, 100); + graph.lineColor = Color::white; + + graph.width = 1; + graph.infoIndex = -1; + + graph.visible = true; + + m_graphs.push_back(graph); + return m_graphs.size(); +} + +void UIGraph::addValue(const size_t index, const int value, const bool ignoreSmallValues) +{ + if (m_graphs.size() <= index - 1) { + g_logger.warning(stdext::format( + "[UIGraph::addValue (%s)] Graph of index %d out of bounds. Use:\n" + " if graph:getGraphsCount() == 0 then\n" + " graph:createGraph()\n" + " graph:setLineWidth(1, 1)\n" + " graph:setLineColor(1, \"#FF0000\")\n" + " end\n" + " graph:addValue(1,value)", + getId(), index)); + + return; + } + + auto& graph = m_graphs[index - 1]; + if (ignoreSmallValues) { - if (!m_values.empty() && m_values.back() <= 2 && value <= 2 && ++m_ignores <= 10) + if (!graph.values.empty() && graph.values.back() <= 2 && value <= 2 && ++m_ignores <= 10) return; m_ignores = 0; } - m_values.push_back(value); - while (m_values.size() > m_capacity) - m_values.pop_front(); + + graph.values.push_back(value); + while (graph.values.size() > m_capacity) + graph.values.pop_front(); + + m_needsUpdate = true; +} + +void UIGraph::setLineColor(const size_t index, const Color& color) +{ + if (m_graphs.size() <= index - 1) { + g_logger.warning(stdext::format("[UIGraph::setLineColor (%s)] Graph of index %d out of bounds.", getId(), index)); + return; + } + + auto& graph = m_graphs[index - 1]; + graph.lineColor = color; +} + +void UIGraph::setInfoText(const size_t index, const std::string& text) +{ + if (m_graphs.size() <= index - 1) { + g_logger.warning(stdext::format("[UIGraph::setInfoText (%s)] Graph of index %d out of bounds.", getId(), index)); + return; + } + + auto& graph = m_graphs[index - 1]; + graph.infoText = text; +} + +void UIGraph::setGraphVisible(const size_t index, const bool visible) +{ + if (m_graphs.size() <= index - 1) { + g_logger.warning(stdext::format("[UIGraph::setGraphVisible (%s)] Graph of index %d out of bounds.", getId(), index)); + return; + } + + auto& graph = m_graphs[index - 1]; + graph.visible = visible; +} + +void UIGraph::setInfoLineColor(const size_t index, const Color& color) +{ + if (m_graphs.size() <= index - 1) { + g_logger.warning(stdext::format("[UIGraph::setInfoLineColor (%s)] Graph of index %d out of bounds.", getId(), index)); + return; + } + + auto& graph = m_graphs[index - 1]; + graph.infoLineColor = color; +} + +void UIGraph::setTextBackground(const size_t index, const Color& color) +{ + if (m_graphs.size() <= index - 1) { + g_logger.warning(stdext::format("[UIGraph::setTextBackground (%s)] Graph of index %d out of bounds.", getId(), index)); + return; + } + + auto& graph = m_graphs[index - 1]; + graph.infoTextBg = color; +} + +void UIGraph::cacheGraphs() +{ + if (!m_needsUpdate) + return; + + if (!m_rect.isEmpty() && m_rect.isValid()) { + if (!m_graphs.empty()) { + const Rect rect = getPaddingRect(); + + const auto paddingX = static_cast(rect.x()); + const auto paddingY = static_cast(rect.y()); + const auto graphWidth = static_cast(rect.width()); + const auto graphHeight = static_cast(rect.height()); + + float minValue = 0.0f; + float maxValue = 0.0f; + for (auto& graph : m_graphs) { + if (graph.values.empty()) + continue; + + graph.points.clear(); + + auto [minValueIter, maxValueIter] = std::ranges::minmax_element(graph.values); + minValue = *minValueIter; + maxValue = *maxValueIter; + float range = maxValue - minValue; + if (range == 0.0f) + range = 1.0f; + + const float pointSpacing = graphWidth / std::max(static_cast(graph.values.size()) - 1, 1); + for (size_t i = 0; i < graph.values.size(); ++i) { + const float x = paddingX + i * pointSpacing; + const float y = paddingY + graphHeight - ((graph.values[i] - minValue) / range) * graphHeight; + graph.points.emplace_back(static_cast(x), static_cast(y)); + } + } + + m_minValue = std::to_string(static_cast(minValue)); + m_maxValue = std::to_string(static_cast(maxValue)); + if (!m_graphs[0].values.empty()) + m_lastValue = std::to_string(m_graphs[0].values.back()); + else + m_lastValue = "0"; + } + + m_needsUpdate = false; + } +} + +void UIGraph::updateGraph(Graph& graph, bool& updated) +{ + if (graph.values.empty()) + return; + + const auto dest = getPaddingRect(); + const auto mousePos = g_window.getMousePosition(); + const auto graphWidth = static_cast(dest.width()); + const auto graphHeight = static_cast(dest.height()); + const float pointSpacing = graphWidth / std::max(static_cast(graph.values.size()) - 1, 1); + + int dataIndex = static_cast((mousePos.x - dest.left()) / pointSpacing + 0.5f); + dataIndex = std::clamp(dataIndex, 0, static_cast(graph.values.size()) - 1); + + if (graph.infoIndex != dataIndex) { + graph.infoIndex = dataIndex; + + const float snappedX = dest.left() + dataIndex * pointSpacing; + const int value = graph.values[graph.infoIndex]; + + graph.infoLine[0] = Point(snappedX, dest.top()); + graph.infoLine[1] = Point(snappedX, dest.bottom()); + + graph.infoValue = stdext::format("%s %d", graph.infoText, value); + + auto [minValueIter, maxValueIter] = std::ranges::minmax_element(graph.values); + const auto minValue = static_cast(*minValueIter); + const auto maxValue = static_cast(*maxValueIter); + float range = maxValue - minValue; + if (range == 0.0f) + range = 1.0f; + + const float pointY = dest.top() + graphHeight - ((value - minValue) / range) * graphHeight; + + const auto textSize = m_font->calculateTextRectSize(graph.infoValue); + graph.infoRectBg.setWidth(textSize.width() + 16); + graph.infoRectBg.setHeight(textSize.height()); + graph.infoRectBg.expand(4); + graph.infoRectBg.moveTop(pointY - graph.infoRectBg.height() / 2.0); + if (snappedX >= dest.horizontalCenter()) + graph.infoRectBg.moveRight(snappedX - 10); + else + graph.infoRectBg.moveLeft(snappedX + 10); + + graph.infoRect.setWidth(textSize.width()); + graph.infoRect.setHeight(textSize.height()); + graph.infoRect.moveRight(graph.infoRectBg.right() - 4); + graph.infoRect.moveVerticalCenter(graph.infoRectBg.verticalCenter()); + + const int iconPadding = graph.infoRectBg.height() - graph.infoRectIcon.width(); + graph.infoRectIcon.moveLeft(graph.infoRectBg.left() + (iconPadding / 2.0)); + graph.infoRectIcon.moveVerticalCenter(graph.infoRectBg.verticalCenter()); + + graph.infoIndicator.moveLeft(snappedX - 3); + graph.infoIndicator.moveTop(pointY - 3); + graph.infoIndicatorBg.moveCenter(graph.infoIndicator.center()); + + graph.originalInfoRect = graph.infoRectBg; + updated = true; + } +} + +void UIGraph::updateInfoBoxes() +{ + const auto dest = getPaddingRect(); + std::vector occupiedSpaces(m_graphs.size()); + for (size_t i = 0; i < m_graphs.size(); ++i) { + auto& graph = m_graphs[i]; + + graph.infoRectBg = graph.originalInfoRect; + graph.infoRect.moveVerticalCenter(graph.infoRectBg.verticalCenter()); + graph.infoRectIcon.moveVerticalCenter(graph.infoRectBg.verticalCenter()); + + occupiedSpaces[i] = graph.infoRectBg; + + for (size_t j = 0; j < occupiedSpaces.size(); ++j) { + if (i == j) continue; // graph's space, ignore + + auto& space = occupiedSpaces[j]; + // first check if this graph occupies another graph's space and move it above the space + if (space.intersects(graph.infoRectBg)) { + graph.infoRectBg.moveBottom(space.top() - 2); + graph.infoRect.moveVerticalCenter(graph.infoRectBg.verticalCenter()); + graph.infoRectIcon.moveVerticalCenter(graph.infoRectBg.verticalCenter()); + } + + // lets make sure its within bounds of this widget + if (graph.infoRectBg.top() < dest.top()) { + graph.infoRectBg.moveTop(dest.top()); + graph.infoRect.moveVerticalCenter(graph.infoRectBg.verticalCenter()); + graph.infoRectIcon.moveVerticalCenter(graph.infoRectBg.verticalCenter()); + } + + // if we just moved due to bounds check, we have to make sure we are not occuping another graph + // this time move it below the occupied space + if (space.intersects(graph.infoRectBg)) { + graph.infoRectBg.moveTop(space.bottom() + 2); + graph.infoRect.moveVerticalCenter(graph.infoRectBg.verticalCenter()); + graph.infoRectIcon.moveVerticalCenter(graph.infoRectBg.verticalCenter()); + } + + // and check again if we are within bounds + if (graph.infoRectBg.bottom() > dest.bottom()) { + graph.infoRectBg.moveBottom(dest.bottom()); + graph.infoRect.moveVerticalCenter(graph.infoRectBg.verticalCenter()); + graph.infoRectIcon.moveVerticalCenter(graph.infoRectBg.verticalCenter()); + } + } + + occupiedSpaces[i] = graph.infoRectBg; + } } void UIGraph::onStyleApply(const std::string& styleName, const OTMLNodePtr& styleNode) @@ -81,13 +400,31 @@ void UIGraph::onStyleApply(const std::string& styleName, const OTMLNodePtr& styl UIWidget::onStyleApply(styleName, styleNode); for (const OTMLNodePtr& node : styleNode->children()) { - if (node->tag() == "line-width") - setLineWidth(node->value()); - else if (node->tag() == "capacity") + if (node->tag() == "capacity") setCapacity(node->value()); else if (node->tag() == "title") - setTitle(node->value()); + setTitle(node->value()); else if (node->tag() == "show-labels") setShowLabels(node->value()); + else if (node->tag() == "show-info") // draw info (vertical line, labels with values) on mouse position + setShowInfo(node->value()); } +} + +void UIGraph::onGeometryChange(const Rect& oldRect, const Rect& newRect) +{ + UIWidget::onGeometryChange(oldRect, newRect); + m_needsUpdate = true; +} + +void UIGraph::onLayoutUpdate() +{ + UIWidget::onLayoutUpdate(); + m_needsUpdate = true; +} + +void UIGraph::onVisibilityChange(const bool visible) +{ + UIWidget::onVisibilityChange(visible); + m_needsUpdate = visible; } \ No newline at end of file diff --git a/src/client/uigraph.h b/src/client/uigraph.h index d1237a1ea2..da5b77e61f 100644 --- a/src/client/uigraph.h +++ b/src/client/uigraph.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2025 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -25,40 +25,77 @@ #include "declarations.h" #include -class UIGraph : public UIWidget +struct Graph +{ + std::vector points; + std::deque values; + Point infoLine[2]; + Rect originalInfoRect; + Rect infoRect; + Rect infoRectBg; + Rect infoRectIcon; + Rect infoIndicator; + Rect infoIndicatorBg; + std::string infoValue; + std::string infoText; + Color infoLineColor; + Color infoTextBg; + Color lineColor; + int width; + int infoIndex; + bool visible; +}; + +class UIGraph final : public UIWidget { public: UIGraph() = default; - void drawSelf(DrawPoolType drawPane); + void drawSelf(DrawPoolType drawPane) override; void clear(); - void addValue(int value, bool ignoreSmallValues = false); - void setLineWidth(int width) - { - m_width = width; - } - void setCapacity(int capacity) - { + size_t createGraph(); + size_t getGraphsCount() { return m_graphs.size(); } + void addValue(size_t index, int value, bool ignoreSmallValues = false); + + void setCapacity(const int capacity) { m_capacity = capacity; + m_needsUpdate = true; } - void setTitle(const std::string& title) - { - m_title = title; - } - void setShowLabels(bool value) - { - m_showLabes = value; - } + void setTitle(const std::string& title) { m_title = title; } + void setShowLabels(const bool value) { m_showLabes = value; } + void setShowInfo(const bool value) { m_showInfo = value; } + + void setLineWidth(size_t index, int width); + void setLineColor(size_t index, const Color& color); + void setInfoText(size_t index, const std::string& text); + void setInfoLineColor(size_t index, const Color& color); + void setTextBackground(size_t index, const Color& color); + void setGraphVisible(size_t index, bool visible); protected: void onStyleApply(const std::string& styleName, const OTMLNodePtr& styleNode); + void onGeometryChange(const Rect& oldRect, const Rect& newRect) override; + void onLayoutUpdate() override; + void onVisibilityChange(bool visible) override; + + void cacheGraphs(); + void updateGraph(Graph& graph, bool& updated); + void updateInfoBoxes(); private: + // cache + std::string m_minValue; + std::string m_maxValue; + std::string m_lastValue; std::string m_title; + + bool m_showLabes{ true }; + bool m_showInfo{ true }; + bool m_needsUpdate{ false }; + size_t m_capacity = 100; size_t m_ignores = 0; - int m_width = 1; - bool m_showLabes = true; - std::deque m_values; + + std::vector m_graphs; }; diff --git a/src/client/uiitem.cpp b/src/client/uiitem.cpp index cfd59f3b19..01be01f243 100644 --- a/src/client/uiitem.cpp +++ b/src/client/uiitem.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -26,7 +26,7 @@ UIItem::UIItem() { setProp(PropDraggable, true, false); } -void UIItem::drawSelf(DrawPoolType drawPane) +void UIItem::drawSelf(const DrawPoolType drawPane) { if (drawPane != DrawPoolType::FOREGROUND) return; @@ -66,7 +66,7 @@ void UIItem::drawSelf(DrawPoolType drawPane) drawText(m_rect); } -void UIItem::setItemId(int id) +void UIItem::setItemId(const int id) { if (id == 0) m_item = nullptr; @@ -79,7 +79,7 @@ void UIItem::setItemId(int id) #endif } -void UIItem::setItemCount(int count) +void UIItem::setItemCount(const int count) { if (m_item) m_item->setCount(count); #ifndef BOT_PROTECTION @@ -87,17 +87,17 @@ void UIItem::setItemCount(int count) #endif } -void UIItem::setItemSubType(int subType) -{ - if (m_item) m_item->setSubType(subType); +void UIItem::setItemSubType(const int subType) +{ + if (m_item) m_item->setSubType(subType); #ifndef BOT_PROTECTION callLuaField("onItemChange"); #endif } -void UIItem::setItem(const ItemPtr& item) -{ - m_item = item; +void UIItem::setItem(const ItemPtr& item) +{ + m_item = item; #ifndef BOT_PROTECTION callLuaField("onItemChange"); diff --git a/src/client/uiitem.h b/src/client/uiitem.h index ad73191fd8..b7b7373527 100644 --- a/src/client/uiitem.h +++ b/src/client/uiitem.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -22,11 +22,11 @@ #pragma once -#include #include "declarations.h" #include "item.h" +#include -class UIItem : public UIWidget +class UIItem final : public UIWidget { public: UIItem(); @@ -35,10 +35,10 @@ class UIItem : public UIWidget void setItemId(int id); void setItemCount(int count); void setItemSubType(int subType); - void setItemVisible(bool visible) { m_itemVisible = visible; } + void setItemVisible(const bool visible) { m_itemVisible = visible; } void setItem(const ItemPtr& item); - void setShowCount(bool value) { m_alwaysShowCount = value; } - void setVirtual(bool virt) { m_virtual = virt; } + void setShowCount(const bool value) { m_alwaysShowCount = value; } + void setVirtual(const bool virt) { m_virtual = virt; } void clearItem() { setItemId(0); } int getItemId() { return m_item ? m_item->getId() : 0; } @@ -50,7 +50,7 @@ class UIItem : public UIWidget bool isItemVisible() { return m_itemVisible; } protected: - void onStyleApply(const std::string_view styleName, const OTMLNodePtr& styleNode) override; + void onStyleApply(std::string_view styleName, const OTMLNodePtr& styleNode) override; ItemPtr m_item; bool m_virtual{ false }; diff --git a/src/client/uimap.cpp b/src/client/uimap.cpp index 25a1f9896d..554f803cd1 100644 --- a/src/client/uimap.cpp +++ b/src/client/uimap.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,13 +21,10 @@ */ #include "uimap.h" -#include -#include -#include -#include #include "game.h" #include "map.h" #include "mapview.h" +#include UIMap::UIMap() { @@ -49,7 +46,7 @@ UIMap::~UIMap() g_map.removeMapView(m_mapView); } -void UIMap::draw(DrawPoolType drawPane) { +void UIMap::draw(const DrawPoolType drawPane) { if (drawPane == DrawPoolType::MAP) { g_drawPool.preDraw(drawPane, [this] { m_mapView->drawFloor(); @@ -72,7 +69,7 @@ void UIMap::draw(DrawPoolType drawPane) { } } -void UIMap::drawSelf(DrawPoolType drawPane) +void UIMap::drawSelf(const DrawPoolType drawPane) { UIWidget::drawSelf(drawPane); @@ -81,7 +78,6 @@ void UIMap::drawSelf(DrawPoolType drawPane) g_drawPool.addAction([] {glDisable(GL_BLEND); }); g_drawPool.addFilledRect(m_mapRect, Color::alpha); g_drawPool.addAction([] {glEnable(GL_BLEND); }); - return; } } @@ -89,7 +85,7 @@ void UIMap::updateMapRect() { m_mapView->updateRect(m_mapviewRect); } -bool UIMap::setZoom(int zoom) +bool UIMap::setZoom(const int zoom) { m_zoom = std::clamp(zoom, m_maxZoomIn, m_maxZoomOut); updateVisibleDimension(); @@ -143,7 +139,7 @@ void UIMap::setVisibleDimension(const Size& visibleDimension) updateMapSize(); } -void UIMap::setKeepAspectRatio(bool enable) +void UIMap::setKeepAspectRatio(const bool enable) { m_keepAspectRatio = enable; if (enable) diff --git a/src/client/uimap.h b/src/client/uimap.h index f8aac263f0..331af407b7 100644 --- a/src/client/uimap.h +++ b/src/client/uimap.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -22,13 +22,13 @@ #pragma once -#include #include "declarations.h" #include "tile.h" +#include #include "mapview.h" -class UIMap : public UIWidget +class UIMap final : public UIWidget { public: UIMap(); @@ -37,25 +37,25 @@ class UIMap : public UIWidget void drawSelf(DrawPoolType drawPane) override; void draw(DrawPoolType drawPane); - void movePixels(int x, int y) { m_mapView->move(x, y); } + void movePixels(const int x, const int y) { m_mapView->move(x, y); } void followCreature(const CreaturePtr& creature) { m_mapView->followCreature(creature); } void setCameraPosition(const Position& pos) { m_mapView->setCameraPosition(pos); } - void setMaxZoomIn(int maxZoomIn) { m_maxZoomIn = maxZoomIn; } - void setMaxZoomOut(int maxZoomOut) { m_maxZoomOut = maxZoomOut; } - void lockVisibleFloor(int floor) { m_mapView->lockFirstVisibleFloor(floor); } + void setMaxZoomIn(const int maxZoomIn) { m_maxZoomIn = maxZoomIn; } + void setMaxZoomOut(const int maxZoomOut) { m_maxZoomOut = maxZoomOut; } + void lockVisibleFloor(const int floor) { m_mapView->lockFirstVisibleFloor(floor); } void unlockVisibleFloor() { m_mapView->unlockFirstVisibleFloor(); } void setVisibleDimension(const Size& visibleDimension); - void setFloorViewMode(MapView::FloorViewMode viewMode) { m_mapView->setFloorViewMode(viewMode); } - void setDrawNames(bool enable) { m_mapView->setDrawNames(enable); } - void setDrawHealthBars(bool enable) { m_mapView->setDrawHealthBars(enable); } - void setDrawLights(bool enable) { m_mapView->setDrawLights(enable); } - void setLimitVisibleDimension(bool enable) { m_mapView->setLimitVisibleDimension(enable); updateVisibleDimension(); } - void setDrawManaBar(bool enable) { m_mapView->setDrawManaBar(enable); } + void setFloorViewMode(const MapView::FloorViewMode viewMode) { m_mapView->setFloorViewMode(viewMode); } + void setDrawNames(const bool enable) { m_mapView->setDrawNames(enable); } + void setDrawHealthBars(const bool enable) { m_mapView->setDrawHealthBars(enable); } + void setDrawLights(const bool enable) { m_mapView->setDrawLights(enable); } + void setLimitVisibleDimension(const bool enable) { m_mapView->setLimitVisibleDimension(enable); updateVisibleDimension(); } + void setDrawManaBar(const bool enable) { m_mapView->setDrawManaBar(enable); } void setKeepAspectRatio(bool enable); - void setShader(const std::string_view name, float fadein, float fadeout) { m_mapView->setShader(name, fadein, fadeout); } - void setMinimumAmbientLight(float intensity) { m_mapView->setMinimumAmbientLight(intensity); } - void setLimitVisibleRange(bool limitVisibleRange) { m_limitVisibleRange = limitVisibleRange; updateVisibleDimension(); } - void setDrawViewportEdge(bool force) { m_mapView->m_forceDrawViewportEdge = force; m_mapView->m_visibleDimension = {}; updateVisibleDimension(); } + void setShader(const std::string_view name, const float fadein, const float fadeout) { m_mapView->setShader(name, fadein, fadeout); } + void setMinimumAmbientLight(const float intensity) { m_mapView->setMinimumAmbientLight(intensity); } + void setLimitVisibleRange(const bool limitVisibleRange) { m_limitVisibleRange = limitVisibleRange; updateVisibleDimension(); } + void setDrawViewportEdge(const bool force) { m_mapView->m_forceDrawViewportEdge = force; m_mapView->m_visibleDimension = {}; updateVisibleDimension(); } bool zoomIn(); bool zoomOut(); @@ -69,10 +69,10 @@ class UIMap : public UIWidget bool isLimitVisibleRangeEnabled() { return m_limitVisibleRange; } bool isSwitchingShader() { return m_mapView->isSwitchingShader(); } - void setShadowFloorIntensity(float intensity) { m_mapView->setShadowFloorIntensity(intensity); } + void setShadowFloorIntensity(const float intensity) { m_mapView->setShadowFloorIntensity(intensity); } - std::vector getSpectators(bool multiFloor = false) { return m_mapView->getSpectators(multiFloor); } - std::vector getSightSpectators(bool multiFloor = false) { return m_mapView->getSightSpectators(multiFloor); } + std::vector getSpectators(const bool multiFloor = false) { return m_mapView->getSpectators(multiFloor); } + std::vector getSightSpectators(const bool multiFloor = false) { return m_mapView->getSightSpectators(multiFloor); } bool isInRange(const Position& pos) { return m_mapView->isInRange(pos); } PainterShaderProgramPtr getShader() { return m_mapView->getShader(); } @@ -102,7 +102,7 @@ class UIMap : public UIWidget void updateMapRect(); protected: - void onStyleApply(const std::string_view styleName, const OTMLNodePtr& styleNode) override; + void onStyleApply(std::string_view styleName, const OTMLNodePtr& styleNode) override; void onGeometryChange(const Rect& oldRect, const Rect& newRect) override; bool onMouseMove(const Point& mousePos, const Point& mouseMoved) override; diff --git a/src/client/uimapanchorlayout.cpp b/src/client/uimapanchorlayout.cpp index 9bd228ab0e..d897287712 100644 --- a/src/client/uimapanchorlayout.cpp +++ b/src/client/uimapanchorlayout.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,9 +21,9 @@ */ #include "uimapanchorlayout.h" -#include #include "declarations.h" #include "uiminimap.h" +#include int UIPositionAnchor::getHookedPoint(const UIWidgetPtr& hookedWidget, const UIWidgetPtr&) { diff --git a/src/client/uimapanchorlayout.h b/src/client/uimapanchorlayout.h index b6aa041526..3c3aba7741 100644 --- a/src/client/uimapanchorlayout.h +++ b/src/client/uimapanchorlayout.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -22,17 +22,18 @@ #pragma once -#include #include "declarations.h" +#include #include -class UIPositionAnchor : public UIAnchor +class UIPositionAnchor final : public UIAnchor { public: - UIPositionAnchor(Fw::AnchorEdge anchoredEdge, const Position& hookedPosition, Fw::AnchorEdge hookedEdge) : + UIPositionAnchor(const Fw::AnchorEdge anchoredEdge, const Position& hookedPosition, const Fw::AnchorEdge hookedEdge) : UIAnchor(anchoredEdge, {}, hookedEdge), m_hookedPosition(hookedPosition) - {} + { + } UIWidgetPtr getHookedWidget(const UIWidgetPtr& /*widget*/, const UIWidgetPtr& parentWidget) override { return parentWidget; } int getHookedPoint(const UIWidgetPtr& hookedWidget, const UIWidgetPtr& parentWidget) override; @@ -41,7 +42,7 @@ class UIPositionAnchor : public UIAnchor Position m_hookedPosition; }; -class UIMapAnchorLayout : public UIAnchorLayout +class UIMapAnchorLayout final : public UIAnchorLayout { public: UIMapAnchorLayout(UIWidgetPtr parentWidget) : UIAnchorLayout(std::move(parentWidget)) {} diff --git a/src/client/uiminimap.cpp b/src/client/uiminimap.cpp index e24ac9fe69..b464e39d4d 100644 --- a/src/client/uiminimap.cpp +++ b/src/client/uiminimap.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -27,7 +27,7 @@ #include "minimap.h" #include "uimapanchorlayout.h" -void UIMinimap::drawSelf(DrawPoolType drawPane) +void UIMinimap::drawSelf(const DrawPoolType drawPane) { UIWidget::drawSelf(drawPane); if (drawPane != DrawPoolType::FOREGROUND) @@ -39,7 +39,7 @@ void UIMinimap::drawSelf(DrawPoolType drawPane) g_minimap.draw(getPaddingRect(), m_cameraPosition, m_scale, m_color); } -bool UIMinimap::setZoom(int8_t zoom) +bool UIMinimap::setZoom(const int8_t zoom) { if (zoom == m_zoom) return true; @@ -71,7 +71,7 @@ void UIMinimap::setCameraPosition(const Position& pos) const Position oldPos = m_cameraPosition; m_cameraPosition = pos; - + if (m_layout) m_layout->update(); @@ -112,9 +112,9 @@ Position UIMinimap::getTilePosition(const Point& mousePos) return g_minimap.getTilePosition(mousePos, getPaddingRect(), m_cameraPosition, m_scale); } -void UIMinimap::anchorPosition(const UIWidgetPtr& anchoredWidget, Fw::AnchorEdge anchoredEdge, const Position& hookedPosition, Fw::AnchorEdge hookedEdge) +void UIMinimap::anchorPosition(const UIWidgetPtr& anchoredWidget, const Fw::AnchorEdge anchoredEdge, const Position& hookedPosition, const Fw::AnchorEdge hookedEdge) { - if(!m_layout) + if (!m_layout) return; const auto& layout = m_layout->static_self_cast(); @@ -124,7 +124,7 @@ void UIMinimap::anchorPosition(const UIWidgetPtr& anchoredWidget, Fw::AnchorEdge void UIMinimap::fillPosition(const UIWidgetPtr& anchoredWidget, const Position& hookedPosition) { - if(!m_layout) + if (!m_layout) return; const auto& layout = m_layout->static_self_cast(); @@ -134,7 +134,7 @@ void UIMinimap::fillPosition(const UIWidgetPtr& anchoredWidget, const Position& void UIMinimap::centerInPosition(const UIWidgetPtr& anchoredWidget, const Position& hookedPosition) { - if(!m_layout) + if (!m_layout) return; const auto& layout = m_layout->static_self_cast(); @@ -142,7 +142,7 @@ void UIMinimap::centerInPosition(const UIWidgetPtr& anchoredWidget, const Positi layout->centerInPosition(anchoredWidget, hookedPosition); } -void UIMinimap::onZoomChange(int zoom, int oldZoom) { callLuaField("onZoomChange", zoom, oldZoom); } +void UIMinimap::onZoomChange(const int zoom, const int oldZoom) { callLuaField("onZoomChange", zoom, oldZoom); } void UIMinimap::onCameraPositionChange(const Position& position, const Position& oldPosition) { callLuaField("onCameraPositionChange", position, oldPosition); } diff --git a/src/client/uiminimap.h b/src/client/uiminimap.h index 8696c45019..63ef2e6dd2 100644 --- a/src/client/uiminimap.h +++ b/src/client/uiminimap.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -22,10 +22,10 @@ #pragma once -#include #include "declarations.h" +#include -class UIMinimap : public UIWidget +class UIMinimap final : public UIWidget { public: void drawSelf(DrawPoolType drawPane) override; @@ -34,8 +34,8 @@ class UIMinimap : public UIWidget bool zoomOut() { return setZoom(m_zoom - 1); } bool setZoom(int8_t zoom); - void setMinZoom(int8_t minZoom) { m_minZoom = minZoom; } - void setMaxZoom(int8_t maxZoom) { m_maxZoom = maxZoom; } + void setMinZoom(const int8_t minZoom) { m_minZoom = minZoom; } + void setMaxZoom(const int8_t maxZoom) { m_maxZoom = maxZoom; } void setCameraPosition(const Position& pos); bool floorUp(); bool floorDown(); @@ -57,7 +57,7 @@ class UIMinimap : public UIWidget protected: virtual void onZoomChange(int zoom, int oldZoom); virtual void onCameraPositionChange(const Position& position, const Position& oldPosition); - void onStyleApply(const std::string_view styleName, const OTMLNodePtr& styleNode) override; + void onStyleApply(std::string_view styleName, const OTMLNodePtr& styleNode) override; private: Rect m_mapArea; diff --git a/src/client/uimissile.cpp b/src/client/uimissile.cpp index 26e7b77be9..aa9064e03d 100644 --- a/src/client/uimissile.cpp +++ b/src/client/uimissile.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -25,7 +25,7 @@ UIMissile::UIMissile() { setProp(PropDraggable, true, false); } -void UIMissile::drawSelf(DrawPoolType drawPane) +void UIMissile::drawSelf(const DrawPoolType drawPane) { if (drawPane != DrawPoolType::FOREGROUND) return; @@ -52,7 +52,7 @@ void UIMissile::drawSelf(DrawPoolType drawPane) drawText(m_rect); } -void UIMissile::setMissileId(int id) +void UIMissile::setMissileId(const int id) { if (id == 0) m_missile = nullptr; diff --git a/src/client/uimissile.h b/src/client/uimissile.h index a07d3e587e..9a73ff0878 100644 --- a/src/client/uimissile.h +++ b/src/client/uimissile.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -22,21 +22,21 @@ #pragma once -#include #include "declarations.h" #include "missile.h" +#include -class UIMissile : public UIWidget +class UIMissile final : public UIWidget { public: UIMissile(); void drawSelf(DrawPoolType drawPane) override; void setMissileId(int id); - void setMissileVisible(bool visible) { m_missileVisible = visible; } + void setMissileVisible(const bool visible) { m_missileVisible = visible; } void setMissile(const MissilePtr& missile); - void setVirtual(bool virt) { m_virtual = virt; } - void setDirection(Otc::Direction dir) { if (m_missile) m_missile->setDirection(dir); } + void setVirtual(const bool virt) { m_virtual = virt; } + void setDirection(const Otc::Direction dir) { if (m_missile) m_missile->setDirection(dir); } void clearMissile() { setMissileId(0); } int getMissileId() { return m_missile ? m_missile->getId() : 0; } @@ -46,7 +46,7 @@ class UIMissile : public UIWidget bool isMissileVisible() { return m_missileVisible; } protected: - void onStyleApply(const std::string_view styleName, const OTMLNodePtr& styleNode) override; + void onStyleApply(std::string_view styleName, const OTMLNodePtr& styleNode) override; MissilePtr m_missile; bool m_virtual{ false }; diff --git a/src/client/uiprogressrect.cpp b/src/client/uiprogressrect.cpp index 56733231c1..340956f6c5 100644 --- a/src/client/uiprogressrect.cpp +++ b/src/client/uiprogressrect.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,12 +21,11 @@ */ #include "uiprogressrect.h" -#include #include "framework/graphics/drawpool.h" #include "framework/graphics/drawpoolmanager.h" -void UIProgressRect::drawSelf(DrawPoolType drawPane) +void UIProgressRect::drawSelf(const DrawPoolType drawPane) { if (drawPane != DrawPoolType::FOREGROUND) return; diff --git a/src/client/uiprogressrect.h b/src/client/uiprogressrect.h index 200424ad13..30577a455b 100644 --- a/src/client/uiprogressrect.h +++ b/src/client/uiprogressrect.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -22,11 +22,11 @@ #pragma once -#include #include "declarations.h" #include "item.h" +#include -class UIProgressRect : public UIWidget +class UIProgressRect final : public UIWidget { public: void drawSelf(DrawPoolType drawPane) override; @@ -35,7 +35,7 @@ class UIProgressRect : public UIWidget float getPercent() { return m_percent; } protected: - void onStyleApply(const std::string_view styleName, const OTMLNodePtr& styleNode) override; + void onStyleApply(std::string_view styleName, const OTMLNodePtr& styleNode) override; float m_percent{ 0 }; }; diff --git a/src/client/uisprite.cpp b/src/client/uisprite.cpp index d73f2b9286..ca6552a3e6 100644 --- a/src/client/uisprite.cpp +++ b/src/client/uisprite.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -27,7 +27,7 @@ #include "framework/graphics/drawpool.h" #include "framework/graphics/drawpoolmanager.h" -void UISprite::drawSelf(DrawPoolType drawPane) +void UISprite::drawSelf(const DrawPoolType drawPane) { if (drawPane != DrawPoolType::FOREGROUND) return; @@ -50,7 +50,7 @@ void UISprite::drawSelf(DrawPoolType drawPane) drawText(m_rect); } -void UISprite::setSpriteId(int id) +void UISprite::setSpriteId(const int id) { if (!g_sprites.isLoaded()) return; diff --git a/src/client/uisprite.h b/src/client/uisprite.h index db42687836..ff5b3765f2 100644 --- a/src/client/uisprite.h +++ b/src/client/uisprite.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -22,10 +22,10 @@ #pragma once -#include #include "declarations.h" +#include -class UISprite : public UIWidget +class UISprite final : public UIWidget { public: void drawSelf(DrawPoolType drawPane) override; @@ -37,12 +37,12 @@ class UISprite : public UIWidget void setSpriteColor(Color color) { m_spriteColor = color; } bool isSpriteVisible() const { return m_spriteVisible; } - void setSpriteVisible(bool visible) { m_spriteVisible = visible; } + void setSpriteVisible(const bool visible) { m_spriteVisible = visible; } bool hasSprite() { return m_sprite != nullptr; } protected: - void onStyleApply(const std::string_view styleName, const OTMLNodePtr& styleNode) override; + void onStyleApply(std::string_view styleName, const OTMLNodePtr& styleNode) override; TexturePtr m_sprite; uint16_t m_spriteId{ 0 }; diff --git a/src/framework/config.h b/src/framework/config.h index 4492f8d4cb..2b67b0fcab 100644 --- a/src/framework/config.h +++ b/src/framework/config.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * 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/src/framework/const.h b/src/framework/const.h index e1636c3b7a..49be900d06 100644 --- a/src/framework/const.h +++ b/src/framework/const.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -23,6 +23,7 @@ #pragma once #include +#include #define DEG_TO_RAD (std::acos(-1.f)/180.f) #define RAD_TO_DEC (180.f/std::acos(-1.f)) @@ -38,6 +39,8 @@ #define BUILD_ARCH "x86" #elif defined(__arm__) #define BUILD_ARCH "ARM" +#elif defined(__EMSCRIPTEN__) +#define BUILD_ARCH "WASM32" #else #define BUILD_ARCH "unknown" #endif @@ -46,7 +49,7 @@ namespace Fw { // clang c++20 dont support std::numbers::pi - static constexpr float pi = 3.141592653589793f; + static constexpr float pi = std::numbers::pi_v; static constexpr float MIN_ALPHA = 0.003f; enum Key : uint8_t diff --git a/src/framework/core/adaptativeframecounter.cpp b/src/framework/core/adaptativeframecounter.cpp index 6c5186e688..eeb515b8de 100644 --- a/src/framework/core/adaptativeframecounter.cpp +++ b/src/framework/core/adaptativeframecounter.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,8 +21,6 @@ */ #include "adaptativeframecounter.h" -#include -#include #include bool AdaptativeFrameCounter::update() diff --git a/src/framework/core/adaptativeframecounter.h b/src/framework/core/adaptativeframecounter.h index 82ba747c2d..833e720a4b 100644 --- a/src/framework/core/adaptativeframecounter.h +++ b/src/framework/core/adaptativeframecounter.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -30,7 +30,7 @@ class AdaptativeFrameCounter { public: - AdaptativeFrameCounter() : m_interval(stdext::millis()) { } + AdaptativeFrameCounter() : m_interval(stdext::millis()) {} void init() { m_timer.restart(); } bool update(); @@ -49,12 +49,12 @@ class AdaptativeFrameCounter return ((maxFps - m_fps) / maxFps) * 100.f; } - float getFpsPercent(float percent) const { + float getFpsPercent(const float percent) const { return getFps() * (percent / 100); } private: - uint32_t getMaxPeriod(uint16_t fps) const { return 1000000u / fps; } + uint32_t getMaxPeriod(const uint16_t fps) const { return 1000000u / fps; } uint16_t m_maxFps{}; uint16_t m_targetFps{ 60u }; diff --git a/src/framework/core/application.cpp b/src/framework/core/application.cpp index 25117c3a47..36037a8cc1 100644 --- a/src/framework/core/application.cpp +++ b/src/framework/core/application.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -22,15 +22,16 @@ #include "application.h" +#include "asyncdispatcher.h" #include #include #include #include +#include #include #include #include -#include -#include "asyncdispatcher.h" +#include #include #include @@ -41,10 +42,14 @@ #include #ifdef FRAMEWORK_NET +#ifdef __EMSCRIPTEN__ +#include +#else #include #endif +#endif -void exitSignalHandler(int sig) +void exitSignalHandler(const int sig) { static bool signaled = false; switch (sig) { @@ -95,6 +100,9 @@ void Application::init(std::vector& args, ApplicationContext* conte // initialize lua g_lua.init(); registerLuaFunctions(); + + // initalize proxy + g_proxy.init(); } void Application::deinit() @@ -121,8 +129,11 @@ void Application::deinit() void Application::terminate() { #ifdef FRAMEWORK_NET - // terminate network +#ifdef __EMSCRIPTEN__ + WebConnection::terminate(); +#else Connection::terminate(); +#endif #endif // release configs @@ -134,6 +145,9 @@ void Application::terminate() // terminate script environment g_lua.terminate(); + // terminate proxy + g_proxy.terminate(); + m_terminated = true; signal(SIGTERM, SIG_DFL); @@ -145,14 +159,22 @@ void Application::poll() g_clock.update(); #ifdef FRAMEWORK_NET +#ifdef __EMSCRIPTEN__ + WebConnection::poll(); +#else Connection::poll(); +#endif #endif g_dispatcher.poll(); // poll connection again to flush pending write #ifdef FRAMEWORK_NET +#ifdef __EMSCRIPTEN__ + WebConnection::poll(); +#else Connection::poll(); +#endif #endif g_clock.update(); @@ -187,6 +209,8 @@ std::string Application::getOs() return "linux"; #elif ANDROID return "android"; +#elif __EMSCRIPTEN__ + return "browser"; #else return "unknown"; #endif diff --git a/src/framework/core/application.h b/src/framework/core/application.h index a4ed4cf010..0e68b24fd8 100644 --- a/src/framework/core/application.h +++ b/src/framework/core/application.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -23,7 +23,6 @@ #pragma once #include -#include class ApplicationContext { @@ -92,7 +91,6 @@ class Application }; #ifdef FRAMEWORK_GRAPHICS -#include "graphicalapplication.h" #else #include "consoleapplication.h" #endif diff --git a/src/framework/core/asyncdispatcher.cpp b/src/framework/core/asyncdispatcher.cpp index 1b39b84c8e..3df076e8c1 100644 --- a/src/framework/core/asyncdispatcher.cpp +++ b/src/framework/core/asyncdispatcher.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * 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/src/framework/core/asyncdispatcher.h b/src/framework/core/asyncdispatcher.h index 8d7b0a66cd..9fbfa0ce14 100644 --- a/src/framework/core/asyncdispatcher.h +++ b/src/framework/core/asyncdispatcher.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -22,6 +22,6 @@ #pragma once -#include +#include extern BS::thread_pool g_asyncDispatcher; diff --git a/src/framework/core/binarytree.cpp b/src/framework/core/binarytree.cpp index 77f0ee8724..e1260b4937 100644 --- a/src/framework/core/binarytree.cpp +++ b/src/framework/core/binarytree.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -82,7 +82,7 @@ BinaryTreeVec BinaryTree::getChildren() } } -void BinaryTree::seek(uint32_t pos) +void BinaryTree::seek(const uint32_t pos) { unserialize(); if (pos > m_buffer.size()) @@ -90,7 +90,7 @@ void BinaryTree::seek(uint32_t pos) m_pos = pos; } -void BinaryTree::skip(uint32_t len) +void BinaryTree::skip(const uint32_t len) { unserialize(); seek(tell() + len); @@ -163,19 +163,19 @@ OutputBinaryTree::OutputBinaryTree(FileStreamPtr fin) : m_fin(std::move(fin)) startNode(0); } -void OutputBinaryTree::addU8(uint8_t v) +void OutputBinaryTree::addU8(const uint8_t v) { write(&v, 1); } -void OutputBinaryTree::addU16(uint16_t v) +void OutputBinaryTree::addU16(const uint16_t v) { uint8_t data[2]; stdext::writeULE16(data, v); write(data, 2); } -void OutputBinaryTree::addU32(uint32_t v) +void OutputBinaryTree::addU32(const uint32_t v) { uint8_t data[4]; stdext::writeULE32(data, v); @@ -191,7 +191,7 @@ void OutputBinaryTree::addString(const std::string_view v) write((const uint8_t*)v.data(), v.length()); } -void OutputBinaryTree::addPos(uint16_t x, uint16_t y, uint8_t z) +void OutputBinaryTree::addPos(const uint16_t x, const uint16_t y, const uint8_t z) { addU16(x); addU16(y); @@ -204,7 +204,7 @@ void OutputBinaryTree::addPoint(const Point& point) addU8(point.y); } -void OutputBinaryTree::startNode(uint8_t node) +void OutputBinaryTree::startNode(const uint8_t node) { m_fin->addU8(static_cast(BinaryTree::Node::START)); write(&node, 1); @@ -215,7 +215,7 @@ void OutputBinaryTree::endNode() const m_fin->addU8(static_cast(BinaryTree::Node::END)); } -void OutputBinaryTree::write(const uint8_t* data, size_t size) const +void OutputBinaryTree::write(const uint8_t* data, const size_t size) const { for (size_t i = 0; i < size; ++i) { if (const auto v = static_cast(data[i]); diff --git a/src/framework/core/binarytree.h b/src/framework/core/binarytree.h index 9fae3f6c44..8566541c49 100644 --- a/src/framework/core/binarytree.h +++ b/src/framework/core/binarytree.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -69,7 +69,7 @@ class OutputBinaryTree void addU8(uint8_t v); void addU16(uint16_t v); void addU32(uint32_t v); - void addString(const std::string_view v); + void addString(std::string_view v); void addPos(uint16_t x, uint16_t y, uint8_t z); void addPoint(const Point& point); diff --git a/src/framework/core/clock.cpp b/src/framework/core/clock.cpp index 371174a57d..33696084d3 100644 --- a/src/framework/core/clock.cpp +++ b/src/framework/core/clock.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -32,4 +32,4 @@ void Clock::update() } ticks_t Clock::realMicros() { return stdext::micros(); } -ticks_t Clock::realMillis(){ return stdext::millis(); } \ No newline at end of file +ticks_t Clock::realMillis() { return stdext::millis(); } \ No newline at end of file diff --git a/src/framework/core/clock.h b/src/framework/core/clock.h index ed90c94927..dbe497bcb1 100644 --- a/src/framework/core/clock.h +++ b/src/framework/core/clock.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * 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/src/framework/core/config.cpp b/src/framework/core/config.cpp index b78ff8a7db..b149cefd3b 100644 --- a/src/framework/core/config.cpp +++ b/src/framework/core/config.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -43,7 +43,7 @@ bool Config::load(const std::string& file) m_confsDoc = confsDoc; return true; - } catch (stdext::exception const& e) { + } catch (const stdext::exception& e) { g_logger.error(stdext::format("Unable to parse configuration file '%s': ", e.what())); return false; } @@ -66,7 +66,7 @@ bool Config::save() return m_confsDoc->save(m_fileName); } -void Config::clear() const +void Config::clear() { m_confsDoc->clear(); } @@ -145,7 +145,7 @@ OTMLNodePtr Config::getNode(const std::string& key) int Config::getNodeSize(const std::string& key) { - auto node = m_confsDoc->get(key); + const auto node = m_confsDoc->get(key); if (node) return node->size(); return 0; @@ -170,4 +170,4 @@ bool Config::isLoaded() const std::string Config::getFileName() { return m_fileName; -} +} \ No newline at end of file diff --git a/src/framework/core/config.h b/src/framework/core/config.h index b31fdcf803..9cd0b5fbdc 100644 --- a/src/framework/core/config.h +++ b/src/framework/core/config.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -28,7 +28,7 @@ #include // @bindclass -class Config : public LuaObject +class Config final : public LuaObject { public: Config(); @@ -36,7 +36,7 @@ class Config : public LuaObject bool load(const std::string& file); bool unload(); bool save(); - void clear() const; + void clear(); void setValue(const std::string& key, const std::string& value); void setList(const std::string& key, const std::vector& list); std::string getValue(const std::string& key); diff --git a/src/framework/core/configmanager.cpp b/src/framework/core/configmanager.cpp index 3b7339387c..85571fe8ac 100644 --- a/src/framework/core/configmanager.cpp +++ b/src/framework/core/configmanager.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * 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/src/framework/core/configmanager.h b/src/framework/core/configmanager.h index 4bb88312e3..1b8b4d5631 100644 --- a/src/framework/core/configmanager.h +++ b/src/framework/core/configmanager.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * 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/src/framework/core/declarations.h b/src/framework/core/declarations.h index 5277c5890d..727a004094 100644 --- a/src/framework/core/declarations.h +++ b/src/framework/core/declarations.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * 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/src/framework/core/event.cpp b/src/framework/core/event.cpp index 975ede11a1..3d08a0322d 100644 --- a/src/framework/core/event.cpp +++ b/src/framework/core/event.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * 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/src/framework/core/event.h b/src/framework/core/event.h index 17d5dd1286..53d5707e32 100644 --- a/src/framework/core/event.h +++ b/src/framework/core/event.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * 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/src/framework/core/eventdispatcher.cpp b/src/framework/core/eventdispatcher.cpp index aa96c00692..1910c97e15 100644 --- a/src/framework/core/eventdispatcher.cpp +++ b/src/framework/core/eventdispatcher.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -23,7 +23,6 @@ #include "eventdispatcher.h" #include "asyncdispatcher.h" -#include #include "timer.h" EventDispatcher g_dispatcher, g_textDispatcher, g_mainDispatcher; @@ -138,7 +137,7 @@ void EventDispatcher::executeEvents() { m_eventList.clear(); } -std::vector> generatePartition(size_t size) { +std::vector> generatePartition(const size_t size) { if (size == 0) return {}; diff --git a/src/framework/core/eventdispatcher.h b/src/framework/core/eventdispatcher.h index 394f4efb18..dee8803c1e 100644 --- a/src/framework/core/eventdispatcher.h +++ b/src/framework/core/eventdispatcher.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -22,12 +22,9 @@ #pragma once -#include "clock.h" #include "scheduledevent.h" -#include - - // @bindsingleton g_dispatcher +// @bindsingleton g_dispatcher class EventDispatcher { public: diff --git a/src/framework/core/filestream.cpp b/src/framework/core/filestream.cpp index 27be851a7c..47705c8710 100644 --- a/src/framework/core/filestream.cpp +++ b/src/framework/core/filestream.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,23 +21,25 @@ */ #include "filestream.h" -#include #include "binarytree.h" +#include "graphicalapplication.h" +#include #include -inline void grow(std::vector& data, size_t size) { +inline void grow(std::vector& data, const size_t size) { if (size > data.size()) data.resize(size); } -FileStream::FileStream(std::string name, PHYSFS_File* fileHandle, bool writeable) : +FileStream::FileStream(std::string name, PHYSFS_File* fileHandle, const bool writeable) : m_name(std::move(name)), m_fileHandle(fileHandle), m_pos(0), m_writeable(writeable), m_caching(false) -{} +{ +} FileStream::FileStream(std::string name, const std::string_view buffer) : m_name(std::move(name)), @@ -59,7 +61,7 @@ FileStream::~FileStream() close(); } -void FileStream::cache(bool useEnc) +void FileStream::cache(bool /*useEnc*/) { m_caching = true; @@ -125,7 +127,7 @@ void FileStream::flush() } } -int FileStream::read(void* buffer, uint32_t size, uint32_t nmemb) +int FileStream::read(void* buffer, const uint32_t size, const uint32_t nmemb) { if (!m_caching) { const int res = PHYSFS_readBytes(m_fileHandle, buffer, static_cast(size) * nmemb); @@ -145,7 +147,7 @@ int FileStream::read(void* buffer, uint32_t size, uint32_t nmemb) return nmemb; } -void FileStream::write(const void* buffer, uint32_t count) +void FileStream::write(const void* buffer, const uint32_t count) { if (!m_caching) { if (PHYSFS_writeBytes(m_fileHandle, buffer, count) != count) @@ -157,7 +159,7 @@ void FileStream::write(const void* buffer, uint32_t count) } } -void FileStream::seek(uint32_t pos) +void FileStream::seek(const uint32_t pos) { if (!m_caching) { if (!PHYSFS_seek(m_fileHandle, pos)) @@ -169,7 +171,7 @@ void FileStream::seek(uint32_t pos) } } -void FileStream::skip(uint32_t len) +void FileStream::skip(const uint32_t len) { seek(tell() + len); } @@ -353,7 +355,7 @@ BinaryTreePtr FileStream::getBinaryTree() return std::make_shared(shared_from_this()); } -void FileStream::startNode(uint8_t n) +void FileStream::startNode(const uint8_t n) { addU8(static_cast(BinaryTree::Node::START)); addU8(n); @@ -364,7 +366,7 @@ void FileStream::endNode() addU8(static_cast(BinaryTree::Node::END)); } -void FileStream::addU8(uint8_t v) +void FileStream::addU8(const uint8_t v) { if (!m_caching) { if (PHYSFS_writeBytes(m_fileHandle, &v, 1) != 1) @@ -375,7 +377,7 @@ void FileStream::addU8(uint8_t v) } } -void FileStream::addU16(uint16_t v) +void FileStream::addU16(const uint16_t v) { if (!m_caching) { if (PHYSFS_writeULE16(m_fileHandle, v) == 0) @@ -387,7 +389,7 @@ void FileStream::addU16(uint16_t v) } } -void FileStream::addU32(uint32_t v) +void FileStream::addU32(const uint32_t v) { if (!m_caching) { if (PHYSFS_writeULE32(m_fileHandle, v) == 0) @@ -399,7 +401,7 @@ void FileStream::addU32(uint32_t v) } } -void FileStream::addU64(uint64_t v) +void FileStream::addU64(const uint64_t v) { if (!m_caching) { if (PHYSFS_writeULE64(m_fileHandle, v) == 0) @@ -411,7 +413,7 @@ void FileStream::addU64(uint64_t v) } } -void FileStream::add8(int8_t v) +void FileStream::add8(const int8_t v) { if (!m_caching) { if (PHYSFS_writeBytes(m_fileHandle, &v, 1) != 1) @@ -422,7 +424,7 @@ void FileStream::add8(int8_t v) } } -void FileStream::add16(int16_t v) +void FileStream::add16(const int16_t v) { if (!m_caching) { if (PHYSFS_writeSLE16(m_fileHandle, v) == 0) @@ -434,7 +436,7 @@ void FileStream::add16(int16_t v) } } -void FileStream::add32(int32_t v) +void FileStream::add32(const int32_t v) { if (!m_caching) { if (PHYSFS_writeSLE32(m_fileHandle, v) == 0) @@ -446,7 +448,7 @@ void FileStream::add32(int32_t v) } } -void FileStream::add64(int64_t v) +void FileStream::add64(const int64_t v) { if (!m_caching) { if (PHYSFS_writeSLE64(m_fileHandle, v) == 0) @@ -464,10 +466,10 @@ void FileStream::addString(const std::string_view v) write(v.data(), v.length()); } -void FileStream::throwError(const std::string_view message, bool physfsError) const +void FileStream::throwError(const std::string_view message, const bool physfsError) const { std::string completeMessage = stdext::format("in file '%s': %s", m_name, message); if (physfsError) completeMessage += ": "s + PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode()); throw Exception(completeMessage); -} +} \ No newline at end of file diff --git a/src/framework/core/filestream.h b/src/framework/core/filestream.h index 343e016b1a..ebe63a1abb 100644 --- a/src/framework/core/filestream.h +++ b/src/framework/core/filestream.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -22,10 +22,10 @@ #pragma once +#include "declarations.h" #include #include #include -#include "declarations.h" struct PHYSFS_File; @@ -34,7 +34,7 @@ class FileStream : public std::enable_shared_from_this { public: FileStream(std::string name, PHYSFS_File* fileHandle, bool writeable); - FileStream(std::string name, const std::string_view buffer); + FileStream(std::string name, std::string_view buffer); ~FileStream(); void cache(bool useEnc = false); @@ -70,14 +70,14 @@ class FileStream : public std::enable_shared_from_this void add16(int16_t v); void add32(int32_t v); void add64(int64_t v); - void addString(const std::string_view v); - void addPos(uint16_t x, uint16_t y, uint8_t z) { addU16(x); addU16(y); addU8(z); } + void addString(std::string_view v); + void addPos(const uint16_t x, const uint16_t y, const uint8_t z) { addU16(x); addU16(y); addU8(z); } void addPoint(const Point& p) { addU8(p.x); addU8(p.y); } std::vector m_data; private: - void throwError(const std::string_view message, bool physfsError = false) const; + void throwError(std::string_view message, bool physfsError = false) const; std::string m_name; PHYSFS_File* m_fileHandle; diff --git a/src/framework/core/garbagecollection.cpp b/src/framework/core/garbagecollection.cpp index 46a8bbf8ff..c02bdd41b8 100644 --- a/src/framework/core/garbagecollection.cpp +++ b/src/framework/core/garbagecollection.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -22,12 +22,12 @@ #include "garbagecollection.h" #include -#include -#include -#include -#include #include #include +#include +#include +#include +#include constexpr uint32_t LUA_TIME = 15 * 60 * 1000; // 15min constexpr uint32_t TEXTURE_TIME = 30 * 60 * 1000; // 30min diff --git a/src/framework/core/garbagecollection.h b/src/framework/core/garbagecollection.h index 8c44ccc071..9150d17d86 100644 --- a/src/framework/core/garbagecollection.h +++ b/src/framework/core/garbagecollection.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -22,8 +22,8 @@ #pragma once -#include #include "timer.h" +#include class GarbageCollection { diff --git a/src/framework/core/graphicalapplication.cpp b/src/framework/core/graphicalapplication.cpp index ab167c73af..b895182211 100644 --- a/src/framework/core/graphicalapplication.cpp +++ b/src/framework/core/graphicalapplication.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -23,26 +23,28 @@ #include "graphicalapplication.h" #include "garbagecollection.h" +#include "framework/stdext/time.h" #include #include #include #include #include #include +#include #include #include #include #include #include #include -#include "framework/stdext/time.h" -#include #ifdef FRAMEWORK_SOUND #include #endif -#include +#ifdef __EMSCRIPTEN__ +#include +#endif GraphicalApplication g_app; @@ -50,7 +52,7 @@ void GraphicalApplication::init(std::vector& args, ApplicationConte { Application::init(args, context); - GraphicalApplicationContext* graphicalContext = static_cast(context); + auto graphicalContext = static_cast(context); setDrawEvents(graphicalContext->getDrawEvents()); // setup platform window @@ -64,10 +66,10 @@ void GraphicalApplication::init(std::vector& args, ApplicationConte g_window.setOnInputEvent([this](auto&& PH1) { if (!m_running) inputEvent(PH1); - else g_dispatcher.addEvent([&, PH1]() { inputEvent(PH1); }); + else g_dispatcher.addEvent([&, PH1] { inputEvent(PH1); }); }); - g_window.setOnClose([this] { g_dispatcher.addEvent([this]() { close(); }); }); + g_window.setOnClose([this] { g_dispatcher.addEvent([this] { close(); }); }); g_mouse.init(); @@ -124,6 +126,35 @@ void GraphicalApplication::terminate() m_terminated = true; } +#ifdef __EMSCRIPTEN__ +void GraphicalApplication::mainLoop() { + if (m_stopping) { + emscripten_cancel_main_loop(); + MAIN_THREAD_EM_ASM({ window.location.reload(); }); + return; + } + mainPoll(); + + if (!g_window.isVisible()) { + stdext::millisleep(10); + return; + } + + const auto FPS = [this] { + m_mapProcessFrameCounter.setTargetFps(g_window.vsyncEnabled() || getMaxFps() || getTargetFps() ? 500u : 0u); + return m_graphicFrameCounter.getFps(); + }; + + g_drawPool.draw(); + + if (m_graphicFrameCounter.update()) { + g_dispatcher.addEvent([this, fps = FPS()] { + g_lua.callGlobalField("g_app", "onFps", fps); + }); + } +} +#endif + void GraphicalApplication::run() { // run the first poll @@ -139,11 +170,12 @@ void GraphicalApplication::run() g_lua.callGlobalField("g_app", "onRun"); - const auto& FPS = [this] { +#ifndef __EMSCRIPTEN__ + const auto FPS = [this] { m_mapProcessFrameCounter.setTargetFps(g_window.vsyncEnabled() || getMaxFps() || getTargetFps() ? 500u : 0u); return m_graphicFrameCounter.getFps(); }; - +#endif // THREAD - POOL & MAP const auto& mapThread = g_asyncDispatcher.submit_task([this] { const auto uiPool = g_drawPool.get(DrawPoolType::FOREGROUND); @@ -198,6 +230,10 @@ void GraphicalApplication::run() } }); +#ifdef __EMSCRIPTEN__ + m_running = true; + emscripten_set_main_loop(([] { g_app.mainLoop(); }), 0, 1); +#else m_running = true; while (!m_stopping) { mainPoll(); @@ -218,6 +254,7 @@ void GraphicalApplication::run() }); } } +#endif mapThread.wait(); m_running = false; @@ -269,11 +306,6 @@ void GraphicalApplication::resize(const Size& size) g_mainDispatcher.addEvent([size, scale] { g_drawPool.get(DrawPoolType::FOREGROUND)->setFramebuffer(size / scale); - - if (USE_FRAMEBUFFER) { - g_drawPool.get(DrawPoolType::CREATURE_INFORMATION)->setFramebuffer(size); - g_drawPool.get(DrawPoolType::FOREGROUND_MAP)->setFramebuffer(size); - } }); } @@ -306,10 +338,10 @@ void GraphicalApplication::doScreenshot(std::string file) g_mainDispatcher.addEvent([file] { auto resolution = g_graphics.getViewportSize(); - int width = resolution.width(); - int height = resolution.height(); + const int width = resolution.width(); + const int height = resolution.height(); auto pixels = std::make_shared>(width * height * 4 * sizeof(GLubyte), 0); - glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, (GLubyte*)(pixels->data())); + glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels->data()); g_asyncDispatcher.detach_task([resolution, pixels, file] { try { @@ -330,7 +362,7 @@ void GraphicalApplication::doMapScreenshot(std::string fileName) } float GraphicalApplication::getHUDScale() const { return g_window.getDisplayDensity(); } -void GraphicalApplication::setHUDScale(float v) { +void GraphicalApplication::setHUDScale(const float v) { g_window.setDisplayDensity(v); resize(g_graphics.getViewportSize()); } \ No newline at end of file diff --git a/src/framework/core/graphicalapplication.h b/src/framework/core/graphicalapplication.h index 20db2b7499..ab7f03c7b5 100644 --- a/src/framework/core/graphicalapplication.h +++ b/src/framework/core/graphicalapplication.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -24,10 +24,9 @@ #include "application.h" -#include #include #include -#include +#include #include class ApplicationDrawEvents @@ -48,13 +47,14 @@ class ApplicationDrawEvents class GraphicalApplicationContext : public ApplicationContext { public: - GraphicalApplicationContext(uint8_t spriteSize, ApplicationDrawEventsPtr drawEvents) : + GraphicalApplicationContext(const uint8_t spriteSize, ApplicationDrawEventsPtr drawEvents) : ApplicationContext(), m_spriteSize(spriteSize), - m_drawEvents(drawEvents) - {} + m_drawEvents(std::move(drawEvents)) + { + } - void setSpriteSize(uint8_t size) { m_spriteSize = size; } + void setSpriteSize(const uint8_t size) { m_spriteSize = size; } uint8_t getSpriteSize() { return m_spriteSize; } void setDrawEvents(ApplicationDrawEventsPtr drawEvents) { m_drawEvents = drawEvents; } @@ -65,7 +65,7 @@ class GraphicalApplicationContext : public ApplicationContext ApplicationDrawEventsPtr m_drawEvents; }; -class GraphicalApplication : public Application +class GraphicalApplication final : public Application { public: void init(std::vector& args, ApplicationContext* context) override; @@ -76,8 +76,8 @@ class GraphicalApplication : public Application void mainPoll(); void close() override; - void setMaxFps(uint16_t maxFps) { m_graphicFrameCounter.setMaxFps(maxFps); } - void setTargetFps(uint16_t targetFps) { m_graphicFrameCounter.setTargetFps(targetFps); } + void setMaxFps(const uint16_t maxFps) { m_graphicFrameCounter.setMaxFps(maxFps); } + void setTargetFps(const uint16_t targetFps) { m_graphicFrameCounter.setTargetFps(targetFps); } uint16_t getFps() { return m_graphicFrameCounter.getFps(); } uint8_t getMaxFps() { return m_graphicFrameCounter.getMaxFps(); } @@ -101,20 +101,20 @@ class GraphicalApplication : public Application void setDrawEffectOnTop(const bool draw) { m_drawEffectOnTop = draw; } bool isDrawingEffectsOnTop() { return m_drawEffectOnTop || mustOptimize(); } - void setDrawTexts(bool v) { m_drawText = v; } + void setDrawTexts(const bool v) { m_drawText = v; } bool isDrawingTexts() { return m_drawText; } float getHUDScale() const; void setHUDScale(float v); float getCreatureInformationScale() const { return m_creatureInformationScale; } - void setCreatureInformationScale(float v) { m_creatureInformationScale = v; } + void setCreatureInformationScale(const float v) { m_creatureInformationScale = v; } float getAnimatedTextScale() const { return m_animatedTextScale; } - void setAnimatedTextScale(float v) { m_animatedTextScale = v; } + void setAnimatedTextScale(const float v) { m_animatedTextScale = v; } float getStaticTextScale() const { return m_staticTextScale; } - void setStaticTextScale(float v) { m_staticTextScale = v; } + void setStaticTextScale(const float v) { m_staticTextScale = v; } bool isLoadingAsyncTexture(); void setLoadingAsyncTexture(bool v); @@ -131,6 +131,9 @@ class GraphicalApplication : public Application void setDrawEvents(const ApplicationDrawEventsPtr& drawEvents) { m_drawEvents = drawEvents; } void doScreenshot(std::string file); void doMapScreenshot(std::string file); +#ifdef __EMSCRIPTEN__ + void mainLoop(); +#endif protected: void resize(const Size& size); diff --git a/src/framework/core/inputevent.h b/src/framework/core/inputevent.h index 8cc4eeee0a..6c1e582b55 100644 --- a/src/framework/core/inputevent.h +++ b/src/framework/core/inputevent.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -32,7 +32,7 @@ struct InputEvent keyboardModifiers = 0; } - void reset(Fw::InputEventType eventType = Fw::NoInputEvent) + void reset(const Fw::InputEventType eventType = Fw::NoInputEvent) { type = eventType; wheelDirection = Fw::MouseNoWheel; diff --git a/src/framework/core/logger.cpp b/src/framework/core/logger.cpp index 7382870f62..2595ed7a6b 100644 --- a/src/framework/core/logger.cpp +++ b/src/framework/core/logger.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * 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/src/framework/core/logger.h b/src/framework/core/logger.h index 9906bda1f4..6edc8330dc 100644 --- a/src/framework/core/logger.h +++ b/src/framework/core/logger.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -25,11 +25,10 @@ #include "../global.h" #include -#include struct LogMessage { - LogMessage(Fw::LogLevel level, std::string_view message, std::size_t when) : level(level), message(message), when(when) {} + LogMessage(const Fw::LogLevel level, const std::string_view message, const std::size_t when) : level(level), message(message), when(when) {} Fw::LogLevel level; std::string message; std::size_t when; @@ -43,11 +42,11 @@ class Logger MAX_LOG_HISTORY = 1000 }; - using OnLogCallback = std::function; + using OnLogCallback = std::function; public: - void log(Fw::LogLevel level, const std::string_view message); - void logFunc(Fw::LogLevel level, const std::string_view message, const std::string_view prettyFunction); + void log(Fw::LogLevel level, std::string_view message); + void logFunc(Fw::LogLevel level, std::string_view message, std::string_view prettyFunction); void fine(const std::string_view what) { log(Fw::LogFine, what); } void debug(const std::string_view what) { log(Fw::LogDebug, what); } @@ -57,9 +56,9 @@ class Logger void fatal(const std::string_view what) { log(Fw::LogFatal, what); } void fireOldMessages(); - void setLogFile(const std::string_view file); + void setLogFile(std::string_view file); void setOnLog(const OnLogCallback& onLog) { m_onLog = onLog; } - void setLevel(Fw::LogLevel level) { m_level = level; } + void setLevel(const Fw::LogLevel level) { m_level = level; } Fw::LogLevel getLevel() { return m_level; } private: diff --git a/src/framework/core/module.cpp b/src/framework/core/module.cpp index 003f20c8f0..038cc30353 100644 --- a/src/framework/core/module.cpp +++ b/src/framework/core/module.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -37,7 +37,7 @@ bool Module::load() if (!m_supportedDevices.empty() && !hasSupportedDevice(g_platform.getDevice())) return true; - ticks_t startTime = stdext::millis(); + const ticks_t startTime = stdext::millis(); g_modules.m_currentModule = static_self_cast(); try { @@ -86,7 +86,7 @@ bool Module::load() m_loaded = true; - g_logger.debug(stdext::format("Loaded module '%s' (%s)", m_name, + g_logger.debug(stdext::format("Loaded module '%s' (%s)", m_name, stdext::format("%.2fs", (stdext::millis() - startTime) / 1000.0))); } catch (const stdext::exception& e) { // remove from package.loaded @@ -135,7 +135,7 @@ void Module::unload() if (m_sandboxed) g_lua.resetGlobalEnvironment(); - } catch (stdext::exception const& e) { + } catch (const stdext::exception& e) { if (m_sandboxed) g_lua.resetGlobalEnvironment(); g_logger.error(stdext::format("Unable to unload module '%s': %s", m_name, e.what())); @@ -173,9 +173,9 @@ bool Module::isDependent() const return false; } -bool Module::hasDependency(const std::string_view name, bool recursive) +bool Module::hasDependency(const std::string_view name, const bool recursive) { - if (std::find(m_dependencies.begin(), m_dependencies.end(), name) != m_dependencies.end()) + if (std::ranges::find(m_dependencies, name) != m_dependencies.end()) return true; if (recursive) { @@ -190,7 +190,7 @@ bool Module::hasDependency(const std::string_view name, bool recursive) return false; } -bool Module::hasSupportedDevice(Platform::Device device) +bool Module::hasSupportedDevice(const Platform::Device device) { for (const auto& sd : m_supportedDevices) { if (sd.type == device.type || sd.type == Platform::DeviceUnknown) { @@ -251,7 +251,7 @@ void Module::discover(const OTMLNodePtr& moduleNode) if (g_resources.isFileType(filePath, "lua")) { filePath = std::filesystem::path(filePath).replace_extension().string(); - auto foundElement = std::find(m_scripts.begin(), m_scripts.end(), filePath); + auto foundElement = std::ranges::find(m_scripts, filePath); if (m_scripts.end() == foundElement) m_scripts.emplace_back(filePath); } @@ -271,4 +271,4 @@ void Module::discover(const OTMLNodePtr& moduleNode) if (const auto& node = moduleNode->get("@onUnload")) m_onUnloadFunc = std::make_tuple(node->value(), "@" + node->source() + ":[" + node->tag() + "]"); -} +} \ No newline at end of file diff --git a/src/framework/core/module.h b/src/framework/core/module.h index 1a1837fc59..73019f3882 100644 --- a/src/framework/core/module.h +++ b/src/framework/core/module.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -28,10 +28,10 @@ #include // @bindclass -class Module : public LuaObject +class Module final : public LuaObject { public: - Module(const std::string_view name); + Module(std::string_view name); bool load(); void unload(); @@ -44,7 +44,7 @@ class Module : public LuaObject bool isReloadable() { return m_reloadable; } bool isDependent() const; bool isSandboxed() { return m_sandboxed; } - bool hasDependency(const std::string_view name, bool recursive = false); + bool hasDependency(std::string_view name, bool recursive = false); bool hasSupportedDevice(Platform::Device device); int getSandbox(LuaInterface* lua); diff --git a/src/framework/core/modulemanager.cpp b/src/framework/core/modulemanager.cpp index 2152585f39..e2558ad445 100644 --- a/src/framework/core/modulemanager.cpp +++ b/src/framework/core/modulemanager.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -24,10 +24,12 @@ #include "resourcemanager.h" #include -#include #include +#include #include +#include + ModuleManager g_modules; void ModuleManager::clear() @@ -55,7 +57,7 @@ void ModuleManager::discoverModules() } } -void ModuleManager::autoLoadModules(int maxPriority) +void ModuleManager::autoLoadModules(const int maxPriority) { for (const auto& [priority, module] : m_autoLoadModules) { if (priority > maxPriority) @@ -132,7 +134,7 @@ ModulePtr ModuleManager::getModule(const std::string_view moduleName) void ModuleManager::updateModuleLoadOrder(const ModulePtr& module) { - if (const auto it = std::find(m_modules.begin(), m_modules.end(), module); + if (const auto it = std::ranges::find(m_modules, module); it != m_modules.end()) m_modules.erase(it); if (module->isLoaded()) @@ -164,7 +166,7 @@ void ModuleManager::enableAutoReload() { if (!module->isReloadable()) continue; - ModuleData data = { module, {} }; + ModuleData data = { .ref = module, .files = {} }; bool hasFile = false; for (auto path : g_resources.listDirectoryFiles("/" + module->getName(), true, false, true)) { diff --git a/src/framework/core/modulemanager.h b/src/framework/core/modulemanager.h index 94a652f894..c5b4867a97 100644 --- a/src/framework/core/modulemanager.h +++ b/src/framework/core/modulemanager.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -33,11 +33,11 @@ class ModuleManager void discoverModules(); void autoLoadModules(int maxPriority); ModulePtr discoverModule(const std::string& moduleFile); - void ensureModuleLoaded(const std::string_view moduleName); + void ensureModuleLoaded(std::string_view moduleName); void unloadModules(); void reloadModules(); - ModulePtr getModule(const std::string_view moduleName); + ModulePtr getModule(std::string_view moduleName); std::deque getModules() { return m_modules; } ModulePtr getCurrentModule() { return m_currentModule; } void enableAutoReload(); diff --git a/src/framework/core/resourcemanager.cpp b/src/framework/core/resourcemanager.cpp index 4682ca0e29..9ddafbc8d7 100644 --- a/src/framework/core/resourcemanager.cpp +++ b/src/framework/core/resourcemanager.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -20,18 +20,20 @@ * THE SOFTWARE. */ +#include #include +#include -#include -#include "resourcemanager.h" #include "filestream.h" +#include "resourcemanager.h" +#include #include +#include #include -#include #include +#include #include -#include #include @@ -44,7 +46,7 @@ void ResourceManager::init(const char* argv0) #if defined(WIN32) char fileName[255]; - GetModuleFileNameA(NULL, fileName, sizeof(fileName)); + GetModuleFileNameA(nullptr, fileName, sizeof(fileName)); m_binaryPath = std::filesystem::absolute(fileName); #elif defined(ANDROID) // nothing @@ -122,7 +124,7 @@ bool ResourceManager::setWriteDir(const std::string& writeDir, bool) return true; } -bool ResourceManager::addSearchPath(const std::string& path, bool pushFront) +bool ResourceManager::addSearchPath(const std::string& path, const bool pushFront) { std::string savePath = path; if (!PHYSFS_mount(path.c_str(), nullptr, pushFront ? 0 : 1)) { @@ -152,7 +154,7 @@ bool ResourceManager::removeSearchPath(const std::string& path) { if (!PHYSFS_unmount(path.c_str())) return false; - const auto it = std::find(m_searchPaths.begin(), m_searchPaths.end(), path); + const auto it = std::ranges::find(m_searchPaths, path); assert(it != m_searchPaths.end()); m_searchPaths.erase(it); return true; @@ -161,9 +163,7 @@ bool ResourceManager::removeSearchPath(const std::string& path) void ResourceManager::searchAndAddPackages(const std::string& packagesDir, const std::string& packageExt) { auto files = listDirectoryFiles(packagesDir); - for (auto it = files.rbegin(); it != files.rend(); ++it) { - const auto& file = *it; - + for (auto& file : std::ranges::reverse_view(files)) { if (!file.ends_with(packageExt)) continue; std::string package = getRealDir(packagesDir) + "/" + file; @@ -210,7 +210,7 @@ std::string ResourceManager::readFileContents(const std::string& fileName) const std::string fullPath = resolvePath(fileName); if (fullPath.find(g_resources.getByteStrings(0)) != std::string::npos) { - auto dfile = g_http.getFile(fullPath.substr(10)); + const auto dfile = g_http.getFile(fullPath.substr(10)); if (dfile) return std::string(dfile->response.begin(), dfile->response.end()); } @@ -224,13 +224,13 @@ std::string ResourceManager::readFileContents(const std::string& fileName) PHYSFS_readBytes(file, &buffer[0], fileSize); PHYSFS_close(file); +#if ENABLE_ENCRYPTION == 1 bool hasHeader = false; - if (buffer.size() >= std::string(ENCRYPTION_HEADER).size() && + if (buffer.size() >= std::string(ENCRYPTION_HEADER).size() && buffer.substr(0, std::string(ENCRYPTION_HEADER).size()) == std::string(ENCRYPTION_HEADER)) { hasHeader = true; } -#if ENABLE_ENCRYPTION == 1 if (g_game.getFeature(Otc::GameAllowCustomBotScripts)) { if (fullPath.find(g_resources.getByteStrings(1)) != std::string::npos && !hasHeader) { return buffer; @@ -246,7 +246,7 @@ std::string ResourceManager::readFileContents(const std::string& fileName) return buffer; } -bool ResourceManager::writeFileBuffer(const std::string& fileName, const uint8_t* data, uint32_t size, bool createDirectory) +bool ResourceManager::writeFileBuffer(const std::string& fileName, const uint8_t* data, const uint32_t size, const bool createDirectory) { if (createDirectory) { const auto& path = std::filesystem::path(fileName); @@ -331,7 +331,7 @@ bool ResourceManager::makeDir(const std::string& directory) return PHYSFS_mkdir(directory.c_str()); } -std::list ResourceManager::listDirectoryFiles(const std::string& directoryPath, bool fullPath /* = false */, bool raw /*= false*/, bool recursive) +std::list ResourceManager::listDirectoryFiles(const std::string& directoryPath, const bool fullPath /* = false */, const bool raw /*= false*/, const bool recursive) { std::list files; const auto path = raw ? directoryPath : resolvePath(directoryPath); @@ -362,7 +362,7 @@ std::list ResourceManager::listDirectoryFiles(const std::string& di return files; } -std::vector ResourceManager::getDirectoryFiles(const std::string& path, bool filenameOnly, bool recursive) +std::vector ResourceManager::getDirectoryFiles(const std::string& path, const bool filenameOnly, const bool recursive) { if (!std::filesystem::exists(path)) return {}; @@ -371,7 +371,7 @@ std::vector ResourceManager::getDirectoryFiles(const std::string& p return discoverPath(p, filenameOnly, recursive); } -std::vector ResourceManager::discoverPath(const std::filesystem::path& path, bool filenameOnly, bool recursive) +std::vector ResourceManager::discoverPath(const std::filesystem::path& path, const bool filenameOnly, const bool recursive) { std::vector files; @@ -439,6 +439,8 @@ std::string ResourceManager::getUserDir() { #ifdef ANDROID return getBaseDir() + "/"; +#elif defined(__EMSCRIPTEN__) + return "/user/"; #else static const char* orgName = g_app.getOrganizationName().data(); static const char* appName = g_app.getCompactName().data(); @@ -520,7 +522,7 @@ std::string ResourceManager::decrypt(const std::string& data) return ss.str(); } -uint8_t* ResourceManager::decrypt(uint8_t* data, int32_t size) +uint8_t* ResourceManager::decrypt(uint8_t* data, const int32_t size) { const auto& password = std::string(ENCRYPTION_PASSWORD); const int plen = password.length(); @@ -550,7 +552,7 @@ void ResourceManager::runEncryption(const std::string& password) std::vector excludedExtensions = { ".rar",".ogg",".xml",".dll",".exe", ".log",".otb" }; for (const auto& entry : std::filesystem::recursive_directory_iterator("./")) { if (std::string ext = entry.path().extension().string(); - std::find(excludedExtensions.begin(), excludedExtensions.end(), ext) != excludedExtensions.end()) + std::ranges::find(excludedExtensions, ext) != excludedExtensions.end()) continue; std::ifstream ifs(entry.path().string(), std::ios_base::binary); @@ -573,7 +575,7 @@ void ResourceManager::save_string_into_file(const std::string& contents, const s std::string ResourceManager::fileChecksum(const std::string& path) { static stdext::map cache; - auto it = cache.find(path); + const auto it = cache.find(path); if (it != cache.end()) return it->second; @@ -581,9 +583,9 @@ std::string ResourceManager::fileChecksum(const std::string& path) { if (!file) return ""; - int fileSize = PHYSFS_fileLength(file); + const int fileSize = PHYSFS_fileLength(file); std::string buffer(fileSize, 0); - PHYSFS_readBytes(file, (void*)&buffer[0], fileSize); + PHYSFS_readBytes(file, &buffer[0], fileSize); PHYSFS_close(file); auto checksum = g_crypt.crc32(buffer, false); @@ -596,18 +598,17 @@ std::unordered_map ResourceManager::filesChecksums() { std::unordered_map ret; auto files = listDirectoryFiles("/", true, false, true); - for (auto it = files.rbegin(); it != files.rend(); ++it) { - const auto& filePath = *it; + for (auto& filePath : std::ranges::reverse_view(files)) { PHYSFS_File* file = PHYSFS_openRead(filePath.c_str()); if (!file) continue; - int fileSize = PHYSFS_fileLength(file); + const int fileSize = PHYSFS_fileLength(file); std::string buffer(fileSize, 0); - PHYSFS_readBytes(file, (void*)&buffer[0], fileSize); + PHYSFS_readBytes(file, &buffer[0], fileSize); PHYSFS_close(file); - auto checksum = g_crypt.crc32(buffer, false); + const auto checksum = g_crypt.crc32(buffer, false); ret[filePath] = checksum; } @@ -673,14 +674,14 @@ void ResourceManager::updateExecutable(std::string fileName) if (fileName[0] == '/') fileName = fileName.substr(1); - auto dFile = g_http.getFile(fileName); + const auto dFile = g_http.getFile(fileName); if (!dFile) g_logger.fatal(stdext::format("Cannot find executable: %s in downloads", fileName)); const auto& oldWriteDir = getWriteDir(); setWriteDir(getWorkDir()); - std::filesystem::path path(m_binaryPath); - auto newBinary = path.stem().string() + "-" + std::to_string(time(nullptr)) + path.extension().string(); + const std::filesystem::path path(m_binaryPath); + const auto newBinary = path.stem().string() + "-" + std::to_string(time(nullptr)) + path.extension().string(); g_logger.info(stdext::format("Updating binary file: %s", newBinary)); PHYSFS_file* file = PHYSFS_openWrite(newBinary.c_str()); if (!file) @@ -693,7 +694,7 @@ void ResourceManager::updateExecutable(std::string fileName) #endif } -bool ResourceManager::launchCorrect(std::vector& args) { // curently works only on windows +bool ResourceManager::launchCorrect(const std::vector& args) { // curently works only on windows #if (defined(ANDROID) || defined(FREE_VERSION)) return false; #else @@ -701,12 +702,12 @@ bool ResourceManager::launchCorrect(std::vector& args) { // curentl fileName2 = stdext::split(fileName2, "-")[0]; stdext::tolower(fileName2); - std::filesystem::path path(m_binaryPath.parent_path()); + const std::filesystem::path path(m_binaryPath.parent_path()); std::error_code ec; - auto lastWrite = std::filesystem::last_write_time(m_binaryPath, ec); + auto lastWrite = last_write_time(m_binaryPath, ec); std::filesystem::path binary = m_binaryPath; for (auto& entry : std::filesystem::directory_iterator(path)) { - if (std::filesystem::is_directory(entry.path())) + if (is_directory(entry.path())) continue; auto fileName1 = entry.path().stem().string(); @@ -717,7 +718,7 @@ bool ResourceManager::launchCorrect(std::vector& args) { // curentl if (entry.path().extension() == m_binaryPath.extension()) { std::error_code _ec; - auto writeTime = std::filesystem::last_write_time(entry.path(), _ec); + auto writeTime = last_write_time(entry.path(), _ec); if (!_ec && writeTime > lastWrite) { lastWrite = writeTime; binary = entry.path(); @@ -726,7 +727,7 @@ bool ResourceManager::launchCorrect(std::vector& args) { // curentl } for (auto& entry : std::filesystem::directory_iterator(path)) { // remove old - if (std::filesystem::is_directory(entry.path())) + if (is_directory(entry.path())) continue; auto fileName1 = entry.path().stem().string(); @@ -761,23 +762,22 @@ std::unordered_map ResourceManager::decompressArchive( std::string ResourceManager::decodificateStrings(const std::vector& bytes) { std::string result; - for (unsigned char c : bytes) { + for (const unsigned char c : bytes) { result.push_back(c ^ 0xAA); } return result; } // used to obfuscate vulnerable strings (provisional) -std::string ResourceManager::getByteStrings(size_t line) { - std::vector> strTable = { +std::string ResourceManager::getByteStrings(const size_t line) { + const std::vector> strTable = { {0x85, 0xCE, 0xC5, 0xDD, 0xC4, 0xC6, 0xC5, 0xCB, 0xCE, 0xD9}, // "/downloads" {0x85, 0xC8, 0xC5, 0xDE, 0x85}, // "/bot/" {0xE6, 0xC3, 0xC4, 0xC2, 0xCB, 0x8A, 0xCE, 0xCF, 0x8A, 0xD8, 0xCF, 0xDE, 0xC5, 0xD8, 0xC4, 0xC5, 0x8A, 0xC3, 0xC4, 0xDC, 0xCB, 0xC6, 0xC3, 0xCE, 0xCB}, // "Linha de retorno invalida" }; - + if (line < strTable.size()) { return decodificateStrings(strTable[line]); - } else { - return decodificateStrings(strTable[2]); } -} + return decodificateStrings(strTable[2]); +} \ No newline at end of file diff --git a/src/framework/core/resourcemanager.h b/src/framework/core/resourcemanager.h index 03a3e606d5..ec5f0a22c2 100644 --- a/src/framework/core/resourcemanager.h +++ b/src/framework/core/resourcemanager.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -22,9 +22,9 @@ #pragma once +#include "declarations.h" #include #include -#include "declarations.h" // @bindsingleton g_resources class ResourceManager @@ -90,7 +90,7 @@ class ResourceManager std::string selfChecksum(); void updateFiles(const std::set& files); void updateExecutable(std::string fileName); - bool launchCorrect(std::vector& args); + bool launchCorrect(const std::vector& args); std::string createArchive(const std::unordered_map& files); std::unordered_map decompressArchive(std::string dataOrPath); std::string decodificateStrings(const std::vector& bytes); diff --git a/src/framework/core/scheduledevent.cpp b/src/framework/core/scheduledevent.cpp index ef3ea44296..10b8fcb708 100644 --- a/src/framework/core/scheduledevent.cpp +++ b/src/framework/core/scheduledevent.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -22,7 +22,7 @@ #include "scheduledevent.h" -ScheduledEvent::ScheduledEvent(const std::function& callback, int delay, int maxCycles) : Event(callback), +ScheduledEvent::ScheduledEvent(const std::function& callback, const int delay, const int maxCycles) : Event(callback), m_ticks(g_clock.millis() + delay), m_delay(delay), m_maxCycles(maxCycles) {} void ScheduledEvent::execute() diff --git a/src/framework/core/scheduledevent.h b/src/framework/core/scheduledevent.h index 03e0c96b42..b90286466a 100644 --- a/src/framework/core/scheduledevent.h +++ b/src/framework/core/scheduledevent.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -26,7 +26,7 @@ #include "event.h" // @bindclass -class ScheduledEvent : public Event +class ScheduledEvent final : public Event { public: ScheduledEvent(const std::function& callback, int delay, int maxCycles = 0); diff --git a/src/framework/core/timer.cpp b/src/framework/core/timer.cpp index 677b881e98..19c245a5e2 100644 --- a/src/framework/core/timer.cpp +++ b/src/framework/core/timer.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -23,9 +23,9 @@ #include "timer.h" #include "clock.h" -void Timer::restart() +void Timer::restart(const int shift) { - m_startTicks = g_clock.millis(); + m_startTicks = g_clock.millis() - shift; m_stopped = false; } diff --git a/src/framework/core/timer.h b/src/framework/core/timer.h index 30c7e76a06..7dc2bd459b 100644 --- a/src/framework/core/timer.h +++ b/src/framework/core/timer.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -29,7 +29,7 @@ class Timer public: Timer() { restart(); } - void restart(); + void restart(const int shift = 0); void stop() { m_stopped = true; } void update(const ticks_t tick) { m_startTicks += tick; } diff --git a/src/framework/discord/discord.cpp b/src/framework/discord/discord.cpp index db94a2df26..7bdc1510c5 100644 --- a/src/framework/discord/discord.cpp +++ b/src/framework/discord/discord.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -23,46 +23,46 @@ #include "discord.h" #ifndef ANDROID - #if ENABLE_DISCORD_RPC == 1 - #include - #include - - const static int64_t EP_TIME = std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(); - - Discord g_discord; - - void Discord::init(std::function& canUpdate, std::function& onUpdate) - { - m_canUpdate = canUpdate; - m_onUpdate = onUpdate; - DiscordEventHandlers Handle; - memset(&Handle, 0, sizeof(Handle)); - Discord_Initialize(RPC_API_KEY, &Handle, 1, NULL); - update(); - } - - void Discord::update() - { - std::string info; - if (m_canUpdate()) { - m_onUpdate(info); - } else { - info = std::string{ OFFLINE_RPC_TEXT }; - } - - if (info.empty()) - info = "Adjust in config.h"; - - DiscordRichPresence discordPresence; - memset(&discordPresence, 0, sizeof(discordPresence)); - discordPresence.state = STATE_RPC_TEXT; - discordPresence.details = info.c_str(); - discordPresence.startTimestamp = EP_TIME; - discordPresence.endTimestamp = 0; - discordPresence.largeImageKey = RPC_LARGE_IMAGE; - discordPresence.largeImageText = RPC_LARGE_TEXT; - Discord_UpdatePresence(&discordPresence); - g_dispatcher.scheduleEvent([this] { update(); }, 30000); - } - #endif +#if ENABLE_DISCORD_RPC == 1 +#include +#include + +const static int64_t EP_TIME = std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(); + +Discord g_discord; + +void Discord::init(std::function& canUpdate, std::function& onUpdate) +{ + m_canUpdate = canUpdate; + m_onUpdate = onUpdate; + DiscordEventHandlers Handle; + memset(&Handle, 0, sizeof(Handle)); + Discord_Initialize(RPC_API_KEY, &Handle, 1, NULL); + update(); +} + +void Discord::update() +{ + std::string info; + if (m_canUpdate()) { + m_onUpdate(info); + } else { + info = std::string{ OFFLINE_RPC_TEXT }; + } + + if (info.empty()) + info = "Adjust in config.h"; + + DiscordRichPresence discordPresence; + memset(&discordPresence, 0, sizeof(discordPresence)); + discordPresence.state = STATE_RPC_TEXT; + discordPresence.details = info.c_str(); + discordPresence.startTimestamp = EP_TIME; + discordPresence.endTimestamp = 0; + discordPresence.largeImageKey = RPC_LARGE_IMAGE; + discordPresence.largeImageText = RPC_LARGE_TEXT; + Discord_UpdatePresence(&discordPresence); + g_dispatcher.scheduleEvent([this] { update(); }, 30000); +} #endif +#endif \ No newline at end of file diff --git a/src/framework/discord/discord.h b/src/framework/discord/discord.h index fb92070051..8d0fe85c63 100644 --- a/src/framework/discord/discord.h +++ b/src/framework/discord/discord.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -27,22 +27,22 @@ #include #ifndef ANDROID - #if ENABLE_DISCORD_RPC == 1 - #include - #include - - class Discord - { - public: - void init(std::function& canUpdate, std::function& onUpdate); - - private: - void update(); +#if ENABLE_DISCORD_RPC == 1 +#include +#include - std::function m_canUpdate; - std::function m_onUpdate; - }; - - extern Discord g_discord; - #endif +class Discord +{ +public: + void init(std::function& canUpdate, std::function& onUpdate); + +private: + void update(); + + std::function m_canUpdate; + std::function m_onUpdate; +}; + +extern Discord g_discord; +#endif #endif diff --git a/src/framework/global.h b/src/framework/global.h index ee5eca143c..dff8311b4e 100644 --- a/src/framework/global.h +++ b/src/framework/global.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * 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/src/framework/graphics/animatedtexture.cpp b/src/framework/graphics/animatedtexture.cpp index 3b763b21e9..d778c08319 100644 --- a/src/framework/graphics/animatedtexture.cpp +++ b/src/framework/graphics/animatedtexture.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -28,7 +28,7 @@ #include -AnimatedTexture::AnimatedTexture(const Size& size, const std::vector& frames, std::vector framesDelay, uint16_t numPlays, bool buildMipmaps, bool compress) +AnimatedTexture::AnimatedTexture(const Size& size, const std::vector& frames, std::vector framesDelay, const uint16_t numPlays, bool buildMipmaps, bool compress) { if (!setupSize(size)) return; @@ -37,7 +37,7 @@ AnimatedTexture::AnimatedTexture(const Size& size, const std::vector& m_frames.emplace_back(std::make_shared(frame, buildMipmaps, compress)); } - setProp(Prop::hasMipMaps, buildMipmaps); + setProp(hasMipMaps, buildMipmaps); m_framesDelay = std::move(framesDelay); m_numPlays = numPlays; @@ -46,8 +46,8 @@ AnimatedTexture::AnimatedTexture(const Size& size, const std::vector& void AnimatedTexture::buildHardwareMipmaps() { - if (getProp(Prop::hasMipMaps)) return; - setProp(Prop::hasMipMaps, true); + if (getProp(hasMipMaps)) return; + setProp(hasMipMaps, true); g_mainDispatcher.addEvent([this] { for (const auto& frame : m_frames) diff --git a/src/framework/graphics/animatedtexture.h b/src/framework/graphics/animatedtexture.h index f9447702f3..52f3a1065d 100644 --- a/src/framework/graphics/animatedtexture.h +++ b/src/framework/graphics/animatedtexture.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -22,10 +22,10 @@ #pragma once -#include #include "texture.h" +#include -class AnimatedTexture : public Texture +class AnimatedTexture final : public Texture { public: AnimatedTexture(const Size& size, const std::vector& frames, std::vector framesDelay, uint16_t numPlays, bool buildMipmaps = false, bool compress = false); @@ -41,10 +41,10 @@ class AnimatedTexture : public Texture void setRepeat(bool repeat) override; uint32_t getNumPlays() const { return m_numPlays; } - void setNumPlays(uint32_t n) { m_numPlays = n; } + void setNumPlays(const uint32_t n) { m_numPlays = n; } bool isOnMap() const { return m_onMap; } - void setOnMap(bool v) { m_onMap = v; } + void setOnMap(const bool v) { m_onMap = v; } void update(); void restart() { m_animTimer.restart(); m_currentPlay = 0; m_currentFrame = 0; } diff --git a/src/framework/graphics/apngloader.cpp b/src/framework/graphics/apngloader.cpp index 24adadf5e0..e18feef8e9 100644 --- a/src/framework/graphics/apngloader.cpp +++ b/src/framework/graphics/apngloader.cpp @@ -99,25 +99,25 @@ uint16_t read16(std::istream& f1) return (static_cast(a) << 8) + static_cast(b); } -uint16_t readshort(uint8_t* p) +uint16_t readshort(const uint8_t* p) { return (static_cast(*p) << 8) + static_cast(*(p + 1)); } -void read_sub_row(uint8_t* row, uint32_t rowbytes, uint32_t bpp) +void read_sub_row(uint8_t* row, const uint32_t rowbytes, const uint32_t bpp) { for (uint32_t i = bpp; i < rowbytes; i++) row[i] += row[i - bpp]; } -void read_up_row(uint8_t* row, uint8_t* prev_row, uint32_t rowbytes, uint32_t) +void read_up_row(uint8_t* row, const uint8_t* prev_row, const uint32_t rowbytes, uint32_t) { if (prev_row) for (uint32_t i = 0; i < rowbytes; i++) row[i] += prev_row[i]; } -void read_average_row(uint8_t* row, uint8_t* prev_row, uint32_t rowbytes, uint32_t bpp) +void read_average_row(uint8_t* row, const uint8_t* prev_row, const uint32_t rowbytes, const uint32_t bpp) { uint32_t i; @@ -132,7 +132,7 @@ void read_average_row(uint8_t* row, uint8_t* prev_row, uint32_t rowbytes, uint32 } } -void read_paeth_row(uint8_t* row, uint8_t* prev_row, uint32_t rowbytes, uint32_t bpp) +void read_paeth_row(uint8_t* row, const uint8_t* prev_row, const uint32_t rowbytes, const uint32_t bpp) { uint32_t i; @@ -156,7 +156,7 @@ void read_paeth_row(uint8_t* row, uint8_t* prev_row, uint32_t rowbytes, uint32_t } } -void unpack(z_stream& zstream, uint8_t* dst, uint32_t dst_size, uint8_t* src, uint32_t src_size, uint32_t h, uint32_t rowbytes, uint8_t bpp) +void unpack(z_stream& zstream, uint8_t* dst, const uint32_t dst_size, uint8_t* src, const uint32_t src_size, const uint32_t h, const uint32_t rowbytes, const uint8_t bpp) { uint8_t* row = dst; uint8_t* prev_row = nullptr; @@ -181,7 +181,7 @@ void unpack(z_stream& zstream, uint8_t* dst, uint32_t dst_size, uint8_t* src, ui } } -void compose0(uint8_t* dst1, uint32_t dstbytes1, uint8_t* dst2, uint32_t dstbytes2, uint8_t* src, uint32_t srcbytes, uint32_t w, uint32_t h, uint32_t bop, uint8_t depth) +void compose0(uint8_t* dst1, const uint32_t dstbytes1, uint8_t* dst2, const uint32_t dstbytes2, uint8_t* src, const uint32_t srcbytes, const uint32_t w, const uint32_t h, const uint32_t bop, const uint8_t depth) { uint32_t i, g, a; @@ -215,7 +215,7 @@ void compose0(uint8_t* dst1, uint32_t dstbytes1, uint8_t* dst2, uint32_t dstbyte } } -void compose2(uint8_t* dst1, uint32_t dstbytes1, uint8_t* dst2, uint32_t dstbytes2, uint8_t* src, uint32_t srcbytes, uint32_t w, uint32_t h, uint32_t bop, uint8_t depth) +void compose2(uint8_t* dst1, const uint32_t dstbytes1, uint8_t* dst2, const uint32_t dstbytes2, uint8_t* src, const uint32_t srcbytes, const uint32_t w, const uint32_t h, const uint32_t bop, const uint8_t depth) { uint32_t i; uint32_t r, g, b, a; @@ -271,7 +271,7 @@ void compose2(uint8_t* dst1, uint32_t dstbytes1, uint8_t* dst2, uint32_t dstbyte } } -void compose3(uint8_t* dst1, uint32_t dstbytes1, uint8_t* dst2, uint32_t dstbytes2, uint8_t* src, uint32_t srcbytes, uint32_t w, uint32_t h, uint32_t bop, uint8_t depth) +void compose3(uint8_t* dst1, const uint32_t dstbytes1, uint8_t* dst2, const uint32_t dstbytes2, const uint8_t* src, const uint32_t srcbytes, const uint32_t w, const uint32_t h, const uint32_t bop, const uint8_t depth) { uint32_t a2; uint8_t col = 0; @@ -331,7 +331,7 @@ void compose3(uint8_t* dst1, uint32_t dstbytes1, uint8_t* dst2, uint32_t dstbyte } } -void compose4(uint8_t* dst, uint32_t dstbytes, uint8_t* src, uint32_t srcbytes, uint32_t w, uint32_t h, uint32_t bop, uint8_t depth) +void compose4(uint8_t* dst, const uint32_t dstbytes, uint8_t* src, const uint32_t srcbytes, const uint32_t w, const uint32_t h, const uint32_t bop, const uint8_t depth) { uint32_t i; uint32_t g, a, a2; @@ -339,7 +339,7 @@ void compose4(uint8_t* dst, uint32_t dstbytes, uint8_t* src, uint32_t srcbytes, const uint32_t step = (depth + 7) / 8; for (uint32_t j = 0; j < h; j++) { - uint8_t* sp = src + 1; + const uint8_t* sp = src + 1; uint8_t* dp = dst; if (bop == PNG_BLEND_OP_SOURCE) { @@ -378,7 +378,7 @@ void compose4(uint8_t* dst, uint32_t dstbytes, uint8_t* src, uint32_t srcbytes, } } -void compose6(uint8_t* dst, uint32_t dstbytes, uint8_t* src, uint32_t srcbytes, uint32_t w, uint32_t h, uint32_t bop, uint8_t depth) +void compose6(uint8_t* dst, const uint32_t dstbytes, uint8_t* src, const uint32_t srcbytes, const uint32_t w, const uint32_t h, const uint32_t bop, const uint8_t depth) { uint32_t i; uint32_t r, g, b, a; @@ -387,7 +387,7 @@ void compose6(uint8_t* dst, uint32_t dstbytes, uint8_t* src, uint32_t srcbytes, const uint32_t step = (depth + 7) / 8; for (uint32_t j = 0; j < h; j++) { - uint8_t* sp = src + 1; + const uint8_t* sp = src + 1; auto* dp = (uint32_t*)dst; if (bop == PNG_BLEND_OP_SOURCE) { @@ -755,7 +755,7 @@ int load_apng(std::stringstream& file, apng_data* apng) return 0; } -void write_chunk(std::ostream& f, const char* name, uint8_t* data, uint32_t length) +void write_chunk(std::ostream& f, const char* name, uint8_t* data, const uint32_t length) { uint32_t crc = crc32(0, nullptr, 0); uint32_t len = swap32(length); @@ -773,7 +773,7 @@ void write_chunk(std::ostream& f, const char* name, uint8_t* data, uint32_t leng f.write((char*)&crc, 4); } -void write_IDATs(std::ostream& f, uint8_t* data, uint32_t length, uint32_t idat_size) +void write_IDATs(std::ostream& f, uint8_t* data, uint32_t length, const uint32_t idat_size) { uint32_t z_cmf = data[0]; @@ -831,9 +831,11 @@ void save_png(std::stringstream& f, uint32_t width, uint32_t height, int channel uint8_t mCompression; uint8_t mFilterMethod; uint8_t mInterlaceMethod; - } ihdr = { swap32(width), swap32(height), 8, coltype, 0, 0, 0 }; + } ihdr = { .mWidth = swap32(width), .mHeight = swap32(height), .mDepth = 8, .mColorType = coltype, .mCompression = 0, + .mFilterMethod = 0, .mInterlaceMethod = 0 + }; - z_stream zstream1; + z_stream zstream1; z_stream zstream2; uint32_t i, j; @@ -1038,7 +1040,7 @@ void save_png(std::stringstream& f, uint32_t width, uint32_t height, int channel free(paeth_row); } -void free_apng(apng_data* apng) +void free_apng(const apng_data* apng) { if (apng->pdata) free(apng->pdata); diff --git a/src/framework/graphics/apngloader.h b/src/framework/graphics/apngloader.h index f00aa0deac..b9c70342bb 100644 --- a/src/framework/graphics/apngloader.h +++ b/src/framework/graphics/apngloader.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -41,4 +41,4 @@ struct apng_data // returns -1 on error, 0 on success int load_apng(std::stringstream& file, apng_data* apng); void save_png(std::stringstream& file, uint32_t width, uint32_t height, int channels, uint8_t* pixels); -void free_apng(apng_data* apng); +void free_apng(const apng_data* apng); diff --git a/src/framework/graphics/bitmapfont.cpp b/src/framework/graphics/bitmapfont.cpp index e17be44ab9..379ecb4b46 100644 --- a/src/framework/graphics/bitmapfont.cpp +++ b/src/framework/graphics/bitmapfont.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -94,7 +94,7 @@ void BitmapFont::drawText(const std::string_view text, const Point& startPos, co drawText(text, screenCoords, color, Fw::AlignTopLeft); } -void BitmapFont::drawText(const std::string_view text, const Rect& screenCoords, const Color& color, Fw::AlignmentFlag align) +void BitmapFont::drawText(const std::string_view text, const Rect& screenCoords, const Color& color, const Fw::AlignmentFlag align) { Size textBoxSize; const auto& glyphsPositions = calculateGlyphsPositions(text, align, &textBoxSize); @@ -103,7 +103,7 @@ void BitmapFont::drawText(const std::string_view text, const Rect& screenCoords, } } -std::vector> BitmapFont::getDrawTextCoords(const std::string_view text, const Size& textBoxSize, Fw::AlignmentFlag align, const Rect& screenCoords, const std::vector& glyphsPositions) const +std::vector> BitmapFont::getDrawTextCoords(const std::string_view text, const Size& textBoxSize, const Fw::AlignmentFlag align, const Rect& screenCoords, const std::vector& glyphsPositions) const { std::vector> list; // prevent glitches from invalid rects @@ -179,7 +179,7 @@ std::vector> BitmapFont::getDrawTextCoords(const std::stri } void BitmapFont::fillTextCoords(const CoordsBufferPtr& coords, const std::string_view text, - const Size& textBoxSize, Fw::AlignmentFlag align, const Rect& screenCoords, + const Size& textBoxSize, const Fw::AlignmentFlag align, const Rect& screenCoords, const std::vector& glyphsPositions) const { coords->clear(); @@ -256,7 +256,7 @@ void BitmapFont::fillTextCoords(const CoordsBufferPtr& coords, const std::string void BitmapFont::fillTextColorCoords(std::vector>& colorCoords, const std::string_view text, const std::vector> textColors, - const Size& textBoxSize, Fw::AlignmentFlag align, + const Size& textBoxSize, const Fw::AlignmentFlag align, const Rect& screenCoords, const std::vector& glyphsPositions) const { colorCoords.clear(); @@ -285,7 +285,7 @@ void BitmapFont::fillTextColorCoords(std::vector())); } @@ -359,7 +359,7 @@ void BitmapFont::fillTextColorCoords(std::vector& BitmapFont::calculateGlyphsPositions(const std::string_view text, Fw::AlignmentFlag align, Size* textBoxSize) const +const std::vector& BitmapFont::calculateGlyphsPositions(const std::string_view text, const Fw::AlignmentFlag align, Size* textBoxSize) const { const int textLength = text.length(); int maxLineWidth = 0; @@ -476,7 +476,7 @@ void BitmapFont::calculateGlyphsWidthsAutomatically(const ImagePtr& image, const } } -std::string BitmapFont::wrapText(const std::string_view text, int maxWidth, std::vector>* colors) +std::string BitmapFont::wrapText(const std::string_view text, const int maxWidth, std::vector>* colors) { if (text.empty()) return ""; @@ -538,7 +538,7 @@ std::string BitmapFont::wrapText(const std::string_view text, int maxWidth, std: return outText; } -void BitmapFont::updateColors(std::vector>* colors, int pos, int newTextLen) +void BitmapFont::updateColors(std::vector>* colors, const int pos, const int newTextLen) { if (!colors) return; for (auto& it : *colors) { diff --git a/src/framework/graphics/bitmapfont.h b/src/framework/graphics/bitmapfont.h index 32231f6fc4..7a02fd153c 100644 --- a/src/framework/graphics/bitmapfont.h +++ b/src/framework/graphics/bitmapfont.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -31,42 +31,41 @@ class BitmapFont { public: - BitmapFont(std::string_view name) : m_name(name) {} + BitmapFont(const std::string_view name) : m_name(name) {} /// Load font from otml node void load(const OTMLNodePtr& fontNode); /// Simple text render starting at startPos - void drawText(const std::string_view text, const Point& startPos, const Color& color = Color::white); + void drawText(std::string_view text, const Point& startPos, const Color& color = Color::white); /// Advanced text render delimited by a screen region and alignment - void drawText(const std::string_view text, const Rect& screenCoords, const Color& color = Color::white, Fw::AlignmentFlag align = Fw::AlignTopLeft); + void drawText(std::string_view text, const Rect& screenCoords, const Color& color = Color::white, Fw::AlignmentFlag align = Fw::AlignTopLeft); - std::vector> getDrawTextCoords(const std::string_view text, - const Size& textBoxSize, - Fw::AlignmentFlag align, - const Rect& screenCoords, - const std::vector& glyphsPositions) const; + std::vector> getDrawTextCoords(std::string_view text, + const Size& textBoxSize, + Fw::AlignmentFlag align, + const Rect& screenCoords, + const std::vector& glyphsPositions) const; - void fillTextCoords(const CoordsBufferPtr& coords, const std::string_view text, + void fillTextCoords(const CoordsBufferPtr& coords, std::string_view text, const Size& textBoxSize, Fw::AlignmentFlag align, const Rect& screenCoords, const std::vector& glyphsPositions) const; - void fillTextColorCoords(std::vector>& colorCoords, const std::string_view text, - const std::vector> textColors, + void fillTextColorCoords(std::vector>& colorCoords, std::string_view text, + std::vector> textColors, const Size& textBoxSize, Fw::AlignmentFlag align, const Rect& screenCoords, const std::vector& glyphsPositions) const; - /// Calculate glyphs positions to use on render, also calculates textBoxSize if wanted - const std::vector& calculateGlyphsPositions(const std::string_view text, + const std::vector& calculateGlyphsPositions(std::string_view text, Fw::AlignmentFlag align, Size* textBoxSize = nullptr) const; /// Simulate render and calculate text size - Size calculateTextRectSize(const std::string_view text); + Size calculateTextRectSize(std::string_view text); - std::string wrapText(const std::string_view text, int maxWidth, std::vector>* colors = nullptr); + std::string wrapText(std::string_view text, int maxWidth, std::vector>* colors = nullptr); const std::string& getName() { return m_name; } int getGlyphHeight() const { return m_glyphHeight; } diff --git a/src/framework/graphics/cachedtext.cpp b/src/framework/graphics/cachedtext.cpp index 38e516bd43..997dafe1c9 100644 --- a/src/framework/graphics/cachedtext.cpp +++ b/src/framework/graphics/cachedtext.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,8 +21,8 @@ */ #include "cachedtext.h" -#include #include "fontmanager.h" +#include CachedText::CachedText() : m_align(Fw::AlignCenter), m_coordsBuffer(std::make_shared()) {} @@ -48,7 +48,7 @@ void CachedText::update() m_textScreenCoords = {}; } -void CachedText::wrapText(int maxWidth) +void CachedText::wrapText(const int maxWidth) { if (!m_font) return; diff --git a/src/framework/graphics/cachedtext.h b/src/framework/graphics/cachedtext.h index 9f79034b8e..5c64fb5f20 100644 --- a/src/framework/graphics/cachedtext.h +++ b/src/framework/graphics/cachedtext.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -33,8 +33,8 @@ class CachedText void wrapText(int maxWidth); void setFont(const BitmapFontPtr& font); - void setText(const std::string_view text); - void setAlign(const Fw::AlignmentFlag align); + void setText(std::string_view text); + void setAlign(Fw::AlignmentFlag align); Size getTextSize() const { return m_textSize; } std::string getText() const { return m_text; } diff --git a/src/framework/graphics/coordsbuffer.cpp b/src/framework/graphics/coordsbuffer.cpp index f72d420acb..b0b0766799 100644 --- a/src/framework/graphics/coordsbuffer.cpp +++ b/src/framework/graphics/coordsbuffer.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -23,7 +23,7 @@ #include "coordsbuffer.h" #include "graphics.h" -void CoordsBuffer::addBoudingRect(const Rect& dest, int innerLineWidth) +void CoordsBuffer::addBoudingRect(const Rect& dest, const int innerLineWidth) { const int left = dest.left(); const int right = dest.right(); diff --git a/src/framework/graphics/coordsbuffer.h b/src/framework/graphics/coordsbuffer.h index 3d127a319a..f9dc89d168 100644 --- a/src/framework/graphics/coordsbuffer.h +++ b/src/framework/graphics/coordsbuffer.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * 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/src/framework/graphics/declarations.h b/src/framework/graphics/declarations.h index 1d88ad06a5..21f2b457e6 100644 --- a/src/framework/graphics/declarations.h +++ b/src/framework/graphics/declarations.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -22,8 +22,8 @@ #pragma once -#include #include "glutil.h" +#include enum class DrawPoolType : uint8_t; diff --git a/src/framework/graphics/drawpool.cpp b/src/framework/graphics/drawpool.cpp index a7d51a9be7..d3ce9bc654 100644 --- a/src/framework/graphics/drawpool.cpp +++ b/src/framework/graphics/drawpool.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -24,7 +24,7 @@ DrawPool* DrawPool::create(const DrawPoolType type) { - DrawPool* pool = new DrawPool; + auto pool = new DrawPool; if (type == DrawPoolType::MAP || type == DrawPoolType::FOREGROUND) { pool->setFramebuffer({}); if (type == DrawPoolType::MAP) { @@ -36,6 +36,8 @@ DrawPool* DrawPool::create(const DrawPoolType type) // creates a temporary framebuffer with smoothing. pool->m_temporaryFramebuffers.emplace_back(std::make_shared()); } + } else if (type == DrawPoolType::LIGHT) { + pool->m_hashCtrl = true; } else { pool->m_alwaysGroupDrawings = true; // CREATURE_INFORMATION & TEXT pool->setFPS(60); @@ -45,17 +47,16 @@ DrawPool* DrawPool::create(const DrawPoolType type) return pool; } -void DrawPool::add(const Color& color, const TexturePtr& texture, DrawPool::DrawMethod&& method, - DrawMode drawMode, const DrawConductor& conductor, const CoordsBufferPtr& coordsBuffer) +void DrawPool::add(const Color& color, const TexturePtr& texture, DrawMethod&& method, const DrawConductor& conductor, const CoordsBufferPtr& coordsBuffer) { if (!updateHash(method, texture, color, coordsBuffer != nullptr)) return; uint8_t order = conductor.order; if (m_type == DrawPoolType::FOREGROUND) - order = DrawOrder::FIRST; - else if (m_type == DrawPoolType::MAP && order == DrawOrder::FIRST && !conductor.agroup) - order = DrawOrder::THIRD; + order = FIRST; + else if (m_type == DrawPoolType::MAP && order == FIRST && !conductor.agroup) + order = THIRD; if (m_alwaysGroupDrawings || conductor.agroup) { auto& coords = m_coords.try_emplace(getCurrentState().hash, nullptr).first->second; @@ -67,7 +68,7 @@ void DrawPool::add(const Color& color, const TexturePtr& texture, DrawPool::Draw if (coordsBuffer) coords->append(coordsBuffer.get()); else - addCoords(coords, method, DrawMode::TRIANGLES); + addCoords(coords, method); } else { bool addNewObj = true; @@ -75,12 +76,10 @@ void DrawPool::add(const Color& color, const TexturePtr& texture, DrawPool::Draw if (!list.empty()) { auto& prevObj = list.back(); if (prevObj.state == getCurrentState()) { - if (!prevObj.coords) - prevObj.addMethod(std::move(method)); - else if (coordsBuffer) + if (coordsBuffer) prevObj.coords->append(coordsBuffer.get()); else - addCoords(prevObj.coords.get(), method, DrawMode::TRIANGLES); + addCoords(prevObj.coords.get(), method); addNewObj = false; } @@ -88,38 +87,34 @@ void DrawPool::add(const Color& color, const TexturePtr& texture, DrawPool::Draw if (addNewObj) { auto state = getState(texture, color); + auto& draw = list.emplace_back(std::move(state), getCoordsBuffer()); + if (coordsBuffer) { - list.emplace_back(std::move(state), getCoordsBuffer()).coords->append(coordsBuffer.get()); + draw.coords->append(coordsBuffer.get()); } else - list.emplace_back(drawMode, std::move(state), std::move(method)); + addCoords(draw.coords.get(), method); } } resetOnlyOnceParameters(); } -void DrawPool::addCoords(CoordsBuffer* buffer, const DrawMethod& method, DrawMode drawMode) +void DrawPool::addCoords(CoordsBuffer* buffer, const DrawMethod& method) { if (method.type == DrawMethodType::BOUNDING_RECT) { buffer->addBoudingRect(method.dest, method.intValue); } else if (method.type == DrawMethodType::RECT) { - if (drawMode == DrawMode::TRIANGLES) - buffer->addRect(method.dest, method.src); - else - buffer->addQuad(method.dest, method.src); + buffer->addRect(method.dest, method.src); } else if (method.type == DrawMethodType::TRIANGLE) { buffer->addTriangle(method.a, method.b, method.c); } else if (method.type == DrawMethodType::UPSIDEDOWN_RECT) { - if (drawMode == DrawMode::TRIANGLES) - buffer->addUpsideDownRect(method.dest, method.src); - else - buffer->addUpsideDownQuad(method.dest, method.src); + buffer->addUpsideDownRect(method.dest, method.src); } else if (method.type == DrawMethodType::REPEATED_RECT) { buffer->addRepeatedRects(method.dest, method.src); } } -bool DrawPool::updateHash(const DrawPool::DrawMethod& method, const TexturePtr& texture, const Color& color, const bool hasCoord) { +bool DrawPool::updateHash(const DrawMethod& method, const TexturePtr& texture, const Color& color, const bool hasCoord) { auto& state = getCurrentState(); state.hash = 0; @@ -155,11 +150,11 @@ bool DrawPool::updateHash(const DrawPool::DrawMethod& method, const TexturePtr& if (hasFrameBuffer()) { // Pool Hash size_t hash = state.hash; - if (method.type == DrawPool::DrawMethodType::TRIANGLE) { + if (method.type == DrawMethodType::TRIANGLE) { if (!method.a.isNull()) stdext::hash_union(hash, method.a.hash()); if (!method.b.isNull()) stdext::hash_union(hash, method.b.hash()); if (!method.c.isNull()) stdext::hash_union(hash, method.c.hash()); - } else if (method.type == DrawPool::DrawMethodType::BOUNDING_RECT) { + } else if (method.type == DrawMethodType::BOUNDING_RECT) { if (method.intValue) stdext::hash_combine(hash, method.intValue); } else { if (method.dest.isValid()) stdext::hash_union(hash, method.dest.hash()); @@ -185,31 +180,31 @@ DrawPool::PoolState DrawPool::getState(const TexturePtr& texture, const Color& c return copy; } -void DrawPool::setCompositionMode(const CompositionMode mode, bool onlyOnce) +void DrawPool::setCompositionMode(const CompositionMode mode, const bool onlyOnce) { getCurrentState().compositionMode = mode; if (onlyOnce) m_onlyOnceStateFlag |= STATE_COMPOSITE_MODE; } -void DrawPool::setBlendEquation(BlendEquation equation, bool onlyOnce) +void DrawPool::setBlendEquation(const BlendEquation equation, const bool onlyOnce) { getCurrentState().blendEquation = equation; if (onlyOnce) m_onlyOnceStateFlag |= STATE_BLEND_EQUATION; } -void DrawPool::setClipRect(const Rect& clipRect, bool onlyOnce) +void DrawPool::setClipRect(const Rect& clipRect, const bool onlyOnce) { getCurrentState().clipRect = clipRect; if (onlyOnce) m_onlyOnceStateFlag |= STATE_CLIP_RECT; } -void DrawPool::setOpacity(const float opacity, bool onlyOnce) +void DrawPool::setOpacity(const float opacity, const bool onlyOnce) { getCurrentState().opacity = opacity; if (onlyOnce) m_onlyOnceStateFlag |= STATE_OPACITY; } -void DrawPool::setShaderProgram(const PainterShaderProgramPtr& shaderProgram, bool onlyOnce, const std::function& action) +void DrawPool::setShaderProgram(const PainterShaderProgramPtr& shaderProgram, const bool onlyOnce, const std::function& action) { if (g_painter->isReplaceColorShader(getCurrentState().shaderProgram)) return; @@ -260,7 +255,7 @@ bool DrawPool::canRepaint() return canRepaint; } -void DrawPool::scale(float factor) +void DrawPool::scale(const float factor) { if (m_scale == factor) return; @@ -273,7 +268,7 @@ void DrawPool::scale(float factor) }.transposed(); } -void DrawPool::translate(float x, float y) +void DrawPool::translate(const float x, const float y) { const Matrix3 translateMatrix = { 1.0f, 0.0f, x, @@ -284,7 +279,7 @@ void DrawPool::translate(float x, float y) getCurrentState().transformMatrix = getCurrentState().transformMatrix * translateMatrix.transposed(); } -void DrawPool::rotate(float angle) +void DrawPool::rotate(const float angle) { const Matrix3 rotationMatrix = { std::cos(angle), -std::sin(angle), 0.0f, @@ -295,7 +290,7 @@ void DrawPool::rotate(float angle) getCurrentState().transformMatrix = getCurrentState().transformMatrix * rotationMatrix.transposed(); } -void DrawPool::rotate(float x, float y, float angle) +void DrawPool::rotate(const float x, const float y, const float angle) { translate(-x, -y); rotate(angle); @@ -347,7 +342,7 @@ void DrawPool::removeFramebuffer() { void DrawPool::addAction(const std::function& action) { - const uint8_t order = m_type == DrawPoolType::MAP ? DrawOrder::THIRD : DrawOrder::FIRST; + const uint8_t order = m_type == DrawPoolType::MAP ? THIRD : FIRST; m_objects[order].emplace_back(action); } diff --git a/src/framework/graphics/drawpool.h b/src/framework/graphics/drawpool.h index 23a0bea67c..9c0f694cf5 100644 --- a/src/framework/graphics/drawpool.h +++ b/src/framework/graphics/drawpool.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -26,10 +26,9 @@ #include "declarations.h" #include "framebuffer.h" -#include "texture.h" #include "framework/core/timer.h" -#include #include +#include #include "../stdext/storage.h" #include @@ -56,10 +55,11 @@ enum DrawOrder : uint8_t struct DrawHashController { - bool put(size_t hash) { - m_lastObjectHash = hash; + DrawHashController(bool agroup = false) : m_agroup(agroup) {} - if (m_hashs.emplace(hash).second) { + bool put(size_t hash) { + if ((m_agroup && m_hashs.emplace(hash).second) || m_lastObjectHash != hash) { + m_lastObjectHash = hash; stdext::hash_union(m_currentHash, hash); return true; } @@ -92,12 +92,13 @@ struct DrawHashController size_t m_lastHash{ 0 }; size_t m_currentHash{ 0 }; size_t m_lastObjectHash{ 0 }; + bool m_agroup{ false }; }; struct DrawConductor { bool agroup{ false }; - uint8_t order{ DrawOrder::FIRST }; + uint8_t order{ FIRST }; }; constexpr DrawConductor DEFAULT_DRAW_CONDUCTOR; @@ -110,12 +111,12 @@ class DrawPool FPS20 = 1000 / 20, FPS60 = 1000 / 60; - void setEnable(bool v) { m_enabled = v; } + void setEnable(const bool v) { m_enabled = v; } DrawPoolType getType() const { return m_type; } bool isEnabled() const { return m_enabled; } - bool isType(DrawPoolType type) const { return m_type == type; } + bool isType(const DrawPoolType type) const { return m_type == type; } bool isValid() const { return !m_framebuffer || m_framebuffer->isValid(); } bool hasFrameBuffer() const { return m_framebuffer != nullptr; } @@ -126,11 +127,11 @@ class DrawPool void resetState(); void scale(float factor); - void agroup(bool agroup) { m_alwaysGroupDrawings = agroup; } + void agroup(const bool agroup) { m_alwaysGroupDrawings = agroup; } - void setScaleFactor(float scale) { m_scaleFactor = scale; } - inline float getScaleFactor() const { return m_scaleFactor; } - inline bool isScaled() const { return m_scaleFactor != PlatformWindow::DEFAULT_DISPLAY_DENSITY; } + void setScaleFactor(const float scale) { m_scaleFactor = scale; } + float getScaleFactor() const { return m_scaleFactor; } + bool isScaled() const { return m_scaleFactor != PlatformWindow::DEFAULT_DISPLAY_DENSITY; } void setFramebuffer(const Size& size); void removeFramebuffer(); @@ -195,24 +196,9 @@ class DrawPool { DrawObject(std::function action) : action(std::move(action)) {} DrawObject(PoolState&& state, const std::shared_ptr& coords) : coords(coords), state(std::move(state)) {} - DrawObject(const DrawMode drawMode, PoolState&& state, DrawMethod&& method) : - state(std::move(state)), drawMode(drawMode) { - methods.reserve(10); - methods.emplace_back(std::move(method)); - } - - void addMethod(DrawMethod&& method) - { - drawMode = DrawMode::TRIANGLES; - methods.emplace_back(std::move(method)); - } - - std::vector methods; std::function action{ nullptr }; std::shared_ptr coords; - PoolState state; - DrawMode drawMode{ DrawMode::TRIANGLES }; }; struct DrawObjectState @@ -226,8 +212,8 @@ class DrawPool }; private: - static DrawPool* create(const DrawPoolType type); - static void addCoords(CoordsBuffer* buffer, const DrawPool::DrawMethod& method, DrawMode drawMode); + static DrawPool* create(DrawPoolType type); + static void addCoords(CoordsBuffer* buffer, const DrawMethod& method); enum STATE_TYPE : uint32_t { @@ -238,17 +224,16 @@ class DrawPool STATE_BLEND_EQUATION = 1 << 4, }; - void add(const Color& color, const TexturePtr& texture, DrawPool::DrawMethod&& method, - DrawMode drawMode = DrawMode::TRIANGLES, const DrawConductor& conductor = DEFAULT_DRAW_CONDUCTOR, + void add(const Color& color, const TexturePtr& texture, DrawMethod&& method, const DrawConductor& conductor = DEFAULT_DRAW_CONDUCTOR, const CoordsBufferPtr& coordsBuffer = nullptr); void addAction(const std::function& action); void bindFrameBuffer(const Size& size, const Color& color = Color::white); void releaseFrameBuffer(const Rect& dest); - inline void setFPS(uint16_t fps) { m_refreshDelay = 1000 / fps; } + void setFPS(const uint16_t fps) { m_refreshDelay = 1000 / fps; } - bool updateHash(const DrawPool::DrawMethod& method, const TexturePtr& texture, const Color& color, const bool hasCoord); + bool updateHash(const DrawMethod& method, const TexturePtr& texture, const Color& color, bool hasCoord); PoolState getState(const TexturePtr& texture, const Color& color); PoolState& getCurrentState() { return m_states[m_lastStateIndex]; } @@ -276,7 +261,7 @@ class DrawPool void translate(const Point& p) { translate(p.x, p.y); } void rotate(float angle); void rotate(float x, float y, float angle); - void rotate(const Point& p, float angle) { rotate(p.x, p.y, angle); } + void rotate(const Point& p, const float angle) { rotate(p.x, p.y, angle); } std::shared_ptr getCoordsBuffer(); @@ -285,18 +270,18 @@ class DrawPool m_parameters.emplace(name, value); } template - T getParameter(std::string_view name) { - auto it = m_parameters.find(name); + T getParameter(const std::string_view name) { + const auto it = m_parameters.find(name); if (it != m_parameters.end()) { return std::any_cast(it->second); } return T(); } - bool containsParameter(std::string_view name) { + bool containsParameter(const std::string_view name) { return m_parameters.contains(name); } - void removeParameter(std::string_view name) { + void removeParameter(const std::string_view name) { const auto& it = m_parameters.find(name); if (it != m_parameters.end()) m_parameters.erase(it); @@ -311,7 +296,7 @@ class DrawPool } } - void release(bool flush = true) { + void release(const bool flush = true) { m_objectsDraw.clear(); if (flush) { @@ -358,7 +343,7 @@ class DrawPool --m_lastStateIndex; } - const FrameBufferPtr& getTemporaryFrameBuffer(const uint8_t index); + const FrameBufferPtr& getTemporaryFrameBuffer(uint8_t index); bool m_enabled{ true }; bool m_alwaysGroupDrawings{ false }; @@ -381,7 +366,7 @@ class DrawPool std::vector m_transformMatrixStack; std::vector m_temporaryFramebuffers; - std::vector m_objects[static_cast(DrawOrder::LAST)]; + std::vector m_objects[static_cast(LAST)]; std::vector m_objectsFlushed; std::vector m_objectsDraw; diff --git a/src/framework/graphics/drawpoolmanager.cpp b/src/framework/graphics/drawpoolmanager.cpp index c0bf643c10..905852b48b 100644 --- a/src/framework/graphics/drawpoolmanager.cpp +++ b/src/framework/graphics/drawpoolmanager.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,8 +21,9 @@ */ #include "drawpoolmanager.h" -#include "drawpool.h" #include "declarations.h" +#include "drawpool.h" +#include "graphics.h" thread_local static uint8_t CURRENT_POOL = static_cast(DrawPoolType::LAST); @@ -32,7 +33,7 @@ void resetSelectedPool() { DrawPoolManager g_drawPool; -void DrawPoolManager::init(uint16_t spriteSize) +void DrawPoolManager::init(const uint16_t spriteSize) { if (spriteSize != 0) m_spriteSize = spriteSize; @@ -72,23 +73,15 @@ void DrawPoolManager::drawObject(const DrawPool::DrawObject& obj) { if (obj.action) { obj.action(); - return; - } - - auto& coords = !obj.coords ? m_coordsBuffer : *obj.coords; - if (!obj.coords) { - coords.clear(); - for (const auto& method : obj.methods) - DrawPool::addCoords(&coords, method, obj.drawMode); + } else { + obj.state.execute(); + g_painter->drawCoords(*obj.coords, DrawMode::TRIANGLES); } - - obj.state.execute(); - g_painter->drawCoords(coords, obj.drawMode); } void DrawPoolManager::addTexturedCoordsBuffer(const TexturePtr& texture, const CoordsBufferPtr& coords, const Color& color, const DrawConductor& condutor) const { - getCurrentPool()->add(color, texture, DrawPool::DrawMethod{}, DrawMode::TRIANGLE_STRIP, condutor, coords); + getCurrentPool()->add(color, texture, DrawPool::DrawMethod{}, condutor, coords); } void DrawPoolManager::addTexturedRect(const Rect& dest, const TexturePtr& texture, const Rect& src, const Color& color, const DrawConductor& condutor) const @@ -101,7 +94,7 @@ void DrawPoolManager::addTexturedRect(const Rect& dest, const TexturePtr& textur getCurrentPool()->add(color, texture, DrawPool::DrawMethod{ .type = DrawPool::DrawMethodType::RECT, .dest = dest, .src = src - }, DrawMode::TRIANGLE_STRIP, condutor); + }, condutor); } void DrawPoolManager::addUpsideDownTexturedRect(const Rect& dest, const TexturePtr& texture, const Rect& src, const Color& color, const DrawConductor& condutor) const @@ -111,7 +104,10 @@ void DrawPoolManager::addUpsideDownTexturedRect(const Rect& dest, const TextureP return; } - getCurrentPool()->add(color, texture, DrawPool::DrawMethod{ DrawPool::DrawMethodType::UPSIDEDOWN_RECT, dest, src }, DrawMode::TRIANGLE_STRIP, condutor); + getCurrentPool()->add(color, texture, DrawPool::DrawMethod{ .type = DrawPool::DrawMethodType::UPSIDEDOWN_RECT, .dest = + dest, + .src = src + }, condutor); } void DrawPoolManager::addTexturedRepeatedRect(const Rect& dest, const TexturePtr& texture, const Rect& src, const Color& color, const DrawConductor& condutor) const @@ -121,7 +117,10 @@ void DrawPoolManager::addTexturedRepeatedRect(const Rect& dest, const TexturePtr return; } - getCurrentPool()->add(color, texture, DrawPool::DrawMethod{ DrawPool::DrawMethodType::REPEATED_RECT, dest, src }, DrawMode::TRIANGLES, condutor); + getCurrentPool()->add(color, texture, DrawPool::DrawMethod{ .type = DrawPool::DrawMethodType::REPEATED_RECT, .dest = + dest, + .src = src + }, condutor); } void DrawPoolManager::addFilledRect(const Rect& dest, const Color& color, const DrawConductor& condutor) const @@ -131,7 +130,7 @@ void DrawPoolManager::addFilledRect(const Rect& dest, const Color& color, const return; } - getCurrentPool()->add(color, nullptr, DrawPool::DrawMethod{ DrawPool::DrawMethodType::RECT, dest }, DrawMode::TRIANGLES, condutor); + getCurrentPool()->add(color, nullptr, DrawPool::DrawMethod{ .type = DrawPool::DrawMethodType::RECT, .dest = dest }, condutor); } void DrawPoolManager::addFilledTriangle(const Point& a, const Point& b, const Point& c, const Color& color, const DrawConductor& condutor) const @@ -146,10 +145,10 @@ void DrawPoolManager::addFilledTriangle(const Point& a, const Point& b, const Po .a = a, .b = b, .c = c - }, DrawMode::TRIANGLES, condutor); + }, condutor); } -void DrawPoolManager::addBoundingRect(const Rect& dest, const Color& color, uint16_t innerLineWidth, const DrawConductor& condutor) const +void DrawPoolManager::addBoundingRect(const Rect& dest, const Color& color, const uint16_t innerLineWidth, const DrawConductor& condutor) const { if (dest.isEmpty() || innerLineWidth == 0) { getCurrentPool()->resetOnlyOnceParameters(); @@ -160,7 +159,7 @@ void DrawPoolManager::addBoundingRect(const Rect& dest, const Color& color, uint .type = DrawPool::DrawMethodType::BOUNDING_RECT, .dest = dest, .intValue = innerLineWidth - }, DrawMode::TRIANGLES, condutor); + }, condutor); } void DrawPoolManager::preDraw(const DrawPoolType type, const std::function& f, const std::function& beforeRelease, const Rect& dest, const Rect& src, const Color& colorClear, const bool alwaysDraw) diff --git a/src/framework/graphics/drawpoolmanager.h b/src/framework/graphics/drawpoolmanager.h index 64f400a6a2..edd22c7443 100644 --- a/src/framework/graphics/drawpoolmanager.h +++ b/src/framework/graphics/drawpoolmanager.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -25,7 +25,6 @@ #include #include #include -#include class DrawPoolManager { @@ -34,13 +33,13 @@ class DrawPoolManager void select(DrawPoolType type); void preDraw(const DrawPoolType type, const std::function& f, const bool alwaysDraw = false) { preDraw(type, f, nullptr, {}, {}, Color::alpha, alwaysDraw); } - void preDraw(DrawPoolType type, const std::function& f, const Rect& dest, const Rect& src, const Color& colorClear = Color::alpha, const bool alwaysDraw = false) { preDraw(type, f, nullptr, dest, src, colorClear, alwaysDraw); } - void preDraw(DrawPoolType type, const std::function& f, const std::function& beforeRelease, const Rect& dest, const Rect& src, const Color& colorClear = Color::alpha, const bool alwaysDraw = false); + void preDraw(const DrawPoolType type, const std::function& f, const Rect& dest, const Rect& src, const Color& colorClear = Color::alpha, const bool alwaysDraw = false) { preDraw(type, f, nullptr, dest, src, colorClear, alwaysDraw); } + void preDraw(DrawPoolType type, const std::function& f, const std::function& beforeRelease, const Rect& dest, const Rect& src, const Color& colorClear = Color::alpha, bool alwaysDraw = false); void addTexturedPoint(const TexturePtr& texture, const Point& point, const Color& color = Color::white) const { addTexturedRect(Rect(point, texture->getSize()), texture, color); } - void addTexturedPos(const TexturePtr& texture, int x, int y, const Color& color = Color::white) const + void addTexturedPos(const TexturePtr& texture, const int x, const int y, const Color& color = Color::white) const { addTexturedRect(Rect(x, y, texture->getSize()), texture, color); } void addTexturedRect(const Rect& dest, const TexturePtr& texture, const Color& color = Color::white) const @@ -58,14 +57,14 @@ class DrawPoolManager void bindFrameBuffer(const Size& size, const Color& color = Color::white) const { getCurrentPool()->bindFrameBuffer(size, color); } void releaseFrameBuffer(const Rect& dest) const { getCurrentPool()->releaseFrameBuffer(dest); }; - void setOpacity(const float opacity, bool onlyOnce = false) const { getCurrentPool()->setOpacity(opacity, onlyOnce); } - void setClipRect(const Rect& clipRect, bool onlyOnce = false) const { getCurrentPool()->setClipRect(clipRect, onlyOnce); } - void setBlendEquation(BlendEquation equation, bool onlyOnce = false) const { getCurrentPool()->setBlendEquation(equation, onlyOnce); } - void setCompositionMode(const CompositionMode mode, bool onlyOnce = false) const { getCurrentPool()->setCompositionMode(mode, onlyOnce); } + void setOpacity(const float opacity, const bool onlyOnce = false) const { getCurrentPool()->setOpacity(opacity, onlyOnce); } + void setClipRect(const Rect& clipRect, const bool onlyOnce = false) const { getCurrentPool()->setClipRect(clipRect, onlyOnce); } + void setBlendEquation(const BlendEquation equation, const bool onlyOnce = false) const { getCurrentPool()->setBlendEquation(equation, onlyOnce); } + void setCompositionMode(const CompositionMode mode, const bool onlyOnce = false) const { getCurrentPool()->setCompositionMode(mode, onlyOnce); } bool shaderNeedFramebuffer() const { return getCurrentPool()->getCurrentState().shaderProgram && getCurrentPool()->getCurrentState().shaderProgram->useFramebuffer(); } void setShaderProgram(const PainterShaderProgramPtr& shaderProgram, const std::function& action) const { getCurrentPool()->setShaderProgram(shaderProgram, false, action); } - void setShaderProgram(const PainterShaderProgramPtr& shaderProgram, bool onlyOnce = false, const std::function& action = nullptr) const { getCurrentPool()->setShaderProgram(shaderProgram, onlyOnce, action); } + void setShaderProgram(const PainterShaderProgramPtr& shaderProgram, const bool onlyOnce = false, const std::function& action = nullptr) const { getCurrentPool()->setShaderProgram(shaderProgram, onlyOnce, action); } float getOpacity() const { return getCurrentPool()->getOpacity(); } Rect getClipRect() const { return getCurrentPool()->getClipRect(); } @@ -78,31 +77,31 @@ class DrawPoolManager void pushTransformMatrix() const { getCurrentPool()->pushTransformMatrix(); } void popTransformMatrix() const { getCurrentPool()->popTransformMatrix(); } - void scale(float factor) const { getCurrentPool()->scale(factor); } - void translate(float x, float y) const { getCurrentPool()->translate(x, y); } + void scale(const float factor) const { getCurrentPool()->scale(factor); } + void translate(const float x, const float y) const { getCurrentPool()->translate(x, y); } void translate(const Point& p) const { getCurrentPool()->translate(p); } - void rotate(float angle) const { getCurrentPool()->rotate(angle); } - void rotate(float x, float y, float angle) const { getCurrentPool()->rotate(x, y, angle); } - void rotate(const Point& p, float angle) const { getCurrentPool()->rotate(p, angle); } + void rotate(const float angle) const { getCurrentPool()->rotate(angle); } + void rotate(const float x, const float y, const float angle) const { getCurrentPool()->rotate(x, y, angle); } + void rotate(const Point& p, const float angle) const { getCurrentPool()->rotate(p, angle); } - void setScaleFactor(float scale) const { getCurrentPool()->setScaleFactor(scale); } - inline float getScaleFactor() const { return getCurrentPool()->getScaleFactor(); } - inline bool isScaled() const { return getCurrentPool()->isScaled(); } - inline uint16_t getScaledSpriteSize() const { return m_spriteSize * getScaleFactor(); } + void setScaleFactor(const float scale) const { getCurrentPool()->setScaleFactor(scale); } + float getScaleFactor() const { return getCurrentPool()->getScaleFactor(); } + bool isScaled() const { return getCurrentPool()->isScaled(); } + uint16_t getScaledSpriteSize() const { return m_spriteSize * getScaleFactor(); } template void setParameter(std::string_view name, T&& value) { getCurrentPool()->setParameter(name, value); } - void removeParameter(std::string_view name) { getCurrentPool()->removeParameter(name); } + void removeParameter(const std::string_view name) { getCurrentPool()->removeParameter(name); } template - T getParameter(std::string_view name) { return getCurrentPool()->getParameter(name); } - bool containsParameter(std::string_view name) { return getCurrentPool()->containsParameter(name); } + T getParameter(const std::string_view name) { return getCurrentPool()->getParameter(name); } + bool containsParameter(const std::string_view name) { return getCurrentPool()->containsParameter(name); } void flush() const { if (getCurrentPool()) getCurrentPool()->flush(); } DrawPoolType getCurrentType() const { return getCurrentPool()->m_type; } - inline void repaint(const DrawPoolType drawPool) const { + void repaint(const DrawPoolType drawPool) const { get(drawPool)->repaint(); } @@ -115,9 +114,8 @@ class DrawPoolManager void init(uint16_t spriteSize); void terminate() const; void drawObject(const DrawPool::DrawObject& obj); - void drawPool(const DrawPoolType type); + void drawPool(DrawPoolType type); - CoordsBuffer m_coordsBuffer; std::array(DrawPoolType::LAST)> m_pools{}; Size m_size; diff --git a/src/framework/graphics/fontmanager.cpp b/src/framework/graphics/fontmanager.cpp index 00057e36fb..bde6b9953c 100644 --- a/src/framework/graphics/fontmanager.cpp +++ b/src/framework/graphics/fontmanager.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * 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/src/framework/graphics/fontmanager.h b/src/framework/graphics/fontmanager.h index 82f49db64c..0a8b768a16 100644 --- a/src/framework/graphics/fontmanager.h +++ b/src/framework/graphics/fontmanager.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -33,8 +33,8 @@ class FontManager bool importFont(const std::string& file); - bool fontExists(const std::string_view fontName); - BitmapFontPtr getFont(const std::string_view fontName); + bool fontExists(std::string_view fontName); + BitmapFontPtr getFont(std::string_view fontName); BitmapFontPtr getDefaultFont() const { return m_defaultFont; } BitmapFontPtr getDefaultWidgetFont() const { return m_defaultWidgetFont; } diff --git a/src/framework/graphics/framebuffer.cpp b/src/framework/graphics/framebuffer.cpp index 86b96f8a94..0973d8951e 100644 --- a/src/framework/graphics/framebuffer.cpp +++ b/src/framework/graphics/framebuffer.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -25,11 +25,11 @@ #include "texture.h" #include -#include #include +#include #include -#include -#include + +#include "framework/core/graphicalapplication.h" uint32_t FrameBuffer::boundFbo = 0; @@ -46,7 +46,7 @@ FrameBuffer::~FrameBuffer() assert(!g_app.isTerminated()); #endif if (g_graphics.ok() && m_fbo != 0) { - g_mainDispatcher.addEvent([id = m_fbo]() { + g_mainDispatcher.addEvent([id = m_fbo] { glDeleteFramebuffers(1, &id); }); } @@ -102,6 +102,10 @@ void FrameBuffer::bind() } } +bool FrameBuffer::canDraw() const { + return m_texture && m_coordsBuffer.getVertexCount() > 0; +} + void FrameBuffer::release() const { internalRelease(); @@ -161,7 +165,7 @@ TexturePtr FrameBuffer::extractTexture() { const int width = size.width(); const int height = size.height(); const auto& pixels = std::make_shared>(width * height * 4 * sizeof(GLubyte), 0); - glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, (GLubyte*)(pixels->data())); + glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels->data()); internalRelease(); const auto& texture = std::make_shared(std::make_shared(getSize(), 4, pixels->data())); @@ -187,7 +191,7 @@ void FrameBuffer::doScreenshot(std::string file, const uint16_t x, const uint16_ const int height = size.height(); const auto& pixels = std::make_shared>(width * height * 4 * sizeof(GLubyte), 0); - glReadPixels(x / 3, y / 1.5, width, height, GL_RGBA, GL_UNSIGNED_BYTE, (GLubyte*)(pixels->data())); + glReadPixels(x / 3, y / 1.5, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels->data()); internalRelease(); diff --git a/src/framework/graphics/framebuffer.h b/src/framework/graphics/framebuffer.h index 935ac60c2b..717049c43c 100644 --- a/src/framework/graphics/framebuffer.h +++ b/src/framework/graphics/framebuffer.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -38,13 +38,11 @@ class FrameBuffer void draw(const Rect& dest) { prepare(dest, Rect(0, 0, getSize())); draw(); } void reset() { m_texture = nullptr; } - void setSmooth(bool enabled) { m_smooth = enabled; m_texture = nullptr; } + void setSmooth(const bool enabled) { m_smooth = enabled; m_texture = nullptr; } bool resize(const Size& size); bool isValid() const { return m_texture != nullptr; } - bool canDraw() const { - return m_texture && m_coordsBuffer.getVertexCount() > 0; - } + bool canDraw() const; TexturePtr getTexture() const { return m_texture; } TexturePtr extractTexture(); @@ -53,7 +51,7 @@ class FrameBuffer void setCompositionMode(const CompositionMode mode) { m_compositeMode = mode; } void disableBlend() { m_disableBlend = true; } - void doScreenshot(std::string file, const uint16_t x = 0, const uint16_t y = 0); + void doScreenshot(std::string file, uint16_t x = 0, uint16_t y = 0); Size getSize(); protected: diff --git a/src/framework/graphics/glutil.h b/src/framework/graphics/glutil.h index f637b5b69c..65e99f5def 100644 --- a/src/framework/graphics/glutil.h +++ b/src/framework/graphics/glutil.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -22,7 +22,7 @@ #pragma once -#ifdef OPENGL_ES +#if defined(OPENGL_ES) || defined(__EMSCRIPTEN__) // for static linking #define GL_APICALL #define EGLAPI diff --git a/src/framework/graphics/graphics.cpp b/src/framework/graphics/graphics.cpp index 9057ffd06a..a07d242dae 100644 --- a/src/framework/graphics/graphics.cpp +++ b/src/framework/graphics/graphics.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -23,9 +23,9 @@ #include "graphics.h" #include "fontmanager.h" -#include -#include "texturemanager.h" #include "painter.h" +#include "texturemanager.h" +#include Graphics g_graphics; diff --git a/src/framework/graphics/graphics.h b/src/framework/graphics/graphics.h index 10ad23a1fa..5db0dd496a 100644 --- a/src/framework/graphics/graphics.h +++ b/src/framework/graphics/graphics.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * 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/src/framework/graphics/hardwarebuffer.cpp b/src/framework/graphics/hardwarebuffer.cpp index 9a691664c1..8288a371bb 100644 --- a/src/framework/graphics/hardwarebuffer.cpp +++ b/src/framework/graphics/hardwarebuffer.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -26,7 +26,9 @@ #include #include -HardwareBuffer::HardwareBuffer(Type type) :m_type(type) +#include "framework/core/graphicalapplication.h" + +HardwareBuffer::HardwareBuffer(const Type type) :m_type(type) { glGenBuffers(1, &m_id); if (!m_id) diff --git a/src/framework/graphics/hardwarebuffer.h b/src/framework/graphics/hardwarebuffer.h index 9c9e2528d7..2994d67861 100644 --- a/src/framework/graphics/hardwarebuffer.h +++ b/src/framework/graphics/hardwarebuffer.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -45,7 +45,7 @@ class HardwareBuffer void bind() const { glBindBuffer(static_cast(m_type), m_id); } static void unbind(Type type) { glBindBuffer(static_cast(type), 0); } - void write(void const* data, int count, UsagePattern usage) const { glBufferData(static_cast(m_type), count, data, static_cast(usage)); } + void write(const void* data, const int count, UsagePattern usage) const { glBufferData(static_cast(m_type), count, data, static_cast(usage)); } private: Type m_type; diff --git a/src/framework/graphics/image.cpp b/src/framework/graphics/image.cpp index 283283dab2..b05999e494 100644 --- a/src/framework/graphics/image.cpp +++ b/src/framework/graphics/image.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -26,12 +26,11 @@ #include #include -#include "framework/stdext/math.h" #include "framework/stdext/qrcodegen.h" using namespace qrcodegen; -Image::Image(const Size& size, int bpp, uint8_t* pixels) : m_size(size), m_bpp(bpp) +Image::Image(const Size& size, const int bpp, const uint8_t* pixels) : m_size(size), m_bpp(bpp) { m_pixels.resize(size.area() * bpp, 0); if (pixels) @@ -49,7 +48,7 @@ ImagePtr Image::load(const std::string& file) return nullptr; } -ImagePtr Image::loadPNG(const char* data, size_t size) +ImagePtr Image::loadPNG(const char* data, const size_t size) { std::stringstream fin(std::string{ data, size }); ImagePtr image; @@ -74,7 +73,7 @@ ImagePtr Image::loadPNG(const std::string& file) std::stringstream fin; g_resources.readFileStream(file, fin); - std::string buffer{ fin.str() }; + const std::string buffer{ fin.str() }; return loadPNG(buffer.data(), buffer.size()); } @@ -256,10 +255,10 @@ void Image::reverseChannels() } } -ImagePtr Image::fromQRCode(const std::string& code, int border) +ImagePtr Image::fromQRCode(const std::string& code, const int border) { try { - QrCode qrCode = QrCode::encodeText(code.c_str(), QrCode::Ecc::MEDIUM); + const QrCode qrCode = QrCode::encodeText(code.c_str(), QrCode::Ecc::MEDIUM); const auto size = qrCode.getSize(); ImagePtr image(new Image(Size(size + border * 2, size + border * 2))); diff --git a/src/framework/graphics/image.h b/src/framework/graphics/image.h index c41a81dacb..202d4e6a2f 100644 --- a/src/framework/graphics/image.h +++ b/src/framework/graphics/image.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -27,7 +27,7 @@ class Image { public: - Image(const Size& size, int bpp = 4, uint8_t* pixels = nullptr); + Image(const Size& size, int bpp = 4, const uint8_t* pixels = nullptr); static ImagePtr load(const std::string& file); static ImagePtr loadPNG(const char* data, size_t size); @@ -49,17 +49,17 @@ class Image bool nextMipmap(); void flipVertically(); - void setOpacity(const uint8_t v); + void setOpacity(uint8_t v); void reverseChannels(); // argb -> bgra or bgra -> argb - void setPixel(int x, int y, const uint8_t* pixel) { + void setPixel(const int x, const int y, const uint8_t* pixel) { const auto index = static_cast(y * m_size.width() + x) * m_bpp; if (index < m_pixels.size()) memcpy(&m_pixels[index], pixel, m_bpp); } - void setPixel(int x, int y, const Color& color) { setPixel(x, y, Color(color.rgba()).rgba()); } - void setPixel(int x, int y, uint32_t rgba) { setPixel(x, y, reinterpret_cast(&rgba)); } + void setPixel(const int x, const int y, const Color& color) { setPixel(x, y, Color(color.rgba()).rgba()); } + void setPixel(const int x, const int y, uint32_t rgba) { setPixel(x, y, reinterpret_cast(&rgba)); } std::vector& getPixels() { return m_pixels; } uint8_t* getPixelData() { return &m_pixels[0]; } @@ -68,7 +68,7 @@ class Image int getWidth() const { return m_size.width(); } int getHeight() const { return m_size.height(); } int getBpp() const { return m_bpp; } - uint8_t* getPixel(int x, int y) { return &m_pixels[static_cast(y * m_size.width() + x) * m_bpp]; } + uint8_t* getPixel(const int x, const int y) { return &m_pixels[static_cast(y * m_size.width() + x) * m_bpp]; } bool hasTransparentPixel() const { return m_transparentPixel; } void setTransparentPixel(const bool value) { m_transparentPixel = value; } diff --git a/src/framework/graphics/painter.cpp b/src/framework/graphics/painter.cpp index a63ab7e126..f4cd8f4cef 100644 --- a/src/framework/graphics/painter.cpp +++ b/src/framework/graphics/painter.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -22,8 +22,8 @@ #include "painter.h" -#include #include "framework/graphics/texture.h" +#include #include "shader/shadersources.h" @@ -121,7 +121,7 @@ void Painter::drawCoords(CoordsBuffer& coordsBuffer, DrawMode drawMode) PainterShaderProgram::enableAttributeArray(PainterShaderProgram::TEXCOORD_ATTR); } -void Painter::drawLine(const std::vector& vertex, int size, int width) +void Painter::drawLine(const std::vector& vertex, const int size, const int width) { m_drawLineProgram->bind(); m_drawLineProgram->setTransformMatrix(m_transformMatrix); @@ -174,7 +174,7 @@ void Painter::clearRect(const Color& color, const Rect& rect) setClipRect(oldClipRect); } -void Painter::setCompositionMode(CompositionMode compositionMode) +void Painter::setCompositionMode(const CompositionMode compositionMode) { if (m_compositionMode == compositionMode) return; @@ -183,7 +183,7 @@ void Painter::setCompositionMode(CompositionMode compositionMode) updateGlCompositionMode(); } -void Painter::setBlendEquation(BlendEquation blendEquation) +void Painter::setBlendEquation(const BlendEquation blendEquation) { if (m_blendEquation == blendEquation) return; @@ -216,7 +216,7 @@ void Painter::setTexture(Texture* texture) updateGlTexture(); } -void Painter::setAlphaWriting(bool enable) +void Painter::setAlphaWriting(const bool enable) { if (m_alphaWriting == enable) return; diff --git a/src/framework/graphics/painter.h b/src/framework/graphics/painter.h index ab6ab4ec1e..83d7f0558e 100644 --- a/src/framework/graphics/painter.h +++ b/src/framework/graphics/painter.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -81,7 +81,7 @@ class Painter void setColor(const Color& color) { if (m_color != color) m_color = color; } void setTexture(Texture* texture); - void setOpacity(float opacity) { m_opacity = opacity; } + void setOpacity(const float opacity) { m_opacity = opacity; } void setClipRect(const Rect& clipRect); void setResolution(const Size& resolution, const Matrix3& projectionMatrix = DEFAULT_MATRIX3); void setDrawProgram(PainterShaderProgram* drawProgram) { m_drawProgram = drawProgram; } diff --git a/src/framework/graphics/paintershaderprogram.cpp b/src/framework/graphics/paintershaderprogram.cpp index 373d41e70c..9970dc27d7 100644 --- a/src/framework/graphics/paintershaderprogram.cpp +++ b/src/framework/graphics/paintershaderprogram.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,10 +21,10 @@ */ #include "paintershaderprogram.h" -#include -#include #include "texture.h" #include "texturemanager.h" +#include +#include PainterShaderProgram::PainterShaderProgram() :m_startTime(g_clock.seconds()) {} @@ -109,7 +109,7 @@ void PainterShaderProgram::setColor(const Color& color) m_color = color; } -void PainterShaderProgram::setOpacity(float opacity) +void PainterShaderProgram::setOpacity(const float opacity) { if (m_opacity == opacity) return; diff --git a/src/framework/graphics/paintershaderprogram.h b/src/framework/graphics/paintershaderprogram.h index b4c7f08ed3..4c94a86fcf 100644 --- a/src/framework/graphics/paintershaderprogram.h +++ b/src/framework/graphics/paintershaderprogram.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -24,7 +24,7 @@ #include "shaderprogram.h" -class PainterShaderProgram : public ShaderProgram +class PainterShaderProgram final : public ShaderProgram { protected: enum @@ -68,7 +68,7 @@ class PainterShaderProgram : public ShaderProgram void addMultiTexture(const std::string& file); void bindMultiTextures() const; - void setUseFramebuffer(bool v) { + void setUseFramebuffer(const bool v) { m_useFramebuffer = v; } diff --git a/src/framework/graphics/particle.cpp b/src/framework/graphics/particle.cpp index 5f0f1571b1..4ea5b0a4dd 100644 --- a/src/framework/graphics/particle.cpp +++ b/src/framework/graphics/particle.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -42,7 +42,7 @@ void Particle::render() const g_drawPool.addTexturedRect(m_rect, m_texture, m_color); } -void Particle::update(float elapsedTime) +void Particle::update(const float elapsedTime) { // check if finished if (m_duration >= 0 && m_elapsedTime >= m_duration) { @@ -60,7 +60,7 @@ void Particle::update(float elapsedTime) m_elapsedTime += elapsedTime; } -void Particle::updatePosition(float elapsedTime) +void Particle::updatePosition(const float elapsedTime) { if (m_ignorePhysicsAfter < 0 || m_elapsedTime < m_ignorePhysicsAfter) { // update position diff --git a/src/framework/graphics/particle.h b/src/framework/graphics/particle.h index 699e7e2b23..53be260110 100644 --- a/src/framework/graphics/particle.h +++ b/src/framework/graphics/particle.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -30,12 +30,15 @@ class Particle { public: Particle(const Point& pos, const Size& startSize, const Size& finalSize, const PointF& velocity, - const PointF& acceleration, float duration, float ignorePhysicsAfter, const std::vector& colors, - const std::vector& colorsStops, CompositionMode compositionMode, const TexturePtr& texture, const AnimatedTexturePtr& animatedTexture) : - m_colors(colors), m_colorsStops(colorsStops), m_texture(texture), m_animatedTexture(animatedTexture), m_position(PointF(pos.x, pos.y)), + const PointF& acceleration, const float duration, const float ignorePhysicsAfter, const std::vector& colors, + const std::vector& colorsStops, const CompositionMode compositionMode, TexturePtr texture, + AnimatedTexturePtr animatedTexture) : + m_colors(colors), m_colorsStops(colorsStops), m_texture(std::move(texture)), m_animatedTexture(std::move( + animatedTexture)), m_position(PointF(pos.x, pos.y)), m_velocity(velocity), m_acceleration(acceleration), m_startSize(startSize), m_finalSize(finalSize), m_duration(duration), m_ignorePhysicsAfter(ignorePhysicsAfter), m_compositionMode(compositionMode) - {} + { + } void render() const; void update(float elapsedTime); diff --git a/src/framework/graphics/particleaffector.cpp b/src/framework/graphics/particleaffector.cpp index e40202354c..3b60ec2400 100644 --- a/src/framework/graphics/particleaffector.cpp +++ b/src/framework/graphics/particleaffector.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -23,7 +23,7 @@ #include "particleaffector.h" #include "particle.h" -void ParticleAffector::update(float elapsedTime) +void ParticleAffector::update(const float elapsedTime) { if (m_duration >= 0 && m_elapsedTime >= m_duration + m_delay) { m_finished = true; @@ -77,7 +77,7 @@ void GravityAffector::load(const OTMLNodePtr& node) } } -void GravityAffector::updateParticle(const ParticlePtr& particle, float elapsedTime) const +void GravityAffector::updateParticle(const ParticlePtr& particle, const float elapsedTime) const { if (!m_active) return; @@ -107,7 +107,7 @@ void AttractionAffector::load(const OTMLNodePtr& node) } } -void AttractionAffector::updateParticle(const ParticlePtr& particle, float elapsedTime) const +void AttractionAffector::updateParticle(const ParticlePtr& particle, const float elapsedTime) const { if (!m_active) return; diff --git a/src/framework/graphics/particleaffector.h b/src/framework/graphics/particleaffector.h index 9ea0b30ecd..e369329efb 100644 --- a/src/framework/graphics/particleaffector.h +++ b/src/framework/graphics/particleaffector.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -28,7 +28,7 @@ class ParticleAffector { public: - virtual ~ParticleAffector() {} // fix clang warning + virtual ~ParticleAffector() = default; // fix clang warning void update(float elapsedTime); virtual void load(const OTMLNodePtr& node); @@ -44,7 +44,7 @@ class ParticleAffector float m_elapsedTime{ 0 }; }; -class GravityAffector : public ParticleAffector +class GravityAffector final : public ParticleAffector { public: void load(const OTMLNodePtr& node) override; @@ -55,7 +55,7 @@ class GravityAffector : public ParticleAffector float m_gravity{ 0 }; }; -class AttractionAffector : public ParticleAffector +class AttractionAffector final : public ParticleAffector { public: void load(const OTMLNodePtr& node) override; diff --git a/src/framework/graphics/particleeffect.cpp b/src/framework/graphics/particleeffect.cpp index 4098e0eadf..80681a457a 100644 --- a/src/framework/graphics/particleeffect.cpp +++ b/src/framework/graphics/particleeffect.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * 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/src/framework/graphics/particleeffect.h b/src/framework/graphics/particleeffect.h index 219a1ad601..732a6c82b5 100644 --- a/src/framework/graphics/particleeffect.h +++ b/src/framework/graphics/particleeffect.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -22,11 +22,11 @@ #pragma once +#include "declarations.h" #include #include -#include "declarations.h" -class ParticleEffectType : public LuaObject +class ParticleEffectType final : public LuaObject { public: void load(const OTMLNodePtr& node); diff --git a/src/framework/graphics/particleemitter.cpp b/src/framework/graphics/particleemitter.cpp index ef31a16e6f..f2515633de 100644 --- a/src/framework/graphics/particleemitter.cpp +++ b/src/framework/graphics/particleemitter.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -47,7 +47,7 @@ void ParticleEmitter::load(const OTMLNodePtr& node) throw Exception("emitter didn't provide a valid particle type"); } -void ParticleEmitter::update(float elapsedTime, const ParticleSystemPtr& system) +void ParticleEmitter::update(const float elapsedTime, const ParticleSystemPtr& system) { m_elapsedTime += elapsedTime; diff --git a/src/framework/graphics/particleemitter.h b/src/framework/graphics/particleemitter.h index 0f0429a779..3638e17545 100644 --- a/src/framework/graphics/particleemitter.h +++ b/src/framework/graphics/particleemitter.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -22,9 +22,9 @@ #pragma once +#include "declarations.h" #include #include -#include "declarations.h" class ParticleEmitter { diff --git a/src/framework/graphics/particlemanager.cpp b/src/framework/graphics/particlemanager.cpp index 0cc6281992..e9f55d9c59 100644 --- a/src/framework/graphics/particlemanager.cpp +++ b/src/framework/graphics/particlemanager.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * 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/src/framework/graphics/particlemanager.h b/src/framework/graphics/particlemanager.h index 705869cf92..3d585399aa 100644 --- a/src/framework/graphics/particlemanager.h +++ b/src/framework/graphics/particlemanager.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -29,7 +29,7 @@ class ParticleManager { public: bool importParticle(std::string file); - ParticleEffectPtr createEffect(const std::string_view name); + ParticleEffectPtr createEffect(std::string_view name); void terminate(); void poll(); diff --git a/src/framework/graphics/particlesystem.cpp b/src/framework/graphics/particlesystem.cpp index 23ce799cb7..0029632850 100644 --- a/src/framework/graphics/particlesystem.cpp +++ b/src/framework/graphics/particlesystem.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,10 +21,10 @@ */ #include "particlesystem.h" -#include -#include #include "particle.h" #include "particleaffector.h" +#include +#include ParticleSystem::ParticleSystem() :m_lastUpdateTime(g_clock.seconds()) {} diff --git a/src/framework/graphics/particlesystem.h b/src/framework/graphics/particlesystem.h index bfae0549cb..6972276e93 100644 --- a/src/framework/graphics/particlesystem.h +++ b/src/framework/graphics/particlesystem.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * 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/src/framework/graphics/particletype.cpp b/src/framework/graphics/particletype.cpp index f49379e07d..97ecab5155 100644 --- a/src/framework/graphics/particletype.cpp +++ b/src/framework/graphics/particletype.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * 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/src/framework/graphics/particletype.h b/src/framework/graphics/particletype.h index 9b5b61a7c7..563bd35101 100644 --- a/src/framework/graphics/particletype.h +++ b/src/framework/graphics/particletype.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -22,11 +22,10 @@ #pragma once -#include +#include "declarations.h" #include -#include +#include #include -#include "declarations.h" class ParticleType { diff --git a/src/framework/graphics/shader.cpp b/src/framework/graphics/shader.cpp index dc9d0f3120..fff167f44b 100644 --- a/src/framework/graphics/shader.cpp +++ b/src/framework/graphics/shader.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -24,8 +24,10 @@ #include "graphics.h" #include -#include #include +#include + +#include "framework/core/graphicalapplication.h" Shader::Shader(ShaderType shaderType) : m_shaderId(glCreateShader(static_cast(shaderType))), m_shaderType(shaderType) { diff --git a/src/framework/graphics/shader.h b/src/framework/graphics/shader.h index 24eedfb13b..5be0a9d230 100644 --- a/src/framework/graphics/shader.h +++ b/src/framework/graphics/shader.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -37,8 +37,8 @@ class Shader Shader(ShaderType shaderType); ~Shader(); - bool compileSourceCode(const std::string_view sourceCode) const; - bool compileSourceFile(const std::string_view sourceFile) const; + bool compileSourceCode(std::string_view sourceCode) const; + bool compileSourceFile(std::string_view sourceFile) const; std::string log() const; uint32_t getShaderId() const { return m_shaderId; } diff --git a/src/framework/graphics/shader/shadersources.h b/src/framework/graphics/shader/shadersources.h index e99de8bd4d..5c8bc5d2b2 100644 --- a/src/framework/graphics/shader/shadersources.h +++ b/src/framework/graphics/shader/shadersources.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * 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/src/framework/graphics/shadermanager.cpp b/src/framework/graphics/shadermanager.cpp index 4e26b43be8..bcc9c92301 100644 --- a/src/framework/graphics/shadermanager.cpp +++ b/src/framework/graphics/shadermanager.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * 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/src/framework/graphics/shadermanager.h b/src/framework/graphics/shadermanager.h index ddda80ec21..4f792638d6 100644 --- a/src/framework/graphics/shadermanager.h +++ b/src/framework/graphics/shadermanager.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -22,8 +22,8 @@ #pragma once -#include #include "declarations.h" +#include //@bindsingleton g_shaders class ShaderManager @@ -46,18 +46,18 @@ class ShaderManager void clear(); // TODO: Move these setup methods to a ClientShaderManager - void setupMapShader(const std::string_view name); - void setupItemShader(const std::string_view name); - void setupOutfitShader(const std::string_view name); - void setupMountShader(const std::string_view name); + void setupMapShader(std::string_view name); + void setupItemShader(std::string_view name); + void setupOutfitShader(std::string_view name); + void setupMountShader(std::string_view name); - void createShader(const std::string_view name, bool useFramebuffer = false); - void createFragmentShader(const std::string_view name, const std::string_view file, bool useFramebuffer = false); - void createFragmentShaderFromCode(const std::string_view name, const std::string_view code, bool useFramebuffer = false); + void createShader(std::string_view name, bool useFramebuffer = false); + void createFragmentShader(std::string_view name, std::string_view file, bool useFramebuffer = false); + void createFragmentShaderFromCode(std::string_view name, std::string_view code, bool useFramebuffer = false); - void addMultiTexture(const std::string_view name, const std::string_view file); + void addMultiTexture(std::string_view name, std::string_view file); - PainterShaderProgramPtr getShader(const std::string_view name); + PainterShaderProgramPtr getShader(std::string_view name); PainterShaderProgramPtr getShaderById(const uint8_t id) const { return id > 0 && id <= m_shadersVector.size() ? m_shadersVector[id - 1] : nullptr; } diff --git a/src/framework/graphics/shaderprogram.cpp b/src/framework/graphics/shaderprogram.cpp index e2b5befaf1..e491a9a199 100644 --- a/src/framework/graphics/shaderprogram.cpp +++ b/src/framework/graphics/shaderprogram.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -24,8 +24,10 @@ #include "graphics.h" #include -#include #include +#include + +#include "framework/core/graphicalapplication.h" uint32_t ShaderProgram::m_currentProgram = 0; @@ -79,7 +81,7 @@ bool ShaderProgram::addShaderFromSourceFile(ShaderType shaderType, const std::st void ShaderProgram::removeShader(const ShaderPtr& shader) { - const auto it = std::find(m_shaders.begin(), m_shaders.end(), shader); + const auto it = std::ranges::find(m_shaders, shader); if (it == m_shaders.end()) return; @@ -149,9 +151,9 @@ std::string ShaderProgram::log() const int ShaderProgram::getAttributeLocation(const char* name) const { return glGetAttribLocation(m_programId, name); } -void ShaderProgram::bindAttributeLocation(int location, const char* name) const { return glBindAttribLocation(m_programId, location, name); } +void ShaderProgram::bindAttributeLocation(const int location, const char* name) const { return glBindAttribLocation(m_programId, location, name); } -void ShaderProgram::bindUniformLocation(int location, const char* name) +void ShaderProgram::bindUniformLocation(const int location, const char* name) { assert(m_linked); assert(location >= 0 && location < MAX_UNIFORM_LOCATIONS); diff --git a/src/framework/graphics/shaderprogram.h b/src/framework/graphics/shaderprogram.h index d64cc8c188..ebc18f497f 100644 --- a/src/framework/graphics/shaderprogram.h +++ b/src/framework/graphics/shaderprogram.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -22,8 +22,8 @@ #pragma once -#include #include "glutil.h" +#include #include "shader.h" @@ -37,11 +37,11 @@ class ShaderProgram : public LuaObject public: ShaderProgram(); - ~ShaderProgram(); + ~ShaderProgram() override; bool addShader(const ShaderPtr& shader); - bool addShaderFromSourceCode(ShaderType shaderType, const std::string_view sourceCode); - bool addShaderFromSourceFile(ShaderType shaderType, const std::string_view sourceFile); + bool addShaderFromSourceCode(ShaderType shaderType, std::string_view sourceCode); + bool addShaderFromSourceFile(ShaderType shaderType, std::string_view sourceFile); void removeShader(const ShaderPtr& shader); void removeAllShaders(); virtual bool link(); @@ -49,8 +49,8 @@ class ShaderProgram : public LuaObject static void release(); std::string log() const; - static void disableAttributeArray(int location) { glDisableVertexAttribArray(location); } - static void enableAttributeArray(int location) { glEnableVertexAttribArray(location); } + static void disableAttributeArray(const int location) { glDisableVertexAttribArray(location); } + static void enableAttributeArray(const int location) { glEnableVertexAttribArray(location); } void disableAttributeArray(const char* name) const { glDisableVertexAttribArray(getAttributeLocation(name)); } void enableAttributeArray(const char* name) const @@ -60,46 +60,46 @@ class ShaderProgram : public LuaObject void bindAttributeLocation(int location, const char* name) const; void bindUniformLocation(int location, const char* name); - void setAttributeArray(int location, const float* values, int size, int stride = 0) { glVertexAttribPointer(location, size, GL_FLOAT, GL_FALSE, stride, values); } - void setAttributeValue(int location, float value) { glVertexAttrib1f(location, value); } - void setAttributeValue(int location, float x, float y) { glVertexAttrib2f(location, x, y); } - void setAttributeValue(int location, float x, float y, float z) { glVertexAttrib3f(location, x, y, z); } - void setAttributeArray(const char* name, const float* values, int size, int stride = 0) const + void setAttributeArray(const int location, const float* values, const int size, const int stride = 0) { glVertexAttribPointer(location, size, GL_FLOAT, GL_FALSE, stride, values); } + void setAttributeValue(const int location, const float value) { glVertexAttrib1f(location, value); } + void setAttributeValue(const int location, const float x, const float y) { glVertexAttrib2f(location, x, y); } + void setAttributeValue(const int location, const float x, const float y, const float z) { glVertexAttrib3f(location, x, y, z); } + void setAttributeArray(const char* name, const float* values, const int size, const int stride = 0) const { glVertexAttribPointer(getAttributeLocation(name), size, GL_FLOAT, GL_FALSE, stride, values); } - void setAttributeValue(const char* name, float value) const + void setAttributeValue(const char* name, const float value) const { glVertexAttrib1f(getAttributeLocation(name), value); } - void setAttributeValue(const char* name, float x, float y) const + void setAttributeValue(const char* name, const float x, const float y) const { glVertexAttrib2f(getAttributeLocation(name), x, y); } - void setAttributeValue(const char* name, float x, float y, float z) const + void setAttributeValue(const char* name, const float x, const float y, const float z) const { glVertexAttrib3f(getAttributeLocation(name), x, y, z); } - void setUniformValue(int location, const Color& color) const + void setUniformValue(const int location, const Color& color) const { glUniform4f(m_uniformLocations[location], color.rF(), color.gF(), color.bF(), color.aF()); } - void setUniformValue(int location, int value) const + void setUniformValue(const int location, const int value) const { glUniform1i(m_uniformLocations[location], value); } - void setUniformValue(int location, float value) const + void setUniformValue(const int location, const float value) const { glUniform1f(m_uniformLocations[location], value); } - void setUniformValue(int location, float x, float y) const + void setUniformValue(const int location, const float x, const float y) const { glUniform2f(m_uniformLocations[location], x, y); } - void setUniformValue(int location, float x, float y, float z) const + void setUniformValue(const int location, const float x, const float y, const float z) const { glUniform3f(m_uniformLocations[location], x, y, z); } - void setUniformValue(int location, float x, float y, float z, float w) const + void setUniformValue(const int location, const float x, const float y, const float z, const float w) const { glUniform4f(m_uniformLocations[location], x, y, z, w); } - void setUniformValue(int location, const Matrix2& mat) const + void setUniformValue(const int location, const Matrix2& mat) const { glUniformMatrix2fv(m_uniformLocations[location], 1, GL_FALSE, mat.data()); } - void setUniformValue(int location, const Matrix3& mat) const + void setUniformValue(const int location, const Matrix3& mat) const { glUniformMatrix3fv(m_uniformLocations[location], 1, GL_FALSE, mat.data()); } void setUniformValue(const char* name, const Color& color) const { glUniform4f(glGetUniformLocation(m_programId, name), color.rF(), color.gF(), color.bF(), color.aF()); } - void setUniformValue(const char* name, int value) const + void setUniformValue(const char* name, const int value) const { glUniform1i(glGetUniformLocation(m_programId, name), value); } - void setUniformValue(const char* name, float value) const + void setUniformValue(const char* name, const float value) const { glUniform1f(glGetUniformLocation(m_programId, name), value); } - void setUniformValue(const char* name, float x, float y) const + void setUniformValue(const char* name, const float x, const float y) const { glUniform2f(glGetUniformLocation(m_programId, name), x, y); } - void setUniformValue(const char* name, float x, float y, float z) const + void setUniformValue(const char* name, const float x, const float y, const float z) const { glUniform3f(glGetUniformLocation(m_programId, name), x, y, z); } - void setUniformValue(const char* name, float x, float y, float z, float w) const + void setUniformValue(const char* name, const float x, const float y, const float z, const float w) const { glUniform4f(glGetUniformLocation(m_programId, name), x, y, z, w); } void setUniformValue(const char* name, const Matrix2& mat) const { glUniformMatrix2fv(glGetUniformLocation(m_programId, name), 1, GL_FALSE, mat.data()); } diff --git a/src/framework/graphics/texture.cpp b/src/framework/graphics/texture.cpp index a418b02775..797438b4d7 100644 --- a/src/framework/graphics/texture.cpp +++ b/src/framework/graphics/texture.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -27,7 +27,8 @@ #include #include -#include "framework/stdext/math.h" + +#include "framework/core/graphicalapplication.h" // UINT16_MAX = just to avoid conflicts with GL generated ID. static std::atomic_uint32_t UID(UINT16_MAX); @@ -46,7 +47,7 @@ Texture::Texture(const Size& size) : m_uniqueId(++UID) setupFilters(); } -Texture::Texture(const ImagePtr& image, bool buildMipmaps, bool compress) : m_uniqueId(++UID) +Texture::Texture(const ImagePtr& image, const bool buildMipmaps, const bool compress) : m_uniqueId(++UID) { generateHash(); @@ -62,7 +63,7 @@ Texture::~Texture() assert(!g_app.isTerminated()); #endif if (g_graphics.ok() && m_id != 0) { - g_mainDispatcher.addEvent([id = m_id]() { + g_mainDispatcher.addEvent([id = m_id] { glDeleteTextures(1, &id); }); } @@ -72,7 +73,7 @@ Texture* Texture::create() { if (m_image) { createTexture(); - uploadPixels(m_image, getProp(Prop::buildMipmaps), getProp(Prop::compress)); + uploadPixels(m_image, getProp(buildMipmaps), getProp(compress)); m_image = nullptr; } @@ -81,11 +82,11 @@ Texture* Texture::create() void Texture::updateImage(const ImagePtr& image) { m_image = image; setupSize(image->getSize()); } -void Texture::updatePixels(uint8_t* pixels, int level, int channels, bool compress) { +void Texture::updatePixels(uint8_t* pixels, const int level, const int channels, const bool compress) { bind(); setupPixels(level, m_size, pixels, channels, compress); } -void Texture::uploadPixels(const ImagePtr& image, bool buildMipmaps, bool compress) +void Texture::uploadPixels(const ImagePtr& image, const bool buildMipmaps, const bool compress) { if (!setupSize(image->getSize())) return; @@ -106,7 +107,7 @@ void Texture::bind() { if (m_id) glBindTexture(GL_TEXTURE_2D, m_id); } void Texture::buildHardwareMipmaps() { - if (getProp(Prop::hasMipMaps)) + if (getProp(hasMipMaps)) return; #ifndef OPENGL_ES @@ -114,14 +115,14 @@ void Texture::buildHardwareMipmaps() return; #endif - setProp(Prop::hasMipMaps, true); + setProp(hasMipMaps, true); bind(); setupFilters(); glGenerateMipmap(GL_TEXTURE_2D); } -void Texture::setSmooth(bool smooth) +void Texture::setSmooth(const bool smooth) { if (smooth == getProp(Prop::smooth)) return; @@ -133,7 +134,7 @@ void Texture::setSmooth(bool smooth) setupFilters(); } -void Texture::setRepeat(bool repeat) +void Texture::setRepeat(const bool repeat) { if (getProp(Prop::repeat) == repeat) return; @@ -145,7 +146,7 @@ void Texture::setRepeat(bool repeat) setupWrap(); } -void Texture::setUpsideDown(bool upsideDown) +void Texture::setUpsideDown(const bool upsideDown) { if (getProp(Prop::upsideDown) == upsideDown) return; @@ -188,7 +189,7 @@ bool Texture::setupSize(const Size& size) void Texture::setupWrap() const { - const GLint texParam = getProp(Prop::repeat) ? GL_REPEAT : GL_CLAMP_TO_EDGE; + const GLint texParam = getProp(repeat) ? GL_REPEAT : GL_CLAMP_TO_EDGE; glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, texParam); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, texParam); } @@ -199,11 +200,11 @@ void Texture::setupFilters() const GLenum minFilter; GLenum magFilter; - if (getProp(Prop::smooth)) { - minFilter = getProp(Prop::hasMipMaps) ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR; + if (getProp(smooth)) { + minFilter = getProp(hasMipMaps) ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR; magFilter = GL_LINEAR; } else { - minFilter = getProp(Prop::hasMipMaps) ? GL_NEAREST_MIPMAP_NEAREST : GL_NEAREST; + minFilter = getProp(hasMipMaps) ? GL_NEAREST_MIPMAP_NEAREST : GL_NEAREST; magFilter = GL_NEAREST; } glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, minFilter); @@ -233,7 +234,7 @@ void Texture::setupTranformMatrix() static Matrix3 MATRIX256x512_CACHED = toMatrix(SIZE256x512); static Matrix3 MATRIX512x1024_CACHED = toMatrix(SIZE512x1024); - if (getProp(Prop::upsideDown)) { + if (getProp(upsideDown)) { m_transformMatrix = { 1.0f / m_size.width(), 0.0f, 0.0f, 0.0f, -1.0f / m_size.height(), 0.0f, 0.0f, m_size.height() / static_cast(m_size.height()), 1.0f }; @@ -254,7 +255,7 @@ void Texture::setupTranformMatrix() } } -void Texture::setupPixels(int level, const Size& size, uint8_t* pixels, int channels, bool compress) const +void Texture::setupPixels(const int level, const Size& size, const uint8_t* pixels, const int channels, const bool compress) const { GLenum format = 0; switch (channels) { diff --git a/src/framework/graphics/texture.h b/src/framework/graphics/texture.h index 9b7306a11c..3007e69c16 100644 --- a/src/framework/graphics/texture.h +++ b/src/framework/graphics/texture.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -43,7 +43,7 @@ class Texture virtual void setSmooth(bool smooth); virtual void setRepeat(bool repeat); void setUpsideDown(bool upsideDown); - void setTime(ticks_t time) { m_time = time; } + void setTime(const ticks_t time) { m_time = time; } const Size& getSize() const { return m_size; } const Matrix3& getTransformMatrix() const { return m_transformMatrix; } @@ -57,8 +57,8 @@ class Texture int getHeight() const { return m_size.height(); } bool isEmpty() const { return m_id == 0; } - bool hasRepeat() const { return getProp(Prop::repeat); } - bool hasMipmaps() const { return getProp(Prop::hasMipMaps); } + bool hasRepeat() const { return getProp(repeat); } + bool hasMipmaps() const { return getProp(hasMipMaps); } virtual bool isAnimatedTexture() const { return false; } bool setupSize(const Size& size); @@ -68,7 +68,7 @@ class Texture void setupFilters() const; void createTexture(); void setupTranformMatrix(); - void setupPixels(int level, const Size& size, uint8_t* pixels, int channels = 4, bool compress = false) const; + void setupPixels(int level, const Size& size, const uint8_t* pixels, int channels = 4, bool compress = false) const; void generateHash() { m_hash = stdext::hash_int(m_id > 0 ? m_id : m_uniqueId); } const uint32_t m_uniqueId; @@ -95,8 +95,8 @@ class Texture }; uint16_t m_props{ 0 }; - void setProp(Prop prop, bool v) { if (v) m_props |= prop; else m_props &= ~prop; } - bool getProp(Prop prop) const { return m_props & prop; }; + void setProp(const Prop prop, const bool v) { if (v) m_props |= prop; else m_props &= ~prop; } + bool getProp(const Prop prop) const { return m_props & prop; }; static const Matrix3 toMatrix(const Size& size) { return { 1.0f / size.width(), 0.0f, 0.0f, diff --git a/src/framework/graphics/texturemanager.cpp b/src/framework/graphics/texturemanager.cpp index 37248dca2f..6e8f1e6b5b 100644 --- a/src/framework/graphics/texturemanager.cpp +++ b/src/framework/graphics/texturemanager.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -93,7 +93,7 @@ void TextureManager::liveReload() }, 1000); } -TexturePtr TextureManager::getTexture(const std::string& fileName, bool smooth) +TexturePtr TextureManager::getTexture(const std::string& fileName, const bool smooth) { TexturePtr texture; diff --git a/src/framework/graphics/texturemanager.h b/src/framework/graphics/texturemanager.h index 14f0f90e15..751ce6b91c 100644 --- a/src/framework/graphics/texturemanager.h +++ b/src/framework/graphics/texturemanager.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -22,8 +22,8 @@ #pragma once -#include #include "texture.h" +#include class TextureManager { @@ -35,7 +35,7 @@ class TextureManager void clearCache(); void liveReload(); - void preload(const std::string& fileName, bool smooth = true) { getTexture(fileName, smooth); } + void preload(const std::string& fileName, const bool smooth = true) { getTexture(fileName, smooth); } TexturePtr getTexture(const std::string& fileName, bool smooth = true); const TexturePtr& getEmptyTexture() { return m_emptyTexture; } TexturePtr loadTexture(std::stringstream& file); diff --git a/src/framework/graphics/vertexarray.h b/src/framework/graphics/vertexarray.h index 6c8fc9a812..a22cb94410 100644 --- a/src/framework/graphics/vertexarray.h +++ b/src/framework/graphics/vertexarray.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -46,7 +46,7 @@ class VertexArray c.x, c.y }; - size_t size = sizeof(arr) / sizeof(int); + const size_t size = sizeof(arr) / sizeof(int); m_buffer.insert(m_buffer.end(), &arr[0], &arr[size]); } @@ -66,16 +66,16 @@ class VertexArray right, bottom }; - size_t size = sizeof(arr) / sizeof(float); + const size_t size = sizeof(arr) / sizeof(float); m_buffer.insert(m_buffer.end(), &arr[0], &arr[size]); } void addRect(const RectF& rect) { - float top = rect.top(); - float right = rect.right() + 1.f; - float bottom = rect.bottom() + 1.f; - float left = rect.left(); + const float top = rect.top(); + const float right = rect.right() + 1.f; + const float bottom = rect.bottom() + 1.f; + const float left = rect.left(); float arr[] = { left, top, @@ -86,7 +86,7 @@ class VertexArray right, bottom }; - size_t size = sizeof(arr) / sizeof(float); + const size_t size = sizeof(arr) / sizeof(float); m_buffer.insert(m_buffer.end(), &arr[0], &arr[size]); } @@ -106,7 +106,7 @@ class VertexArray right, bottom }; - size_t size = sizeof(arr) / sizeof(float); + const size_t size = sizeof(arr) / sizeof(float); m_buffer.insert(m_buffer.end(), &arr[0], &arr[size]); } @@ -124,7 +124,7 @@ class VertexArray right, top, }; - size_t size = sizeof(arr) / sizeof(float); + const size_t size = sizeof(arr) / sizeof(float); m_buffer.insert(m_buffer.end(), &arr[0], &arr[size]); } @@ -144,7 +144,7 @@ class VertexArray right, top }; - size_t size = sizeof(arr) / sizeof(float); + const size_t size = sizeof(arr) / sizeof(float); m_buffer.insert(m_buffer.end(), &arr[0], &arr[size]); } diff --git a/src/framework/input/mouse.cpp b/src/framework/input/mouse.cpp index 2ae26af9a4..aa55bcf0e8 100644 --- a/src/framework/input/mouse.cpp +++ b/src/framework/input/mouse.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -102,7 +102,7 @@ bool Mouse::isCursorChanged() return !m_cursorStack.empty(); } -bool Mouse::isPressed(Fw::MouseButton mouseButton) +bool Mouse::isPressed(const Fw::MouseButton mouseButton) { return g_window.isMouseButtonPressed(mouseButton); } diff --git a/src/framework/input/mouse.h b/src/framework/input/mouse.h index 901f155028..6bee06d4d0 100644 --- a/src/framework/input/mouse.h +++ b/src/framework/input/mouse.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * 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/src/framework/luaengine/declarations.h b/src/framework/luaengine/declarations.h index 0ec1d2a01a..5b8304f240 100644 --- a/src/framework/luaengine/declarations.h +++ b/src/framework/luaengine/declarations.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * 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/src/framework/luaengine/luabinder.h b/src/framework/luaengine/luabinder.h index fd62733411..1a4a5c67e9 100644 --- a/src/framework/luaengine/luabinder.h +++ b/src/framework/luaengine/luabinder.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -25,8 +25,8 @@ // this file is and must be included only from luainterface.h #include "luaexception.h" -#include #include +#include /// This namespace contains some dirty metaprogamming that uses a lot of C++0x features /// The purpose here is to create templates that can bind any function from C++ @@ -58,8 +58,9 @@ namespace luabinder /// C++ function caller that can push results to lua template - std::enable_if_t, int> + int call_fun_and_push_result(const F& f, LuaInterface* lua, const Args&... args) + requires (!std::is_void_v) { Ret ret = f(args...); int numRets = lua->polymorphicPush(ret); @@ -68,8 +69,9 @@ namespace luabinder /// C++ void function caller template - std::enable_if_t, int> + int call_fun_and_push_result(const F& f, LuaInterface* /*lua*/, const Args&... args) + requires (std::is_void_v) { f(args...); return 0; @@ -147,7 +149,8 @@ namespace luabinder }; template - std::enable_if_t, LuaCppFunction> bind_fun(const Lambda& f) + LuaCppFunction bind_fun(const Lambda& f) + requires (std::is_constructible_v) { using F = decltype(&Lambda::operator()); return bind_lambda_fun::call(f); diff --git a/src/framework/luaengine/luaexception.cpp b/src/framework/luaengine/luaexception.cpp index 52408d1451..4475ba9170 100644 --- a/src/framework/luaengine/luaexception.cpp +++ b/src/framework/luaengine/luaexception.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -23,13 +23,13 @@ #include "luaexception.h" #include "luainterface.h" -LuaException::LuaException(const std::string_view error, int traceLevel) +LuaException::LuaException(const std::string_view error, const int traceLevel) { g_lua.clearStack(); // on every exception, clear lua stack generateLuaErrorMessage(error, traceLevel); } -void LuaException::generateLuaErrorMessage(const std::string_view error, int traceLevel) +void LuaException::generateLuaErrorMessage(const std::string_view error, const int traceLevel) { // append trace level to error message if (traceLevel >= 0) @@ -38,7 +38,7 @@ void LuaException::generateLuaErrorMessage(const std::string_view error, int tra m_what = stdext::format("LUA ERROR:\n%s", error); } -LuaBadNumberOfArgumentsException::LuaBadNumberOfArgumentsException(int expected, int got) +LuaBadNumberOfArgumentsException::LuaBadNumberOfArgumentsException(const int expected, const int got) { std::string error = "attempt to call a function with wrong number of arguments"; if (expected >= 0 && got >= 0) diff --git a/src/framework/luaengine/luaexception.h b/src/framework/luaengine/luaexception.h index 0bca922f30..23d70f648e 100644 --- a/src/framework/luaengine/luaexception.h +++ b/src/framework/luaengine/luaexception.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -27,10 +27,10 @@ class LuaException : public stdext::exception { public: - LuaException(const std::string_view error, int traceLevel = -1); + LuaException(std::string_view error, int traceLevel = -1); ~LuaException() noexcept override = default; - void generateLuaErrorMessage(const std::string_view error, int traceLevel); + void generateLuaErrorMessage(std::string_view error, int traceLevel); const char* what() const noexcept override { return m_what.data(); } @@ -40,14 +40,14 @@ class LuaException : public stdext::exception std::string m_what; }; -class LuaBadNumberOfArgumentsException : public LuaException +class LuaBadNumberOfArgumentsException final : public LuaException { public: LuaBadNumberOfArgumentsException(int expected = -1, int got = -1); }; -class LuaBadValueCastException : public LuaException +class LuaBadValueCastException final : public LuaException { public: - LuaBadValueCastException(const std::string_view luaTypeName, const std::string_view cppTypeName); + LuaBadValueCastException(std::string_view luaTypeName, std::string_view cppTypeName); }; diff --git a/src/framework/luaengine/luainterface.cpp b/src/framework/luaengine/luainterface.cpp index 31a271d98e..184b36c850 100644 --- a/src/framework/luaengine/luainterface.cpp +++ b/src/framework/luaengine/luainterface.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -23,6 +23,10 @@ #include "luainterface.h" #include "luaobject.h" +#ifdef __EMSCRIPTEN__ +#include +#endif + #include LuaInterface g_lua; @@ -360,7 +364,7 @@ void LuaInterface::evaluateExpression(const std::string_view expression, const s pushNil(); } -std::string LuaInterface::traceback(const std::string_view errorMessage, int level) +std::string LuaInterface::traceback(const std::string_view errorMessage, const int level) { // gets debug.traceback getGlobal("debug"); @@ -418,7 +422,7 @@ std::string LuaInterface::getCurrentSourcePath(int level) return path; } -int LuaInterface::safeCall(int numArgs, int numRets) +int LuaInterface::safeCall(const int numArgs, const int numRets) { assert(hasIndex(-numArgs - 1)); @@ -457,7 +461,7 @@ int LuaInterface::safeCall(int numArgs, int numRets) return rets; } -int LuaInterface::signalCall(int numArgs, int numRets) +int LuaInterface::signalCall(const int numArgs, const int numRets) { int rets = 0; const int funcIndex = -numArgs - 1; @@ -656,7 +660,7 @@ void LuaInterface::registerTable(lua_State* L_STATE, const std::string& tableNam lua_setglobal(L_STATE, tableName.c_str()); } -void LuaInterface::registerMethod(lua_State* L_STATE, const std::string& globalName, const std::string& methodName, lua_CFunction func) +void LuaInterface::registerMethod(lua_State* L_STATE, const std::string& globalName, const std::string& methodName, const lua_CFunction func) { // globalName.methodName = func lua_getglobal(L_STATE, globalName.c_str()); @@ -734,6 +738,10 @@ void LuaInterface::createLuaState() // load lua standard libraries luaL_openlibs(L); +#ifdef __EMSCRIPTEN__ + luaopen_bit(L); +#endif + #ifndef LUAJIT_VERSION // load Bit lib for bitwise operations registerTable(L, "Bit"); @@ -806,13 +814,13 @@ void LuaInterface::loadBuffer(const std::string_view buffer, const std::string_v throw LuaException(popString(), 0); } -int LuaInterface::pcall(int numArgs, int numRets, int errorFuncIndex) +int LuaInterface::pcall(const int numArgs, const int numRets, const int errorFuncIndex) { assert(hasIndex(-numArgs - 1)); return lua_pcall(L, numArgs, numRets, errorFuncIndex); } -void LuaInterface::call(int numArgs, int numRets) +void LuaInterface::call(const int numArgs, const int numRets) { assert(hasIndex(-numArgs - 1)); lua_call(L, numArgs, numRets); @@ -853,13 +861,13 @@ int LuaInterface::weakRef() return id; } -void LuaInterface::unref(int ref) const +void LuaInterface::unref(const int ref) const { if (ref >= 0 && L != nullptr) luaL_unref(L, LUA_REGISTRYINDEX, ref); } -const char* LuaInterface::typeName(int index) +const char* LuaInterface::typeName(const int index) { assert(hasIndex(index)); const int type = lua_type(L, index); @@ -886,25 +894,25 @@ std::string LuaInterface::functionSourcePath() const return path; } -void LuaInterface::insert(int index) +void LuaInterface::insert(const int index) { assert(hasIndex(index)); lua_insert(L, index); } -void LuaInterface::remove(int index) +void LuaInterface::remove(const int index) { assert(hasIndex(index)); lua_remove(L, index); } -bool LuaInterface::next(int index) +bool LuaInterface::next(const int index) { assert(hasIndex(index)); return lua_next(L, index); } -void LuaInterface::getStackFunction(int level) +void LuaInterface::getStackFunction(const int level) { lua_Debug ar; if (lua_getstack(L, level, &ar) == 1) @@ -913,12 +921,12 @@ void LuaInterface::getStackFunction(int level) pushNil(); } -void LuaInterface::getRef(int ref) const +void LuaInterface::getRef(const int ref) const { lua_rawgeti(L, LUA_REGISTRYINDEX, ref); } -void LuaInterface::getWeakRef(int weakRef) +void LuaInterface::getWeakRef(const int weakRef) { // pushes weak_table[weakRef] getRef(m_weakTableRef); @@ -926,7 +934,7 @@ void LuaInterface::getWeakRef(int weakRef) remove(-2); } -void LuaInterface::setGlobalEnvironment(int env) +void LuaInterface::setGlobalEnvironment(const int env) { pushThread(); getRef(env); @@ -935,26 +943,26 @@ void LuaInterface::setGlobalEnvironment(int env) pop(); } -void LuaInterface::setMetatable(int index) +void LuaInterface::setMetatable(const int index) { assert(hasIndex(index)); lua_setmetatable(L, index); } -void LuaInterface::getMetatable(int index) +void LuaInterface::getMetatable(const int index) { assert(hasIndex(index)); lua_getmetatable(L, index); } -void LuaInterface::getField(const std::string_view key, int index) +void LuaInterface::getField(const std::string_view key, const int index) { assert(hasIndex(index)); assert(isUserdata(index) || isTable(index)); lua_getfield(L, index, key.data()); } -void LuaInterface::setField(const std::string_view key, int index) +void LuaInterface::setField(const std::string_view key, const int index) { assert(hasIndex(index)); assert(isUserdata(index) || isTable(index)); @@ -982,19 +990,19 @@ void LuaInterface::setEnv(int index) #endif } -void LuaInterface::getTable(int index) +void LuaInterface::getTable(const int index) { assert(hasIndex(index)); lua_gettable(L, index); } -void LuaInterface::setTable(int index) +void LuaInterface::setTable(const int index) { assert(hasIndex(index)); lua_settable(L, index); } -void LuaInterface::clearTable(int index) +void LuaInterface::clearTable(const int index) { assert(hasIndex(index) && isTable(index)); @@ -1037,25 +1045,25 @@ void LuaInterface::setGlobal(const std::string_view key) lua_setglobal(L, key.data()); } -void LuaInterface::rawGet(int index) +void LuaInterface::rawGet(const int index) { assert(hasIndex(index)); lua_rawget(L, index); } -void LuaInterface::rawGeti(int n, int index) +void LuaInterface::rawGeti(const int n, const int index) { assert(hasIndex(index)); lua_rawgeti(L, index, n); } -void LuaInterface::rawSet(int index) +void LuaInterface::rawSet(const int index) { assert(hasIndex(index)); lua_rawset(L, index); } -void LuaInterface::rawSeti(int n, int index) +void LuaInterface::rawSeti(const int n, const int index) { assert(hasIndex(index)); lua_rawseti(L, index, n); @@ -1066,17 +1074,17 @@ void LuaInterface::newTable() const lua_newtable(L); } -void LuaInterface::createTable(int narr, int nrec) const +void LuaInterface::createTable(const int narr, const int nrec) const { lua_createtable(L, narr, nrec); } -void* LuaInterface::newUserdata(int size) const +void* LuaInterface::newUserdata(const int size) const { return lua_newuserdata(L, size); } -void LuaInterface::pop(int n) +void LuaInterface::pop(const int n) { if (n > 0) { assert(hasIndex(-n)); @@ -1143,19 +1151,19 @@ void LuaInterface::pushNil() checkStack(); } -void LuaInterface::pushInteger(long v) +void LuaInterface::pushInteger(const long v) { lua_pushinteger(L, v); checkStack(); } -void LuaInterface::pushNumber(double v) +void LuaInterface::pushNumber(const double v) { lua_pushnumber(L, v); checkStack(); } -void LuaInterface::pushBoolean(bool v) +void LuaInterface::pushBoolean(const bool v) { lua_pushboolean(L, v); checkStack(); @@ -1191,7 +1199,7 @@ void LuaInterface::pushObject(const LuaObjectPtr& obj) setMetatable(); } -void LuaInterface::pushCFunction(LuaCFunction func, int n) +void LuaInterface::pushCFunction(const LuaCFunction func, const int n) { lua_pushcclosure(L, func, n); checkStack(); @@ -1213,87 +1221,87 @@ void LuaInterface::pushCppFunction(const LuaCppFunction& func) pushCFunction(&LuaInterface::luaCppFunctionCallback, 1); } -void LuaInterface::pushValue(int index) +void LuaInterface::pushValue(const int index) { assert(hasIndex(index)); lua_pushvalue(L, index); checkStack(); } -bool LuaInterface::isNil(int index) +bool LuaInterface::isNil(const int index) { assert(hasIndex(index)); return lua_isnil(L, index); } -bool LuaInterface::isBoolean(int index) +bool LuaInterface::isBoolean(const int index) { assert(hasIndex(index)); return lua_isboolean(L, index); } -bool LuaInterface::isNumber(int index) +bool LuaInterface::isNumber(const int index) { assert(hasIndex(index)); return lua_isnumber(L, index); } -bool LuaInterface::isString(int index) +bool LuaInterface::isString(const int index) { assert(hasIndex(index)); return lua_isstring(L, index); } -bool LuaInterface::isTable(int index) +bool LuaInterface::isTable(const int index) { assert(hasIndex(index)); return lua_istable(L, index); } -bool LuaInterface::isFunction(int index) +bool LuaInterface::isFunction(const int index) { assert(hasIndex(index)); return lua_isfunction(L, index); } -bool LuaInterface::isCFunction(int index) +bool LuaInterface::isCFunction(const int index) { assert(hasIndex(index)); return lua_iscfunction(L, index); } -bool LuaInterface::isUserdata(int index) +bool LuaInterface::isUserdata(const int index) { assert(hasIndex(index)); return lua_isuserdata(L, index); } -bool LuaInterface::toBoolean(int index) +bool LuaInterface::toBoolean(const int index) { assert(hasIndex(index)); return static_cast(lua_toboolean(L, index)); } -int LuaInterface::toInteger(int index) +int LuaInterface::toInteger(const int index) { assert(hasIndex(index)); return lua_tointeger(L, index); } -double LuaInterface::toNumber(int index) +double LuaInterface::toNumber(const int index) { assert(hasIndex(index)); return lua_tonumber(L, index); } -std::string_view LuaInterface::toVString(int index) +std::string_view LuaInterface::toVString(const int index) { assert(hasIndex(index)); const char* value = lua_tostring(L, index); return value != nullptr ? value : ""sv; } -std::string LuaInterface::toString(int index) +std::string LuaInterface::toString(const int index) { assert(hasIndex(index)); std::string str; @@ -1304,13 +1312,13 @@ std::string LuaInterface::toString(int index) return str; } -void* LuaInterface::toUserdata(int index) +void* LuaInterface::toUserdata(const int index) { assert(hasIndex(index)); return lua_touserdata(L, index); } -LuaObjectPtr LuaInterface::toObject(int index) +LuaObjectPtr LuaInterface::toObject(const int index) { assert(hasIndex(index)); if (isUserdata(index)) { @@ -1326,7 +1334,7 @@ int LuaInterface::getTop() const return lua_gettop(L); } -std::string LuaInterface::getSource(int level) +std::string LuaInterface::getSource(const int level) { lua_Debug ar; ar.short_src[0] = 0; @@ -1337,7 +1345,7 @@ std::string LuaInterface::getSource(int level) return std::string(ar.short_src) + ":" + std::to_string(ar.currentline); } -void LuaInterface::loadFiles(const std::string& directory, bool recursive, const std::string& contains) +void LuaInterface::loadFiles(const std::string& directory, const bool recursive, const std::string& contains) { for (const std::string& fileName : g_resources.listDirectoryFiles(directory)) { std::string fullPath = directory.data() + "/"s + fileName; diff --git a/src/framework/luaengine/luainterface.h b/src/framework/luaengine/luainterface.h index 43bdd061d0..9112908d1d 100644 --- a/src/framework/luaengine/luainterface.h +++ b/src/framework/luaengine/luainterface.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -30,6 +30,13 @@ #include #elif __has_include() #include +#elif defined(__EMSCRIPTEN__) +extern "C" { +#include +#include +#include +} +#define LUAJIT_VERSION = "LUA 5.1" #else #error "Cannot detect luajit library" #endif @@ -62,23 +69,23 @@ class LuaInterface void terminate(); // functions that will register all script stuff in lua global environment - void registerSingletonClass(const std::string_view className); - void registerClass(const std::string_view className, const std::string_view baseClass = "LuaObject"); + void registerSingletonClass(std::string_view className); + void registerClass(std::string_view className, std::string_view baseClass = "LuaObject"); - void registerClassStaticFunction(const std::string_view className, - const std::string_view functionName, + void registerClassStaticFunction(std::string_view className, + std::string_view functionName, const LuaCppFunction& function); - void registerClassMemberFunction(const std::string_view className, - const std::string_view functionName, + void registerClassMemberFunction(std::string_view className, + std::string_view functionName, const LuaCppFunction& function); - void registerClassMemberField(const std::string_view className, - const std::string_view field, + void registerClassMemberField(std::string_view className, + std::string_view field, const LuaCppFunction& getFunction, const LuaCppFunction& setFunction); - void registerGlobalFunction(const std::string_view functionName, + void registerGlobalFunction(std::string_view functionName, const LuaCppFunction& function); // register shortcuts using templates @@ -110,37 +117,37 @@ class LuaInterface // methods for binding functions template - void bindSingletonFunction(const std::string_view functionName, F C::* function, C* instance); + void bindSingletonFunction(std::string_view functionName, F C::* function, C* instance); template - void bindSingletonFunction(const std::string_view className, const std::string_view functionName, F C::* function, C* instance); + void bindSingletonFunction(std::string_view className, std::string_view functionName, F C::* function, C* instance); template - void bindClassStaticFunction(const std::string_view functionName, const F& function); + void bindClassStaticFunction(std::string_view functionName, const F& function); template - void bindClassStaticFunction(const std::string_view className, const std::string_view functionName, const F& function); + void bindClassStaticFunction(std::string_view className, std::string_view functionName, const F& function); template - void bindClassMemberFunction(const std::string_view functionName, F FC::* function); + void bindClassMemberFunction(std::string_view functionName, F FC::* function); template - void bindClassMemberFunction(const std::string_view className, const std::string_view functionName, F FC::* function); + void bindClassMemberFunction(std::string_view className, std::string_view functionName, F FC::* function); template - void bindClassMemberField(const std::string_view fieldName, F1 FC::* getFunction, F2 FC::* setFunction); + void bindClassMemberField(std::string_view fieldName, F1 FC::* getFunction, F2 FC::* setFunction); template - void bindClassMemberField(const std::string_view className, const std::string_view fieldName, F1 FC::* getFunction, F2 FC::* setFunction); + void bindClassMemberField(std::string_view className, std::string_view fieldName, F1 FC::* getFunction, F2 FC::* setFunction); template - void bindClassMemberGetField(const std::string_view fieldName, F FC::* getFunction); + void bindClassMemberGetField(std::string_view fieldName, F FC::* getFunction); template - void bindClassMemberGetField(const std::string_view className, const std::string_view fieldName, F FC::* getFunction); + void bindClassMemberGetField(std::string_view className, std::string_view fieldName, F FC::* getFunction); template - void bindClassMemberSetField(const std::string_view fieldName, F FC::* setFunction); + void bindClassMemberSetField(std::string_view fieldName, F FC::* setFunction); template - void bindClassMemberSetField(const std::string_view className, const std::string_view fieldName, F FC::* setFunction); + void bindClassMemberSetField(std::string_view className, std::string_view fieldName, F FC::* setFunction); template - void bindGlobalFunction(const std::string_view functionName, const F& function); + void bindGlobalFunction(std::string_view functionName, const F& function); private: /// Metamethod that will retrieve fields values (that include functions) from the object when using '.' or ':' @@ -165,7 +172,7 @@ class LuaInterface /// Loads and runs the script from buffer /// @exception LuaException is thrown on any lua error - void runBuffer(const std::string_view buffer, const std::string_view source); + void runBuffer(std::string_view buffer, std::string_view source); /// Loads a script file and pushes it's main function onto stack, /// @exception LuaException is thrown on any lua error @@ -173,22 +180,22 @@ class LuaInterface /// Loads a function from buffer and pushes it onto stack, /// @exception LuaException is thrown on any lua error - void loadFunction(const std::string_view buffer, const std::string_view source = "lua function buffer"); + void loadFunction(std::string_view buffer, std::string_view source = "lua function buffer"); /// Evaluates a lua expression and pushes the result value onto the stack /// @exception LuaException is thrown on any lua error - void evaluateExpression(const std::string_view expression, const std::string_view source = "lua expression"); + void evaluateExpression(std::string_view expression, std::string_view source = "lua expression"); /// Generates a traceback message for the current call stack /// @param errorMessage is an additional error message /// @param level is the level of the traceback, 0 means trace from calling function /// @return the generated traceback message - std::string traceback(const std::string_view errorMessage = "", int level = 0); + std::string traceback(std::string_view errorMessage = "", int level = 0); /// Throw a lua error if inside a lua call or generates an C++ stdext::exception /// @param message is the error message wich will be displayed before the error traceback /// @exception stdext::exception is thrown with the error message if the error is not captured by lua - void throwError(const std::string_view message); + void throwError(std::string_view message); /// Searches for the source of the current running function std::string getCurrentSourcePath(int level = 0); @@ -213,13 +220,13 @@ class LuaInterface int newSandboxEnv(); template - int luaCallGlobalField(const std::string_view global, const std::string_view field, const T&... args); + int luaCallGlobalField(std::string_view global, std::string_view field, const T&... args); template - void callGlobalField(const std::string_view global, const std::string_view field, const T&... args); + void callGlobalField(std::string_view global, std::string_view field, const T&... args); template - R callGlobalField(const std::string_view global, const std::string_view field, const T&... args); + R callGlobalField(std::string_view global, std::string_view field, const T&... args); bool isInCppCallback() const { return m_cppCallbackDepth != 0; } @@ -258,7 +265,7 @@ class LuaInterface void collectGarbage() const; - void loadBuffer(const std::string_view buffer, const std::string_view source); + void loadBuffer(std::string_view buffer, std::string_view source); int pcall(int numArgs = 0, int numRets = 0, int errorFuncIndex = 0); void call(int numArgs = 0, int numRets = 0); @@ -289,8 +296,8 @@ class LuaInterface void setMetatable(int index = -2); void getMetatable(int index = -1); - void getField(const std::string_view key, int index = -1); - void setField(const std::string_view key, int index = -2); + void getField(std::string_view key, int index = -1); + void setField(std::string_view key, int index = -2); void getTable(int index = -2); void setTable(int index = -3); @@ -299,9 +306,9 @@ class LuaInterface void getEnv(int index = -1); void setEnv(int index = -2); - void getGlobal(const std::string_view key) const; - void getGlobalField(const std::string_view globalKey, const std::string_view fieldKey); - void setGlobal(const std::string_view key); + void getGlobal(std::string_view key) const; + void getGlobalField(std::string_view globalKey, std::string_view fieldKey); + void setGlobal(std::string_view key); void rawGet(int index = -1); void rawGeti(int n, int index = -1); @@ -325,7 +332,7 @@ class LuaInterface void pushInteger(long v); void pushNumber(double v); void pushBoolean(bool v); - void pushString(const std::string_view v); + void pushString(std::string_view v); void pushLightUserdata(void* p); void pushThread(); void pushValue(int index = -1); @@ -340,7 +347,7 @@ class LuaInterface bool isTable(int index = -1); bool isFunction(int index = -1); bool isCFunction(int index = -1); - bool isLuaFunction(int index = -1) { return (isFunction(index) && !isCFunction(index)); } + bool isLuaFunction(const int index = -1) { return (isFunction(index) && !isCFunction(index)); } bool isUserdata(int index = -1); bool toBoolean(int index = -1); @@ -354,7 +361,7 @@ class LuaInterface int getTop() const; int stackSize() const { return getTop(); } void clearStack() { pop(stackSize()); } - bool hasIndex(int index) { return (stackSize() >= (index < 0 ? -index : index) && index != 0); } + bool hasIndex(const int index) { return (stackSize() >= (index < 0 ? -index : index) && index != 0); } std::string getSource(int level = 2); diff --git a/src/framework/luaengine/luaobject.cpp b/src/framework/luaengine/luaobject.cpp index b305ac4545..1e023065db 100644 --- a/src/framework/luaengine/luaobject.cpp +++ b/src/framework/luaengine/luaobject.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -23,14 +23,17 @@ #include "luaobject.h" #include "luainterface.h" -#include #include +#include "framework/core/graphicalapplication.h" + +#include int16_t g_luaThreadId = -1; LuaObject::LuaObject() : m_fieldsTableRef(-1) -{} +{ +} LuaObject::~LuaObject() { diff --git a/src/framework/luaengine/luaobject.h b/src/framework/luaengine/luaobject.h index b585eac764..1cea8d6e2a 100644 --- a/src/framework/luaengine/luaobject.h +++ b/src/framework/luaengine/luaobject.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -33,40 +33,40 @@ class LuaObject : public std::enable_shared_from_this virtual ~LuaObject(); template - void connectLuaField(const std::string_view field, const std::function& f, bool pushFront = false); + void connectLuaField(std::string_view field, const std::function& f, bool pushFront = false); /// Calls a function or table of functions stored in a lua field, results are pushed onto the stack, /// if any lua error occurs, it will be reported to stdout and return 0 results /// @return the number of results template - int luaCallLuaField(const std::string_view field, const T&... args); + int luaCallLuaField(std::string_view field, const T&... args); template - R callLuaField(const std::string_view field, const T&... args); + R callLuaField(std::string_view field, const T&... args); template - void callLuaField(const std::string_view field, const T&... args); + void callLuaField(std::string_view field, const T&... args); /// Returns true if the lua field exists - bool hasLuaField(const std::string_view field) const; + bool hasLuaField(std::string_view field) const; /// Sets a field in this lua object template - void setLuaField(const std::string_view key, const T& value); + void setLuaField(std::string_view key, const T& value); - void clearLuaField(const std::string_view key); + void clearLuaField(std::string_view key); /// Gets a field from this lua object template - T getLuaField(const std::string_view key); + T getLuaField(std::string_view key); /// Release fields table reference void releaseLuaFieldsTable(); /// Sets a field from this lua object, the value must be on the stack - void luaSetField(const std::string_view key); + void luaSetField(std::string_view key); /// Gets a field from this lua object, the result is pushed onto the stack - void luaGetField(const std::string_view key) const; + void luaGetField(std::string_view key) const; /// Get object's metatable void luaGetMetatable(); @@ -91,16 +91,16 @@ class LuaObject : public std::enable_shared_from_this extern int16_t g_luaThreadId; template -void connect(const LuaObjectPtr& obj, const std::string_view field, const std::function& f, bool pushFront = false); +void connect(const LuaObjectPtr& obj, std::string_view field, const std::function& f, bool pushFront = false); template std::enable_if_t, void> -connect(const LuaObjectPtr& obj, const std::string_view field, const Lambda& f, bool pushFront = false); +connect(const LuaObjectPtr& obj, std::string_view field, const Lambda& f, bool pushFront = false); #include "luainterface.h" template -void LuaObject::connectLuaField(const std::string_view field, const std::function& f, bool pushFront) +void LuaObject::connectLuaField(const std::string_view field, const std::function& f, const bool pushFront) { luaGetField(field); if (g_lua.isTable()) { @@ -126,7 +126,7 @@ void LuaObject::connectLuaField(const std::string_view field, const std::functio // connect for std::function template -void connect(const LuaObjectPtr& obj, const std::string_view field, const std::function& f, bool pushFront) +void connect(const LuaObjectPtr& obj, const std::string_view field, const std::function& f, const bool pushFront) { obj->connectLuaField(field, f, pushFront); } diff --git a/src/framework/luaengine/luavaluecasts.cpp b/src/framework/luaengine/luavaluecasts.cpp index 65fb64d6bd..a23e24b3b4 100644 --- a/src/framework/luaengine/luavaluecasts.cpp +++ b/src/framework/luaengine/luavaluecasts.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -24,26 +24,26 @@ #include // bool -int push_luavalue(bool b) +int push_luavalue(const bool b) { g_lua.pushBoolean(b); return 1; } -bool luavalue_cast(int index, bool& b) +bool luavalue_cast(const int index, bool& b) { b = g_lua.toBoolean(index); return true; } // int -int push_luavalue(int i) +int push_luavalue(const int i) { g_lua.pushInteger(i); return 1; } -bool luavalue_cast(int index, int& i) +bool luavalue_cast(const int index, int& i) { i = g_lua.toInteger(index); if (i == 0 && !g_lua.isNumber(index) && !g_lua.isNil()) @@ -52,13 +52,13 @@ bool luavalue_cast(int index, int& i) } // double -int push_luavalue(double d) +int push_luavalue(const double d) { g_lua.pushNumber(d); return 1; } -bool luavalue_cast(int index, double& d) +bool luavalue_cast(const int index, double& d) { d = g_lua.toNumber(index); if (d == 0 && !g_lua.isNumber(index) && !g_lua.isNil()) @@ -73,7 +73,7 @@ int push_luavalue(const std::string_view str) return 1; } -bool luavalue_cast(int index, std::string& str) +bool luavalue_cast(const int index, std::string& str) { str = g_lua.toString(index); return true; @@ -101,7 +101,7 @@ int push_luavalue(const Color& color) return 1; } -bool luavalue_cast(int index, Color& color) +bool luavalue_cast(const int index, Color& color) { if (g_lua.isTable(index)) { g_lua.getField("r", index); @@ -139,7 +139,7 @@ int push_luavalue(const Rect& rect) return 1; } -bool luavalue_cast(int index, Rect& rect) +bool luavalue_cast(const int index, Rect& rect) { if (g_lua.isTable(index)) { g_lua.getField("x", index); @@ -173,7 +173,7 @@ int push_luavalue(const Point& point) return 1; } -bool luavalue_cast(int index, Point& point) +bool luavalue_cast(const int index, Point& point) { if (g_lua.isTable(index)) { g_lua.getField("x", index); @@ -203,7 +203,7 @@ int push_luavalue(const Size& size) return 1; } -bool luavalue_cast(int index, Size& size) +bool luavalue_cast(const int index, Size& size) { if (g_lua.isTable(index)) { g_lua.getField("width", index); @@ -233,7 +233,7 @@ int push_luavalue(const Platform::Device& device) return 1; } -bool luavalue_cast(int index, Platform::Device& device) +bool luavalue_cast(const int index, Platform::Device& device) { if (g_lua.isTable(index)) { g_lua.getField("type", index); @@ -310,7 +310,7 @@ int push_luavalue(const OTMLNodePtr& node) return 1; } -bool luavalue_cast(int index, OTMLNodePtr& node) +bool luavalue_cast(const int index, OTMLNodePtr& node) { node = OTMLNode::create(); node->setUnique(true); @@ -352,7 +352,7 @@ bool luavalue_cast(int index, OTMLNodePtr& node) } // object ptr -bool luavalue_cast(int index, LuaObjectPtr& obj) +bool luavalue_cast(const int index, LuaObjectPtr& obj) { if (g_lua.isUserdata(index)) { obj = g_lua.toObject(index); diff --git a/src/framework/luaengine/luavaluecasts.h b/src/framework/luaengine/luavaluecasts.h index 2769829d14..4df06b1532 100644 --- a/src/framework/luaengine/luavaluecasts.h +++ b/src/framework/luaengine/luavaluecasts.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -24,9 +24,9 @@ // this file is and must be included only from luainterface.h +#include "declarations.h" #include #include -#include "declarations.h" #include @@ -46,51 +46,51 @@ int push_luavalue(double d); bool luavalue_cast(int index, double& d); // float -inline int push_luavalue(float f) { push_luavalue(static_cast(f)); return 1; } -inline bool luavalue_cast(int index, float& f) +inline int push_luavalue(const float f) { push_luavalue(static_cast(f)); return 1; } +inline bool luavalue_cast(const int index, float& f) { double d; const bool r = luavalue_cast(index, d); f = d; return r; } // int8 -inline int push_luavalue(int8_t v) { push_luavalue(static_cast(v)); return 1; } -inline bool luavalue_cast(int index, int8_t& v) +inline int push_luavalue(const int8_t v) { push_luavalue(static_cast(v)); return 1; } +inline bool luavalue_cast(const int index, int8_t& v) { int i; const bool r = luavalue_cast(index, i); v = i; return r; } // uint8_t -inline int push_luavalue(uint8_t v) { push_luavalue(static_cast(v)); return 1; } -inline bool luavalue_cast(int index, uint8_t& v) +inline int push_luavalue(const uint8_t v) { push_luavalue(static_cast(v)); return 1; } +inline bool luavalue_cast(const int index, uint8_t& v) { int i; const bool r = luavalue_cast(index, i); v = i; return r; } // int16 -inline int push_luavalue(int16_t v) { push_luavalue(static_cast(v)); return 1; } -inline bool luavalue_cast(int index, int16_t& v) +inline int push_luavalue(const int16_t v) { push_luavalue(static_cast(v)); return 1; } +inline bool luavalue_cast(const int index, int16_t& v) { int i; const bool r = luavalue_cast(index, i); v = i; return r; } // uint16 -inline int push_luavalue(uint16_t v) { push_luavalue(static_cast(v)); return 1; } -inline bool luavalue_cast(int index, uint16_t& v) +inline int push_luavalue(const uint16_t v) { push_luavalue(static_cast(v)); return 1; } +inline bool luavalue_cast(const int index, uint16_t& v) { int i; const bool r = luavalue_cast(index, i); v = i; return r; } // uint32 -inline int push_luavalue(uint32_t v) { push_luavalue(static_cast(v)); return 1; } -inline bool luavalue_cast(int index, uint32_t& v) +inline int push_luavalue(const uint32_t v) { push_luavalue(static_cast(v)); return 1; } +inline bool luavalue_cast(const int index, uint32_t& v) { double d; const bool r = luavalue_cast(index, d); v = d; return r; } // int64 -inline int push_luavalue(int64_t v) { push_luavalue(static_cast(v)); return 1; } -inline bool luavalue_cast(int index, int64_t& v) +inline int push_luavalue(const int64_t v) { push_luavalue(static_cast(v)); return 1; } +inline bool luavalue_cast(const int index, int64_t& v) { double d; const bool r = luavalue_cast(index, d); v = d; return r; @@ -107,8 +107,8 @@ inline bool luavalue_cast(int index, ulong& v) #endif // uint64 -inline int push_luavalue(uint64_t v) { push_luavalue(static_cast(v)); return 1; } -inline bool luavalue_cast(int index, uint64_t& v) +inline int push_luavalue(const uint64_t v) { push_luavalue(static_cast(v)); return 1; } +inline bool luavalue_cast(const int index, uint64_t& v) { double d; const bool r = luavalue_cast(index, d); v = d; return r; @@ -116,7 +116,7 @@ inline bool luavalue_cast(int index, uint64_t& v) // string int push_luavalue(const char* cstr); -int push_luavalue(const std::string_view str); +int push_luavalue(std::string_view str); bool luavalue_cast(int index, std::string& str); // lua cpp function @@ -148,8 +148,8 @@ bool luavalue_cast(int index, OTMLNodePtr& node); // enum template -std::enable_if_t, int> -push_luavalue(T e) { return push_luavalue(static_cast(e)); } +int +push_luavalue(T e) requires (std::is_enum_v) { return push_luavalue(static_cast(e)); } template std::enable_if_t, bool> @@ -242,7 +242,7 @@ int push_internal_luavalue(T v) template std::enable_if_t, bool> -luavalue_cast(int index, T& myenum) +luavalue_cast(const int index, T& myenum) { if (int i; luavalue_cast(index, i)) { myenum = static_cast(i); @@ -264,7 +264,7 @@ push_luavalue(const T& obj) template std::enable_if_t, bool> -luavalue_cast(int index, std::shared_ptr& ptr) +luavalue_cast(const int index, std::shared_ptr& ptr) { LuaObjectPtr obj; if (!luavalue_cast(index, obj)) @@ -286,7 +286,7 @@ int push_luavalue(const std::function& func) } template -bool luavalue_cast(int index, std::function& func) +bool luavalue_cast(const int index, std::function& func) { if (g_lua.isFunction(index)) { g_lua.pushValue(index); @@ -321,7 +321,7 @@ bool luavalue_cast(int index, std::function& func) template std::enable_if_t, bool> -luavalue_cast(int index, std::function& func) +luavalue_cast(const int index, std::function& func) { if (g_lua.isFunction(index)) { g_lua.pushValue(index); @@ -368,7 +368,7 @@ int push_luavalue(const std::list& list) } template -bool luavalue_cast(int index, std::list& list) +bool luavalue_cast(const int index, std::list& list) { if (g_lua.isTable(index)) { g_lua.pushNil(); @@ -397,7 +397,7 @@ int push_luavalue(const std::vector& vec) } template -bool luavalue_cast(int index, std::vector& vec) +bool luavalue_cast(const int index, std::vector& vec) { if (g_lua.isTable(index)) { g_lua.pushNil(); @@ -426,7 +426,7 @@ int push_luavalue(const std::set& set) } template -bool luavalue_cast(int index, std::set& set) +bool luavalue_cast(const int index, std::set& set) { if (g_lua.isTable(index)) { g_lua.pushNil(); @@ -455,7 +455,7 @@ int push_luavalue(const std::deque& set) } template -bool luavalue_cast(int index, std::deque& vec) +bool luavalue_cast(const int index, std::deque& vec) { if (g_lua.isTable(index)) { g_lua.pushNil(); @@ -483,7 +483,7 @@ int push_luavalue(const stdext::map& map) } template -bool luavalue_cast(int index, stdext::map& map) +bool luavalue_cast(const int index, stdext::map& map) { if (g_lua.isTable(index)) { g_lua.pushNil(); @@ -512,7 +512,7 @@ int push_luavalue(const std::map& map) } template -bool luavalue_cast(int index, std::map& map) +bool luavalue_cast(const int index, std::map& map) { if (g_lua.isTable(index)) { g_lua.pushNil(); @@ -541,7 +541,7 @@ int push_luavalue(const std::unordered_map& map) } template -bool luavalue_cast(int index, std::unordered_map& map) +bool luavalue_cast(const int index, std::unordered_map& map) { if (g_lua.isTable(index)) { g_lua.pushNil(); @@ -558,7 +558,7 @@ bool luavalue_cast(int index, std::unordered_map& map) } template -bool luavalue_cast(int index, std::pair& pair) +bool luavalue_cast(const int index, std::pair& pair) { if (g_lua.isTable(index)) { g_lua.pushNil(); diff --git a/src/framework/luafunctions.cpp b/src/framework/luafunctions.cpp index edba4f14f7..e7042b5317 100644 --- a/src/framework/luafunctions.cpp +++ b/src/framework/luafunctions.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -29,16 +29,17 @@ #include #include #include +#include #include #include #ifdef FRAMEWORK_GRAPHICS -#include "framework/graphics/particleeffect.h" -#include "framework/graphics/texturemanager.h" #include "framework/graphics/fontmanager.h" #include "framework/graphics/graphics.h" +#include "framework/graphics/particleeffect.h" #include "framework/graphics/particlemanager.h" #include "framework/graphics/shadermanager.h" +#include "framework/graphics/texturemanager.h" #include "framework/input/mouse.h" #include "framework/platform/platformwindow.h" #include "framework/ui/ui.h" @@ -47,21 +48,24 @@ #ifdef FRAMEWORK_SOUND #include #include +#include #include #include #include -#include #endif #ifdef FRAMEWORK_NET +#include #include #include -#include #include #endif #include +#include "net/inputmessage.h" +#include "net/outputmessage.h" + void Application::registerLuaFunctions() { // conversion globals @@ -73,9 +77,9 @@ void Application::registerLuaFunctions() g_lua.bindGlobalFunction("pointtostring", [](const Point& v) { return stdext::to_string(v); }); g_lua.bindGlobalFunction("colortostring", [](const Color& v) { return stdext::to_string(v); }); g_lua.bindGlobalFunction("sizetostring", [](const Size& v) { return stdext::to_string(v); }); - g_lua.bindGlobalFunction("iptostring", [](uint32_t v) { return stdext::ip_to_string(v); }); + g_lua.bindGlobalFunction("iptostring", [](const uint32_t v) { return stdext::ip_to_string(v); }); g_lua.bindGlobalFunction("stringtoip", [](const std::string_view v) { return stdext::string_to_ip(v); }); - g_lua.bindGlobalFunction("listSubnetAddresses", [](uint32_t a, uint8_t b) { return stdext::listSubnetAddresses(a, b); }); + g_lua.bindGlobalFunction("listSubnetAddresses", [](const uint32_t a, const uint8_t b) { return stdext::listSubnetAddresses(a, b); }); g_lua.bindGlobalFunction("ucwords", [](std::string s) { return stdext::ucwords(s); }); g_lua.bindGlobalFunction("regexMatch", [](std::string s, const std::string& exp) { int limit = 10000; @@ -84,9 +88,9 @@ void Application::registerLuaFunctions() return ret; try { std::smatch m; - std::regex e(exp, std::regex::ECMAScript); + const std::regex e(exp, std::regex::ECMAScript); while (std::regex_search(s, m, e)) { - ret.push_back(std::vector()); + ret.emplace_back(); for (auto x : m) ret[ret.size() - 1].push_back(x); s = m.suffix().str(); @@ -118,6 +122,7 @@ void Application::registerLuaFunctions() g_lua.bindSingletonFunction("g_platform", "getOsShortName", &Platform::getOsShortName, &g_platform); g_lua.bindSingletonFunction("g_platform", "isDesktop", &Platform::isDesktop, &g_platform); g_lua.bindSingletonFunction("g_platform", "isMobile", &Platform::isMobile, &g_platform); + g_lua.bindSingletonFunction("g_platform", "isBrowser", &Platform::isBrowser, &g_platform); g_lua.bindSingletonFunction("g_platform", "isConsole", &Platform::isConsole, &g_platform); g_lua.bindSingletonFunction("g_platform", "openDir", &Platform::openDir, &g_platform); @@ -255,6 +260,16 @@ void Application::registerLuaFunctions() g_lua.bindSingletonFunction("g_resources", "createArchive", &ResourceManager::createArchive, &g_resources); g_lua.bindSingletonFunction("g_resources", "decompressArchive", &ResourceManager::decompressArchive, &g_resources); + // OTCv8 proxy system + g_lua.registerSingletonClass("g_proxy"); + g_lua.bindSingletonFunction("g_proxy", "addProxy", &ProxyManager::addProxy, &g_proxy); + g_lua.bindSingletonFunction("g_proxy", "removeProxy", &ProxyManager::removeProxy, &g_proxy); + g_lua.bindSingletonFunction("g_proxy", "clear", &ProxyManager::clear, &g_proxy); + g_lua.bindSingletonFunction("g_proxy", "setMaxActiveProxies", &ProxyManager::setMaxActiveProxies, &g_proxy); + g_lua.bindSingletonFunction("g_proxy", "getProxies", &ProxyManager::getProxies, &g_proxy); + g_lua.bindSingletonFunction("g_proxy", "getProxiesDebugInfo", &ProxyManager::getProxiesDebugInfo, &g_proxy); + g_lua.bindSingletonFunction("g_proxy", "getPing", &ProxyManager::getPing, &g_proxy); + // Config g_lua.registerClass(); g_lua.bindClassMemberFunction("save", &Config::save); @@ -270,6 +285,7 @@ void Application::registerLuaFunctions() g_lua.bindClassMemberFunction("getOrCreateNode", &Config::getOrCreateNode); g_lua.bindClassMemberFunction("mergeNode", &Config::mergeNode); g_lua.bindClassMemberFunction("getFileName", &Config::getFileName); + g_lua.bindClassMemberFunction("clear", &Config::clear); // Module g_lua.registerClass(); @@ -898,16 +914,23 @@ void Application::registerLuaFunctions() #endif #ifdef FRAMEWORK_NET +#ifndef __EMSCRIPTEN__ // Server g_lua.registerClass(); g_lua.bindClassStaticFunction("create", &Server::create); g_lua.bindClassMemberFunction("close", &Server::close); g_lua.bindClassMemberFunction("isOpen", &Server::isOpen); g_lua.bindClassMemberFunction("acceptNext", &Server::acceptNext); +#endif // Connection +#ifdef __EMSCRIPTEN__ + g_lua.registerClass(); + g_lua.bindClassMemberFunction("getIp", &WebConnection::getIp); +#else g_lua.registerClass(); g_lua.bindClassMemberFunction("getIp", &Connection::getIp); +#endif // Protocol g_lua.registerClass(); diff --git a/src/framework/net/connection.cpp b/src/framework/net/connection.cpp index 71a6f986f5..830f63b90e 100644 --- a/src/framework/net/connection.cpp +++ b/src/framework/net/connection.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -19,14 +19,18 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ +#ifndef __EMSCRIPTEN__ #include "connection.h" #include +#include "framework/core/graphicalapplication.h" -#include #include #include +#include + +#include asio::io_service g_ioService; std::list> Connection::m_outputStreams; @@ -37,7 +41,8 @@ Connection::Connection() : m_delayedWriteTimer(g_ioService), m_resolver(g_ioService), m_socket(g_ioService) -{} +{ +} Connection::~Connection() { @@ -87,7 +92,7 @@ void Connection::close() } } -void Connection::connect(const std::string_view host, uint16_t port, const std::function& connectCallback) +void Connection::connect(const std::string_view host, const uint16_t port, const std::function& connectCallback) { m_connected = false; m_connecting = true; @@ -96,7 +101,7 @@ void Connection::connect(const std::string_view host, uint16_t port, const std:: const asio::ip::tcp::resolver::query query(host.data(), stdext::unsafe_cast(port)); m_resolver.async_resolve(query, [this](auto&& error, auto&& endpointIterator) { - onResolve(std::move(error), std::move(endpointIterator)); + onResolve(std::move(error), std::move(endpointIterator)); }); m_readTimer.cancel(); @@ -106,7 +111,6 @@ void Connection::connect(const std::string_view host, uint16_t port, const std:: }); } - void Connection::internal_connect(const asio::ip::basic_resolver::iterator& endpointIterator) { m_socket.async_connect(*endpointIterator, [capture0 = asConnection()](auto&& PH1) { @@ -120,7 +124,7 @@ void Connection::internal_connect(const asio::ip::basic_resolver: }); } -void Connection::write(uint8_t* buffer, size_t size) +void Connection::write(const uint8_t* buffer, const size_t size) { if (!m_connected) return; @@ -166,7 +170,7 @@ void Connection::internal_write() }); } -void Connection::read(uint16_t bytes, const RecvCallback& callback) +void Connection::read(const uint16_t bytes, const RecvCallback& callback) { if (!m_connected) return; @@ -290,7 +294,7 @@ void Connection::onWrite(const std::error_code& error, size_t, const std::shared handleError(error); } -void Connection::onRecv(const std::error_code& error, size_t recvSize) +void Connection::onRecv(const std::error_code& error, const size_t recvSize) { m_readTimer.cancel(); m_activityTimer.restart(); @@ -342,3 +346,5 @@ int Connection::getIp() g_logger.error("Getting remote ip"); return 0; } + +#endif \ No newline at end of file diff --git a/src/framework/net/connection.h b/src/framework/net/connection.h index 9abf436a0a..624982e24a 100644 --- a/src/framework/net/connection.h +++ b/src/framework/net/connection.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,13 +21,14 @@ */ #pragma once +#ifndef __EMSCRIPTEN__ #include -#include #include "declarations.h" +#include -class Connection : public LuaObject +class Connection final : public LuaObject { using ErrorCallback = std::function; using RecvCallback = std::function; @@ -47,12 +48,12 @@ class Connection : public LuaObject static void poll(); static void terminate(); - void connect(const std::string_view host, uint16_t port, const std::function& connectCallback); + void connect(std::string_view host, uint16_t port, const std::function& connectCallback); void close(); - void write(uint8_t* buffer, size_t size); + void write(const uint8_t* buffer, size_t size); void read(uint16_t bytes, const RecvCallback& callback); - void read_until(const std::string_view what, const RecvCallback& callback); + void read_until(std::string_view what, const RecvCallback& callback); void read_some(const RecvCallback& callback); void setErrorCallback(const ErrorCallback& errorCallback) { m_errorCallback = errorCallback; } @@ -97,3 +98,4 @@ class Connection : public LuaObject friend class Server; }; +#endif diff --git a/src/framework/net/declarations.h b/src/framework/net/declarations.h index 0051900bf4..8503d9ed7e 100644 --- a/src/framework/net/declarations.h +++ b/src/framework/net/declarations.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -22,21 +22,27 @@ #pragma once -#include -#include #include -#include +#include class InputMessage; class OutputMessage; +#ifdef __EMSCRIPTEN__ +class WebConnection; +#else class Connection; +#endif class Protocol; class ProtocolHttp; class Server; using InputMessagePtr = std::shared_ptr; using OutputMessagePtr = std::shared_ptr; +#ifdef __EMSCRIPTEN__ +using WebConnectionPtr = std::shared_ptr; +#else using ConnectionPtr = std::shared_ptr; +#endif using ProtocolPtr = std::shared_ptr; using ProtocolHttpPtr = std::shared_ptr; using ServerPtr = std::shared_ptr; diff --git a/src/framework/net/httplogin.cpp b/src/framework/net/httplogin.cpp index 94962d9fdd..939ff3220b 100644 --- a/src/framework/net/httplogin.cpp +++ b/src/framework/net/httplogin.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -24,18 +24,22 @@ #include #include -#include #include #include #include #include +#ifdef __EMSCRIPTEN__ +#include +#endif + using json = nlohmann::json; LoginHttp::LoginHttp() { this->characters.clear(); this->worlds.clear(); this->session.clear(); + this->errorMessage.clear(); } void LoginHttp::Logger(const auto& req, const auto& res) { @@ -63,26 +67,26 @@ void LoginHttp::Logger(const auto& req, const auto& res) { } void LoginHttp::startHttpLogin(const std::string& host, const std::string& path, - uint16_t port, const std::string& email, + const uint16_t port, const std::string& email, const std::string& password) { httplib::SSLClient cli(host, port); cli.set_logger( [this](const auto& req, const auto& res) { LoginHttp::Logger(req, res); }); - json body = json{ {"email", email}, {"password", password}, {"stayloggedin", true}, {"type", "login"} }; - httplib::Headers headers = { {"User-Agent", "Mozilla/5.0"} }; + const auto body = json{ {"email", email}, {"password", password}, {"stayloggedin", true}, {"type", "login"} }; + const httplib::Headers headers = { {"User-Agent", "Mozilla/5.0"} }; if (auto res = cli.Post(path, headers, body.dump(1), "application/json")) { if (res->status == 200) { - json bodyResponse = json::parse(res->body); + const json bodyResponse = json::parse(res->body); std::cout << bodyResponse.dump() << std::endl; std::cout << std::boolalpha << json::accept(res->body) << std::endl; } } else { - auto err = res.error(); - std::cout << "HTTP error: " << httplib::to_string(err) << std::endl; + const auto err = res.error(); + std::cout << "HTTP error: " << to_string(err) << std::endl; } } @@ -96,6 +100,7 @@ void LoginHttp::httpLogin(const std::string& host, const std::string& path, uint16_t port, const std::string& email, const std::string& password, int request_id, bool httpLogin) { +#ifndef __EMSCRIPTEN__ g_asyncDispatcher.detach_task( [this, host, path, port, email, password, request_id, httpLogin] { httplib::Result result = @@ -123,7 +128,7 @@ void LoginHttp::httpLogin(const std::string& host, const std::string& path, msg = "Unexpected JSON format."; } } catch (const std::exception&) { - msg = httplib::to_string(result.error()); + msg = to_string(result.error()); } } else { status = -1; @@ -136,11 +141,69 @@ void LoginHttp::httpLogin(const std::string& host, const std::string& path, }); } }); +#else + g_asyncDispatcher.detach_task( + [this, host, path, port, email, password, request_id, httpLogin] { + emscripten_fetch_attr_t attr; + emscripten_fetch_attr_init(&attr); + strcpy(attr.requestMethod, "POST"); + static const char* const headers[] = { + "Content-Type", "application/json; charset=utf-8", + 0, + }; + attr.requestHeaders = headers; + attr.attributes = EMSCRIPTEN_FETCH_LOAD_TO_MEMORY | EMSCRIPTEN_FETCH_SYNCHRONOUS; + json body = json{ {"email", email}, {"password", password}, {"stayloggedin", true}, {"type", "login"} }; + std::string bodyStr = body.dump(1); + attr.requestData = bodyStr.data(); + attr.requestDataSize = bodyStr.length(); + + std::string url = "https://" + (host.length() > 0 ? host : "127.0.0.1") + ":" + std::to_string(port) + path; + emscripten_fetch_t* fetch = emscripten_fetch(&attr, url.c_str()); + + if (fetch->status != 200 && httpLogin) { + std::string url = "http://" + (host.length() > 0 ? host : "127.0.0.1") + ":" + std::to_string(port) + path; + fetch = emscripten_fetch(&attr, url.c_str()); + } + + if (fetch && fetch->status == 200 && + !parseJsonResponse(std::string(fetch->data, fetch->numBytes))) { + fetch->status = -1; + } + + emscripten_fetch_close(fetch); + if (fetch && fetch->status == 200) { + g_dispatcher.addEvent([this, request_id] { + g_lua.callGlobalField("EnterGame", "loginSuccess", request_id, + this->getSession(), this->getWorldList(), + this->getCharacterList()); + }); + } else { + int status = 0; + std::string msg = ""; + if (fetch) { + status = fetch->status; + } else { + status = -1; + } + if (this->errorMessage.length() == 0) { + msg = "Unknown error"; + } else { + msg = this->errorMessage; + } + + g_dispatcher.addEvent([this, request_id, status, msg] { + g_lua.callGlobalField("EnterGame", "loginFailed", request_id, msg, + status); + }); + } + }); +#endif } httplib::Result LoginHttp::loginHttpsJson(const std::string& host, const std::string& path, - uint16_t port, + const uint16_t port, const std::string& email, const std::string& password) { httplib::SSLClient client(host, port); @@ -148,18 +211,18 @@ httplib::Result LoginHttp::loginHttpsJson(const std::string& host, client.set_logger( [this](const auto& req, const auto& res) { LoginHttp::Logger(req, res); }); - json body = { {"email", email}, {"password", password}, {"stayloggedin", true}, {"type", "login"} }; - httplib::Headers headers = { {"User-Agent", "Mozilla/5.0"} }; + const json body = { {"email", email}, {"password", password}, {"stayloggedin", true}, {"type", "login"} }; + const httplib::Headers headers = { {"User-Agent", "Mozilla/5.0"} }; httplib::Result response = client.Post(path, headers, body.dump(), "application/json"); if (!response) { std::cout << "HTTPS error: unknown" << std::endl; } else if (response->status != Success) { - std::cout << "HTTPS error: " << httplib::to_string(response.error()) + std::cout << "HTTPS error: " << to_string(response.error()) << std::endl; } else { - std::cout << "HTTPS status: " << httplib::to_string(response.error()) + std::cout << "HTTPS status: " << to_string(response.error()) << std::endl; } @@ -173,30 +236,29 @@ httplib::Result LoginHttp::loginHttpsJson(const std::string& host, httplib::Result LoginHttp::loginHttpJson(const std::string& host, const std::string& path, - uint16_t port, + const uint16_t port, const std::string& email, const std::string& password) { httplib::Client client(host, port); client.set_logger( [this](const auto& req, const auto& res) { LoginHttp::Logger(req, res); }); - httplib::Headers headers = { {"User-Agent", "Mozilla/5.0"} }; - json body = { {"email", email}, {"password", password}, {"stayloggedin", true}, {"type", "login"} }; + const httplib::Headers headers = { {"User-Agent", "Mozilla/5.0"} }; + const json body = { {"email", email}, {"password", password}, {"stayloggedin", true}, {"type", "login"} }; httplib::Result response = client.Post(path, headers, body.dump(), "application/json"); if (!response) { std::cout << "HTTP error: unknown" << std::endl; } else if (response->status != Success) { - std::cout << "HTTP error: " << httplib::to_string(response.error()) + std::cout << "HTTP error: " << to_string(response.error()) << std::endl; } else { - std::cout << "HTTP status: " << httplib::to_string(response.error()) + std::cout << "HTTP status: " << to_string(response.error()) << std::endl; } - if (response && response->status == Success && - !parseJsonResponse(response->body)) { + !parseJsonResponse(response->body)) { response->status = -1; } @@ -208,10 +270,17 @@ bool LoginHttp::parseJsonResponse(const std::string& body) { try { responseJson = json::parse(body); } catch (...) { + g_logger.info("Failed to parse json response"); + return false; + } + + if (responseJson.contains("errorMessage")) { + this->errorMessage = to_string(responseJson.at("errorMessage")); return false; } if (!responseJson.contains("session")) { + g_logger.info("No session data"); return false; } diff --git a/src/framework/net/httplogin.h b/src/framework/net/httplogin.h index a1025fa9b3..4994b265f9 100644 --- a/src/framework/net/httplogin.h +++ b/src/framework/net/httplogin.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -23,45 +23,47 @@ #pragma once #define CPPHTTPLIB_OPENSSL_SUPPORT -#include #include +#include -class LoginHttp : public LuaObject { +class LoginHttp final : public LuaObject +{ public: - LoginHttp(); + LoginHttp(); - void startHttpLogin(const std::string &host, const std::string &path, - uint16_t port, const std::string &email, - const std::string &password); + void startHttpLogin(const std::string& host, const std::string& path, + uint16_t port, const std::string& email, + const std::string& password); - void Logger(const auto &req, const auto &res); + void Logger(const auto& req, const auto& res); - std::string getCharacterList(); + std::string getCharacterList(); - std::string getWorldList(); + std::string getWorldList(); - std::string getSession(); + std::string getSession(); - bool parseJsonResponse(const std::string &body); + bool parseJsonResponse(const std::string& body); - void httpLogin(const std::string &host, const std::string &path, - uint16_t port, const std::string &email, - const std::string &password, int request_id, bool httpLogin); + void httpLogin(const std::string& host, const std::string& path, + uint16_t port, const std::string& email, + const std::string& password, int request_id, bool httpLogin); - httplib::Result loginHttpsJson(const std::string &host, - const std::string &path, uint16_t port, - const std::string &email, - const std::string &password); + httplib::Result loginHttpsJson(const std::string& host, + const std::string& path, uint16_t port, + const std::string& email, + const std::string& password); - httplib::Result loginHttpJson(const std::string &host, - const std::string &path, uint16_t port, - const std::string &email, - const std::string &password); + httplib::Result loginHttpJson(const std::string& host, + const std::string& path, uint16_t port, + const std::string& email, + const std::string& password); - enum Result : int { Success = 200, Error = -1 }; + enum Result : int { Success = 200, Error = -1 }; private: - std::string characters; - std::string worlds; - std::string session; + std::string characters; + std::string worlds; + std::string session; + std::string errorMessage; }; diff --git a/src/framework/net/inputmessage.cpp b/src/framework/net/inputmessage.cpp index 132b70e6ef..825414361b 100644 --- a/src/framework/net/inputmessage.cpp +++ b/src/framework/net/inputmessage.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -96,21 +96,21 @@ double InputMessage::getDouble() return (v / std::pow(10.f, precision)); } -bool InputMessage::decryptRsa(int size) +bool InputMessage::decryptRsa(const int size) { checkRead(size); g_crypt.rsaDecrypt(static_cast(m_buffer) + m_readPos, size); return (getU8() == 0x00); } -void InputMessage::fillBuffer(uint8_t* buffer, uint16_t size) +void InputMessage::fillBuffer(const uint8_t* buffer, const uint16_t size) { checkWrite(m_readPos + size); memcpy(m_buffer + m_readPos, buffer, size); m_messageSize += size; } -void InputMessage::setHeaderSize(uint16_t size) +void InputMessage::setHeaderSize(const uint16_t size) { assert(MAX_HEADER_SIZE - size >= 0); m_headerPos = MAX_HEADER_SIZE - size; @@ -124,19 +124,19 @@ bool InputMessage::readChecksum() return receivedCheck == checksum; } -bool InputMessage::canRead(int bytes) const +bool InputMessage::canRead(const int bytes) const { if ((m_readPos - m_headerPos + bytes > m_messageSize) || (m_readPos + bytes > BUFFER_MAXSIZE)) return false; return true; } -void InputMessage::checkRead(int bytes) +void InputMessage::checkRead(const int bytes) { if (!canRead(bytes)) throw stdext::exception("InputMessage eof reached"); } -void InputMessage::checkWrite(int bytes) +void InputMessage::checkWrite(const int bytes) { if (bytes > BUFFER_MAXSIZE) throw stdext::exception("InputMessage max buffer size reached"); diff --git a/src/framework/net/inputmessage.h b/src/framework/net/inputmessage.h index ead47d3983..830dd6137b 100644 --- a/src/framework/net/inputmessage.h +++ b/src/framework/net/inputmessage.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -22,11 +22,11 @@ #pragma once -#include #include "declarations.h" +#include // @bindclass -class InputMessage : public LuaObject +class InputMessage final : public LuaObject { public: enum @@ -38,8 +38,8 @@ class InputMessage : public LuaObject void setBuffer(const std::string& buffer); std::string_view getBuffer() { return std::string_view{ (char*)m_buffer + m_headerPos, m_messageSize }; } - void skipBytes(uint16_t bytes) { m_readPos += bytes; } - void setReadPos(uint16_t readPos) { m_readPos = readPos; } + void skipBytes(const uint16_t bytes) { m_readPos += bytes; } + void setReadPos(const uint16_t readPos) { m_readPos = readPos; } uint8_t getU8(); uint16_t getU16(); uint32_t getU32(); @@ -76,10 +76,10 @@ class InputMessage : public LuaObject protected: void reset(); - void fillBuffer(uint8_t* buffer, uint16_t size); + void fillBuffer(const uint8_t* buffer, uint16_t size); void setHeaderSize(uint16_t size); - void setMessageSize(uint16_t size) { m_messageSize = size; } + void setMessageSize(const uint16_t size) { m_messageSize = size; } uint8_t* getReadBuffer() { return m_buffer + m_readPos; } uint8_t* getHeaderBuffer() { return m_buffer + m_headerPos; } diff --git a/src/framework/net/outputmessage.cpp b/src/framework/net/outputmessage.cpp index c738dad2e3..b01cb61173 100644 --- a/src/framework/net/outputmessage.cpp +++ b/src/framework/net/outputmessage.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -40,7 +40,7 @@ void OutputMessage::setBuffer(const std::string& buffer) m_messageSize += len; } -void OutputMessage::addU8(uint8_t value) +void OutputMessage::addU8(const uint8_t value) { checkWrite(1); m_buffer[m_writePos] = value; @@ -48,7 +48,7 @@ void OutputMessage::addU8(uint8_t value) m_messageSize += 1; } -void OutputMessage::addU16(uint16_t value) +void OutputMessage::addU16(const uint16_t value) { checkWrite(2); stdext::writeULE16(m_buffer + m_writePos, value); @@ -56,7 +56,7 @@ void OutputMessage::addU16(uint16_t value) m_messageSize += 2; } -void OutputMessage::addU32(uint32_t value) +void OutputMessage::addU32(const uint32_t value) { checkWrite(4); stdext::writeULE32(m_buffer + m_writePos, value); @@ -64,7 +64,7 @@ void OutputMessage::addU32(uint32_t value) m_messageSize += 4; } -void OutputMessage::addU64(uint64_t value) +void OutputMessage::addU64(const uint64_t value) { checkWrite(8); stdext::writeULE64(m_buffer + m_writePos, value); @@ -84,7 +84,7 @@ void OutputMessage::addString(const std::string_view buffer) m_messageSize += len; } -void OutputMessage::addPaddingBytes(int bytes, uint8_t byte) +void OutputMessage::addPaddingBytes(const int bytes, const uint8_t byte) { if (bytes <= 0) return; @@ -113,7 +113,7 @@ void OutputMessage::writeChecksum() m_messageSize += 4; } -void OutputMessage::writeSequence(uint32_t sequence) +void OutputMessage::writeSequence(const uint32_t sequence) { assert(m_headerPos >= 4); m_headerPos -= 4; @@ -129,12 +129,12 @@ void OutputMessage::writeMessageSize() m_messageSize += 2; } -bool OutputMessage::canWrite(int bytes) const +bool OutputMessage::canWrite(const int bytes) const { return m_writePos + bytes <= BUFFER_MAXSIZE; } -void OutputMessage::checkWrite(int bytes) +void OutputMessage::checkWrite(const int bytes) { if (!canWrite(bytes)) throw stdext::exception("OutputMessage max buffer size reached"); diff --git a/src/framework/net/outputmessage.h b/src/framework/net/outputmessage.h index 0479ae6dc9..b79c9e61f8 100644 --- a/src/framework/net/outputmessage.h +++ b/src/framework/net/outputmessage.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -22,11 +22,11 @@ #pragma once -#include #include "declarations.h" +#include // @bindclass -class OutputMessage : public LuaObject +class OutputMessage final : public LuaObject { public: enum @@ -45,7 +45,7 @@ class OutputMessage : public LuaObject void addU16(uint16_t value); void addU32(uint32_t value); void addU64(uint64_t value); - void addString(const std::string_view buffer); + void addString(std::string_view buffer); void addPaddingBytes(int bytes, uint8_t byte = 0); void encryptRsa(); @@ -53,8 +53,8 @@ class OutputMessage : public LuaObject uint16_t getWritePos() { return m_writePos; } uint16_t getMessageSize() { return m_messageSize; } - void setWritePos(uint16_t writePos) { m_writePos = writePos; } - void setMessageSize(uint16_t messageSize) { m_messageSize = messageSize; } + void setWritePos(const uint16_t writePos) { m_writePos = writePos; } + void setMessageSize(const uint16_t messageSize) { m_messageSize = messageSize; } protected: uint8_t* getWriteBuffer() { return m_buffer + m_writePos; } diff --git a/src/framework/net/protocol.cpp b/src/framework/net/protocol.cpp index 4af697311b..8ecb7bbf25 100644 --- a/src/framework/net/protocol.cpp +++ b/src/framework/net/protocol.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,9 +21,20 @@ */ #include "protocol.h" -#include +#include #include +#include + +#include "inputmessage.h" +#include "outputmessage.h" +#include "framework/core/graphicalapplication.h" +#ifdef __EMSCRIPTEN__ +#include "webconnection.h" +#else #include "connection.h" +#endif + +extern asio::io_service g_ioService; Protocol::Protocol() :m_inputMessage(std::make_shared()) { inflateInit2(&m_zstream, -15); @@ -38,21 +49,64 @@ Protocol::~Protocol() inflateEnd(&m_zstream); } -void Protocol::connect(const std::string_view host, uint16_t port) +#ifndef __EMSCRIPTEN__ +void Protocol::connect(const std::string_view host, const uint16_t port) { + if (host == "proxy" || host == "0.0.0.0" || (host == "127.0.0.1" && g_proxy.isActive())) { + m_disconnected = false; + m_proxy = g_proxy.addSession(port, + [capture0 = asProtocol()](auto&& PH1) { + capture0->onProxyPacket(std::forward(PH1)); + }, + [capture0 = asProtocol()](auto&& PH1) { + capture0->onLocalDisconnected(std::forward(PH1)); + }); + return onConnect(); + } + m_connection = std::make_shared(); m_connection->setErrorCallback([capture0 = asProtocol()](auto&& PH1) { capture0->onError(std::forward(PH1)); }); m_connection->connect(host, port, [capture0 = asProtocol()] { capture0->onConnect(); }); } +#else +void Protocol::connect(const std::string_view host, uint16_t port, bool gameWorld) +{ + m_connection = std::make_shared(); + m_connection->setErrorCallback([capture0 = asProtocol()](auto&& PH1) { capture0->onError(std::forward(PH1)); }); + m_connection->connect(host, port, [capture0 = asProtocol()] { capture0->onConnect(); }, gameWorld); +} +#endif void Protocol::disconnect() { + m_disconnected = true; + if (m_proxy) { + g_proxy.removeSession(m_proxy); + return; + } + if (m_connection) { m_connection->close(); m_connection.reset(); } } +bool Protocol::isConnected() +{ + if (m_proxy) + return !m_disconnected; + + return m_connection && m_connection->isConnected(); +} + +bool Protocol::isConnecting() +{ + if (m_proxy) + return false; + + return m_connection && m_connection->isConnecting(); +} + void Protocol::send(const OutputMessagePtr& outputMessage) { // encrypt @@ -68,6 +122,13 @@ void Protocol::send(const OutputMessagePtr& outputMessage) // write message size outputMessage->writeMessageSize(); + if (m_proxy) { + const auto packet = std::make_shared(outputMessage->getHeaderBuffer(), outputMessage->getWriteBuffer()); + g_proxy.send(m_proxy, packet); + outputMessage->reset(); + return; + } + // send if (m_connection) m_connection->write(outputMessage->getHeaderBuffer(), outputMessage->getMessageSize()); @@ -78,6 +139,10 @@ void Protocol::send(const OutputMessagePtr& outputMessage) void Protocol::recv() { + if (m_proxy) { + return; + } + m_inputMessage->reset(); // first update message header size @@ -96,7 +161,7 @@ void Protocol::recv() }); } -void Protocol::internalRecvHeader(uint8_t* buffer, uint16_t size) +void Protocol::internalRecvHeader(const uint8_t* buffer, const uint16_t size) { // read message size m_inputMessage->fillBuffer(buffer, size); @@ -110,7 +175,7 @@ void Protocol::internalRecvHeader(uint8_t* buffer, uint16_t size) }); } -void Protocol::internalRecvData(uint8_t* buffer, uint16_t size) +void Protocol::internalRecvData(const uint8_t* buffer, const uint16_t size) { // process data only if really connected if (!isConnected()) { @@ -124,7 +189,7 @@ void Protocol::internalRecvData(uint8_t* buffer, uint16_t size) if (m_sequencedPackets) { decompress = (m_inputMessage->getU32() & 1 << 31); } else if (m_checksumEnabled && !m_inputMessage->readChecksum()) { - g_logger.traceError(stdext::format("got a network message with invalid checksum, size: %i", (int)m_inputMessage->getMessageSize())); + g_logger.traceError(stdext::format("got a network message with invalid checksum, size: %i", static_cast(m_inputMessage->getMessageSize()))); return; } @@ -143,7 +208,7 @@ void Protocol::internalRecvData(uint8_t* buffer, uint16_t size) m_zstream.avail_in = m_inputMessage->getUnreadSize(); m_zstream.avail_out = InputMessage::BUFFER_MAXSIZE; - int32_t ret = inflate(&m_zstream, Z_FINISH); + const int32_t ret = inflate(&m_zstream, Z_FINISH); if (ret != Z_OK && ret != Z_STREAM_END) { g_logger.traceError(stdext::format("failed to decompress message - %s", m_zstream.msg)); return; @@ -167,7 +232,7 @@ void Protocol::generateXteaKey() { std::random_device rd; std::uniform_int_distribution unif; - std::generate(m_xteaKey.begin(), m_xteaKey.end(), [&unif, &rd] { return unif(rd); }); + std::ranges::generate(m_xteaKey, [&unif, &rd] { return unif(rd); }); } namespace @@ -175,7 +240,7 @@ namespace constexpr uint32_t delta = 0x9E3779B9; template - void apply_rounds(uint8_t* data, size_t length, Round round) + void apply_rounds(uint8_t* data, const size_t length, Round round) { for (auto j = 0u; j < length; j += 8) { uint32_t left = data[j + 0] | data[j + 1] << 8u | data[j + 2] << 16u | data[j + 3] << 24u, @@ -252,4 +317,40 @@ void Protocol::onError(const std::error_code& err) { callLuaField("onError", err.message(), err.value()); disconnect(); +} + +void Protocol::onProxyPacket(const std::shared_ptr>& packet) +{ + if (m_disconnected) + return; + auto self(asProtocol()); + post(g_ioService, [&, packet] { + if (m_disconnected) + return; + m_inputMessage->reset(); + + // first update message header size + int headerSize = 2; // 2 bytes for message size + if (m_checksumEnabled) + headerSize += 4; // 4 bytes for checksum + if (m_xteaEncryptionEnabled) + headerSize += 2; // 2 bytes for XTEA encrypted message size + m_inputMessage->setHeaderSize(headerSize); + m_inputMessage->fillBuffer(packet->data(), 2); + m_inputMessage->readSize(); + internalRecvData(packet->data() + 2, packet->size() - 2); + }); +} + +void Protocol::onLocalDisconnected(std::error_code ec) +{ + if (m_disconnected) + return; + auto self(asProtocol()); + post(g_ioService, [&, ec] { + if (m_disconnected) + return; + m_disconnected = true; + onError(ec); + }); } \ No newline at end of file diff --git a/src/framework/net/protocol.h b/src/framework/net/protocol.h index 015b6dbe81..30f7be03b1 100644 --- a/src/framework/net/protocol.h +++ b/src/framework/net/protocol.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,13 +21,15 @@ */ #pragma once - +#ifdef __EMSCRIPTEN__ +#include "webconnection.h" +#else #include "connection.h" +#endif #include "declarations.h" -#include "inputmessage.h" -#include "outputmessage.h" #include +#include #include // @bindclass @@ -37,18 +39,29 @@ class Protocol : public LuaObject Protocol(); ~Protocol() override; - void connect(const std::string_view host, uint16_t port); +#ifndef __EMSCRIPTEN__ + void connect(std::string_view host, uint16_t port); +#else + void connect(const std::string_view host, uint16_t port, bool gameWorld = false); +#endif void disconnect(); - bool isConnected() { return m_connection && m_connection->isConnected(); } - bool isConnecting() { return m_connection && m_connection->isConnecting(); } + bool isConnected(); + bool isConnecting(); ticks_t getElapsedTicksSinceLastRead() const { return m_connection ? m_connection->getElapsedTicksSinceLastRead() : -1; } - +#ifdef __EMSCRIPTEN__ + WebConnectionPtr getConnection() { return m_connection; } +#else ConnectionPtr getConnection() { return m_connection; } +#endif +#ifdef __EMSCRIPTEN__ + void setConnection(const WebConnectionPtr& connection) { m_connection = connection; } +#else void setConnection(const ConnectionPtr& connection) { m_connection = connection; } +#endif void generateXteaKey(); - void setXteaKey(uint32_t a, uint32_t b, uint32_t c, uint32_t d) { m_xteaKey = { a, b, c, d }; } + void setXteaKey(const uint32_t a, const uint32_t b, const uint32_t c, const uint32_t d) { m_xteaKey = { a, b, c, d }; } std::vector getXteaKey() { return { m_xteaKey.begin(), m_xteaKey.end() }; } void enableXteaEncryption() { m_xteaEncryptionEnabled = true; } @@ -65,12 +78,17 @@ class Protocol : public LuaObject virtual void onRecv(const InputMessagePtr& inputMessage); virtual void onError(const std::error_code& err); + void onProxyPacket(const std::shared_ptr>& packet); + void onLocalDisconnected(std::error_code ec); + bool m_disconnected = false; + uint32_t m_proxy = 0; + std::array m_xteaKey{}; uint32_t m_packetNumber{ 0 }; private: - void internalRecvHeader(uint8_t* buffer, uint16_t size); - void internalRecvData(uint8_t* buffer, uint16_t size); + void internalRecvHeader(const uint8_t* buffer, uint16_t size); + void internalRecvData(const uint8_t* buffer, uint16_t size); bool xteaDecrypt(const InputMessagePtr& inputMessage) const; void xteaEncrypt(const OutputMessagePtr& outputMessage) const; @@ -78,8 +96,11 @@ class Protocol : public LuaObject bool m_checksumEnabled{ false }; bool m_sequencedPackets{ false }; bool m_xteaEncryptionEnabled{ false }; - +#ifdef __EMSCRIPTEN__ + WebConnectionPtr m_connection; +#else ConnectionPtr m_connection; +#endif InputMessagePtr m_inputMessage; z_stream m_zstream{}; diff --git a/src/framework/net/protocolhttp.cpp b/src/framework/net/protocolhttp.cpp index f028cfe330..33ace2f7d2 100644 --- a/src/framework/net/protocolhttp.cpp +++ b/src/framework/net/protocolhttp.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -175,7 +175,7 @@ int Http::ws(const std::string& url, int timeout) result->operationId = operationId; m_operations[operationId] = result; const auto& session = std::make_shared(m_ios, url, m_userAgent, m_enable_time_out_on_read_write, timeout, result, [&, result](WebsocketCallbackType type, std::string message) { - g_dispatcher.addEvent([result, type, message]() { + g_dispatcher.addEvent([result, type, message] { if (type == WebsocketCallbackType::OPEN) { g_lua.callGlobalField("g_http", "onWsOpen", result->operationId, message); } else if (type == WebsocketCallbackType::MESSAGE) { @@ -209,7 +209,7 @@ bool Http::wsSend(int operationId, const std::string& message) return true; } -bool Http::wsClose(int operationId) +bool Http::wsClose(const int operationId) { cancel(operationId); return true; @@ -325,7 +325,7 @@ void HttpSession::on_connect(const std::error_code& ec) m_ssl.set_verify_mode(asio::ssl::verify_peer); m_ssl.set_verify_callback([](bool, const asio::ssl::verify_context&) { return true; }); if (!SSL_set_tlsext_host_name(m_ssl.native_handle(), instance_uri.domain.c_str())) { - const std::error_code _ec{ static_cast(::ERR_get_error()), asio::error::get_ssl_category() }; + const std::error_code _ec{ static_cast(ERR_get_error()), asio::error::get_ssl_category() }; onError("HttpSession on SSL_set_tlsext_host_name unable to handshake " + m_url + ": " + _ec.message()); return; } @@ -350,11 +350,11 @@ void HttpSession::on_connect(const std::error_code& ec) void HttpSession::on_write() { if (instance_uri.port == "443") { - asio::async_write(m_ssl, asio::buffer(m_request), [sft = shared_from_this()] - (const std::error_code& ec, size_t bytes) { sft->on_request_sent(ec, bytes); }); + async_write(m_ssl, asio::buffer(m_request), [sft = shared_from_this()] + (const std::error_code& ec, const size_t bytes) { sft->on_request_sent(ec, bytes); }); } else { - asio::async_write(m_socket, asio::buffer(m_request), [sft = shared_from_this()] - (const std::error_code& ec, size_t bytes) {sft->on_request_sent(ec, bytes); }); + async_write(m_socket, asio::buffer(m_request), [sft = shared_from_this()] + (const std::error_code& ec, const size_t bytes) {sft->on_request_sent(ec, bytes); }); } m_timer.cancel(); @@ -370,16 +370,16 @@ void HttpSession::on_request_sent(const std::error_code& ec, size_t /*bytes_tran } if (instance_uri.port == "443") { - asio::async_read_until( + async_read_until( m_ssl, m_response, "\r\n\r\n", - [this](const std::error_code& ec, size_t size) { + [this](const std::error_code& ec, const size_t size) { if (ec) { onError("HttpSession error receiving header " + m_url + ": " + ec.message()); return; } std::string header( - asio::buffers_begin(m_response.data()), - asio::buffers_begin(m_response.data()) + size); + buffers_begin(m_response.data()), + buffers_begin(m_response.data()) + size); m_response.consume(size); const size_t pos = header.find("Content-Length: "); @@ -390,24 +390,24 @@ void HttpSession::on_request_sent(const std::error_code& ec, size_t /*bytes_tran m_result->size = len - m_response.size(); } - asio::async_read(m_ssl, m_response, + async_read(m_ssl, m_response, asio::transfer_at_least(1), [sft = shared_from_this()]( - const std::error_code& ec, size_t bytes) { + const std::error_code& ec, const size_t bytes) { sft->on_read(ec, bytes); }); }); } else { - asio::async_read_until( + async_read_until( m_socket, m_response, "\r\n\r\n", - [this](const std::error_code& ec, size_t size) { + [this](const std::error_code& ec, const size_t size) { if (ec) { onError("HttpSession error receiving header " + m_url + ": " + ec.message()); return; } std::string header( - asio::buffers_begin(m_response.data()), - asio::buffers_begin(m_response.data()) + size); + buffers_begin(m_response.data()), + buffers_begin(m_response.data()) + size); m_response.consume(size); const size_t pos = header.find("Content-Length: "); @@ -421,10 +421,10 @@ void HttpSession::on_request_sent(const std::error_code& ec, size_t /*bytes_tran return; } - asio::async_read(m_socket, m_response, + async_read(m_socket, m_response, asio::transfer_at_least(1), [sft = shared_from_this()]( - const std::error_code& ec, size_t bytes) { + const std::error_code& ec, const size_t bytes) { sft->on_read(ec, bytes); }); }); @@ -435,12 +435,12 @@ void HttpSession::on_request_sent(const std::error_code& ec, size_t /*bytes_tran m_timer.async_wait([sft = shared_from_this()](const std::error_code& ec) {sft->onTimeout(ec); }); } -void HttpSession::on_read(const std::error_code& ec, size_t bytes_transferred) +void HttpSession::on_read(const std::error_code& ec, const size_t bytes_transferred) { - auto on_done_read = [this]() { + auto on_done_read = [this] { m_timer.cancel(); const auto& data = m_response.data(); - m_result->response.append(asio::buffers_begin(data), asio::buffers_end(data)); + m_result->response.append(buffers_begin(data), buffers_end(data)); m_result->finished = true; m_callback(m_result); }; @@ -456,7 +456,7 @@ void HttpSession::on_read(const std::error_code& ec, size_t bytes_transferred) if (stdext::millis() > m_last_progress_update) { m_result->speed = (sum_bytes_speed_response) / ((stdext::millis() - (m_last_progress_update - 100))); - m_result->progress = ((double)sum_bytes_response / m_result->size) * 100; + m_result->progress = (static_cast(sum_bytes_response) / m_result->size) * 100; m_last_progress_update = stdext::millis() + 100; sum_bytes_speed_response = 0; m_callback(m_result); @@ -470,10 +470,10 @@ void HttpSession::on_read(const std::error_code& ec, size_t bytes_transferred) } if (instance_uri.port == "443") { - asio::async_read(m_ssl, m_response, + async_read(m_ssl, m_response, asio::transfer_at_least(1), [sft = shared_from_this(), on_done_read]( - const std::error_code& ec, size_t bytes) { + const std::error_code& ec, const size_t bytes) { if (bytes > 0) { sft->on_read(ec, bytes); } else { @@ -481,10 +481,10 @@ void HttpSession::on_read(const std::error_code& ec, size_t bytes_transferred) } }); } else { - asio::async_read(m_socket, m_response, + async_read(m_socket, m_response, asio::transfer_at_least(1), [sft = shared_from_this(), on_done_read]( - const std::error_code& ec, size_t bytes) { + const std::error_code& ec, const size_t bytes) { if (bytes > 0) { sft->on_read(ec, bytes); } else { @@ -508,7 +508,6 @@ void HttpSession::close() if (ec) { sft->onError("shutdown " + sft->m_url + ": " + ec.message()); - return; } }); } else { @@ -518,7 +517,6 @@ void HttpSession::close() // not_connected happens sometimes so don't bother reporting it. if (ec && ec != asio::error::not_connected) { onError("shutdown " + m_url + ": " + ec.message()); - return; } } } @@ -613,17 +611,17 @@ void WebsocketSession::on_connect(const std::error_code& ec) onError("WebsocketSession unable to handshake " + m_url + ": " + _ec.message()); return; } - asio::async_write( + async_write( m_ssl, asio::buffer(m_request), [sft = shared_from_this()]( - const std::error_code& ec, size_t bytes) { + const std::error_code& ec, const size_t bytes) { sft->on_request_sent(ec, bytes); }); } else { - asio::async_write( + async_write( m_socket, asio::buffer(m_request), [sft = shared_from_this()]( - const std::error_code& ec, size_t bytes) { + const std::error_code& ec, const size_t bytes) { sft->on_request_sent(ec, bytes); }); } @@ -641,16 +639,16 @@ void WebsocketSession::on_request_sent(const std::error_code& ec, size_t /*bytes } if (instance_uri.port == "443") { - asio::async_read_until( + async_read_until( m_ssl, m_response, "\r\n\r\n", - [this](const std::error_code& ec, size_t size) { + [this](const std::error_code& ec, const size_t size) { if (ec) { onError("WebsocketSession error receiving header " + m_url + ": " + ec.message()); return; } std::string header( - asio::buffers_begin(m_response.data()), - asio::buffers_begin(m_response.data()) + size); + buffers_begin(m_response.data()), + buffers_begin(m_response.data()) + size); m_response.consume(size); //TODO: Local variable 'websocket_accept' is only assigned but never accessed @@ -660,24 +658,24 @@ void WebsocketSession::on_request_sent(const std::error_code& ec, size_t /*bytes websocket_accept = header.c_str() + pos + sizeof("Sec-WebSocket-Accept: ") - 1; }*/ - asio::async_read(m_ssl, m_response, + async_read(m_ssl, m_response, asio::transfer_at_least(1), [sft = shared_from_this()]( - const std::error_code& ec, size_t bytes) { + const std::error_code& ec, const size_t bytes) { sft->on_read(ec, bytes); }); }); } else { - asio::async_read_until( + async_read_until( m_socket, m_response, "\r\n\r\n", - [this](const std::error_code& ec, size_t size) { + [this](const std::error_code& ec, const size_t size) { if (ec) { onError("WebsocketSession error receiving header " + m_url + ": " + ec.message()); return; } std::string header( - asio::buffers_begin(m_response.data()), - asio::buffers_begin(m_response.data()) + size); + buffers_begin(m_response.data()), + buffers_begin(m_response.data()) + size); m_response.consume(size); //TODO: Local variable 'websocket_accept' is only assigned but never accessed @@ -687,10 +685,10 @@ void WebsocketSession::on_request_sent(const std::error_code& ec, size_t /*bytes websocket_accept = header.c_str() + pos + sizeof("Sec-WebSocket-Accept: ") - 1; }*/ - asio::async_read(m_socket, m_response, + async_read(m_socket, m_response, asio::transfer_at_least(1), [sft = shared_from_this()]( - const std::error_code& ec, size_t bytes) { + const std::error_code& ec, const size_t bytes) { sft->on_read(ec, bytes); }); }); @@ -719,21 +717,21 @@ void WebsocketSession::on_write(const std::error_code& ec, size_t /*bytes_transf if (instance_uri.port == "443") { if (!m_sendQueue.empty()) - asio::async_write(m_ssl, asio::buffer(m_sendQueue.front()), [sft = shared_from_this()](const std::error_code& ec, size_t bytes) { + async_write(m_ssl, asio::buffer(m_sendQueue.front()), [sft = shared_from_this()](const std::error_code& ec, const size_t bytes) { sft->on_write(ec, bytes); }); } else { if (!m_sendQueue.empty()) - asio::async_write( + async_write( m_socket, asio::buffer(m_sendQueue.front()), [sft = shared_from_this()]( - const std::error_code& ec, size_t bytes) { + const std::error_code& ec, const size_t bytes) { sft->on_write(ec, bytes); }); } } -void WebsocketSession::on_read(const std::error_code& ec, size_t bytes_transferred) +void WebsocketSession::on_read(const std::error_code& ec, const size_t bytes_transferred) { if (ec && ec != asio::error::eof) { onError("WebsocketSession unable to on_read " + m_url + ": " + ec.message()); @@ -748,7 +746,7 @@ void WebsocketSession::on_read(const std::error_code& ec, size_t bytes_transferr if (bytes_transferred > 0) { m_response.prepare(bytes_transferred); const auto& data = m_response.data(); - std::string response = { asio::buffers_begin(data), asio::buffers_end(data) }; + std::string response = { buffers_begin(data), buffers_end(data) }; const uint8_t fin_code = response.at(0); // size_t length = (response.at(1) & 127); response.erase(0, 1); @@ -772,17 +770,17 @@ void WebsocketSession::on_read(const std::error_code& ec, size_t bytes_transferr } if (instance_uri.port == "443") { - asio::async_read(m_ssl, m_response, + async_read(m_ssl, m_response, asio::transfer_at_least(1), [sft = shared_from_this()]( - const std::error_code& ec, size_t bytes) { + const std::error_code& ec, const size_t bytes) { sft->on_read(ec, bytes); }); } else { - asio::async_read(m_socket, m_response, + async_read(m_socket, m_response, asio::transfer_at_least(1), [sft = shared_from_this()]( - const std::error_code& ec, size_t bytes) { + const std::error_code& ec, const size_t bytes) { sft->on_read(ec, bytes); }); } @@ -815,7 +813,7 @@ void WebsocketSession::onTimeout(const std::error_code& ec) } } -void WebsocketSession::send(const std::string& data, uint8_t ws_opcode) +void WebsocketSession::send(const std::string& data, const uint8_t ws_opcode) { std::vector ws_frame; std::array mask; @@ -925,17 +923,17 @@ void WebsocketSession::send(const std::string& data, uint8_t ws_opcode) return; if (instance_uri.port == "443") { - asio::async_write( + async_write( m_ssl, asio::buffer(m_sendQueue.front()), [sft = shared_from_this()]( - const std::error_code& ec, size_t bytes) { + const std::error_code& ec, const size_t bytes) { sft->on_write(ec, bytes); }); } else { - asio::async_write( + async_write( m_socket, asio::buffer(m_sendQueue.front()), [sft = shared_from_this()]( - const std::error_code& ec, size_t bytes) { + const std::error_code& ec, const size_t bytes) { sft->on_write(ec, bytes); }); } @@ -962,7 +960,6 @@ void WebsocketSession::close() if (ec) { sft->onError("shutdown " + sft->m_url + ": " + ec.message()); - return; } }); } else { @@ -972,7 +969,6 @@ void WebsocketSession::close() // not_connected happens sometimes so don't bother reporting it. if (ec && ec != asio::error::not_connected) { onError("shutdown " + m_url + ": " + ec.message()); - return; } } } diff --git a/src/framework/net/protocolhttp.h b/src/framework/net/protocolhttp.h index db77bcf78a..e84d732379 100644 --- a/src/framework/net/protocolhttp.h +++ b/src/framework/net/protocolhttp.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -30,7 +30,6 @@ #include #include -#include #include // result @@ -63,19 +62,19 @@ class HttpSession : public std::enable_shared_from_this { public: - HttpSession(asio::io_service& service, const std::string& url, const std::string& agent, + HttpSession(asio::io_service& service, std::string url, std::string agent, const bool& enable_time_out_on_read_write, const std::unordered_map& custom_header, - int timeout, bool isJson, bool checkContentLength, const HttpResult_ptr& result, HttpResult_cb callback) : + const int timeout, const bool isJson, const bool checkContentLength, HttpResult_ptr result, HttpResult_cb callback) : m_service(service), - m_url(url), - m_agent(agent), + m_url(std::move(url)), + m_agent(std::move(agent)), m_enable_time_out_on_read_write(enable_time_out_on_read_write), m_custom_header(custom_header), m_timeout(timeout), m_isJson(isJson), m_checkContentLength(checkContentLength), - m_result(result), + m_result(std::move(result)), m_callback(std::move(callback)), m_socket(service), m_resolver(service), @@ -133,15 +132,15 @@ class WebsocketSession : public std::enable_shared_from_this { public: - WebsocketSession(asio::io_service& service, const std::string& url, const std::string& agent, - const bool& enable_time_out_on_read_write, int timeout, HttpResult_ptr result, WebsocketSession_cb callback) : + WebsocketSession(asio::io_service& service, std::string url, std::string agent, + const bool& enable_time_out_on_read_write, const int timeout, HttpResult_ptr result, WebsocketSession_cb callback) : m_service(service), - m_url(url), - m_agent(agent), + m_url(std::move(url)), + m_agent(std::move(agent)), m_enable_time_out_on_read_write(enable_time_out_on_read_write), m_timeout(timeout), - m_result(result), - m_callback(callback), + m_result(std::move(result)), + m_callback(std::move(callback)), m_timer(service), m_socket(service), m_resolver(service) @@ -191,7 +190,7 @@ class WebsocketSession : public std::enable_shared_from_this class Http { public: - Http() : m_ios(), m_guard(asio::make_work_guard(m_ios)) {} + Http() : m_guard(make_work_guard(m_ios)) {} void init(); void terminate(); @@ -222,7 +221,7 @@ class Http void addCustomHeader(const std::string& name, const std::string& value) { m_custom_header[name] = value; } - void setEnableTimeOutOnReadWrite(bool enable_time_out_on_read_write) { m_enable_time_out_on_read_write = enable_time_out_on_read_write; } + void setEnableTimeOutOnReadWrite(const bool enable_time_out_on_read_write) { m_enable_time_out_on_read_write = enable_time_out_on_read_write; } private: bool m_working = false; diff --git a/src/framework/net/server.cpp b/src/framework/net/server.cpp index 269d8589d4..ce0d0f50e8 100644 --- a/src/framework/net/server.cpp +++ b/src/framework/net/server.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -20,14 +20,18 @@ * THE SOFTWARE. */ +#ifndef __EMSCRIPTEN__ + #include "server.h" #include "connection.h" +#include extern asio::io_service g_ioService; -Server::Server(int port) +Server::Server(const int port) : m_acceptor(g_ioService, asio::ip::tcp::endpoint(asio::ip::tcp::v4(), port)) -{} +{ +} ServerPtr Server::create(int port) { @@ -59,4 +63,6 @@ void Server::acceptNext() } self->callLuaField("onAccept", connection, error.message(), error.value()); }); -} \ No newline at end of file +} + +#endif \ No newline at end of file diff --git a/src/framework/net/server.h b/src/framework/net/server.h index 0cdfaaf128..f11f5aafb2 100644 --- a/src/framework/net/server.h +++ b/src/framework/net/server.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -22,10 +22,10 @@ #pragma once -#include #include "declarations.h" +#include -class Server : public LuaObject +class Server final : public LuaObject { public: Server(int port); diff --git a/src/framework/net/webconnection.cpp b/src/framework/net/webconnection.cpp new file mode 100644 index 0000000000..9ff913d2f9 --- /dev/null +++ b/src/framework/net/webconnection.cpp @@ -0,0 +1,290 @@ +/* + * Copyright (c) 2024 OTArchive + * Copyright (c) 2010-2022 OTClient + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifdef __EMSCRIPTEN__ + +#include "webconnection.h" + +#include +#include + +#include +#include +#include +#include + +#include + + + +std::list> WebConnection::m_outputStreams; +WebConnection::WebConnection() +{ +} + +WebConnection::~WebConnection() +{ +#ifndef NDEBUG + assert(!g_app.isTerminated()); +#endif + close(); +} + +void WebConnection::poll() +{ + +} + +void WebConnection::terminate() +{ + emscripten_websocket_deinitialize(); +} + +void WebConnection::close() +{ + if (!m_connected && !m_connecting) + return; + + emscripten_websocket_deinitialize(); + m_websocket = 0; + + if (!m_gameWorld) + return; + + m_connecting = false; + m_connected = false; + m_connectCallback = nullptr; + m_errorCallback = nullptr; + m_recvCallback = nullptr; + + m_inputStream.consume(m_inputStream.size()); + + //Workaround for the abrupt termination of the websocket + g_dispatcher.addEvent([] { + g_game.forceLogout(); + }); +} + + +void WebConnection::connect(const std::string_view host, uint16_t port, const std::function& connectCallback, bool gameWorld) +{ + m_gameWorld = gameWorld; + + m_connected = false; + m_connecting = true; + m_connectCallback = connectCallback; + + std::string ip = std::string(host); + ip.length() == 0 ? ip = "localhost" : ip; + +#ifdef NDEBUG + const std::string prefix = "wss://"; +#else + const std::string prefix = "ws://"; +#endif + + m_pthread = pthread_self(); + + const std::string url = prefix + ip + ":" + std::to_string(port); + EmscriptenWebSocketCreateAttributes attributes = + { + url.c_str(), + "binary", + EM_FALSE // if the webscocket should be created in the main thread. Currently not implemented by emscripten so this does nothing + }; + + m_websocket = emscripten_websocket_new(&attributes); + + if (m_websocket < 1) { + if (m_errorCallback) + m_errorCallback(asio::error::network_unreachable); + + close(); + return; + } + + emscripten_websocket_set_onopen_callback(m_websocket, this, ([](int /*eventType*/, const EmscriptenWebSocketOpenEvent* /*event*/, void* userData) -> EM_BOOL { + WebConnection* webConnection = static_cast(userData); + webConnection->m_connected = true; + + if (webConnection->m_connectCallback) { + emscripten_dispatch_to_thread(webConnection->m_pthread, EM_FUNC_SIG_VI, reinterpret_cast(runOnConnectCallback), nullptr, &webConnection->m_connectCallback); + } + + webConnection->m_connecting = false; + + return EM_TRUE; + })); + + emscripten_websocket_set_onerror_callback(m_websocket, this, ([](int /*eventType*/, const EmscriptenWebSocketErrorEvent* /*event*/, void* userData) -> EM_BOOL { + WebConnection* webConnection = static_cast(userData); + if (webConnection->m_errorCallback) { + emscripten_dispatch_to_thread(webConnection->m_pthread, EM_FUNC_SIG_VI, reinterpret_cast(runOnErrorCallback), nullptr, &webConnection->m_errorCallback); + } + if (webConnection->m_connected || webConnection->m_connecting) { + webConnection->close(); + } + return EM_TRUE; + })); + + emscripten_websocket_set_onclose_callback(m_websocket, this, ([](int /*eventType*/, const EmscriptenWebSocketCloseEvent* /*event*/, void* userData) -> EM_BOOL { + WebConnection* webConnection = static_cast(userData); + webConnection->close(); + return EM_TRUE; + })); + + emscripten_websocket_set_onmessage_callback(m_websocket, this, ([](int /*eventType*/, const EmscriptenWebSocketMessageEvent* webSocketEvent, void* userData) -> EM_BOOL { + auto numBytes = webSocketEvent->numBytes; + if (numBytes == 0) + return EM_TRUE; + if (webSocketEvent->isText) + return EM_TRUE; + + uint8_t* const data = webSocketEvent->data; + auto webConnection = static_cast(userData); + + std::ostream os(&webConnection->m_inputStream); + os.write((const char*)data, numBytes); + os.flush(); + + return EM_TRUE; + })); +} + +bool WebConnection::sendPacket(uint8_t* buffer, uint16_t size) +{ + if (m_websocket < 1) { + close(); + return false; + } + + const EMSCRIPTEN_RESULT result = emscripten_websocket_send_binary(m_websocket, buffer, size); + return (result == EMSCRIPTEN_RESULT_SUCCESS); +} + +void WebConnection::write(uint8_t* buffer, size_t size) +{ + if (!m_connected) + return; + + if (!m_outputStream) { + if (!m_outputStreams.empty()) { + m_outputStream = m_outputStreams.front(); + m_outputStreams.pop_front(); + } else + m_outputStream = std::make_shared(); + } + + std::ostream os(m_outputStream.get()); + os.write((const char*)buffer, size); + os.flush(); + + internal_write(); +} + +void WebConnection::internal_write() +{ + if (!m_connected) + return; + + std::shared_ptr outputStream = m_outputStream; + m_outputStream = nullptr; + + const auto* data = asio::buffer_cast(outputStream->data()); + bool write = sendPacket((uint8_t*)data, outputStream->size()); + if (write) { + onWrite(outputStream); + } +} + +void WebConnection::read(const uint16_t size, const RecvCallback& callback, int tries) +{ + if (!m_connected) + return; + + m_recvCallback = callback; + + if (tries > 1000) { + onTimeout(); + return; + } + + auto retry = [capture0 = asWebConnection(), size, callback, tries] { capture0->read(size, callback, tries + 1); }; + + if (tries == 0) { + g_dispatcher.addEvent(std::move(retry)); + return; + } + + if (m_inputStream.size() < size) { + emscripten_thread_sleep(10); + g_dispatcher.addEvent(std::move(retry)); + return; + } + + onRecv(size); +} + +void WebConnection::runOnConnectCallback(std::function callback) { + callback(); +} + +void WebConnection::runOnErrorCallback(ErrorCallback callback) { + callback(asio::error::timed_out); +} + +void WebConnection::onWrite(const std::shared_ptr& outputStream) +{ + // free output stream and store for using it again later + outputStream->consume(outputStream->size()); + m_outputStreams.emplace_back(outputStream); +} + +void WebConnection::onRecv(const uint16_t recvSize) +{ + m_activityTimer.restart(); + + if (m_connected) { + if (m_recvCallback) { + const auto* header = asio::buffer_cast(m_inputStream.data()); + m_recvCallback((uint8_t*)header, recvSize); + } + } + m_inputStream.consume(recvSize); +} + +void WebConnection::onTimeout() +{ + if (m_errorCallback) + m_errorCallback(asio::error::timed_out); + + if (m_connected || m_connecting) + close(); +} + +int WebConnection::getIp() +{ + g_logger.error("Getting remote ip"); + return 0; +} + +#endif \ No newline at end of file diff --git a/src/framework/net/webconnection.h b/src/framework/net/webconnection.h new file mode 100644 index 0000000000..f06fbf09e4 --- /dev/null +++ b/src/framework/net/webconnection.h @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2010-2022 OTClient + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#pragma once + +#ifdef __EMSCRIPTEN__ + +#include +#include +#include "declarations.h" +#include +#include + + +class WebConnection : public LuaObject +{ + using ErrorCallback = std::function; + using RecvCallback = std::function; + + enum + { + READ_TIMEOUT = 30, + WRITE_TIMEOUT = 30, + SEND_BUFFER_SIZE = 65536, + RECV_BUFFER_SIZE = 65536 + }; + +public: + WebConnection(); + ~WebConnection() override; + + static void poll(); + static void terminate(); + + void connect(const std::string_view host, uint16_t port, const std::function& connectCallback, bool gameWorld); + void close(); + + void write(uint8_t* buffer, size_t size); + void read(const uint16_t size, const RecvCallback& callback, int tries = 0); + + void setErrorCallback(const ErrorCallback& errorCallback) { m_errorCallback = errorCallback; } + + int getIp(); + bool isConnecting() const { return m_connecting; } + bool isConnected() const { return m_connected; } + ticks_t getElapsedTicksSinceLastRead() const { return m_connected ? m_activityTimer.elapsed_millis() : -1; } + + WebConnectionPtr asWebConnection() { return static_self_cast(); } + +protected: + bool sendPacket(uint8_t* buffer, uint16_t size); + + void internal_write(); + void onWrite(const std::shared_ptr& + outputStream); + void onRecv(const uint16_t recvSize); + void onTimeout(); + + static void runOnConnectCallback(std::function callback); + static void runOnErrorCallback(ErrorCallback callback); + + std::function m_connectCallback; + ErrorCallback m_errorCallback; + RecvCallback m_recvCallback; + + EMSCRIPTEN_WEBSOCKET_T m_websocket = 0; + bool m_gameWorld; + pthread_t m_pthread; + + static std::list> m_outputStreams; + std::shared_ptr m_outputStream; + bool m_connected{ false }; + bool m_connecting{ false }; + stdext::timer m_activityTimer; + + asio::streambuf m_inputStream; +}; +#endif diff --git a/src/framework/otml/declarations.h b/src/framework/otml/declarations.h index 6157cfa3f4..6878cc0cdb 100644 --- a/src/framework/otml/declarations.h +++ b/src/framework/otml/declarations.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * 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/src/framework/otml/otml.h b/src/framework/otml/otml.h index 1f8c61812c..16ee0ce052 100644 --- a/src/framework/otml/otml.h +++ b/src/framework/otml/otml.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * 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/src/framework/otml/otmldocument.cpp b/src/framework/otml/otmldocument.cpp index 661860fb9a..102b8aa614 100644 --- a/src/framework/otml/otmldocument.cpp +++ b/src/framework/otml/otmldocument.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * 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/src/framework/otml/otmldocument.h b/src/framework/otml/otmldocument.h index b8d9a1a9c1..b473ebc81b 100644 --- a/src/framework/otml/otmldocument.h +++ b/src/framework/otml/otmldocument.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -24,7 +24,7 @@ #include "otmlnode.h" -class OTMLDocument : public OTMLNode +class OTMLDocument final : public OTMLNode { public: /// Create a new OTML document for filling it with nodes @@ -36,13 +36,13 @@ class OTMLDocument : public OTMLNode /// Parse OTML from input stream /// @param in /// @param source is the file name that will be used to show errors messages - static OTMLDocumentPtr parse(std::istream& in, const std::string_view source); + static OTMLDocumentPtr parse(std::istream& in, std::string_view source); /// Emits this document and all it's children to a std::string std::string emit() override; /// Save this document to a file - bool save(const std::string_view fileName); + bool save(std::string_view fileName); private: OTMLDocument() = default; diff --git a/src/framework/otml/otmlemitter.cpp b/src/framework/otml/otmlemitter.cpp index 0ea5e84d83..2c238e54fc 100644 --- a/src/framework/otml/otmlemitter.cpp +++ b/src/framework/otml/otmlemitter.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -23,7 +23,7 @@ #include "otmlemitter.h" #include "otmldocument.h" -std::string OTMLEmitter::emitNode(const OTMLNodePtr& node, int currentDepth) +std::string OTMLEmitter::emitNode(const OTMLNodePtr& node, const int currentDepth) { std::stringstream ss; diff --git a/src/framework/otml/otmlemitter.h b/src/framework/otml/otmlemitter.h index 48e97b703a..e7bc896ce7 100644 --- a/src/framework/otml/otmlemitter.h +++ b/src/framework/otml/otmlemitter.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * 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/src/framework/otml/otmlexception.cpp b/src/framework/otml/otmlexception.cpp index 9958a04ec4..90589a32fd 100644 --- a/src/framework/otml/otmlexception.cpp +++ b/src/framework/otml/otmlexception.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -33,7 +33,7 @@ OTMLException::OTMLException(const OTMLNodePtr& node, const std::string_view err m_what = ss.str(); } -OTMLException::OTMLException(const OTMLDocumentPtr& doc, const std::string_view error, int line) +OTMLException::OTMLException(const OTMLDocumentPtr& doc, const std::string_view error, const int line) { std::stringstream ss; ss << "OTML error"; diff --git a/src/framework/otml/otmlexception.h b/src/framework/otml/otmlexception.h index db3cf96978..02ebfa5e9d 100644 --- a/src/framework/otml/otmlexception.h +++ b/src/framework/otml/otmlexception.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -25,11 +25,11 @@ #include "declarations.h" /// All OTML errors throw this exception -class OTMLException : public stdext::exception +class OTMLException final : public stdext::exception { public: - OTMLException(const OTMLNodePtr& node, const std::string_view error); - OTMLException(const OTMLDocumentPtr& doc, const std::string_view error, int line = -1); + OTMLException(const OTMLNodePtr& node, std::string_view error); + OTMLException(const OTMLDocumentPtr& doc, std::string_view error, int line = -1); ~OTMLException() noexcept override = default; const char* what() const noexcept override { return m_what.data(); } diff --git a/src/framework/otml/otmlnode.cpp b/src/framework/otml/otmlnode.cpp index 1bafc3e17c..c2b3287642 100644 --- a/src/framework/otml/otmlnode.cpp +++ b/src/framework/otml/otmlnode.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,9 +21,10 @@ */ #include "otmlnode.h" + #include "otmlemitter.h" -OTMLNodePtr OTMLNode::create(const std::string_view tag, bool unique) +OTMLNodePtr OTMLNode::create(const std::string_view tag, const bool unique) { const auto& node = std::make_shared(); node->setTag(tag); @@ -59,7 +60,7 @@ OTMLNodePtr OTMLNode::get(const std::string_view childTag) const return nullptr; } -OTMLNodePtr OTMLNode::getIndex(int childIndex) +OTMLNodePtr OTMLNode::getIndex(const int childIndex) { return childIndex < size() && childIndex >= 0 ? m_children[childIndex] : nullptr; } @@ -75,7 +76,7 @@ OTMLNodePtr OTMLNode::at(const std::string_view childTag) throw OTMLException(asOTMLNode(), stdext::format("child node with tag '%s' not found", childTag)); } -OTMLNodePtr OTMLNode::atIndex(int childIndex) +OTMLNodePtr OTMLNode::atIndex(const int childIndex) { if (childIndex >= size() || childIndex < 0) throw OTMLException(asOTMLNode(), stdext::format("child node with index '%d' not found", childIndex)); @@ -117,7 +118,7 @@ void OTMLNode::addChild(const OTMLNodePtr& newChild) bool OTMLNode::removeChild(const OTMLNodePtr& oldChild) { - const auto it = std::find(m_children.begin(), m_children.end(), oldChild); + const auto it = std::ranges::find(m_children, oldChild); if (it == m_children.end()) return false; @@ -127,7 +128,7 @@ bool OTMLNode::removeChild(const OTMLNodePtr& oldChild) bool OTMLNode::replaceChild(const OTMLNodePtr& oldChild, const OTMLNodePtr& newChild) { - auto it = std::find(m_children.begin(), m_children.end(), oldChild); + auto it = std::ranges::find(m_children, oldChild); if (it != m_children.end()) { it = m_children.erase(it); m_children.insert(it, newChild); diff --git a/src/framework/otml/otmlnode.h b/src/framework/otml/otmlnode.h index b492c7fef3..5ae6370c61 100644 --- a/src/framework/otml/otmlnode.h +++ b/src/framework/otml/otmlnode.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -27,10 +27,10 @@ class OTMLNode : public std::enable_shared_from_this { public: - virtual ~OTMLNode() {} // fix clang warning + virtual ~OTMLNode() = default; // fix clang warning - static OTMLNodePtr create(const std::string_view tag = "", bool unique = false); - static OTMLNodePtr create(const std::string_view tag, const std::string_view value); + static OTMLNodePtr create(std::string_view tag = "", bool unique = false); + static OTMLNodePtr create(std::string_view tag, std::string_view value); std::string tag() { return m_tag; } int size() const { return m_children.size(); } @@ -44,18 +44,18 @@ class OTMLNode : public std::enable_shared_from_this bool hasValue() const { return !m_value.empty(); } bool hasChildren() const; bool hasChildAt(const std::string_view childTag) const { return !!get(childTag); } - bool hasChildAtIndex(int childIndex) { return !!getIndex(childIndex); } + bool hasChildAtIndex(const int childIndex) { return !!getIndex(childIndex); } void setTag(const std::string_view tag) { m_tag = tag; } void setValue(const std::string_view value) { m_value = value; } - void setNull(bool null) { m_null = null; } - void setUnique(bool unique) { m_unique = unique; } + void setNull(const bool null) { m_null = null; } + void setUnique(const bool unique) { m_unique = unique; } void setSource(const std::string_view source) { m_source = source; } - OTMLNodePtr get(const std::string_view childTag) const; + OTMLNodePtr get(std::string_view childTag) const; OTMLNodePtr getIndex(int childIndex); - OTMLNodePtr at(const std::string_view childTag); + OTMLNodePtr at(std::string_view childTag); OTMLNodePtr atIndex(int childIndex); void addChild(const OTMLNodePtr& newChild); @@ -71,18 +71,18 @@ class OTMLNode : public std::enable_shared_from_this template T value(); template - T valueAt(const std::string_view childTag); + T valueAt(std::string_view childTag); template T valueAtIndex(int childIndex); template - T valueAt(const std::string_view childTag, const T& def); + T valueAt(std::string_view childTag, const T& def); template T valueAtIndex(int childIndex, const T& def); template void write(const T& v); template - void writeAt(const std::string_view childTag, const T& v); + void writeAt(std::string_view childTag, const T& v); template void writeIn(const T& v); @@ -133,7 +133,7 @@ T OTMLNode::valueAt(const std::string_view childTag) } template -T OTMLNode::valueAtIndex(int childIndex) +T OTMLNode::valueAtIndex(const int childIndex) { const OTMLNodePtr node = atIndex(childIndex); return node->value(); @@ -149,7 +149,7 @@ T OTMLNode::valueAt(const std::string_view childTag, const T& def) } template -T OTMLNode::valueAtIndex(int childIndex, const T& def) +T OTMLNode::valueAtIndex(const int childIndex, const T& def) { if (const auto& node = getIndex(childIndex)) return node->value(); diff --git a/src/framework/otml/otmlparser.cpp b/src/framework/otml/otmlparser.cpp index df8d3f8489..35ba07bdac 100644 --- a/src/framework/otml/otmlparser.cpp +++ b/src/framework/otml/otmlparser.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -28,7 +28,8 @@ OTMLParser::OTMLParser(const OTMLDocumentPtr& doc, std::istream& in) : currentDepth(0), currentLine(0), doc(doc), currentParent(doc), previousNode(nullptr), in(in) -{} +{ +} void OTMLParser::parse() { @@ -47,7 +48,7 @@ std::string OTMLParser::getNextLine() return line; } -int OTMLParser::getLineDepth(const std::string_view line, bool multilining) const +int OTMLParser::getLineDepth(const std::string_view line, const bool multilining) const { auto _line = std::string{ line }; stdext::trim(_line); // fix for lines without content. @@ -208,4 +209,4 @@ void OTMLParser::parseNode(const std::string_view data) currentParent->addChild(node); parentMap[node] = currentParent; previousNode = node; -} +} \ No newline at end of file diff --git a/src/framework/otml/otmlparser.h b/src/framework/otml/otmlparser.h index 5d17251f56..5f4a83c661 100644 --- a/src/framework/otml/otmlparser.h +++ b/src/framework/otml/otmlparser.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -36,12 +36,12 @@ class OTMLParser /// Retrieve next line from the input stream std::string getNextLine(); /// Counts depth of a line (every 2 spaces increments one depth) - int getLineDepth(const std::string_view line, bool multilining = false) const; + int getLineDepth(std::string_view line, bool multilining = false) const; /// Parse each line of the input stream void parseLine(std::string line); /// Parse nodes tag and value - void parseNode(const std::string_view data); + void parseNode(std::string_view data); int currentDepth; int currentLine; diff --git a/src/framework/pch.h b/src/framework/pch.h index e2dad35867..aa61bf513c 100644 --- a/src/framework/pch.h +++ b/src/framework/pch.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -22,7 +22,7 @@ #pragma once -// common C headers + // common C headers #include #include #include @@ -39,18 +39,18 @@ #include #include #include +#include #include #include #include #include #include #include -#include #include -#include +#include -#include #include +#include #include using namespace std::literals; diff --git a/src/framework/platform/browserplatform.cpp b/src/framework/platform/browserplatform.cpp new file mode 100644 index 0000000000..9cdc769b3e --- /dev/null +++ b/src/framework/platform/browserplatform.cpp @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2010-2016 OTClient + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifdef __EMSCRIPTEN__ + +#include "platform.h" +#include +#include +#include +#include +#include +#include + +#include + +void Platform::init(std::vector& args) +{ + processArgs(args); + setDevice({ Browser, OsUnknown }); +} + +void Platform::processArgs(std::vector& /*args*/) +{ + //nothing todo, linux args are already utf8 encoded +} + +bool Platform::spawnProcess(std::string process, const std::vector& args) +{ + return false; +} + +int Platform::getProcessId() +{ + return getpid(); +} + +bool Platform::isProcessRunning(const std::string_view /*name*/) +{ + return false; +} + +bool Platform::killProcess(const std::string_view /*name*/) +{ + return false; +} + +std::string Platform::getTempPath() +{ + return std::filesystem::temp_directory_path(); +} + +std::string Platform::getCurrentDir() +{ + return std::filesystem::current_path(); +} + +bool Platform::copyFile(std::string from, std::string to) +{ + return std::filesystem::copy_file(from, to); +} + +bool Platform::fileExists(std::string file) +{ + return std::filesystem::exists(file); +} + +bool Platform::removeFile(std::string file) +{ + return std::filesystem::remove(file); +} + +ticks_t Platform::getFileModificationTime(std::string file) +{ + return 0; +} + +bool Platform::openUrl(std::string url, bool now) +{ + return true; +} + +bool Platform::openDir(std::string path, bool now) +{ + return true; +} + +std::string Platform::getCPUName() +{ + return std::string(); +} + +double Platform::getTotalSystemMemory() +{ + return 0; +} + +std::string Platform::getOSName() +{ + return "browser"; +} + +std::string Platform::traceback(const std::string_view where, int level, int maxDepth) +{ + return ""; +} + + +#endif \ No newline at end of file diff --git a/src/framework/platform/browserwindow.cpp b/src/framework/platform/browserwindow.cpp new file mode 100644 index 0000000000..9a6b44c50c --- /dev/null +++ b/src/framework/platform/browserwindow.cpp @@ -0,0 +1,581 @@ +/* + * Copyright (c) 2024 OTArchive + * Copyright (c) 2010-2014 OTClient + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifdef __EMSCRIPTEN__ + +#include +#include "browserwindow.h" +#include +#include +#include + +BrowserWindow& g_browserWindow = (BrowserWindow&)g_window; + +stdext::map m_keyMapStr; +EmscriptenWebGLContextAttributes attr; + +BrowserWindow::BrowserWindow() { + m_minimumSize = Size(600, 480); + m_size = Size(1280, 720); + m_running = false; + web_keymap.push_back({ "Backspace", Fw::KeyBackspace }); + web_keymap.push_back({ "Tab", Fw::KeyTab }); + web_keymap.push_back({ "Enter", Fw::KeyEnter }); + web_keymap.push_back({ "ShiftLeft", Fw::KeyShift }); + web_keymap.push_back({ "ShiftRight", Fw::KeyShift }); + web_keymap.push_back({ "ControlLeft", Fw::KeyCtrl }); + web_keymap.push_back({ "ControlRight", Fw::KeyCtrl }); + web_keymap.push_back({ "AltLeft", Fw::KeyAlt }); + web_keymap.push_back({ "AltRight", Fw::KeyAlt }); + web_keymap.push_back({ "Pause", Fw::KeyPause }); + web_keymap.push_back({ "CapsLock", Fw::KeyCapsLock }); + web_keymap.push_back({ "Escape", Fw::KeyEscape }); + web_keymap.push_back({ "Space", Fw::KeySpace }); + web_keymap.push_back({ "PageUp", Fw::KeyPageUp }); + web_keymap.push_back({ "PageDown", Fw::KeyPageDown }); + web_keymap.push_back({ "End", Fw::KeyEnd }); + web_keymap.push_back({ "Home", Fw::KeyHome }); + web_keymap.push_back({ "ArrowLeft", Fw::KeyLeft }); + web_keymap.push_back({ "ArrowUp", Fw::KeyUp }); + web_keymap.push_back({ "ArrowRight", Fw::KeyRight }); + web_keymap.push_back({ "ArrowDown", Fw::KeyDown }); + web_keymap.push_back({ "PrintScreen", Fw::KeyPrintScreen }); + web_keymap.push_back({ "Insert", Fw::KeyInsert }); + web_keymap.push_back({ "Delete", Fw::KeyDelete }); + web_keymap.push_back({ "Digit0", Fw::Key0 }); + web_keymap.push_back({ "Digit1", Fw::Key1 }); + web_keymap.push_back({ "Digit2", Fw::Key2 }); + web_keymap.push_back({ "Digit3", Fw::Key3 }); + web_keymap.push_back({ "Digit4", Fw::Key4 }); + web_keymap.push_back({ "Digit5", Fw::Key5 }); + web_keymap.push_back({ "Digit6", Fw::Key6 }); + web_keymap.push_back({ "Digit7", Fw::Key7 }); + web_keymap.push_back({ "Digit8", Fw::Key8 }); + web_keymap.push_back({ "Digit9", Fw::Key9 }); + web_keymap.push_back({ "KeyA", Fw::KeyA }); + web_keymap.push_back({ "KeyB", Fw::KeyB }); + web_keymap.push_back({ "KeyC", Fw::KeyC }); + web_keymap.push_back({ "KeyD", Fw::KeyD }); + web_keymap.push_back({ "KeyE", Fw::KeyE }); + web_keymap.push_back({ "KeyF", Fw::KeyF }); + web_keymap.push_back({ "KeyG", Fw::KeyG }); + web_keymap.push_back({ "KeyH", Fw::KeyH }); + web_keymap.push_back({ "KeyI", Fw::KeyI }); + web_keymap.push_back({ "KeyJ", Fw::KeyJ }); + web_keymap.push_back({ "KeyK", Fw::KeyK }); + web_keymap.push_back({ "KeyL", Fw::KeyL }); + web_keymap.push_back({ "KeyM", Fw::KeyM }); + web_keymap.push_back({ "KeyN", Fw::KeyN }); + web_keymap.push_back({ "KeyO", Fw::KeyO }); + web_keymap.push_back({ "KeyP", Fw::KeyP }); + web_keymap.push_back({ "KeyQ", Fw::KeyQ }); + web_keymap.push_back({ "KeyR", Fw::KeyR }); + web_keymap.push_back({ "KeyS", Fw::KeyS }); + web_keymap.push_back({ "KeyT", Fw::KeyT }); + web_keymap.push_back({ "KeyU", Fw::KeyU }); + web_keymap.push_back({ "KeyV", Fw::KeyV }); + web_keymap.push_back({ "KeyW", Fw::KeyW }); + web_keymap.push_back({ "KeyX", Fw::KeyX }); + web_keymap.push_back({ "KeyY", Fw::KeyY }); + web_keymap.push_back({ "KeyZ", Fw::KeyZ }); + web_keymap.push_back({ "MetaLeft", Fw::KeyMeta }); + web_keymap.push_back({ "MetaRight", Fw::KeyMeta }); + web_keymap.push_back({ "Numpad1", Fw::KeyNumpad1 }); + web_keymap.push_back({ "Numpad2", Fw::KeyNumpad2 }); + web_keymap.push_back({ "Numpad3", Fw::KeyNumpad3 }); + web_keymap.push_back({ "Numpad4", Fw::KeyNumpad4 }); + web_keymap.push_back({ "Numpad5", Fw::KeyNumpad5 }); + web_keymap.push_back({ "Numpad6", Fw::KeyNumpad6 }); + web_keymap.push_back({ "Numpad7", Fw::KeyNumpad7 }); + web_keymap.push_back({ "Numpad8", Fw::KeyNumpad8 }); + web_keymap.push_back({ "Numpad9", Fw::KeyNumpad9 }); + web_keymap.push_back({ "Numpad0", Fw::KeyNumpad0 }); + web_keymap.push_back({ "NumpadMultiply", Fw::KeyAsterisk }); + web_keymap.push_back({ "NumpadAdd", Fw::KeyPlus }); + web_keymap.push_back({ "NumpadSubtract", Fw::KeyMinus }); + web_keymap.push_back({ "NumpadDecimal", Fw::KeyPeriod }); + web_keymap.push_back({ "NumpadDivide", Fw::KeySlash }); + web_keymap.push_back({ "F1", Fw::KeyF1 }); + web_keymap.push_back({ "F2", Fw::KeyF2 }); + web_keymap.push_back({ "F3", Fw::KeyF3 }); + web_keymap.push_back({ "F4", Fw::KeyF4 }); + web_keymap.push_back({ "F5", Fw::KeyF5 }); + web_keymap.push_back({ "F6", Fw::KeyF6 }); + web_keymap.push_back({ "F7", Fw::KeyF7 }); + web_keymap.push_back({ "F8", Fw::KeyF8 }); + web_keymap.push_back({ "F9", Fw::KeyF9 }); + web_keymap.push_back({ "F10", Fw::KeyF10 }); + web_keymap.push_back({ "F11", Fw::KeyF11 }); + web_keymap.push_back({ "F12", Fw::KeyF12 }); + web_keymap.push_back({ "NumLock", Fw::KeyNumLock }); + web_keymap.push_back({ "ScrollLock", Fw::KeyScrollLock }); + web_keymap.push_back({ "Semicolon", Fw::KeySemicolon }); + web_keymap.push_back({ "Equal", Fw::KeyEqual }); + web_keymap.push_back({ "Comma", Fw::KeyComma }); + web_keymap.push_back({ "Minus", Fw::KeyMinus }); + web_keymap.push_back({ "Period", Fw::KeyPeriod }); + web_keymap.push_back({ "Slash", Fw::KeySlash }); + web_keymap.push_back({ "Backquote", Fw::KeyGrave }); + web_keymap.push_back({ "BracketLeft", Fw::KeyLeftBracket }); + web_keymap.push_back({ "Backslash", Fw::KeyBackslash }); + web_keymap.push_back({ "BracketRight", Fw::KeyRightBracket }); + web_keymap.push_back({ "Quote", Fw::KeyQuote }); + web_keymap.push_back({ 0, Fw::KeyUnknown }); +} + +void BrowserWindow::terminate() { + emscripten_set_mouseup_callback("#canvas", this, EM_TRUE, nullptr); + emscripten_set_mousedown_callback("#canvas", this, EM_TRUE, nullptr); + emscripten_set_wheel_callback("#canvas", this, EM_TRUE, nullptr); + emscripten_set_mousemove_callback("#canvas", this, EM_TRUE, nullptr); + emscripten_set_keydown_callback("#canvas", this, EM_TRUE, nullptr); + emscripten_set_keyup_callback("#canvas", this, EM_TRUE, nullptr); + emscripten_set_keypress_callback("#canvas", this, EM_TRUE, nullptr); + emscripten_set_resize_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, this, EM_TRUE, nullptr); + emscripten_set_focus_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, this, EM_TRUE, nullptr); + emscripten_set_blur_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, this, EM_TRUE, nullptr); + emscripten_set_touchend_callback("#canvas", this, EM_TRUE, nullptr); + emscripten_set_touchstart_callback("#canvas", this, EM_TRUE, nullptr); + emscripten_set_touchmove_callback("#canvas", this, EM_TRUE, nullptr); + EMSCRIPTEN_WEBGL_CONTEXT_HANDLE ctx = emscripten_webgl_get_current_context(); + emscripten_webgl_destroy_context(ctx); + + m_visible = false; + m_running = false; +} + +void BrowserWindow::internalInitGL() { + double w, h; + emscripten_get_element_css_size("#canvas", &w, &h); + m_size = Size(int(w), int(h)); + emscripten_set_canvas_element_size("#canvas", int(w), int(h)); + + + EmscriptenWebGLContextAttributes attr; + emscripten_webgl_init_context_attributes(&attr); + attr.majorVersion = 2; + attr.renderViaOffscreenBackBuffer = attr.explicitSwapControl = attr.alpha = attr.depth = attr.stencil = attr.antialias = attr.preserveDrawingBuffer = attr.failIfMajorPerformanceCaveat = 0; + EMSCRIPTEN_WEBGL_CONTEXT_HANDLE ctx = emscripten_webgl_create_context("#canvas", &attr); + emscripten_webgl_make_context_current(ctx); + + + glViewport(0, 0, int(w), int(h)); +} + +void BrowserWindow::poll() { + if (!g_app.isRunning()) + return; + + + if (!m_running) { + m_visible = true; + + emscripten_set_mouseup_callback("#canvas", this, EM_TRUE, ([](int eventType, const EmscriptenMouseEvent* event, void* userData) -> EM_BOOL { + static_cast(userData)->handleMouseCallback(eventType, event); + return EM_TRUE; + })); + emscripten_set_mousedown_callback("#canvas", this, EM_TRUE, ([](int eventType, const EmscriptenMouseEvent* event, void* userData) -> EM_BOOL { + static_cast(userData)->handleMouseCallback(eventType, event); + return EM_TRUE; + })); + emscripten_set_wheel_callback("#canvas", this, EM_TRUE, ([](int eventType, const EmscriptenWheelEvent* event, void* userData) -> EM_BOOL { + static_cast(userData)->handleMouseWheelCallback(event); + return EM_TRUE; + })); + emscripten_set_mousemove_callback("#canvas", this, EM_TRUE, ([](int eventType, const EmscriptenMouseEvent* event, void* userData) -> EM_BOOL { + static_cast(userData)->handleMouseMotionCallback(event); + return EM_TRUE; + })); + emscripten_set_keydown_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, this, EM_TRUE, ([](int eventType, const EmscriptenKeyboardEvent* event, void* userData) -> EM_BOOL { + static_cast(userData)->handleKeyboardCallback(eventType, event); + return EM_TRUE; + })); + emscripten_set_keyup_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, this, EM_TRUE, ([](int eventType, const EmscriptenKeyboardEvent* event, void* userData) -> EM_BOOL { + static_cast(userData)->handleKeyboardCallback(eventType, event); + return EM_TRUE; + })); + emscripten_set_keypress_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, this, EM_TRUE, ([](int eventType, const EmscriptenKeyboardEvent* event, void* userData) -> EM_BOOL { + static_cast(userData)->handleKeyboardCallback(eventType, event); + return EM_TRUE; + })); + emscripten_set_resize_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, this, EM_TRUE, ([](int eventType, const EmscriptenUiEvent* event, void* userData) -> EM_BOOL { + static_cast(userData)->handleResizeCallback(event); + return EM_TRUE; + })); + emscripten_set_focus_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, this, EM_TRUE, ([](int eventType, const EmscriptenFocusEvent* event, void* userData) -> EM_BOOL { + static_cast(userData)->handleFocusCallback(eventType, event); + return EM_TRUE; + })); + emscripten_set_blur_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, this, EM_TRUE, ([](int eventType, const EmscriptenFocusEvent* event, void* userData) -> EM_BOOL { + static_cast(userData)->handleFocusCallback(eventType, event); + return EM_TRUE; + })); + emscripten_set_touchend_callback("#canvas", this, EM_TRUE, ([](int eventType, const EmscriptenTouchEvent* event, void* userData) -> EM_BOOL { + static_cast(userData)->handleTouchCallback(eventType, event); + return EM_TRUE; + })); + emscripten_set_touchstart_callback("#canvas", this, EM_TRUE, ([](int eventType, const EmscriptenTouchEvent* event, void* userData) -> EM_BOOL { + static_cast(userData)->handleTouchCallback(eventType, event); + return EM_TRUE; + })); + emscripten_set_touchmove_callback("#canvas", this, EM_TRUE, ([](int eventType, const EmscriptenTouchEvent* event, void* userData) -> EM_BOOL { + static_cast(userData)->handleTouchCallback(eventType, event); + return EM_TRUE; + })); + + // clang-format off + MAIN_THREAD_ASYNC_EM_ASM({ + document.addEventListener("paste", function(event){ + Module["ccall"]("paste_return", "number",["string", "number"],[event.clipboardData.getData("text/plain"), $0]); + }); + }, this); + MAIN_THREAD_ASYNC_EM_ASM({ + if (navigator && "virtualKeyboard" in navigator && (/iphone|ipod|ipad|android/i).test(navigator.userAgent)) { + navigator.virtualKeyboard.overlaysContent = true; + const textInput = document.getElementById("title-text"); + const DOM_VK_BACK_SPACE = 8; + const DOM_VK_RETURN = 13; + const DOM_ANDROID_CODE = 229; //https://stackoverflow.com/questions/36753548/keycode-on-android-is-always-229 + textInput.addEventListener("input", function(ev) { + textInput.innerHTML = ""; + ev.preventDefault(); + ev.stopPropagation(); + }); + textInput.addEventListener("keydown", function(ev) { + if (ev.which === DOM_VK_BACK_SPACE) { + const options = { + code: 'Backspace', + key : 'Backspace', + keyCode : DOM_VK_BACK_SPACE, + which : DOM_VK_BACK_SPACE + }; + window.dispatchEvent(new KeyboardEvent('keydown', options)); + window.dispatchEvent(new KeyboardEvent('keyup', options)); + ev.preventDefault(); + ev.stopPropagation(); + } + if (ev.which === DOM_VK_RETURN) { + const options = { + charCode: DOM_VK_RETURN, + code : 'Enter', + key : 'Enter', + keyCode : DOM_VK_RETURN, + which : DOM_VK_RETURN + }; + window.dispatchEvent(new KeyboardEvent('keydown', options)); + window.dispatchEvent(new KeyboardEvent('keypress', options)); + window.dispatchEvent(new KeyboardEvent('keyup', options)); + ev.preventDefault(); + ev.stopPropagation(); + } + if (ev.which === DOM_ANDROID_CODE) { + ev.preventDefault(); + ev.stopPropagation(); + } + }); + textInput.addEventListener("keyup", function(ev) { + if (ev.which === DOM_VK_BACK_SPACE || ev.which === DOM_VK_RETURN || ev.which === DOM_ANDROID_CODE) { + ev.preventDefault(); + ev.stopPropagation(); + } + }); + } + }); + // clang-format on + + m_onResize(m_size); + m_running = true; + } + + fireKeysPress(); +} + +extern "C" { + //Called from javascript + EMSCRIPTEN_KEEPALIVE inline int paste_return(char const* paste_data, void* callback_data) { + static_cast(callback_data)->setClipboardText(paste_data); + return 1; + } +} + +void BrowserWindow::handleMouseCallback(int eventType, const EmscriptenMouseEvent* mouseEvent) { + if (!m_usingTouch && mouseEvent->screenX != 0 && mouseEvent->screenY != 0 && mouseEvent->clientX != 0 && mouseEvent->clientY != 0 && mouseEvent->targetX != 0 && mouseEvent->targetY != 0) { + int button = mouseEvent->button; + g_dispatcher.addEvent([this, eventType, button] { + m_inputEvent.reset(); + m_inputEvent.type = (eventType == EMSCRIPTEN_EVENT_MOUSEDOWN) ? Fw::MousePressInputEvent : Fw::MouseReleaseInputEvent; + switch (button) { + case 0: + m_inputEvent.mouseButton = Fw::MouseLeftButton; + if (eventType == EMSCRIPTEN_EVENT_MOUSEDOWN) { m_mouseButtonStates |= 1 << Fw::MouseLeftButton; } else { g_dispatcher.addEvent([this] { m_mouseButtonStates &= ~(1 << Fw::MouseLeftButton); }); } + break; + case 2: + m_inputEvent.mouseButton = Fw::MouseRightButton; + if (eventType == EMSCRIPTEN_EVENT_MOUSEDOWN) { m_mouseButtonStates |= 1 << Fw::MouseRightButton; } else { g_dispatcher.addEvent([this] { m_mouseButtonStates &= ~(1 << Fw::MouseRightButton); }); } + break; + case 1: + m_inputEvent.mouseButton = Fw::MouseMidButton; + if (eventType == EMSCRIPTEN_EVENT_MOUSEDOWN) { m_mouseButtonStates |= 1 << Fw::MouseMidButton; } else { g_dispatcher.addEvent([this] { m_mouseButtonStates &= ~(1 << Fw::MouseMidButton); }); } + break; + default: + m_inputEvent.type = Fw::NoInputEvent; + break; + } + if (m_inputEvent.type != Fw::NoInputEvent && m_onInputEvent) + m_onInputEvent(m_inputEvent); + }); + } +} + +void BrowserWindow::handleMouseWheelCallback(const EmscriptenWheelEvent* event) { + if (event->mouse.screenX != 0 && event->mouse.screenY != 0 && event->mouse.clientX != 0 && event->mouse.clientY != 0 && event->mouse.targetX != 0 && event->mouse.targetY != 0) { + g_dispatcher.addEvent([this, event] { + m_inputEvent.reset(); + m_inputEvent.type = Fw::MouseReleaseInputEvent; + event->deltaY > 0 ? m_inputEvent.wheelDirection = Fw::MouseWheelDown : m_inputEvent.wheelDirection = Fw::MouseWheelUp; + m_inputEvent.type = Fw::MouseWheelInputEvent; + m_inputEvent.mouseButton = Fw::MouseMidButton; + if (m_inputEvent.type != Fw::NoInputEvent && m_onInputEvent) + m_onInputEvent(m_inputEvent); + }); + } +} + + +void BrowserWindow::handleResizeCallback(const EmscriptenUiEvent* event) { + double w, h; + emscripten_get_element_css_size("#canvas", &w, &h); + if (m_size.width() != int(w) || m_size.height() != int(h)) { + emscripten_set_canvas_element_size("#canvas", int(w), int(h)); + glViewport(0, 0, int(w), int(h)); + m_size = Size(int(w), int(h)); + m_onResize(m_size); + } +} + +void BrowserWindow::handleMouseMotionCallback(const EmscriptenMouseEvent* mouseEvent) { + m_inputEvent.reset(); + m_inputEvent.type = Fw::MouseMoveInputEvent; + Point newMousePos(mouseEvent->clientX / m_displayDensity, mouseEvent->clientY / m_displayDensity); + m_inputEvent.mouseMoved = newMousePos - m_inputEvent.mousePos; + m_inputEvent.mousePos = newMousePos; + if (m_onInputEvent) + m_onInputEvent(m_inputEvent); +} + +void BrowserWindow::handleTouchCallback(int eventType, const EmscriptenTouchEvent* event) { + m_usingTouch = true; + if (event->touches->screenX != 0 && event->touches->screenY != 0 && event->touches->clientX != 0 && event->touches->clientY != 0 && event->touches->targetX != 0 && event->touches->targetY != 0) { + updateTouchPosition(event); + if (eventType == EMSCRIPTEN_EVENT_TOUCHMOVE) { + m_clickTimer.stop(); + return; + }; + g_dispatcher.addEvent([this, eventType, event] { + m_inputEvent.reset(); + Point newMousePos(event->touches->targetX / m_displayDensity, event->touches->targetY / m_displayDensity); + m_inputEvent.mouseButton = Fw::MouseLeftButton; + if (eventType == EMSCRIPTEN_EVENT_TOUCHSTART) { + m_clickTimer.restart(); + m_inputEvent.type = Fw::MousePressInputEvent; + m_mouseButtonStates |= 1 << Fw::MouseLeftButton; + } else if (eventType == EMSCRIPTEN_EVENT_TOUCHEND) { + m_inputEvent.type = Fw::MouseReleaseInputEvent; + g_dispatcher.addEvent([this] { m_mouseButtonStates &= ~(1 << Fw::MouseLeftButton); }); + if (m_clickTimer.running() && m_clickTimer.ticksElapsed() >= 200) { + processLongTouch(event); + } + m_clickTimer.stop(); + } + if (m_inputEvent.type != Fw::NoInputEvent && m_onInputEvent) + m_onInputEvent(m_inputEvent); + }); + } +} + +void BrowserWindow::updateTouchPosition(const EmscriptenTouchEvent* event) { + g_dispatcher.addEvent([this, event] { + m_inputEvent.reset(); + Point newMousePos(event->touches->targetX / m_displayDensity, event->touches->targetY / m_displayDensity); + m_inputEvent.mouseMoved = newMousePos - m_inputEvent.mousePos; + m_inputEvent.mousePos = newMousePos; + m_inputEvent.type = Fw::MouseMoveInputEvent; + if (m_onInputEvent) + m_onInputEvent(m_inputEvent); + }); +} + +void BrowserWindow::processLongTouch(const EmscriptenTouchEvent* event) { + m_clickTimer.stop(); + g_dispatcher.addEvent([this, event] { + m_inputEvent.reset(); + m_inputEvent.mouseButton = Fw::MouseRightButton; + m_inputEvent.type = Fw::MousePressInputEvent; + if (m_onInputEvent) + m_onInputEvent(m_inputEvent); + }); + g_dispatcher.addEvent([this, event] { + m_inputEvent.reset(); + m_inputEvent.mouseButton = Fw::MouseRightButton; + m_inputEvent.type = Fw::MouseReleaseInputEvent; + if (m_onInputEvent) + m_onInputEvent(m_inputEvent); + }); +} + +size_t number_of_characters_in_utf8_string(const char* str) { + if (!str) return 0; + size_t num_chars = 0; + while (*str) { + if ((*str++ & 0xC0) != 0x80) ++num_chars; // Skip all continuation bytes + } + return num_chars; +} + +bool string_eq(const char* a, const char* b) { + if (a == nullptr || b == nullptr) return false; + return std::strcmp(a, b) == 0; +} + +void BrowserWindow::handleKeyboardCallback(int eventType, const EmscriptenKeyboardEvent* keyboardEvent) { + if (eventType == EMSCRIPTEN_EVENT_KEYPRESS) { + if (m_onInputEvent && keyboardEvent->key[0] && number_of_characters_in_utf8_string(keyboardEvent->key) == 1) { + m_inputEvent.reset(Fw::KeyTextInputEvent); + m_inputEvent.keyText = keyboardEvent->key; + m_onInputEvent(m_inputEvent); + } + } + if (!keyboardEvent->repeat || eventType == EMSCRIPTEN_EVENT_KEYDOWN) { + Fw::Key keyCode = Fw::KeyUnknown; + for (size_t i = 0; i < web_keymap.size(); i++) { + if (string_eq(web_keymap[i].first, keyboardEvent->code)) { + keyCode = web_keymap[i].second; + break; + } + } + if (eventType == EMSCRIPTEN_EVENT_KEYDOWN) + processKeyDown(keyCode); + else if (eventType == EMSCRIPTEN_EVENT_KEYUP) + processKeyUp(keyCode); + } +} + +void BrowserWindow::handleFocusCallback(int eventType, const EmscriptenFocusEvent* event) { + releaseAllKeys(); + if (eventType == EMSCRIPTEN_EVENT_FOCUS) { + m_focused = true; + } else if (eventType == EMSCRIPTEN_EVENT_BLUR) { + m_focused = false; + } +} + +void BrowserWindow::swapBuffers() { + // emscripten_webgl_commit_frame(); // removed to improve performance (reduce CPU overhead) +} + +void BrowserWindow::setVerticalSync(bool enable) { +} + +std::string BrowserWindow::getClipboardText() { + return m_clipboardText; +} + +void BrowserWindow::setClipboardText(const std::string_view text) { + m_clipboardText = text.data(); + std::string const& content = text.data(); + // clang-format off + MAIN_THREAD_EM_ASM({ + navigator.clipboard.writeText(UTF8ToString($0)); + }, content.c_str()); + // clang-format on +} + +Size BrowserWindow::getDisplaySize() { + return m_size; +} + +std::string BrowserWindow::getPlatformType() { + return "BROWSER-WEBGL"; +} + +void BrowserWindow::init() { + internalInitGL(); +} + +int BrowserWindow::loadMouseCursor(const std::string& file, const Point& hotSpot) +{ + const auto& path = g_resources.guessFilePath(file, "png"); + std::stringstream fin; + g_resources.readFileStream(path, fin); + std::string base64Image = g_crypt.base64Encode(fin.str()); + std::string cursor = "url(data:image/png;base64," + base64Image + ") " + std::to_string(hotSpot.x) + " " + std::to_string(hotSpot.y) + ", auto"; + + m_cursors.push_back(cursor); + return m_cursors.size() - 1; +} + +void BrowserWindow::setMouseCursor(int cursorId) { + if (cursorId >= (int)m_cursors.size() || cursorId < 0) + return; + // clang-format off + MAIN_THREAD_ASYNC_EM_ASM({ + document.body.style.cursor = UTF8ToString($0); + }, m_cursors[cursorId].c_str()); + // clang-format on +} + +void BrowserWindow::restoreMouseCursor() { + // clang-format off + MAIN_THREAD_ASYNC_EM_ASM( + document.body.style.cursor = ""; + ); + // clang-format on +} + +/* Does not apply to Browser */ +void BrowserWindow::resize(const Size& size) {} + +void BrowserWindow::show() {} + +void BrowserWindow::hide() {} + +void BrowserWindow::maximize() {} + +void BrowserWindow::move(const Point& pos) {} + +void BrowserWindow::showMouse() {} + +void BrowserWindow::hideMouse() {} + +int BrowserWindow::internalLoadMouseCursor(const ImagePtr& image, const Point& hotSpot) { return 0; } + +void BrowserWindow::setTitle(const std::string_view title) {} + +void BrowserWindow::setMinimumSize(const Size& minimumSize) {} + +void BrowserWindow::setFullscreen(bool fullscreen) {} + +void BrowserWindow::setIcon(const std::string& iconFile) {} + + +#endif // __EMSCRIPTEN__ diff --git a/src/framework/platform/browserwindow.h b/src/framework/platform/browserwindow.h new file mode 100644 index 0000000000..c30953fab9 --- /dev/null +++ b/src/framework/platform/browserwindow.h @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2010-2014 OTClient + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#pragma once + +#ifdef __EMSCRIPTEN__ + +#include "platformwindow.h" +#include +#include +#include + +class BrowserWindow : public PlatformWindow +{ + void internalInitGL(); + + +public: + BrowserWindow(); + + void init() override; + void terminate() override; + + void move(const Point& pos) override; + void resize(const Size& size) override; + void show() override; + void hide() override; + void maximize() override; + void poll() override; + void swapBuffers() override; + void showMouse() override; + void hideMouse() override; + + void setMouseCursor(int cursorId) override; + void restoreMouseCursor() override; + int loadMouseCursor(const std::string& file, const Point& hotSpot) override; + + void setTitle(const std::string_view title) override; + void setMinimumSize(const Size& minimumSize) override; + void setFullscreen(bool fullscreen) override; + void setVerticalSync(bool enable) override; + void setIcon(const std::string& iconFile) override; + void setClipboardText(const std::string_view text) override; + void setRunning(bool running) { m_running = running; } + + void handleResizeCallback(const EmscriptenUiEvent* event); + void handleMouseCallback(int eventType, const EmscriptenMouseEvent* event); + void handleMouseWheelCallback(const EmscriptenWheelEvent* event); + void handleMouseMotionCallback(const EmscriptenMouseEvent* event); + void handleKeyboardCallback(int eventType, const EmscriptenKeyboardEvent* event); + void handleFocusCallback(int eventType, const EmscriptenFocusEvent* event); + void handleTouchCallback(int eventType, const EmscriptenTouchEvent* event); + void updateTouchPosition(const EmscriptenTouchEvent* event); + void processLongTouch(const EmscriptenTouchEvent* event); + + Size getDisplaySize() override; + std::string getClipboardText() override; + std::string getPlatformType() override; + +protected: + int internalLoadMouseCursor(const ImagePtr& image, const Point& hotSpot) override; +private: + bool m_running; + Timer m_clickTimer; + bool m_usingTouch = false; + std::vector> web_keymap; + std::string m_clipboardText; + std::vector m_cursors; +}; + +extern BrowserWindow& g_browserWindow; + +#endif diff --git a/src/framework/platform/crashhandler.h b/src/framework/platform/crashhandler.h index 18431ba46c..3950c13f30 100644 --- a/src/framework/platform/crashhandler.h +++ b/src/framework/platform/crashhandler.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * 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/src/framework/platform/platform.cpp b/src/framework/platform/platform.cpp index 8b36360354..e36ee8991d 100644 --- a/src/framework/platform/platform.cpp +++ b/src/framework/platform/platform.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -25,17 +25,17 @@ Platform g_platform; std::unordered_map Platform::m_deviceShortNames = { - {Platform::Desktop, "desktop"}, - {Platform::Mobile, "mobile"}, - {Platform::Console, "console"}, + {Desktop, "desktop"}, + {Mobile, "mobile"}, + {Console, "console"}, }; std::unordered_map Platform::m_osShortNames = { - {Platform::Windows, "windows"}, - {Platform::Linux, "linux"}, - {Platform::macOS, "macos"}, - {Platform::Android, "android"}, - {Platform::iOS, "ios"}, + {Windows, "windows"}, + {Linux, "linux"}, + {macOS, "macos"}, + {Android, "android"}, + {iOS, "ios"}, }; std::string Platform::getDeviceShortName(DeviceType type) @@ -43,7 +43,7 @@ std::string Platform::getDeviceShortName(DeviceType type) if (type == DeviceUnknown) type = m_device.type; - auto it = m_deviceShortNames.find(type); + const auto it = m_deviceShortNames.find(type); if (it == m_deviceShortNames.end()) return ""; return it->second; @@ -54,7 +54,7 @@ std::string Platform::getOsShortName(OperatingSystem os) if (os == OsUnknown) os = m_device.os; - auto it = m_osShortNames.find(os); + const auto it = m_osShortNames.find(os); if (it == m_osShortNames.end()) return ""; return it->second; @@ -62,7 +62,7 @@ std::string Platform::getOsShortName(OperatingSystem os) Platform::DeviceType Platform::getDeviceTypeByName(std::string shortName) { - for (auto const& [type, name] : m_deviceShortNames) { + for (const auto& [type, name] : m_deviceShortNames) { if (name == shortName) return type; } @@ -71,7 +71,7 @@ Platform::DeviceType Platform::getDeviceTypeByName(std::string shortName) Platform::OperatingSystem Platform::getOsByName(std::string shortName) { - for (auto const& [type, name] : m_osShortNames) { + for (const auto& [type, name] : m_osShortNames) { if (name == shortName) return type; } diff --git a/src/framework/platform/platform.h b/src/framework/platform/platform.h index 889ca0dde7..1b01ddeddd 100644 --- a/src/framework/platform/platform.h +++ b/src/framework/platform/platform.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -22,11 +22,14 @@ #pragma once -#include -#include #include #include -#include +#include +#include + +#ifdef __EMSCRIPTEN__ +#include +#endif class Platform { @@ -46,13 +49,14 @@ class Platform DeviceUnknown, Desktop, Mobile, + Browser, Console }; struct Device { - Device() {} - Device(DeviceType t, OperatingSystem o) : type(t), os(o) {} + Device() = default; + Device(const DeviceType t, const OperatingSystem o) : type(t), os(o) {} DeviceType type{ DeviceUnknown }; OperatingSystem os{ OsUnknown }; @@ -63,8 +67,8 @@ class Platform void processArgs(std::vector& args); bool spawnProcess(std::string process, const std::vector& args); int getProcessId(); - bool isProcessRunning(const std::string_view name); - bool killProcess(const std::string_view name); + bool isProcessRunning(std::string_view name); + bool killProcess(std::string_view name); std::string getTempPath(); std::string getCurrentDir(); bool copyFile(std::string from, std::string to); @@ -77,23 +81,32 @@ class Platform double getTotalSystemMemory(); std::string getOSName(); Device getDevice() { return m_device; } - void setDevice(Device device) { m_device = device; } + void setDevice(const Device device) { m_device = device; } bool isDesktop() { return m_device.type == Desktop; } - bool isMobile() { return m_device.type == Mobile; } + bool isMobile() { +#ifndef __EMSCRIPTEN__ + return m_device.type == Mobile; +#else + return MAIN_THREAD_EM_ASM_INT({ + return (/ iphone | ipod | ipad | android / i).test(navigator.userAgent); + }) == 1; +#endif + } + bool isBrowser() { return m_device.type == Browser; } bool isConsole() { return m_device.type == Console; } std::string getDeviceShortName(DeviceType type = DeviceUnknown); std::string getOsShortName(OperatingSystem os = OsUnknown); - std::string traceback(const std::string_view where, int level = 1, int maxDepth = 32); + std::string traceback(std::string_view where, int level = 1, int maxDepth = 32); void addKeyListener(std::function /*listener*/) {} - static Platform::DeviceType getDeviceTypeByName(std::string shortName); - static Platform::OperatingSystem getOsByName(std::string shortName); + static DeviceType getDeviceTypeByName(std::string shortName); + static OperatingSystem getOsByName(std::string shortName); private: Device m_device{ Device(Desktop, Windows) }; - static std::unordered_map m_deviceShortNames; - static std::unordered_map m_osShortNames; + static std::unordered_map m_deviceShortNames; + static std::unordered_map m_osShortNames; }; extern Platform g_platform; diff --git a/src/framework/platform/platformwindow.cpp b/src/framework/platform/platformwindow.cpp index 47835c13dd..e6590372c2 100644 --- a/src/framework/platform/platformwindow.cpp +++ b/src/framework/platform/platformwindow.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -28,6 +28,9 @@ WIN32Window window; #elif defined ANDROID #include "androidwindow.h" AndroidWindow window; +#elif defined __EMSCRIPTEN__ +#include "browserwindow.h" +BrowserWindow window; #else #include "x11window.h" #include diff --git a/src/framework/platform/platformwindow.h b/src/framework/platform/platformwindow.h index 4fbf97535c..e4fdca8bce 100644 --- a/src/framework/platform/platformwindow.h +++ b/src/framework/platform/platformwindow.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -22,9 +22,9 @@ #pragma once -#include #include #include +#include #include //@bindsingleton g_window @@ -63,16 +63,16 @@ class PlatformWindow virtual void hideMouse() = 0; virtual void displayFatalError(const std::string_view /*message*/) {} - int loadMouseCursor(const std::string& file, const Point& hotSpot); + virtual int loadMouseCursor(const std::string& file, const Point& hotSpot); virtual void setMouseCursor(int cursorId) = 0; virtual void restoreMouseCursor() = 0; - virtual void setTitle(const std::string_view title) = 0; + virtual void setTitle(std::string_view title) = 0; virtual void setMinimumSize(const Size& minimumSize) = 0; virtual void setFullscreen(bool fullscreen) = 0; virtual void setVerticalSync(bool enable) = 0; virtual void setIcon(const std::string& iconFile) = 0; - virtual void setClipboardText(const std::string_view text) = 0; + virtual void setClipboardText(std::string_view text) = 0; virtual Size getDisplaySize() = 0; virtual std::string getClipboardText() = 0; @@ -81,7 +81,7 @@ class PlatformWindow int getDisplayWidth() { return getDisplaySize().width(); } int getDisplayHeight() { return getDisplaySize().height(); } float getDisplayDensity() { return m_displayDensity; } - void setDisplayDensity(float v) { m_displayDensity = v; } + void setDisplayDensity(const float v) { m_displayDensity = v; } Size getUnmaximizedSize() { return m_unmaximizedSize; } Size getSize() { return m_size; } @@ -95,8 +95,8 @@ class PlatformWindow Point getMousePosition() { return m_inputEvent.mousePos; } int getKeyboardModifiers() { return m_inputEvent.keyboardModifiers; } - bool isKeyPressed(Fw::Key keyCode) { return m_keyInfo[keyCode].state; } - bool isMouseButtonPressed(Fw::MouseButton mouseButton) + bool isKeyPressed(const Fw::Key keyCode) { return m_keyInfo[keyCode].state; } + bool isMouseButtonPressed(const Fw::MouseButton mouseButton) { if (mouseButton == Fw::MouseNoButton) return m_mouseButtonStates != 0; return (m_mouseButtonStates & (1u << mouseButton)) == (1u << mouseButton); } bool isVisible() { return m_visible; } bool isMaximized() { return m_maximized; } @@ -111,7 +111,7 @@ class PlatformWindow void addKeyListener(std::function listener) { m_keyListeners.push_back(listener); } - void setKeyDelay(const Fw::Key key, uint8_t delay) { if (key < Fw::KeyLast) m_keyInfo[key].delay = delay; } + void setKeyDelay(const Fw::Key key, const uint8_t delay) { if (key < Fw::KeyLast) m_keyInfo[key].delay = delay; } protected: diff --git a/src/framework/platform/unixplatform.cpp b/src/framework/platform/unixplatform.cpp index 8b182cc1ec..f76ac69681 100644 --- a/src/framework/platform/unixplatform.cpp +++ b/src/framework/platform/unixplatform.cpp @@ -20,7 +20,7 @@ * THE SOFTWARE. */ -#ifndef WIN32 +#if !defined(WIN32) && !defined(__EMSCRIPTEN__) #include "platform.h" #include diff --git a/src/framework/platform/win32crashhandler.cpp b/src/framework/platform/win32crashhandler.cpp index 15f51044ec..5542937c8e 100644 --- a/src/framework/platform/win32crashhandler.cpp +++ b/src/framework/platform/win32crashhandler.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -23,8 +23,8 @@ #include "framework/core/application.h" #if defined(WIN32) && defined(CRASH_HANDLER) -#include #include "crashhandler.h" +#include #include #include @@ -42,7 +42,9 @@ #endif -const char* getExceptionName(DWORD exceptionCode) +#include + +const char* getExceptionName(const DWORD exceptionCode) { switch (exceptionCode) { case EXCEPTION_ACCESS_VIOLATION: return "Access violation"; @@ -128,7 +130,7 @@ void Stacktrace(LPEXCEPTION_POINTERS e, std::stringstream& ss) GlobalFree(pSym); } -LONG CALLBACK ExceptionHandler(LPEXCEPTION_POINTERS e) +LONG CALLBACK ExceptionHandler(const LPEXCEPTION_POINTERS e) { // generate crash report SymInitialize(GetCurrentProcess(), nullptr, TRUE); @@ -182,4 +184,4 @@ void installCrashHandler() SetUnhandledExceptionFilter(ExceptionHandler); } -#endif +#endif \ No newline at end of file diff --git a/src/framework/platform/win32platform.cpp b/src/framework/platform/win32platform.cpp index 5bc848a744..343e4794ee 100644 --- a/src/framework/platform/win32platform.cpp +++ b/src/framework/platform/win32platform.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -23,8 +23,8 @@ #ifdef WIN32 #include "platform.h" -#include #include +#include #include #ifdef NDEBUG @@ -154,7 +154,7 @@ ticks_t Platform::getFileModificationTime(std::string file) return uli.QuadPart; } -bool Platform::openUrl(std::string url, bool now) +bool Platform::openUrl(std::string url, const bool now) { if (url.find("http://") == std::string::npos && url.find("https://") == std::string::npos) url.insert(0, "http://"); @@ -169,10 +169,10 @@ bool Platform::openUrl(std::string url, bool now) return true; } -bool Platform::openDir(std::string path, bool now) +bool Platform::openDir(std::string path, const bool now) { const auto& action = [path] { - return reinterpret_cast(ShellExecuteW(NULL, L"open", L"explorer.exe", stdext::utf8_to_utf16(path).c_str(), NULL, SW_SHOWNORMAL)) >= 32; + return reinterpret_cast(ShellExecuteW(nullptr, L"open", L"explorer.exe", stdext::utf8_to_utf16(path).c_str(), nullptr, SW_SHOWNORMAL)) >= 32; }; if (now) return action(); diff --git a/src/framework/platform/win32window.cpp b/src/framework/platform/win32window.cpp index 11e0e260cc..68ce279cbd 100644 --- a/src/framework/platform/win32window.cpp +++ b/src/framework/platform/win32window.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -253,7 +253,7 @@ void WIN32Window::terminate() struct WindowProcProxy { - static LRESULT CALLBACK call(HWND hWnd, uint32_t uMsg, WPARAM wParam, LPARAM lParam) + static LRESULT CALLBACK call(const HWND hWnd, const uint32_t uMsg, const WPARAM wParam, const LPARAM lParam) { auto* const ww = static_cast(&g_window); return ww->windowProc(hWnd, uMsg, wParam, lParam); @@ -426,7 +426,7 @@ bool WIN32Window::isExtensionSupported(const char* ext) //TODO return false; #else - const auto wglGetExtensionsString = (const char* (WINAPI*)())(getExtensionProcAddress("wglGetExtensionsStringEXT")); + const auto wglGetExtensionsString = static_cast(getExtensionProcAddress("wglGetExtensionsStringEXT")); if (!wglGetExtensionsString) return false; @@ -513,7 +513,7 @@ void WIN32Window::poll() updateUnmaximizedCoords(); } -Fw::Key WIN32Window::retranslateVirtualKey(WPARAM wParam, LPARAM lParam) +Fw::Key WIN32Window::retranslateVirtualKey(const WPARAM wParam, const LPARAM lParam) { // ignore numpad keys when numlock is on if ((wParam >= VK_NUMPAD0 && wParam <= VK_NUMPAD9) || wParam == VK_SEPARATOR) @@ -565,7 +565,7 @@ Fw::Key WIN32Window::retranslateVirtualKey(WPARAM wParam, LPARAM lParam) #define IsKeyDown(a) (GetKeyState(a) & 0x80) -LRESULT WIN32Window::windowProc(HWND hWnd, uint32_t uMsg, WPARAM wParam, LPARAM lParam) +LRESULT WIN32Window::windowProc(const HWND hWnd, const uint32_t uMsg, const WPARAM wParam, const LPARAM lParam) { m_inputEvent.keyboardModifiers = 0; if (IsKeyDown(VK_CONTROL)) @@ -945,7 +945,7 @@ void WIN32Window::setVerticalSync(bool enable) if (!isExtensionSupported("WGL_EXT_swap_control")) return; - const auto wglSwapInterval = (BOOL(WINAPI*)(int))getExtensionProcAddress("wglSwapIntervalEXT"); + const auto wglSwapInterval = static_cast(getExtensionProcAddress("wglSwapIntervalEXT")); if (!wglSwapInterval) return; diff --git a/src/framework/platform/win32window.h b/src/framework/platform/win32window.h index 513ce27b3a..2ba57d5664 100644 --- a/src/framework/platform/win32window.h +++ b/src/framework/platform/win32window.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -62,17 +62,17 @@ class WIN32Window : public PlatformWindow void swapBuffers() override; void showMouse() override; void hideMouse() override; - void displayFatalError(const std::string_view message) override; + void displayFatalError(std::string_view message) override; void setMouseCursor(int cursorId) override; void restoreMouseCursor() override; - void setTitle(const std::string_view title) override; + void setTitle(std::string_view title) override; void setMinimumSize(const Size& minimumSize) override; void setFullscreen(bool fullscreen) override; void setVerticalSync(bool enable) override; void setIcon(const std::string& file) override; - void setClipboardText(const std::string_view text) override; + void setClipboardText(std::string_view text) override; Size getDisplaySize() override; std::string getClipboardText() override; diff --git a/src/framework/platform/x11window.cpp b/src/framework/platform/x11window.cpp index b35466922c..afb9447f6e 100644 --- a/src/framework/platform/x11window.cpp +++ b/src/framework/platform/x11window.cpp @@ -20,7 +20,7 @@ * THE SOFTWARE. */ -#if !defined WIN32 && !defined ANDROID +#if !defined WIN32 && !defined ANDROID && !defined __EMSCRIPTEN__ #include "x11window.h" #include diff --git a/src/framework/proxy/proxy.cpp b/src/framework/proxy/proxy.cpp new file mode 100644 index 0000000000..7b0c47ed7b --- /dev/null +++ b/src/framework/proxy/proxy.cpp @@ -0,0 +1,180 @@ +/* + * Copyright (c) 2010-2024 OTClient + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "proxy.h" +#include "proxy_client.h" +#include + +ProxyManager g_proxy; + +void ProxyManager::init() +{ + if (m_working) + return; + m_working = true; + m_thread = std::thread([&] { + m_io.run(); + }); +} + +void ProxyManager::terminate() +{ + if (!m_working) + return; + m_working = false; + clear(); + m_guard.reset(); + if (!m_thread.joinable()) { + stdext::millisleep(100); + m_io.stop(); + } + m_thread.join(); +} + +void ProxyManager::clear() +{ + for (auto& session_weak : m_sessions) { + if (const auto session = session_weak.lock()) { + session->terminate(); + } + } + m_sessions.clear(); + for (auto& proxy_weak : m_proxies) { + if (const auto proxy = proxy_weak.lock()) { + proxy->terminate(); + } + } + m_proxies.clear(); +} + +bool ProxyManager::isActive() +{ + return m_proxies.size() > 0; +} + +void ProxyManager::addProxy(const std::string& host, uint16_t port, int priority) +{ + for (auto& proxy_weak : m_proxies) { + if (const auto proxy = proxy_weak.lock()) { + if (proxy->getHost() == host && proxy->getPort() == port) { + return; // already exist + } + } + } + + const auto proxy = std::make_shared(m_io, host, port, priority); + proxy->start(); + m_proxies.push_back(proxy); +} + +void ProxyManager::removeProxy(const std::string& host, const uint16_t port) +{ + for (auto it = m_proxies.begin(); it != m_proxies.end(); ) { + if (const auto proxy = it->lock()) { + if (proxy->getHost() == host && proxy->getPort() == port) { + proxy->terminate(); + it = m_proxies.erase(it); + } else { + ++it; + } + continue; + } + it = m_proxies.erase(it); + } +} + +uint32_t ProxyManager::addSession(uint16_t port, std::function recvCallback, std::function disconnectCallback) +{ + assert(recvCallback && disconnectCallback); + const auto session = std::make_shared(m_io, port, recvCallback, disconnectCallback); + session->start(m_maxActiveProxies); + m_sessions.push_back(session); + return session->getId(); +} + +void ProxyManager::removeSession(const uint32_t sessionId) +{ + for (auto it = m_sessions.begin(); it != m_sessions.end(); ) { + if (const auto session = it->lock()) { + if (session->getId() == sessionId) { + session->terminate(); + it = m_sessions.erase(it); + } else { + ++it; + } + continue; + } + it = m_sessions.erase(it); + } +} + +void ProxyManager::send(const uint32_t sessionId, ProxyPacketPtr packet) +{ + SessionPtr session = nullptr; + for (auto& session_weak : m_sessions) { + if (const auto tsession = session_weak.lock()) { + if (tsession->getId() == sessionId) { + session = tsession; + break; + } + } + } + + if (!session) + return; + + session->onPacket(packet); +} + +std::map ProxyManager::getProxies() +{ + std::map ret; + for (auto& proxy_weak : m_proxies) { + if (const auto proxy = proxy_weak.lock()) { + ret[proxy->getHost() + ":" + std::to_string(proxy->getPort())] = proxy->getRealPing(); + } + } + return ret; +} + +std::map ProxyManager::getProxiesDebugInfo() +{ + std::map ret; + for (auto& proxy_weak : m_proxies) { + if (const auto proxy = proxy_weak.lock()) { + ret[proxy->getHost() + ":" + std::to_string(proxy->getPort())] = proxy->getDebugInfo(); + } + } + return ret; +} + +int ProxyManager::getPing() +{ + uint32_t ret = 0; + for (auto& proxy_weak : m_proxies) { + if (const auto proxy = proxy_weak.lock()) { + if ((proxy->getRealPing() < ret || ret == 0) && proxy->getRealPing() > 0) + ret = proxy->getRealPing(); + } + } + return ret; +} \ No newline at end of file diff --git a/src/framework/proxy/proxy.h b/src/framework/proxy/proxy.h new file mode 100644 index 0000000000..483ef32343 --- /dev/null +++ b/src/framework/proxy/proxy.h @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2010-2024 OTClient + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#pragma once + +#include +#include +#include + +class Proxy; +class Session; + +using ProxyPacket = std::vector; +using ProxyPacketPtr = std::shared_ptr; + +class ProxyManager +{ +public: + ProxyManager() : m_guard(make_work_guard(m_io)) + { + } + void init(); + void terminate(); + void clear(); + void setMaxActiveProxies(const int value) + { + m_maxActiveProxies = value; + if (m_maxActiveProxies < 1) + m_maxActiveProxies = 1; + } + bool isActive(); + void addProxy(const std::string& host, uint16_t port, int priority); + void removeProxy(const std::string& host, uint16_t port); + uint32_t addSession(uint16_t port, std::function recvCallback, std::function disconnectCallback); + void removeSession(uint32_t sessionId); + void send(uint32_t sessionId, ProxyPacketPtr packet); + // tools + std::map getProxies(); + std::map getProxiesDebugInfo(); + int getPing(); + +private: + asio::io_context m_io; + asio::executor_work_guard m_guard; + + bool m_working = false; + std::thread m_thread; + + int m_maxActiveProxies = 2; + + std::list> m_proxies; + std::list> m_sessions; +}; + +extern ProxyManager g_proxy; diff --git a/src/framework/proxy/proxy_client.cpp b/src/framework/proxy/proxy_client.cpp new file mode 100644 index 0000000000..ebe820c58b --- /dev/null +++ b/src/framework/proxy/proxy_client.cpp @@ -0,0 +1,585 @@ +/* + * Copyright (c) 2010-2024 OTClient + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + + //#define PROXY_DEBUG + +#include "proxy_client.h" + +std::map> g_sessions; +std::set> g_proxies; +uint32_t UID = (std::chrono::high_resolution_clock::now().time_since_epoch().count()) & 0xFFFFFFFF; + +void Proxy::start() +{ +#ifdef PROXY_DEBUG + std::clog << "[Proxy " << m_host << "] start" << std::endl; +#endif + auto self(shared_from_this()); + post(m_io, [&, self] { + const std::error_code ec; + g_proxies.insert(self); + check(ec); + }); +} + +void Proxy::terminate() +{ + if (m_terminated) + return; + m_terminated = true; + +#ifdef PROXY_DEBUG + std::clog << "[Proxy " << m_host << "] terminate" << std::endl; +#endif + + auto self(shared_from_this()); + post(m_io, [&, self] { + g_proxies.erase(self); + disconnect(); + std::error_code ec; + m_timer.cancel(ec); + }); +} + +std::string Proxy::getDebugInfo() +{ + std::stringstream ss; + ss << "P: " << getPing() << " RP: " << getRealPing() << " In: " << m_packetsRecived << " (" << m_bytesRecived + << ") Out: " << m_packetsSent << " (" << m_bytesSent << ") Conns: " << m_connections << " Sess: " << m_sessions << " R: " << m_resolvedIp; + return ss.str(); +} + +void Proxy::check(const std::error_code& ec) +{ + if (ec || m_terminated) { + return; + } + + const int32_t lastPing = static_cast(std::chrono::duration_cast( + std::chrono::high_resolution_clock::now() - m_lastPingSent).count()); + if (m_state == STATE_NOT_CONNECTED) { + connect(); + } else if (m_state == STATE_CONNECTING) { // timeout for async_connect + if (lastPing + 50 > CHECK_INTERVAL * 5) { + disconnect(); + } + } else if (m_state == STATE_CONNECTED || m_state == STATE_CONNECTING_WAIT_FOR_PING) { + if (m_waitingForPing) { + if (lastPing + 50 > CHECK_INTERVAL * (m_state == STATE_CONNECTING_WAIT_FOR_PING ? 5 : 3)) { +#ifdef PROXY_DEBUG + std::clog << "[Proxy " << m_host << "] ping timeout" << std::endl; +#endif + disconnect(); + } + } else if (m_state == STATE_CONNECTED) { + ping(); + } + } + m_timer.expires_from_now(std::chrono::milliseconds(CHECK_INTERVAL)); + m_timer.async_wait([capture0 = shared_from_this()](auto&& PH1) { + capture0->check(std::forward(PH1)); + }); +} + +void Proxy::connect() +{ +#ifdef PROXY_DEBUG + std::clog << "[Proxy " << m_host << "] connecting to " << m_host << ":" << m_port << std::endl; +#endif + m_sendQueue.clear(); + m_waitingForPing = false; + m_state = STATE_CONNECTING; + m_connections += 1; + m_sessions = 0; + m_resolver = asio::ip::tcp::resolver(m_io); + auto self(shared_from_this()); + m_resolver.async_resolve(m_host, "http", [self](const std::error_code& ec, + asio::ip::tcp::resolver::results_type results) { + auto endpoint = asio::ip::tcp::endpoint(); + if (ec || results.empty()) { +#ifdef PROXY_DEBUG + std::clog << "[Proxy " << self->m_host << "] resolve error: " << ec.message() << std::endl; +#endif + std::error_code ecc; + const auto address = asio::ip::make_address_v4(self->m_host, ecc); + if (ecc) { + self->m_state = STATE_NOT_CONNECTED; + return; + } + endpoint = asio::ip::tcp::endpoint(address, self->m_port); + } else { + endpoint = asio::ip::tcp::endpoint(*results); + endpoint.port(self->m_port); + } + self->m_resolvedIp = endpoint.address().to_string(); + self->m_socket = asio::ip::tcp::socket(self->m_io); + self->m_lastPingSent = std::chrono::high_resolution_clock::now(); // used for async_connect timeout + self->m_socket.async_connect(endpoint, [self, endpoint](const std::error_code& ec) { + if (ec) { + self->m_state = STATE_NOT_CONNECTED; + return; + } + std::error_code ecc; + self->m_socket.set_option(asio::ip::tcp::no_delay(true), ecc); + self->m_socket.set_option(asio::socket_base::send_buffer_size(65536), ecc); + self->m_socket.set_option(asio::socket_base::receive_buffer_size(65536), ecc); + if (ecc) { +#ifdef PROXY_DEBUG + std::clog << "[Proxy " << self->m_host << "] connect error: " << ecc.message() << std::endl; +#endif + } + + self->m_state = STATE_CONNECTING_WAIT_FOR_PING; + self->readHeader(); + self->ping(); +#ifdef PROXY_DEBUG + std::clog << "[Proxy " << self->m_host << "] connected " << std::endl; +#endif + }); + }); +} + +void Proxy::disconnect() +{ + std::error_code ec; + m_socket.close(ec); + m_state = STATE_NOT_CONNECTED; + m_ping = CHECK_INTERVAL * 2; +} + +void Proxy::ping() +{ + m_lastPingSent = std::chrono::high_resolution_clock::now(); + m_waitingForPing = true; + // 2 byte size + 4 byte session (0 so it's ping) + 4 byte packet num (0) + 4 byte last recived packet num + 4 byte local ping + const auto packet = std::make_shared(18, 0); + packet->at(0) = 16; // size = 12 + *(uint32_t*)(&packet->data()[10]) = UID; + *(uint32_t*)(&packet->data()[14]) = m_ping; + send(packet); +} + +void Proxy::onPing(uint32_t /*packetId*/) +{ + if (m_state == STATE_CONNECTING_WAIT_FOR_PING) { + m_state = STATE_CONNECTED; + } + m_waitingForPing = false; + m_ping = static_cast(std::chrono::duration_cast( + std::chrono::high_resolution_clock::now() - m_lastPingSent).count()); +} + +void Proxy::addSession(const uint32_t id, const int port) +{ + const auto packet = std::make_shared(14, 0); + packet->at(0) = 12; // size = 12 + *(uint32_t*)(&(packet->data()[2])) = id; + *(uint32_t*)(&(packet->data()[10])) = port; + send(packet); + m_sessions += 1; +} + +void Proxy::removeSession(const uint32_t id) +{ + const auto packet = std::make_shared(14, 0); + packet->at(0) = 12; // size = 12 + *(uint32_t*)(&(packet->data()[2])) = id; + *(uint32_t*)(&(packet->data()[6])) = 0xFFFFFFFF; + send(packet); + m_sessions -= 1; +} + +void Proxy::readHeader() +{ + async_read(m_socket, asio::buffer(m_buffer, 2), [capture0 = shared_from_this()](auto&& PH1, auto&& PH2) { + capture0->onHeader(std::forward(PH1), std::forward(PH2)); + }); +} + +void Proxy::onHeader(const std::error_code& ec, const std::size_t bytes_transferred) +{ + if (ec || bytes_transferred != 2) { +#ifdef PROXY_DEBUG + std::clog << "[Proxy " << m_host << "] onHeader error " << ec.message() << std::endl; +#endif + return disconnect(); + } + + m_packetsRecived += 1; + m_bytesRecived += static_cast(bytes_transferred); + + uint16_t packetSize = *(uint16_t*)m_buffer; + if (packetSize < 12 || packetSize > BUFFER_SIZE) { +#ifdef PROXY_DEBUG + std::clog << "[Proxy " << m_host << "] onHeader wrong packet size " << packetSize << std::endl; +#endif + return disconnect(); + } + + async_read(m_socket, asio::buffer(m_buffer, packetSize), [capture0 = shared_from_this()](auto&& PH1, auto&& PH2) { + capture0->onPacket(std::forward(PH1), std::forward(PH2)); + }); +} + +void Proxy::onPacket(const std::error_code& ec, const std::size_t bytes_transferred) +{ + if (ec || bytes_transferred < 12) { +#ifdef PROXY_DEBUG + std::clog << "[Proxy " << m_host << "] onPacket error " << ec.message() << std::endl; +#endif + return disconnect(); + } + m_bytesRecived += static_cast(bytes_transferred); + + uint32_t sessionId = *(uint32_t*)(&m_buffer[0]); + const uint32_t packetId = *(uint32_t*)(&m_buffer[4]); + const uint32_t lastRecivedPacketId = *(uint32_t*)(&m_buffer[8]); + + if (sessionId == 0) { + readHeader(); + return onPing(packetId); + } + if (packetId == 0xFFFFFFFFu) { +#ifdef PROXY_DEBUG + std::clog << "[Proxy " << m_host << "] onPacket, session end: " << sessionId << std::endl; +#endif + const auto it = g_sessions.find(sessionId); + if (it != g_sessions.end()) { + if (const auto session = it->second.lock()) { + session->terminate(); + } + } + readHeader(); + return; + } + + const uint16_t packetSize = *(uint16_t*)(&m_buffer[12]); + +#ifdef PROXY_DEBUG + //std::clog << "[Proxy " << m_host << "] onPacket, session: " << sessionId << " packetId: " << packetId << " lastRecivedPacket: " << lastRecivedPacketId << " size: " << packetSize << std::endl; +#endif + + const auto packet = std::make_shared(m_buffer + 12, m_buffer + 14 + packetSize); + const auto it = g_sessions.find(sessionId); + if (it != g_sessions.end()) { + if (const auto session = it->second.lock()) { + session->onProxyPacket(packetId, lastRecivedPacketId, packet); + } + } + readHeader(); +} + +void Proxy::send(const ProxyPacketPtr& packet) +{ + const bool sendNow = m_sendQueue.empty(); + m_sendQueue.push_back(packet); + if (sendNow) { + async_write(m_socket, asio::buffer(packet->data(), packet->size()), + [capture0 = shared_from_this()](auto&& PH1, auto&& PH2) { + capture0->onSent(std::forward(PH1), std::forward(PH2)); + }); + } +} + +void Proxy::onSent(const std::error_code& ec, const std::size_t bytes_transferred) +{ + if (ec) { +#ifdef PROXY_DEBUG + std::clog << "[Proxy " << m_host << "] onSent error " << ec.message() << std::endl; +#endif + return disconnect(); + } + m_packetsSent += 1; + m_bytesSent += static_cast(bytes_transferred); + m_sendQueue.pop_front(); + if (!m_sendQueue.empty()) { + async_write(m_socket, asio::buffer(m_sendQueue.front()->data(), m_sendQueue.front()->size()), + [capture0 = shared_from_this()](auto&& PH1, auto&& PH2) { + capture0->onSent(std::forward(PH1), std::forward(PH2)); + }); + } +} + +void Session::start(const int maxConnections) +{ +#ifdef PROXY_DEBUG + std::clog << "[Session " << m_id << "] start" << std::endl; +#endif + m_maxConnections = maxConnections; + auto self(shared_from_this()); + post(m_io, [&, self] { + g_sessions[self->m_id] = self; + m_lastPacket = std::chrono::high_resolution_clock::now(); + check(std::error_code()); + if (m_useSocket) { + readHeader(); + } + }); +} + +void Session::terminate(std::error_code ec) +{ + if (m_terminated) + return; + m_terminated = true; + +#ifdef PROXY_DEBUG + std::clog << "[Session " << m_id << "] terminate" << std::endl; +#endif + + auto self(shared_from_this()); + post(m_io, [&, ec] { + g_sessions.erase(m_id); + if (m_useSocket) { + std::error_code ecc; + m_socket.shutdown(asio::ip::tcp::socket::shutdown_both, ecc); + m_socket.close(ecc); + m_timer.cancel(ecc); + } else if (m_disconnectCallback) { + m_disconnectCallback(ec); + } + + for (auto& proxy : m_proxies) { + proxy->removeSession(m_id); + } + m_proxies.clear(); + }); +} + +void Session::check(const std::error_code& ec) +{ + if (ec || m_terminated) { + return; + } + + const uint32_t lastPacket = static_cast(std::chrono::duration_cast( + std::chrono::high_resolution_clock::now() - m_lastPacket).count()); + if (lastPacket > TIMEOUT) { + return terminate(asio::error::timed_out); + } + + selectProxies(); + + m_timer.expires_from_now(std::chrono::milliseconds(CHECK_INTERVAL)); + m_timer.async_wait([capture0 = shared_from_this()](auto&& PH1) { + capture0->check(std::forward(PH1)); + }); +} + +void Session::selectProxies() +{ + ProxyPtr worst_ping = nullptr; + ProxyPtr best_ping = nullptr; + ProxyPtr candidate_proxy = nullptr; + for (auto& proxy : g_proxies) { + if (!proxy->isConnected()) { + m_proxies.erase(proxy); + continue; + } + if (!m_proxies.contains(proxy)) { + if (!candidate_proxy || proxy->getPing() < candidate_proxy->getPing()) { + candidate_proxy = proxy; + } + continue; + } + if (!best_ping || proxy->getPing() < best_ping->getPing()) { + best_ping = proxy; + } + if (!worst_ping || proxy->getPing() > worst_ping->getPing()) { + worst_ping = proxy; + } + } + if (candidate_proxy) { + // change worst to new proxy only if it has at least 20 ms better ping then worst proxy + const bool disconnectWorst = worst_ping && worst_ping != best_ping && worst_ping->getPing() > candidate_proxy->getPing() + 20; + if (m_proxies.size() != m_maxConnections || disconnectWorst) { +#ifdef PROXY_DEBUG + std::clog << "[Session " << m_id << "] new proxy: " << candidate_proxy->getHost() << std::endl; +#endif + candidate_proxy->addSession(m_id, m_port); + m_proxies.insert(candidate_proxy); + for (auto& packet : m_proxySendQueue) { + candidate_proxy->send(packet.second); + } + } + if (m_proxies.size() > m_maxConnections) { +#ifdef PROXY_DEBUG + std::clog << "[Session " << m_id << "] remove proxy: " << worst_ping->getHost() << std::endl; +#endif + worst_ping->removeSession(m_id); + m_proxies.erase(worst_ping); + } + } +} + +void Session::onProxyPacket(uint32_t packetId, uint32_t lastRecivedPacketId, const ProxyPacketPtr& packet) +{ +#ifdef PROXY_DEBUG + std::clog << "[Session " << m_id << "] onProxyPacket, id: " << packetId << " (" << m_inputPacketId << ") last: " << lastRecivedPacketId << + " (" << m_outputPacketId << ") size: " << packet->size() << std::endl; +#endif + if (packetId < m_inputPacketId) { + return; // old packet, ignore + } + + auto it = m_proxySendQueue.begin(); + while (it != m_proxySendQueue.end() && it->first <= lastRecivedPacketId) { + it = m_proxySendQueue.erase(it); + } + + m_lastPacket = std::chrono::high_resolution_clock::now(); + const bool sendNow = m_sendQueue.emplace(packetId, packet).second; + + if (!sendNow || packetId != m_inputPacketId) { + return; + } + + if (!m_useSocket) { + while (!m_sendQueue.empty() && m_sendQueue.begin()->first == m_inputPacketId) { + m_inputPacketId += 1; + if (m_recvCallback) { + m_recvCallback(packet); + } + m_sendQueue.erase(m_sendQueue.begin()); + } + return; + } + + async_write(m_socket, asio::buffer(packet->data(), packet->size()), + [capture0 = shared_from_this()](auto&& PH1, auto&& PH2) { + capture0->onSent(std::forward(PH1), std::forward(PH2)); + }); +} + +void Session::readTibia12Header() +{ + auto self(shared_from_this()); + async_read(m_socket, asio::buffer(m_buffer, 1), + [self](const std::error_code& ec, std::size_t /*bytes_transferred*/) { + if (ec) { + return self->terminate(); + } + if (self->m_buffer[0] == 0x0A) { +#ifdef PROXY_DEBUG + std::clog << "[Session " << self->m_id << "] Tibia 12 read header finished" << std::endl; +#endif + return self->readHeader(); + } + self->readTibia12Header(); + }); +} + +void Session::readHeader() +{ + async_read(m_socket, asio::buffer(m_buffer, 2), + [capture0 = shared_from_this()](auto&& PH1, auto&& PH2) { + capture0->onHeader(std::forward(PH1), std::forward(PH2)); + }); +} + +void Session::onHeader(const std::error_code& ec, std::size_t /*bytes_transferred*/) +{ + if (ec) { +#ifdef PROXY_DEBUG + std::clog << "[Session " << m_id << "] onHeader error: " << ec.message() << std::endl; +#endif + return terminate(); + } + + uint16_t packetSize = *(uint16_t*)(m_buffer); + if (packetSize > 1024 && m_outputPacketId == 1) { + return readTibia12Header(); + } + + if (packetSize == 0 || packetSize + 16 > BUFFER_SIZE) { +#ifdef PROXY_DEBUG + std::clog << "[Session " << m_id << "] onHeader invalid packet size: " << packetSize << std::endl; +#endif + return terminate(); + } + + async_read(m_socket, asio::buffer(m_buffer + 2, packetSize), + [capture0 = shared_from_this()](auto&& PH1, auto&& PH2) { + capture0->onBody(std::forward(PH1), std::forward(PH2)); + }); +} + +void Session::onBody(const std::error_code& ec, const std::size_t bytes_transferred) +{ + if (ec) { +#ifdef PROXY_DEBUG + std::clog << "[Session " << m_id << "] onBody error: " << ec.message() << std::endl; +#endif + return terminate(); + } + + const auto packet = std::make_shared(m_buffer, m_buffer + bytes_transferred + 2); + onPacket(packet); + + readHeader(); +} + +void Session::onPacket(const ProxyPacketPtr& packet) +{ + if (!packet || packet->empty() || packet->size() + 14 > BUFFER_SIZE) { +#ifdef PROXY_DEBUG + std::clog << "[Session " << m_id << "] onPacket error: missing packet or wrong size" << std::endl; +#endif + return terminate(); + } + + auto self(shared_from_this()); + post(m_io, [&, packet] { + const uint32_t packetId = m_outputPacketId++; + const auto newPacket = std::make_shared(packet->size() + 14); + + *(uint16_t*)(&(newPacket->data()[0])) = static_cast(packet->size()) + 12; + *(uint32_t*)(&(newPacket->data()[2])) = m_id; + *(uint32_t*)(&(newPacket->data()[6])) = packetId; + *(uint32_t*)(&(newPacket->data()[10])) = m_inputPacketId - 1; + std::copy(packet->begin(), packet->end(), newPacket->begin() + 14); + + m_proxySendQueue[packetId] = newPacket; + for (auto& proxy : m_proxies) { + proxy->send(newPacket); + } + }); +} + +void Session::onSent(const std::error_code& ec, std::size_t /*bytes_transferred*/) +{ + if (ec) { +#ifdef PROXY_DEBUG + std::clog << "[Session " << m_id << "] onSent error: " << ec.message() << std::endl; +#endif + return terminate(); + } + + m_inputPacketId += 1; + m_sendQueue.erase(m_sendQueue.begin()); + if (!m_sendQueue.empty() && m_sendQueue.begin()->first == m_inputPacketId) { + async_write(m_socket, asio::buffer(m_sendQueue.begin()->second->data(), m_sendQueue.begin()->second->size()), + [capture0 = shared_from_this()](auto&& PH1, auto&& PH2) { + capture0->onSent(std::forward(PH1), std::forward(PH2)); + }); + } +} \ No newline at end of file diff --git a/src/framework/proxy/proxy_client.h b/src/framework/proxy/proxy_client.h new file mode 100644 index 0000000000..690af0cfad --- /dev/null +++ b/src/framework/proxy/proxy_client.h @@ -0,0 +1,189 @@ +/* + * Copyright (c) 2010-2024 OTClient + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#pragma once + +#include +#include +#include +#include + +using ProxyPacket = std::vector; +using ProxyPacketPtr = std::shared_ptr; + +class Session; +using SessionPtr = std::shared_ptr; + +class Proxy : public std::enable_shared_from_this +{ + static constexpr int CHECK_INTERVAL = 2500; // also timeout for ping + static constexpr int BUFFER_SIZE = 65535; + enum ProxyState + { + STATE_NOT_CONNECTED, + STATE_CONNECTING, + STATE_CONNECTING_WAIT_FOR_PING, + STATE_CONNECTED + }; +public: + Proxy(asio::io_context& io, const std::string& host, const uint16_t port, const int priority) + : m_io(io), m_timer(io), m_socket(io), m_resolver(io) + + { + m_host = host; + m_port = port; + m_priority = priority; + } + + // thread-safe + void start(); + void terminate(); + + uint32_t getPing() { return m_ping + m_priority; } + uint32_t getRealPing() { return m_ping; } + uint32_t getPriority() { return m_priority; } + bool isConnected() { return m_state == STATE_CONNECTED; } + std::string getHost() { return m_host; } + uint16_t getPort() { return m_port; } + std::string getDebugInfo(); + bool isActive() { return m_sessions > 0; } + + // not thread-safe + void addSession(uint32_t id, int m_port); + void removeSession(uint32_t id); + + void send(const ProxyPacketPtr& packet); + +private: + void check(const std::error_code& ec); + void connect(); + void disconnect(); + + void ping(); + void onPing(uint32_t packetId); + + void readHeader(); + void onHeader(const std::error_code& ec, std::size_t bytes_transferred); + void onPacket(const std::error_code& ec, std::size_t bytes_transferred); + void onSent(const std::error_code& ec, std::size_t bytes_transferred); + + asio::io_context& m_io; + asio::steady_timer m_timer; + asio::ip::tcp::socket m_socket; + asio::ip::tcp::resolver m_resolver; + + ProxyState m_state{ STATE_NOT_CONNECTED }; + + std::string m_host; + uint16_t m_port; + + bool m_terminated = false; + + uint8_t m_buffer[BUFFER_SIZE]; + std::list m_sendQueue; + + bool m_waitingForPing; + uint32_t m_ping = 0; + int m_priority = 0; + std::chrono::time_point m_lastPingSent; + + int m_packetsRecived = 0; + int m_packetsSent = 0; + int m_bytesRecived = 0; + int m_bytesSent = 0; + int m_connections = 0; + int m_sessions = 0; + std::string m_resolvedIp; +}; + +using ProxyPtr = std::shared_ptr; + +class Session : public std::enable_shared_from_this +{ + static constexpr int CHECK_INTERVAL = 500; + static constexpr int BUFFER_SIZE = 65535; + static constexpr int TIMEOUT = 30000; +public: + Session(asio::io_context& io, asio::ip::tcp::socket socket, const int port) + : m_io(io), m_timer(io), m_socket(std::move(socket)) + { + m_id = (std::chrono::high_resolution_clock::now().time_since_epoch().count()) & 0xFFFFFFFF; + if (m_id == 0) m_id = 1; + m_port = port; + m_useSocket = true; + } + + Session(asio::io_context& io, const int port, std::function recvCallback, std::function disconnectCallback) + : m_io(io), m_timer(io), m_socket(io) + { + m_id = (std::chrono::high_resolution_clock::now().time_since_epoch().count()) & 0xFFFFFFFF; + if (m_id == 0) m_id = 1; + m_port = port; + m_useSocket = false; + m_recvCallback = recvCallback; + m_disconnectCallback = disconnectCallback; + } + + // thread safe + uint32_t getId() { return m_id; } + void start(int maxConnections = 3); + void terminate(std::error_code ec = asio::error::eof); + void onPacket(const ProxyPacketPtr& packet); + + // not thread safe + void onProxyPacket(uint32_t packetId, uint32_t lastRecivedPacketId, const ProxyPacketPtr& packet); + +private: + void check(const std::error_code& ec); + void selectProxies(); + + void readTibia12Header(); + void readHeader(); + void onHeader(const std::error_code& ec, std::size_t bytes_transferred); + void onBody(const std::error_code& ec, std::size_t bytes_transferred); + void onSent(const std::error_code& ec, std::size_t bytes_transferred); + + asio::io_context& m_io; + asio::steady_timer m_timer; + asio::ip::tcp::socket m_socket; + + uint32_t m_id; + uint16_t m_port; + bool m_useSocket; + bool m_terminated = false; + + std::function m_recvCallback = nullptr; + std::function m_disconnectCallback = nullptr; + + std::set m_proxies; + + size_t m_maxConnections; + + uint8_t m_buffer[BUFFER_SIZE]; + std::map m_sendQueue; + std::map m_proxySendQueue; + + uint32_t m_inputPacketId = 1; + uint32_t m_outputPacketId = 1; + + std::chrono::time_point m_lastPacket; +}; diff --git a/src/framework/sound/combinedsoundsource.cpp b/src/framework/sound/combinedsoundsource.cpp index d3705a6b8a..02c1cafc5c 100644 --- a/src/framework/sound/combinedsoundsource.cpp +++ b/src/framework/sound/combinedsoundsource.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -59,31 +59,31 @@ bool CombinedSoundSource::isPlaying() return false; } -void CombinedSoundSource::setLooping(bool looping) +void CombinedSoundSource::setLooping(const bool looping) { for (const auto& source : m_sources) source->setLooping(looping); } -void CombinedSoundSource::setRelative(bool relative) +void CombinedSoundSource::setRelative(const bool relative) { for (const auto& source : m_sources) source->setRelative(relative); } -void CombinedSoundSource::setReferenceDistance(float distance) +void CombinedSoundSource::setReferenceDistance(const float distance) { for (const auto& source : m_sources) source->setReferenceDistance(distance); } -void CombinedSoundSource::setGain(float gain) +void CombinedSoundSource::setGain(const float gain) { for (const auto& source : m_sources) source->setGain(gain); } -void CombinedSoundSource::setPitch(float pitch) +void CombinedSoundSource::setPitch(const float pitch) { for (const auto& source : m_sources) source->setPitch(pitch); @@ -101,13 +101,13 @@ void CombinedSoundSource::setVelocity(const Point& velocity) source->setVelocity(velocity); } -void CombinedSoundSource::setFading(FadeState state, float fadetime) +void CombinedSoundSource::setFading(const FadeState state, const float fadetime) { for (const auto& source : m_sources) source->setFading(state, fadetime); } -void CombinedSoundSource::setEffect(SoundEffectPtr soundEffect) +void CombinedSoundSource::setEffect(const SoundEffectPtr soundEffect) { for (const SoundSourcePtr& source : m_sources) source->setEffect(soundEffect); diff --git a/src/framework/sound/combinedsoundsource.h b/src/framework/sound/combinedsoundsource.h index 13dae6cbdc..440b5b3a9a 100644 --- a/src/framework/sound/combinedsoundsource.h +++ b/src/framework/sound/combinedsoundsource.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -24,7 +24,7 @@ #include "soundsource.h" -class CombinedSoundSource : public SoundSource +class CombinedSoundSource final : public SoundSource { public: CombinedSoundSource(); diff --git a/src/framework/sound/declarations.h b/src/framework/sound/declarations.h index 87f57df195..6fd5469996 100644 --- a/src/framework/sound/declarations.h +++ b/src/framework/sound/declarations.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -30,8 +30,8 @@ #else #include #include -#include #include +#include #endif class SoundManager; diff --git a/src/framework/sound/oggsoundfile.cpp b/src/framework/sound/oggsoundfile.cpp index 256ba6d5b4..01c2234865 100644 --- a/src/framework/sound/oggsoundfile.cpp +++ b/src/framework/sound/oggsoundfile.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -61,7 +61,7 @@ int OggSoundFile::read(void* buffer, int bufferSize) return totalBytesRead; } -int OggSoundFile::cb_seek(void* source, ogg_int64_t offset, int whence) +int OggSoundFile::cb_seek(void* source, const ogg_int64_t offset, const int whence) { auto* const file = static_cast(source); switch (whence) { @@ -85,4 +85,4 @@ int OggSoundFile::cb_close(void* source) { void OggSoundFile::reset() { ov_pcm_seek(&m_vorbisFile, 0); } long OggSoundFile::cb_tell(void* source) { return static_cast(source)->tell(); } -size_t OggSoundFile::cb_read(void* ptr, size_t size, size_t nmemb, void* source) { return static_cast(source)->read(ptr, size, nmemb); } \ No newline at end of file +size_t OggSoundFile::cb_read(void* ptr, const size_t size, const size_t nmemb, void* source) { return static_cast(source)->read(ptr, size, nmemb); } \ No newline at end of file diff --git a/src/framework/sound/oggsoundfile.h b/src/framework/sound/oggsoundfile.h index 6a9a1b8781..ffaa8385c8 100644 --- a/src/framework/sound/oggsoundfile.h +++ b/src/framework/sound/oggsoundfile.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -26,11 +26,11 @@ #include -class OggSoundFile : public SoundFile +class OggSoundFile final : public SoundFile { public: OggSoundFile(const FileStreamPtr& fileStream) : SoundFile(fileStream) { memset(&m_vorbisFile, 0, sizeof(m_vorbisFile)); } - ~OggSoundFile() { ov_clear(&m_vorbisFile); } + ~OggSoundFile() override { ov_clear(&m_vorbisFile); } bool prepareOgg(); diff --git a/src/framework/sound/soundbuffer.cpp b/src/framework/sound/soundbuffer.cpp index 24873d5483..0550a8b2bf 100644 --- a/src/framework/sound/soundbuffer.cpp +++ b/src/framework/sound/soundbuffer.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -53,7 +53,7 @@ bool SoundBuffer::fillBuffer(const SoundFilePtr& soundFile) return fillBuffer(format, samples, samples.size(), soundFile->getRate()); } -bool SoundBuffer::fillBuffer(ALenum sampleFormat, const std::vector& data, int size, int rate) const +bool SoundBuffer::fillBuffer(const ALenum sampleFormat, const std::vector& data, const int size, const int rate) const { alBufferData(m_bufferId, sampleFormat, data.data(), size, rate); const ALenum err = alGetError(); diff --git a/src/framework/sound/soundbuffer.h b/src/framework/sound/soundbuffer.h index 6831759af6..4ab4580bc8 100644 --- a/src/framework/sound/soundbuffer.h +++ b/src/framework/sound/soundbuffer.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * 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/src/framework/sound/soundchannel.cpp b/src/framework/sound/soundchannel.cpp index f61cafa2c8..c67af30d6a 100644 --- a/src/framework/sound/soundchannel.cpp +++ b/src/framework/sound/soundchannel.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,11 +21,11 @@ */ #include "soundchannel.h" -#include #include "soundmanager.h" #include "streamsoundsource.h" +#include -SoundSourcePtr SoundChannel::play(const std::string& filename, float fadetime, float gain, float pitch) +SoundSourcePtr SoundChannel::play(const std::string& filename, const float fadetime, const float gain, const float pitch) { if (!g_sounds.isAudioEnabled() || !m_enabled) return nullptr; @@ -37,7 +37,7 @@ SoundSourcePtr SoundChannel::play(const std::string& filename, float fadetime, f return m_currentSource; } -void SoundChannel::stop(float fadetime) +void SoundChannel::stop(const float fadetime) { m_queue.clear(); @@ -74,7 +74,7 @@ void SoundChannel::update() } } -void SoundChannel::setEnabled(bool enable) +void SoundChannel::setEnabled(const bool enable) { if (m_enabled == enable) return; @@ -91,18 +91,18 @@ void SoundChannel::setEnabled(bool enable) } } -void SoundChannel::setGain(float gain) +void SoundChannel::setGain(const float gain) { if (m_currentSource) m_currentSource->setGain(gain); m_gain = gain; } -void SoundChannel::setPitch(float pitch) +void SoundChannel::setPitch(const float pitch) { if (m_currentSource) m_currentSource->setPitch(pitch); - m_pitch = pitch; + m_pitch = pitch; } void SoundChannel::setPosition(const Point& pos) diff --git a/src/framework/sound/soundchannel.h b/src/framework/sound/soundchannel.h index f4c5727579..89ed38b4d1 100644 --- a/src/framework/sound/soundchannel.h +++ b/src/framework/sound/soundchannel.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -25,10 +25,11 @@ #include "soundsource.h" // @bindclass -class SoundChannel : public LuaObject +class SoundChannel final : public LuaObject { public: - SoundChannel(int id) : m_id(id), m_gain(1), m_pitch(1) {} + SoundChannel(const int id) : m_id(id) + {} SoundSourcePtr play(const std::string& filename, float fadetime = 0, float gain = 1.0f, float pitch = 1.0f); void stop(float fadetime = 0); @@ -57,7 +58,7 @@ class SoundChannel : public LuaObject private: struct QueueEntry { - QueueEntry(std::string fn, float ft, float g, float p) : filename(fn), fadetime(ft), gain(g), pitch(p) {}; + QueueEntry(std::string fn, const float ft, const float g, const float p) : filename(std::move(fn)), fadetime(ft), gain(g), pitch(p) {}; std::string filename; float fadetime; @@ -68,7 +69,7 @@ class SoundChannel : public LuaObject SoundSourcePtr m_currentSource; bool m_enabled{ true }; int m_id; - float m_gain; - float m_pitch; + float m_gain{ 1 }; + float m_pitch{ 1 }; Point m_pos; }; diff --git a/src/framework/sound/soundeffect.cpp b/src/framework/sound/soundeffect.cpp index 49290e8982..8748038c4b 100644 --- a/src/framework/sound/soundeffect.cpp +++ b/src/framework/sound/soundeffect.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,18 +21,13 @@ */ #include "soundeffect.h" -#include "soundmanager.h" -#include "soundsource.h" -#include "declarations.h" -#include "soundbuffer.h" #include "soundfile.h" - -#include "framework/stdext/time.h" +#include "soundmanager.h" #include #include -#include #include +#include #include @@ -64,7 +59,6 @@ static LPALGETAUXILIARYEFFECTSLOTFV alGetAuxiliaryEffectSlotfv; // Remove duplicates from the EffectPresets map const std::unordered_map EffectPresets{ - // Basic Standard Presets {"generic", EFX_REVERB_PRESET_GENERIC}, {"paddedCell", EFX_REVERB_PRESET_PADDEDCELL}, @@ -102,7 +96,7 @@ const std::unordered_map EffectPresets{ {"castleCourtyard", EFX_REVERB_PRESET_CASTLE_COURTYARD}, {"castleAlcove", EFX_REVERB_PRESET_CASTLE_ALCOVE}, - // Factory + // Factory {"factoryHall", EFX_REVERB_PRESET_FACTORY_HALL}, {"factoryShortPassage", EFX_REVERB_PRESET_FACTORY_SHORTPASSAGE}, {"factoryLongPassage", EFX_REVERB_PRESET_FACTORY_LONGPASSAGE}, @@ -146,29 +140,29 @@ const std::unordered_map EffectPresets{ {"prefabWorkshop", EFX_REVERB_PRESET_PREFAB_WORKSHOP}, {"prefabSchoolroom", EFX_REVERB_PRESET_PREFAB_SCHOOLROOM}, {"prefabOutHouse", EFX_REVERB_PRESET_PREFAB_OUTHOUSE}, - {"prefabCaravan", EFX_REVERB_PRESET_PREFAB_CARAVAN}, + {"prefabCaravan", EFX_REVERB_PRESET_PREFAB_CARAVAN}, {"prefabPractiseRoom", EFX_REVERB_PRESET_PREFAB_PRACTISEROOM}, // Dome and Pipes - {"domeTomb", EFX_REVERB_PRESET_DOME_TOMB}, - {"pipeSmall", EFX_REVERB_PRESET_PIPE_SMALL}, + {"domeTomb", EFX_REVERB_PRESET_DOME_TOMB}, + {"pipeSmall", EFX_REVERB_PRESET_PIPE_SMALL}, {"domedSaintPauls", EFX_REVERB_PRESET_DOME_SAINTPAULS}, {"pipeLongThin", EFX_REVERB_PRESET_PIPE_LONGTHIN}, {"pipeLarge", EFX_REVERB_PRESET_PIPE_LARGE}, - {"pipeResonant", EFX_REVERB_PRESET_PIPE_RESONANT}, + {"pipeResonant", EFX_REVERB_PRESET_PIPE_RESONANT}, // Outdoors {"outdoorsBackyard", EFX_REVERB_PRESET_OUTDOORS_BACKYARD}, - {"outdoorsRollingPlains", EFX_REVERB_PRESET_OUTDOORS_ROLLINGPLAINS}, - {"outdoorsDeepCanyon", EFX_REVERB_PRESET_OUTDOORS_DEEPCANYON}, - {"outdoorsCreek", EFX_REVERB_PRESET_OUTDOORS_CREEK}, - {"outdoorsValley", EFX_REVERB_PRESET_OUTDOORS_VALLEY}, + {"outdoorsRollingPlains", EFX_REVERB_PRESET_OUTDOORS_ROLLINGPLAINS}, + {"outdoorsDeepCanyon", EFX_REVERB_PRESET_OUTDOORS_DEEPCANYON}, + {"outdoorsCreek", EFX_REVERB_PRESET_OUTDOORS_CREEK}, + {"outdoorsValley", EFX_REVERB_PRESET_OUTDOORS_VALLEY}, // Mood - {"moodHeaven", EFX_REVERB_PRESET_MOOD_HEAVEN}, - {"moodHell", EFX_REVERB_PRESET_MOOD_HELL}, - {"moodMemory", EFX_REVERB_PRESET_MOOD_MEMORY}, - + {"moodHeaven", EFX_REVERB_PRESET_MOOD_HEAVEN}, + {"moodHell", EFX_REVERB_PRESET_MOOD_HELL}, + {"moodMemory", EFX_REVERB_PRESET_MOOD_MEMORY}, + // Driving {"drivingCommentator", EFX_REVERB_PRESET_DRIVING_COMMENTATOR}, {"drivingPitGarage", EFX_REVERB_PRESET_DRIVING_PITGARAGE}, @@ -185,13 +179,13 @@ const std::unordered_map EffectPresets{ // Misc {"dustyRoom", EFX_REVERB_PRESET_DUSTYROOM}, - {"chapel", EFX_REVERB_PRESET_CHAPEL}, - {"smallWaterRoom", EFX_REVERB_PRESET_SMALLWATERROOM}, + {"chapel", EFX_REVERB_PRESET_CHAPEL}, + {"smallWaterRoom", EFX_REVERB_PRESET_SMALLWATERROOM}, }; template T LoadProcAddress(const char* name) { - void const* addr = alGetProcAddress(name); + const void* addr = alGetProcAddress(name); if (!addr) { g_logger.error(stdext::format("Failed to Load Proc Address during SoundEffect ctor for preset : %s", name)); } @@ -201,7 +195,6 @@ T LoadProcAddress(const char* name) { #define LOAD_PROC(x) x = LoadProcAddress(#x) void SoundEffect::init(ALCdevice* device) { - m_device = device; LOAD_PROC(alGenEffects); @@ -238,19 +231,18 @@ SoundEffect::SoundEffect(ALCdevice* device) : m_device(device) { if (!alGenEffects) { g_logger.error(stdext::format("unable to load OpenAl EFX extension")); return; - } else { - auto effects = std::make_unique(1); - auto slots = std::make_unique(1); - alGenEffects(1, effects.get()); - alGenAuxiliaryEffectSlots(1, slots.get()); - // Check for errors - if (alGetError() != AL_NO_ERROR) { - g_logger.error("Failed to generate effects or slots"); - return; - } - m_effectId = effects[0]; - m_effectSlot = slots[0]; } + const auto effects = std::make_unique(1); + const auto slots = std::make_unique(1); + alGenEffects(1, effects.get()); + alGenAuxiliaryEffectSlots(1, slots.get()); + // Check for errors + if (alGetError() != AL_NO_ERROR) { + g_logger.error("Failed to generate effects or slots"); + return; + } + m_effectId = effects[0]; + m_effectSlot = slots[0]; } assert(alGetError() == AL_NO_ERROR); } @@ -260,14 +252,14 @@ SoundEffect::~SoundEffect() if (m_effectId != 0) { alDeleteEffects(1, &m_effectId); //alDeleteAuxiliaryEffectSlots(1, &m_effectSlot); - auto err = alGetError(); + const auto err = alGetError(); if (err != AL_NO_ERROR) { g_logger.error(stdext::format("error while deleting sound effect: %s", alGetString(err))); } } if (m_effectSlot != 0) { alDeleteAuxiliaryEffectSlots(1, &m_effectSlot); - auto err = alGetError(); + const auto err = alGetError(); if (err != AL_NO_ERROR) { g_logger.error(stdext::format("error while deleting sound aux effect slot: %s", alGetString(err))); } @@ -329,18 +321,17 @@ void SoundEffect::loadPreset(const EFXEAXREVERBPROPERTIES& preset) } /* Update effect slot */ - alAuxiliaryEffectSloti(m_effectSlot, AL_EFFECTSLOT_EFFECT, (ALint)m_effectId); + alAuxiliaryEffectSloti(m_effectSlot, AL_EFFECTSLOT_EFFECT, static_cast(m_effectId)); assert(alGetError() == AL_NO_ERROR && "Failed to set effect slot"); } void SoundEffect::setPreset(const std::string& presetName) { - auto it = EffectPresets.find(presetName); + const auto it = EffectPresets.find(presetName); if (it != EffectPresets.end()) { loadPreset(it->second); } else { g_logger.error(stdext::format("Failed to find preset: %s", presetName)); - return; } } @@ -350,7 +341,7 @@ void SoundEffect::setReverbDensity(const float density) const { } else { alEffectf(m_effectId, AL_REVERB_DENSITY, density); } - alAuxiliaryEffectSloti(m_effectSlot, AL_EFFECTSLOT_EFFECT, (ALint)m_effectId); + alAuxiliaryEffectSloti(m_effectSlot, AL_EFFECTSLOT_EFFECT, static_cast(m_effectId)); } void SoundEffect::setReverbDiffusion(const float diffusion) const { @@ -359,7 +350,7 @@ void SoundEffect::setReverbDiffusion(const float diffusion) const { } else { alEffectf(m_effectId, AL_REVERB_DIFFUSION, diffusion); } - alAuxiliaryEffectSloti(m_effectSlot, AL_EFFECTSLOT_EFFECT, (ALint)m_effectId); + alAuxiliaryEffectSloti(m_effectSlot, AL_EFFECTSLOT_EFFECT, static_cast(m_effectId)); } void SoundEffect::setReverbGain(const float gain) const { @@ -368,16 +359,16 @@ void SoundEffect::setReverbGain(const float gain) const { } else { alEffectf(m_effectId, AL_REVERB_GAIN, gain); } - alAuxiliaryEffectSloti(m_effectSlot, AL_EFFECTSLOT_EFFECT, (ALint)m_effectId); + alAuxiliaryEffectSloti(m_effectSlot, AL_EFFECTSLOT_EFFECT, static_cast(m_effectId)); } -void SoundEffect::setReverbGainHF(const float gainHF) const{ +void SoundEffect::setReverbGainHF(const float gainHF) const { if (g_sounds.isEaxEnabled()) { alEffectf(m_effectId, AL_EAXREVERB_GAINHF, gainHF); } else { alEffectf(m_effectId, AL_REVERB_GAINHF, gainHF); } - alAuxiliaryEffectSloti(m_effectSlot, AL_EFFECTSLOT_EFFECT, (ALint)m_effectId); + alAuxiliaryEffectSloti(m_effectSlot, AL_EFFECTSLOT_EFFECT, static_cast(m_effectId)); } void SoundEffect::setReverbGainLF(const float gainLF) const { @@ -392,7 +383,7 @@ void SoundEffect::setReverbDecayTime(const float decayTime) const { } else { alEffectf(m_effectId, AL_REVERB_DECAY_TIME, decayTime); } - alAuxiliaryEffectSloti(m_effectSlot, AL_EFFECTSLOT_EFFECT, (ALint)m_effectId); + alAuxiliaryEffectSloti(m_effectSlot, AL_EFFECTSLOT_EFFECT, static_cast(m_effectId)); } void SoundEffect::setReverbDecayHfRatio(const float decayHfRatio) const { @@ -401,7 +392,7 @@ void SoundEffect::setReverbDecayHfRatio(const float decayHfRatio) const { } else { alEffectf(m_effectId, AL_REVERB_DECAY_HFRATIO, decayHfRatio); } - alAuxiliaryEffectSloti(m_effectSlot, AL_EFFECTSLOT_EFFECT, (ALint)m_effectId); + alAuxiliaryEffectSloti(m_effectSlot, AL_EFFECTSLOT_EFFECT, static_cast(m_effectId)); } void SoundEffect::setReverbDecayLfRatio(const float decayLfRatio) const { @@ -416,7 +407,7 @@ void SoundEffect::setReverbReflectionsGain(const float reflectionsGain) const { } else { alEffectf(m_effectId, AL_REVERB_REFLECTIONS_GAIN, reflectionsGain); } - alAuxiliaryEffectSloti(m_effectSlot, AL_EFFECTSLOT_EFFECT, (ALint)m_effectId); + alAuxiliaryEffectSloti(m_effectSlot, AL_EFFECTSLOT_EFFECT, static_cast(m_effectId)); } void SoundEffect::setReverbReflectionsDelay(const float reflectionsDelay) const { @@ -425,5 +416,5 @@ void SoundEffect::setReverbReflectionsDelay(const float reflectionsDelay) const } else { alEffectf(m_effectId, AL_REVERB_REFLECTIONS_DELAY, reflectionsDelay); } - alAuxiliaryEffectSloti(m_effectSlot, AL_EFFECTSLOT_EFFECT, (ALint)m_effectId); + alAuxiliaryEffectSloti(m_effectSlot, AL_EFFECTSLOT_EFFECT, static_cast(m_effectId)); } \ No newline at end of file diff --git a/src/framework/sound/soundeffect.h b/src/framework/sound/soundeffect.h index 6b9ba84704..4cedd50665 100644 --- a/src/framework/sound/soundeffect.h +++ b/src/framework/sound/soundeffect.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -22,12 +22,12 @@ #ifndef SOUNDEFFECT_H #define SOUNDEFFECT_H -#include "declarations.h" #include +#include +#include -class SoundEffect : public LuaObject +class SoundEffect final : public LuaObject { - public: explicit SoundEffect(ALCdevice* device); ~SoundEffect() override; @@ -35,16 +35,16 @@ class SoundEffect : public LuaObject void init(ALCdevice* device); void setPreset(const std::string& presetName); - void setReverbDensity(const float density) const; - void setReverbDiffusion(const float diffusion) const; - void setReverbGain(const float gain) const; - void setReverbGainHF(const float gainHF) const; - void setReverbGainLF(const float gainLF) const; - void setReverbDecayTime(const float decayTime) const; - void setReverbDecayHfRatio(const float decayHfRatio) const; - void setReverbDecayLfRatio(const float decayLfRatio) const; - void setReverbReflectionsGain(const float reflectionsGain) const; - void setReverbReflectionsDelay(const float reflectionsDelay) const; + void setReverbDensity(float density) const; + void setReverbDiffusion(float diffusion) const; + void setReverbGain(float gain) const; + void setReverbGainHF(float gainHF) const; + void setReverbGainLF(float gainLF) const; + void setReverbDecayTime(float decayTime) const; + void setReverbDecayHfRatio(float decayHfRatio) const; + void setReverbDecayLfRatio(float decayLfRatio) const; + void setReverbReflectionsGain(float reflectionsGain) const; + void setReverbReflectionsDelay(float reflectionsDelay) const; private: diff --git a/src/framework/sound/soundfile.cpp b/src/framework/sound/soundfile.cpp index f01dda62cf..ae21f27901 100644 --- a/src/framework/sound/soundfile.cpp +++ b/src/framework/sound/soundfile.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,10 +21,8 @@ */ #include "soundfile.h" -#include #include "oggsoundfile.h" - -#include "framework/stdext/time.h" +#include SoundFilePtr SoundFile::loadSoundFile(const std::string& filename) { diff --git a/src/framework/sound/soundfile.h b/src/framework/sound/soundfile.h index d533a0897c..ec1a33c2e3 100644 --- a/src/framework/sound/soundfile.h +++ b/src/framework/sound/soundfile.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -22,15 +22,15 @@ #pragma once -#include #include "declarations.h" +#include class SoundFile : public std::enable_shared_from_this { public: - virtual ~SoundFile() {} // fix clang warning + virtual ~SoundFile() = default; // fix clang warning - SoundFile(const FileStreamPtr& fileStream) : m_file(fileStream) {} + SoundFile(FileStreamPtr fileStream) : m_file(std::move(fileStream)) {} static SoundFilePtr loadSoundFile(const std::string& filename); virtual int read(void* /*buffer*/, int /*bufferSize*/) { return -1; } diff --git a/src/framework/sound/soundmanager.cpp b/src/framework/sound/soundmanager.cpp index 3de078200f..086c1ffd89 100644 --- a/src/framework/sound/soundmanager.cpp +++ b/src/framework/sound/soundmanager.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,18 +21,19 @@ */ #include "soundmanager.h" -#include "combinedsoundsource.h" #include "soundbuffer.h" +#include "soundeffect.h" #include "soundfile.h" #include "streamsoundsource.h" -#include "soundeffect.h" +#include "combinedsoundsource.h" #include #include #include -#include #include +#include "soundchannel.h" + class StreamSoundSource; class CombinedSoundSource; class SoundFile; @@ -150,7 +151,7 @@ void SoundManager::poll() } } -void SoundManager::setAudioEnabled(bool enable) +void SoundManager::setAudioEnabled(const bool enable) { if (m_audioEnabled == enable) return; @@ -184,7 +185,7 @@ void SoundManager::preload(std::string filename) m_buffers[filename] = buffer; } -SoundSourcePtr SoundManager::play(const std::string& fn, float fadetime, float gain, float pitch) +SoundSourcePtr SoundManager::play(const std::string& fn, const float fadetime, float gain, float pitch) { if (!m_audioEnabled) return nullptr; @@ -328,7 +329,7 @@ void SoundManager::setPosition(const Point& pos) SoundEffectPtr SoundManager::createSoundEffect() { - SoundEffectPtr soundEffect = std::make_shared(m_device); + auto soundEffect = std::make_shared(m_device); return soundEffect; } @@ -336,7 +337,6 @@ bool SoundManager::isEaxEnabled() { if (alGetEnumValue("AL_EFFECT_EAXREVERB") != 0) { return true; - } else { - return false; } + return false; } \ No newline at end of file diff --git a/src/framework/sound/soundmanager.h b/src/framework/sound/soundmanager.h index 039f9446a1..79222b15f5 100644 --- a/src/framework/sound/soundmanager.h +++ b/src/framework/sound/soundmanager.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -22,11 +22,10 @@ #pragma once -#include #include "declarations.h" -#include "soundchannel.h" #include "soundsource.h" #include +#include //@bindsingleton g_sounds class SoundManager diff --git a/src/framework/sound/soundsource.cpp b/src/framework/sound/soundsource.cpp index 34ac2fd8da..025b153d20 100644 --- a/src/framework/sound/soundsource.cpp +++ b/src/framework/sound/soundsource.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -76,17 +76,17 @@ void SoundSource::setBuffer(const SoundBufferPtr& buffer) m_buffer = buffer; } -void SoundSource::setLooping(bool looping) +void SoundSource::setLooping(const bool looping) { alSourcei(m_sourceId, AL_LOOPING, looping ? AL_TRUE : AL_FALSE); } -void SoundSource::setRelative(bool relative) +void SoundSource::setRelative(const bool relative) { alSourcei(m_sourceId, AL_SOURCE_RELATIVE, relative ? AL_TRUE : AL_FALSE); } -void SoundSource::setReferenceDistance(float distance) +void SoundSource::setReferenceDistance(const float distance) { alSourcef(m_sourceId, AL_REFERENCE_DISTANCE, distance); } @@ -98,13 +98,13 @@ float SoundSource::getReferenceDistance() return distance; } -void SoundSource::setGain(float gain) +void SoundSource::setGain(const float gain) { alSourcef(m_sourceId, AL_GAIN, gain); m_gain = gain; } -void SoundSource::setPitch(float pitch) +void SoundSource::setPitch(const float pitch) { alSourcef(m_sourceId, AL_PITCH, pitch); } @@ -114,7 +114,7 @@ void SoundSource::setPosition(const Point& pos) alSource3f(m_sourceId, AL_POSITION, pos.x, pos.y, 0); } -void SoundSource::setRolloff(float rolloff) +void SoundSource::setRolloff(const float rolloff) { alSourcef(m_sourceId, AL_ROLLOFF_FACTOR, rolloff); } @@ -124,7 +124,7 @@ void SoundSource::setVelocity(const Point& velocity) alSource3f(m_sourceId, AL_VELOCITY, velocity.x, velocity.y, 0); } -void SoundSource::setFading(FadeState state, float fadeTime) +void SoundSource::setFading(const FadeState state, const float fadeTime) { const float now = stdext::millis() / 1000.0f; if (m_fadeState != NoFading) { @@ -168,11 +168,11 @@ void SoundSource::update() } } -void SoundSource::setEffect(SoundEffectPtr soundEffect) +void SoundSource::setEffect(const SoundEffectPtr soundEffect) { m_effectId = soundEffect->m_effectId; - alSource3i(m_sourceId, AL_AUXILIARY_SEND_FILTER, (ALint)soundEffect->m_effectId, 0, AL_FILTER_NULL); - ALenum err = alGetError(); + alSource3i(m_sourceId, AL_AUXILIARY_SEND_FILTER, static_cast(soundEffect->m_effectId), 0, AL_FILTER_NULL); + const ALenum err = alGetError(); if (err != AL_NO_ERROR) { g_logger.error(stdext::format("Failed to set effect on source: %s", alGetString(err))); } @@ -183,7 +183,7 @@ void SoundSource::removeEffect() if (m_effectId != 0) { m_effectId = 0; alSource3i(m_sourceId, AL_AUXILIARY_SEND_FILTER, AL_EFFECTSLOT_NULL, 0, AL_FILTER_NULL); - ALenum err = alGetError(); + const ALenum err = alGetError(); if (err != AL_NO_ERROR) { g_logger.error(stdext::format("Failed to remove effect on source: %s", alGetString(err))); } diff --git a/src/framework/sound/soundsource.h b/src/framework/sound/soundsource.h index 7fff8dcb15..aba463f412 100644 --- a/src/framework/sound/soundsource.h +++ b/src/framework/sound/soundsource.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -22,13 +22,13 @@ #pragma once -#include #include "declarations.h" +#include class SoundSource : public LuaObject { protected: - SoundSource(uint32_t sourceId) : m_sourceId(sourceId) {} + SoundSource(const uint32_t sourceId) : m_sourceId(sourceId) {} public: enum FadeState { NoFading, FadingOn, FadingOff }; @@ -62,7 +62,7 @@ class SoundSource : public LuaObject protected: void setBuffer(const SoundBufferPtr& buffer); - void setChannel(uint8_t channel) { m_channel = channel; } + void setChannel(const uint8_t channel) { m_channel = channel; } virtual void update(); friend class SoundManager; diff --git a/src/framework/sound/streamsoundsource.cpp b/src/framework/sound/streamsoundsource.cpp index 9dc4197482..9e5b283b9c 100644 --- a/src/framework/sound/streamsoundsource.cpp +++ b/src/framework/sound/streamsoundsource.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -41,12 +41,12 @@ void StreamSoundSource::setFile(std::string filename) filename = g_resources.guessFilePath(filename, "ogg"); filename = g_resources.resolvePath(filename); - SoundFilePtr soundFile = SoundFile::loadSoundFile(filename); + const SoundFilePtr soundFile = SoundFile::loadSoundFile(filename); if (!soundFile) { - g_logger.error(stdext::format("unable to load sound file '%s'", filename)); - return; - } + g_logger.error(stdext::format("unable to load sound file '%s'", filename)); + return; + } setSoundFile(soundFile); } @@ -139,7 +139,7 @@ void StreamSoundSource::update() } } -bool StreamSoundSource::fillBufferAndQueue(uint32_t buffer) +bool StreamSoundSource::fillBufferAndQueue(const uint32_t buffer) { if (m_waitingFile) return false; @@ -154,7 +154,7 @@ bool StreamSoundSource::fillBufferAndQueue(uint32_t buffer) int bytesRead = 0; do { - bytesRead += m_soundFile->read(reinterpret_cast(bufferData.data() + bytesRead), maxRead - bytesRead); + bytesRead += m_soundFile->read(bufferData.data() + bytesRead, maxRead - bytesRead); // end of sound file if (bytesRead < maxRead) { @@ -194,7 +194,7 @@ bool StreamSoundSource::fillBufferAndQueue(uint32_t buffer) return (bytesRead >= STREAM_FRAGMENT_SIZE && !m_eof); } -void StreamSoundSource::downMix(DownMix downMix) +void StreamSoundSource::downMix(const DownMix downMix) { m_downMix = downMix; } \ No newline at end of file diff --git a/src/framework/sound/streamsoundsource.h b/src/framework/sound/streamsoundsource.h index 0c77cc713b..0791a615a1 100644 --- a/src/framework/sound/streamsoundsource.h +++ b/src/framework/sound/streamsoundsource.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -24,7 +24,7 @@ #include "soundsource.h" -class StreamSoundSource : public SoundSource +class StreamSoundSource final : public SoundSource { enum { diff --git a/src/framework/stdext/cast.h b/src/framework/stdext/cast.h index 218d53fc7a..7c749c9608 100644 --- a/src/framework/stdext/cast.h +++ b/src/framework/stdext/cast.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -133,7 +133,7 @@ namespace stdext } // used by safe_cast - class cast_exception : public exception + class cast_exception final : public exception { public: ~cast_exception() noexcept override = default; diff --git a/src/framework/stdext/compiler.h b/src/framework/stdext/compiler.h index 3c350670de..5c46d63b77 100644 --- a/src/framework/stdext/compiler.h +++ b/src/framework/stdext/compiler.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * 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/src/framework/stdext/demangle.cpp b/src/framework/stdext/demangle.cpp index 07bd9e675e..7c40fd154a 100644 --- a/src/framework/stdext/demangle.cpp +++ b/src/framework/stdext/demangle.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -65,4 +65,4 @@ namespace stdext return Buffer; } -} +} \ No newline at end of file diff --git a/src/framework/stdext/demangle.h b/src/framework/stdext/demangle.h index b385e78aff..3863b7e72d 100644 --- a/src/framework/stdext/demangle.h +++ b/src/framework/stdext/demangle.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * 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/src/framework/stdext/exception.h b/src/framework/stdext/exception.h index 8d9216792c..cea1908f38 100644 --- a/src/framework/stdext/exception.h +++ b/src/framework/stdext/exception.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -22,9 +22,9 @@ #pragma once +#include "format.h" #include #include -#include "format.h" namespace stdext { @@ -33,7 +33,7 @@ namespace stdext public: exception() = default; - exception(std::string_view what) : m_what(std::string(what)) {} + exception(const std::string_view what) : m_what(std::string(what)) {} template exception(std::string_view what, const Args&... args) : m_what(stdext::format({ what }, args...)) {} diff --git a/src/framework/stdext/format.h b/src/framework/stdext/format.h index 2b99f63dd9..905ff2bf48 100644 --- a/src/framework/stdext/format.h +++ b/src/framework/stdext/format.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -44,10 +44,13 @@ namespace stdext void print(const T&... args) { std::ostringstream buf; print_ostream(buf, args...); std::cout << buf.str() << std::endl; } template - std::enable_if_t || + T sprintf_cast(const T& t) requires (std::is_integral_v || std::is_pointer_v || std::is_floating_point_v || - std::is_enum_v, T> sprintf_cast(const T& t) { return t; } + std::is_enum_v) { + return t; + } + inline const char* sprintf_cast(const char* s) { return s; } inline const char* sprintf_cast(const std::string_view s) { return s.data(); } @@ -79,7 +82,7 @@ namespace stdext } template - int snprintf(char* s, size_t maxlen, const char* format) + int snprintf(char* s, const size_t maxlen, const char* format) { std::strncpy(s, format, maxlen); s[maxlen - 1] = 0; @@ -96,7 +99,7 @@ namespace stdext template std::string format(const std::string_view format, const Args&... args) { - int n = snprintf(NULL, 0, format.data(), args...); + int n = snprintf(nullptr, 0, format.data(), args...); assert(n != -1); std::string buffer(n + 1, '\0'); n = snprintf(&buffer[0], buffer.size(), format.data(), args...); diff --git a/src/framework/stdext/hash.h b/src/framework/stdext/hash.h index 8ae0ff9040..c71314c332 100644 --- a/src/framework/stdext/hash.h +++ b/src/framework/stdext/hash.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -35,7 +35,7 @@ namespace stdext x ^= x >> 33U; x *= UINT64_C(0xff51afd7ed558ccd); x ^= x >> 33U; - return static_cast(x); + return x; } // Boost Lib @@ -47,7 +47,7 @@ namespace stdext template void hash_combine(size_t& seed, const T& v) { - stdext::hash hasher; + hash hasher; hash_union(seed, hasher(v)); } } diff --git a/src/framework/stdext/math.cpp b/src/framework/stdext/math.cpp index bc18a3a504..bee6068e43 100644 --- a/src/framework/stdext/math.cpp +++ b/src/framework/stdext/math.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -20,7 +20,6 @@ * THE SOFTWARE. */ -#include "math.h" #include #include #include @@ -49,7 +48,7 @@ namespace stdext return (b << 16) | a; } - int random_range(int min, int max) + int random_range(const int min, const int max) { static std::random_device rd; static std::mt19937 gen(rd()); @@ -57,7 +56,7 @@ namespace stdext return min + (dis(gen) % (max - min + 1)); } - float random_range(float min, float max) + float random_range(const float min, const float max) { static std::random_device rd; static std::mt19937 gen(rd()); @@ -67,27 +66,27 @@ namespace stdext std::mt19937& random_gen() { - static std::random_device rd; - static std::mt19937 generator(rd()); - return generator; + static std::random_device rd; + static std::mt19937 generator(rd()); + return generator; } - bool random_bool(double probability) + bool random_bool(const double probability) { - static std::bernoulli_distribution booleanRand; - return booleanRand(random_gen(), std::bernoulli_distribution::param_type(probability)); + static std::bernoulli_distribution booleanRand; + return booleanRand(random_gen(), std::bernoulli_distribution::param_type(probability)); } - int32_t normal_random(int32_t minNumber, int32_t maxNumber) + int32_t normal_random(const int32_t minNumber, const int32_t maxNumber) { - static std::normal_distribution normalRand(0.5f, 0.25f); + static std::normal_distribution normalRand(0.5f, 0.25f); float v; do { - v = normalRand(stdext::random_gen()); + v = normalRand(random_gen()); } while (v < 0.0 || v > 1.0); auto&& [a, b] = std::minmax(minNumber, maxNumber); return a + std::lround(v * (b - a)); } -} +} \ No newline at end of file diff --git a/src/framework/stdext/math.h b/src/framework/stdext/math.h index 8e89c16f46..ba7a179b81 100644 --- a/src/framework/stdext/math.h +++ b/src/framework/stdext/math.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -22,30 +22,28 @@ #pragma once -#include "types.h" - #include namespace stdext { - inline bool is_power_of_two(size_t v) { return ((v != 0) && !(v & (v - 1))); } - inline size_t to_power_of_two(size_t v) { if (v == 0) return 0; size_t r = 1; while (r < v && r != 0xffffffff) r <<= 1; return r; } + inline bool is_power_of_two(const size_t v) { return ((v != 0) && !(v & (v - 1))); } + inline size_t to_power_of_two(const size_t v) { if (v == 0) return 0; size_t r = 1; while (r < v && r != 0xffffffff) r <<= 1; return r; } inline uint16_t readULE16(const uint8_t* addr) { return static_cast(addr[1]) << 8 | addr[0]; } inline uint32_t readULE32(const uint8_t* addr) { return static_cast(readULE16(addr + 2)) << 16 | readULE16(addr); } inline uint64_t readULE64(const uint8_t* addr) { return static_cast(readULE32(addr + 4)) << 32 | readULE32(addr); } - inline void writeULE16(uint8_t* addr, uint16_t value) { addr[1] = value >> 8; addr[0] = static_cast(value); } - inline void writeULE32(uint8_t* addr, uint32_t value) { writeULE16(addr + 2, value >> 16); writeULE16(addr, static_cast(value)); } - inline void writeULE64(uint8_t* addr, uint64_t value) { writeULE32(addr + 4, value >> 32); writeULE32(addr, static_cast(value)); } + inline void writeULE16(uint8_t* addr, const uint16_t value) { addr[1] = value >> 8; addr[0] = static_cast(value); } + inline void writeULE32(uint8_t* addr, const uint32_t value) { writeULE16(addr + 2, value >> 16); writeULE16(addr, static_cast(value)); } + inline void writeULE64(uint8_t* addr, const uint64_t value) { writeULE32(addr + 4, value >> 32); writeULE32(addr, static_cast(value)); } inline int16_t readSLE16(const uint8_t* addr) { return static_cast(addr[1]) << 8 | addr[0]; } inline int32_t readSLE32(const uint8_t* addr) { return static_cast(readSLE16(addr + 2)) << 16 | readSLE16(addr); } inline int64_t readSLE64(const uint8_t* addr) { return static_cast(readSLE32(addr + 4)) << 32 | readSLE32(addr); } - inline void writeSLE16(uint8_t* addr, int16_t value) { addr[1] = value >> 8; addr[0] = static_cast(value); } - inline void writeSLE32(uint8_t* addr, int32_t value) { writeSLE16(addr + 2, value >> 16); writeSLE16(addr, static_cast(value)); } - inline void writeSLE64(uint8_t* addr, int64_t value) { writeSLE32(addr + 4, value >> 32); writeSLE32(addr, static_cast(value)); } + inline void writeSLE16(uint8_t* addr, const int16_t value) { addr[1] = value >> 8; addr[0] = static_cast(value); } + inline void writeSLE32(uint8_t* addr, const int32_t value) { writeSLE16(addr + 2, value >> 16); writeSLE16(addr, static_cast(value)); } + inline void writeSLE64(uint8_t* addr, const int64_t value) { writeSLE32(addr + 4, value >> 32); writeSLE32(addr, static_cast(value)); } uint32_t adler32(const uint8_t* buffer, size_t size); int random_range(int min, int max); @@ -54,5 +52,5 @@ namespace stdext bool random_bool(double probability = 0.5); std::mt19937& random_gen(); - inline static uint32_t circularShift(int bits, uint32_t value) { return (value << bits) | (value >> (32 - bits)); } + inline static uint32_t circularShift(const int bits, const uint32_t value) { return (value << bits) | (value >> (32 - bits)); } } diff --git a/src/framework/stdext/net.cpp b/src/framework/stdext/net.cpp index 0ad314ff72..4c99965306 100644 --- a/src/framework/stdext/net.cpp +++ b/src/framework/stdext/net.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -38,7 +38,7 @@ namespace stdext return asio::detail::socket_ops::host_to_network_long(address_v4.to_ulong()); } - std::vector listSubnetAddresses(uint32_t address, uint8_t mask) + std::vector listSubnetAddresses(const uint32_t address, const uint8_t mask) { std::vector list; if (mask < 32) { diff --git a/src/framework/stdext/net.h b/src/framework/stdext/net.h index 8de681cd5e..19c185db44 100644 --- a/src/framework/stdext/net.h +++ b/src/framework/stdext/net.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -22,13 +22,13 @@ #pragma once +#include "types.h" #include #include -#include "types.h" namespace stdext { std::string ip_to_string(uint32_t ip); - uint32_t string_to_ip(const std::string_view string); + uint32_t string_to_ip(std::string_view string); std::vector listSubnetAddresses(uint32_t address, uint8_t mask); } diff --git a/src/framework/stdext/qrcodegen.cpp b/src/framework/stdext/qrcodegen.cpp index d7711fc6f1..3cdb515fbe 100644 --- a/src/framework/stdext/qrcodegen.cpp +++ b/src/framework/stdext/qrcodegen.cpp @@ -40,7 +40,7 @@ using std::vector; namespace qrcodegen { /*---- Class QrSegment ----*/ - QrSegment::Mode::Mode(int mode, int cc0, int cc1, int cc2) : + QrSegment::Mode::Mode(const int mode, const int cc0, const int cc1, const int cc2) : modeBits(mode) { numBitsCharCount[0] = cc0; numBitsCharCount[1] = cc1; @@ -51,7 +51,7 @@ namespace qrcodegen { return modeBits; } - int QrSegment::Mode::numCharCountBits(int ver) const { + int QrSegment::Mode::numCharCountBits(const int ver) const { return numBitsCharCount[(ver + 7) / 17]; } @@ -65,7 +65,7 @@ namespace qrcodegen { if (data.size() > static_cast(INT_MAX)) throw std::length_error("Data too long"); BitBuffer bb; - for (uint8_t b : data) + for (const uint8_t b : data) bb.appendBits(b, 8); return QrSegment(Mode::BYTE, static_cast(data.size()), std::move(bb)); } @@ -76,7 +76,7 @@ namespace qrcodegen { int accumCount = 0; int charCount = 0; for (; *digits != '\0'; digits++, charCount++) { - char c = *digits; + const char c = *digits; if (c < '0' || c > '9') throw std::domain_error("String contains non-numeric characters"); accumData = accumData * 10 + (c - '0'); @@ -131,11 +131,11 @@ namespace qrcodegen { return result; } - QrSegment QrSegment::makeEci(long assignVal) { + QrSegment QrSegment::makeEci(const long assignVal) { BitBuffer bb; if (assignVal < 0) throw std::domain_error("ECI assignment value out of range"); - else if (assignVal < (1 << 7)) + if (assignVal < (1 << 7)) bb.appendBits(static_cast(assignVal), 8); else if (assignVal < (1 << 14)) { bb.appendBits(2, 2); @@ -148,7 +148,7 @@ namespace qrcodegen { return QrSegment(Mode::ECI, 0, std::move(bb)); } - QrSegment::QrSegment(const Mode& md, int numCh, const std::vector& dt) : + QrSegment::QrSegment(const Mode& md, const int numCh, const std::vector& dt) : mode(&md), numChars(numCh), data(dt) { @@ -156,7 +156,7 @@ namespace qrcodegen { throw std::domain_error("Invalid value"); } - QrSegment::QrSegment(const Mode& md, int numCh, std::vector&& dt) : + QrSegment::QrSegment(const Mode& md, const int numCh, std::vector&& dt) : mode(&md), numChars(numCh), data(std::move(dt)) { @@ -164,10 +164,10 @@ namespace qrcodegen { throw std::domain_error("Invalid value"); } - int QrSegment::getTotalBits(const vector& segs, int version) { + int QrSegment::getTotalBits(const vector& segs, const int version) { int result = 0; for (const QrSegment& seg : segs) { - int ccbits = seg.mode->numCharCountBits(version); + const int ccbits = seg.mode->numCharCountBits(version); if (seg.numChars >= (1L << ccbits)) return -1; // The segment's length doesn't fit the field's bit width if (4 + ccbits > INT_MAX - result) @@ -182,7 +182,7 @@ namespace qrcodegen { bool QrSegment::isNumeric(const char* text) { for (; *text != '\0'; text++) { - char c = *text; + const char c = *text; if (c < '0' || c > '9') return false; } @@ -213,7 +213,7 @@ namespace qrcodegen { /*---- Class QrCode ----*/ - int QrCode::getFormatBits(Ecc ecl) { + int QrCode::getFormatBits(const Ecc ecl) { switch (ecl) { case Ecc::LOW: return 1; case Ecc::MEDIUM: return 0; @@ -223,25 +223,25 @@ namespace qrcodegen { } } - QrCode QrCode::encodeText(const char* text, Ecc ecl) { - vector segs = QrSegment::makeSegments(text); + QrCode QrCode::encodeText(const char* text, const Ecc ecl) { + const vector segs = QrSegment::makeSegments(text); return encodeSegments(segs, ecl); } - QrCode QrCode::encodeBinary(const vector& data, Ecc ecl) { - vector segs{ QrSegment::makeBytes(data) }; + QrCode QrCode::encodeBinary(const vector& data, const Ecc ecl) { + const vector segs{ QrSegment::makeBytes(data) }; return encodeSegments(segs, ecl); } QrCode QrCode::encodeSegments(const vector& segs, Ecc ecl, - int minVersion, int maxVersion, int mask, bool boostEcl) { + const int minVersion, const int maxVersion, const int mask, const bool boostEcl) { if (!(MIN_VERSION <= minVersion && minVersion <= maxVersion && maxVersion <= MAX_VERSION) || mask < -1 || mask > 7) throw std::invalid_argument("Invalid value"); // Find the minimal version number to use int version, dataUsedBits; for (version = minVersion; ; version++) { - int dataCapacityBits = getNumDataCodewords(version, ecl) * 8; // Number of data bits available + const int dataCapacityBits = getNumDataCodewords(version, ecl) * 8; // Number of data bits available dataUsedBits = QrSegment::getTotalBits(segs, version); if (dataUsedBits != -1 && dataUsedBits <= dataCapacityBits) break; // This version number is found to be suitable @@ -259,7 +259,7 @@ namespace qrcodegen { assert(dataUsedBits != -1); // Increase the error correction level while the data still fits in the current version number - for (Ecc newEcl : {Ecc::MEDIUM, Ecc::QUARTILE, Ecc::HIGH}) { // From low to high + for (const Ecc newEcl : {Ecc::MEDIUM, Ecc::QUARTILE, Ecc::HIGH}) { // From low to high if (boostEcl && dataUsedBits <= getNumDataCodewords(version, newEcl) * 8) ecl = newEcl; } @@ -274,7 +274,7 @@ namespace qrcodegen { assert(bb.size() == static_cast(dataUsedBits)); // Add terminator and pad up to a byte if applicable - size_t dataCapacityBits = static_cast(getNumDataCodewords(version, ecl)) * 8; + const size_t dataCapacityBits = static_cast(getNumDataCodewords(version, ecl)) * 8; assert(bb.size() <= dataCapacityBits); bb.appendBits(0, std::min(4, static_cast(dataCapacityBits - bb.size()))); bb.appendBits(0, (8 - static_cast(bb.size() % 8)) % 8); @@ -293,7 +293,7 @@ namespace qrcodegen { return QrCode(version, ecl, dataCodewords, mask); } - QrCode::QrCode(int ver, Ecc ecl, const vector& dataCodewords, int msk) : + QrCode::QrCode(const int ver, const Ecc ecl, const vector& dataCodewords, int msk) : // Initialize fields and check arguments version(ver), errorCorrectionLevel(ecl) { @@ -302,9 +302,9 @@ namespace qrcodegen { if (msk < -1 || msk > 7) throw std::domain_error("Mask value out of range"); size = ver * 4 + 17; - size_t sz = static_cast(size); - modules = vector >(sz, vector(sz)); // Initially all light - isFunction = vector >(sz, vector(sz)); + const auto sz = static_cast(size); + modules = vector(sz, vector(sz)); // Initially all light + isFunction = vector(sz, vector(sz)); // Compute ECC, draw modules drawFunctionPatterns(); @@ -317,7 +317,7 @@ namespace qrcodegen { for (int i = 0; i < 8; i++) { applyMask(i); drawFormatBits(i); - long penalty = getPenaltyScore(); + const long penalty = getPenaltyScore(); if (penalty < minPenalty) { msk = i; minPenalty = penalty; @@ -350,7 +350,7 @@ namespace qrcodegen { return mask; } - bool QrCode::getModule(int x, int y) const { + bool QrCode::getModule(const int x, const int y) const { return 0 <= x && x < size && 0 <= y && y < size && module(x, y); } @@ -368,7 +368,7 @@ namespace qrcodegen { // Draw numerous alignment patterns const vector alignPatPos = getAlignmentPatternPositions(); - size_t numAlign = alignPatPos.size(); + const size_t numAlign = alignPatPos.size(); for (size_t i = 0; i < numAlign; i++) { for (size_t j = 0; j < numAlign; j++) { // Don't draw on the three finder corners @@ -382,13 +382,13 @@ namespace qrcodegen { drawVersion(); } - void QrCode::drawFormatBits(int msk) { + void QrCode::drawFormatBits(const int msk) { // Calculate error correction code and pack bits - int data = getFormatBits(errorCorrectionLevel) << 3 | msk; // errCorrLvl is uint2, msk is uint3 + const int data = getFormatBits(errorCorrectionLevel) << 3 | msk; // errCorrLvl is uint2, msk is uint3 int rem = data; for (int i = 0; i < 10; i++) rem = (rem << 1) ^ ((rem >> 9) * 0x537); - int bits = (data << 10 | rem) ^ 0x5412; // uint15 + const int bits = (data << 10 | rem) ^ 0x5412; // uint15 assert(bits >> 15 == 0); // Draw first copy @@ -416,45 +416,45 @@ namespace qrcodegen { int rem = version; // version is uint6, in the range [7, 40] for (int i = 0; i < 12; i++) rem = (rem << 1) ^ ((rem >> 11) * 0x1F25); - long bits = static_cast(version) << 12 | rem; // uint18 + const long bits = static_cast(version) << 12 | rem; // uint18 assert(bits >> 18 == 0); // Draw two copies for (int i = 0; i < 18; i++) { - bool bit = getBit(bits, i); - int a = size - 11 + i % 3; - int b = i / 3; + const bool bit = getBit(bits, i); + const int a = size - 11 + i % 3; + const int b = i / 3; setFunctionModule(a, b, bit); setFunctionModule(b, a, bit); } } - void QrCode::drawFinderPattern(int x, int y) { + void QrCode::drawFinderPattern(const int x, const int y) { for (int dy = -4; dy <= 4; dy++) { for (int dx = -4; dx <= 4; dx++) { - int dist = std::max(std::abs(dx), std::abs(dy)); // Chebyshev/infinity norm - int xx = x + dx, yy = y + dy; + const int dist = std::max(std::abs(dx), std::abs(dy)); // Chebyshev/infinity norm + const int xx = x + dx, yy = y + dy; if (0 <= xx && xx < size && 0 <= yy && yy < size) setFunctionModule(xx, yy, dist != 2 && dist != 4); } } } - void QrCode::drawAlignmentPattern(int x, int y) { + void QrCode::drawAlignmentPattern(const int x, const int y) { for (int dy = -2; dy <= 2; dy++) { for (int dx = -2; dx <= 2; dx++) setFunctionModule(x + dx, y + dy, std::max(std::abs(dx), std::abs(dy)) != 1); } } - void QrCode::setFunctionModule(int x, int y, bool isDark) { - size_t ux = static_cast(x); - size_t uy = static_cast(y); + void QrCode::setFunctionModule(const int x, const int y, const bool isDark) { + const auto ux = static_cast(x); + const auto uy = static_cast(y); modules.at(uy).at(ux) = isDark; isFunction.at(uy).at(ux) = true; } - bool QrCode::module(int x, int y) const { + bool QrCode::module(const int x, const int y) const { return modules.at(static_cast(y)).at(static_cast(x)); } @@ -463,17 +463,17 @@ namespace qrcodegen { throw std::invalid_argument("Invalid argument"); // Calculate parameter numbers - int numBlocks = NUM_ERROR_CORRECTION_BLOCKS[static_cast(errorCorrectionLevel)][version]; - int blockEccLen = ECC_CODEWORDS_PER_BLOCK[static_cast(errorCorrectionLevel)][version]; - int rawCodewords = getNumRawDataModules(version) / 8; - int numShortBlocks = numBlocks - rawCodewords % numBlocks; - int shortBlockLen = rawCodewords / numBlocks; + const int numBlocks = NUM_ERROR_CORRECTION_BLOCKS[static_cast(errorCorrectionLevel)][version]; + const int blockEccLen = ECC_CODEWORDS_PER_BLOCK[static_cast(errorCorrectionLevel)][version]; + const int rawCodewords = getNumRawDataModules(version) / 8; + const int numShortBlocks = numBlocks - rawCodewords % numBlocks; + const int shortBlockLen = rawCodewords / numBlocks; // Split data into blocks and append ECC to each block vector > blocks; const vector rsDiv = reedSolomonComputeDivisor(blockEccLen); for (int i = 0, k = 0; i < numBlocks; i++) { - vector dat(data.cbegin() + k, data.cbegin() + (k + shortBlockLen - blockEccLen + (i < numShortBlocks ? 0 : 1))); + vector dat(data.cbegin() + k, data.cbegin() + (k + shortBlockLen - blockEccLen + (i < numShortBlocks ? 0 : 1))); k += static_cast(dat.size()); const vector ecc = reedSolomonComputeRemainder(dat, rsDiv); if (i < numShortBlocks) @@ -506,9 +506,9 @@ namespace qrcodegen { right = 5; for (int vert = 0; vert < size; vert++) { // Vertical counter for (int j = 0; j < 2; j++) { - size_t x = static_cast(right - j); // Actual x coordinate - bool upward = ((right + 1) & 2) == 0; - size_t y = static_cast(upward ? size - 1 - vert : vert); // Actual y coordinate + const auto x = static_cast(right - j); // Actual x coordinate + const bool upward = ((right + 1) & 2) == 0; + const auto y = static_cast(upward ? size - 1 - vert : vert); // Actual y coordinate if (!isFunction.at(y).at(x) && i < data.size() * 8) { modules.at(y).at(x) = getBit(data.at(i >> 3), 7 - static_cast(i & 7)); i++; @@ -521,10 +521,10 @@ namespace qrcodegen { assert(i == data.size() * 8); } - void QrCode::applyMask(int msk) { + void QrCode::applyMask(const int msk) { if (msk < 0 || msk > 7) throw std::domain_error("Mask value out of range"); - size_t sz = static_cast(size); + const auto sz = static_cast(size); for (size_t y = 0; y < sz; y++) { for (size_t x = 0; x < sz; x++) { bool invert; @@ -595,7 +595,7 @@ namespace qrcodegen { // 2*2 blocks of modules having same color for (int y = 0; y < size - 1; y++) { for (int x = 0; x < size - 1; x++) { - bool color = module(x, y); + const bool color = module(x, y); if (color == module(x + 1, y) && color == module(x, y + 1) && color == module(x + 1, y + 1)) @@ -606,14 +606,14 @@ namespace qrcodegen { // Balance of dark and light modules int dark = 0; for (const vector& row : modules) { - for (bool color : row) { + for (const bool color : row) { if (color) dark++; } } - int total = size * size; // Note that size is odd, so dark/total != 1/2 + const int total = size * size; // Note that size is odd, so dark/total != 1/2 // Compute the smallest integer k >= 0 such that (45-5k)% <= dark/total <= (55+5k)% - int k = static_cast((std::abs(dark * 20L - total * 10L) + total - 1) / total) - 1; + const int k = static_cast((std::abs(dark * 20L - total * 10L) + total - 1) / total) - 1; assert(0 <= k && k <= 9); result += k * PENALTY_N4; assert(0 <= result && result <= 2568888L); // Non-tight upper bound based on default values of PENALTY_N1, ..., N4 @@ -622,25 +622,23 @@ namespace qrcodegen { vector QrCode::getAlignmentPatternPositions() const { if (version == 1) - return vector(); - else { - int numAlign = version / 7 + 2; - int step = (version == 32) ? 26 : - (version * 4 + numAlign * 2 + 1) / (numAlign * 2 - 2) * 2; - vector result; - for (int i = 0, pos = size - 7; i < numAlign - 1; i++, pos -= step) - result.insert(result.begin(), pos); - result.insert(result.begin(), 6); - return result; - } + return {}; + const int numAlign = version / 7 + 2; + const int step = (version == 32) ? 26 : + (version * 4 + numAlign * 2 + 1) / (numAlign * 2 - 2) * 2; + vector result; + for (int i = 0, pos = size - 7; i < numAlign - 1; i++, pos -= step) + result.insert(result.begin(), pos); + result.insert(result.begin(), 6); + return result; } - int QrCode::getNumRawDataModules(int ver) { + int QrCode::getNumRawDataModules(const int ver) { if (ver < MIN_VERSION || ver > MAX_VERSION) throw std::domain_error("Version number out of range"); int result = (16 * ver + 128) * ver + 64; if (ver >= 2) { - int numAlign = ver / 7 + 2; + const int numAlign = ver / 7 + 2; result -= (25 * numAlign - 10) * numAlign - 55; if (ver >= 7) result -= 36; @@ -649,13 +647,13 @@ namespace qrcodegen { return result; } - int QrCode::getNumDataCodewords(int ver, Ecc ecl) { + int QrCode::getNumDataCodewords(const int ver, Ecc ecl) { return getNumRawDataModules(ver) / 8 - ECC_CODEWORDS_PER_BLOCK[static_cast(ecl)][ver] * NUM_ERROR_CORRECTION_BLOCKS[static_cast(ecl)][ver]; } - vector QrCode::reedSolomonComputeDivisor(int degree) { + vector QrCode::reedSolomonComputeDivisor(const int degree) { if (degree < 1 || degree > 255) throw std::domain_error("Degree out of range"); // Polynomial coefficients are stored from highest to lowest power, excluding the leading term which is always 1. @@ -681,8 +679,8 @@ namespace qrcodegen { vector QrCode::reedSolomonComputeRemainder(const vector& data, const vector& divisor) { vector result(divisor.size()); - for (uint8_t b : data) { // Polynomial division - uint8_t factor = b ^ result.at(0); + for (const uint8_t b : data) { // Polynomial division + const uint8_t factor = b ^ result.at(0); result.erase(result.begin()); result.push_back(0); for (size_t i = 0; i < result.size(); i++) @@ -691,7 +689,7 @@ namespace qrcodegen { return result; } - uint8_t QrCode::reedSolomonMultiply(uint8_t x, uint8_t y) { + uint8_t QrCode::reedSolomonMultiply(const uint8_t x, const uint8_t y) { // Russian peasant multiplication int z = 0; for (int i = 7; i >= 0; i--) { @@ -703,14 +701,14 @@ namespace qrcodegen { } int QrCode::finderPenaltyCountPatterns(const std::array& runHistory) const { - int n = runHistory.at(1); + const int n = runHistory.at(1); assert(n <= size * 3); - bool core = n > 0 && runHistory.at(2) == n && runHistory.at(3) == n * 3 && runHistory.at(4) == n && runHistory.at(5) == n; + const bool core = n > 0 && runHistory.at(2) == n && runHistory.at(3) == n * 3 && runHistory.at(4) == n && runHistory.at(5) == n; return (core && runHistory.at(0) >= n * 4 && runHistory.at(6) >= n ? 1 : 0) + (core && runHistory.at(6) >= n * 4 && runHistory.at(0) >= n ? 1 : 0); } - int QrCode::finderPenaltyTerminateAndCount(bool currentRunColor, int currentRunLength, std::array& runHistory) const { + int QrCode::finderPenaltyTerminateAndCount(const bool currentRunColor, int currentRunLength, std::array& runHistory) const { if (currentRunColor) { // Terminate dark run finderPenaltyAddHistory(currentRunLength, runHistory); currentRunLength = 0; @@ -727,7 +725,7 @@ namespace qrcodegen { runHistory.at(0) = currentRunLength; } - bool QrCode::getBit(long x, int i) { + bool QrCode::getBit(const long x, const int i) { return ((x >> i) & 1) != 0; } @@ -762,9 +760,9 @@ namespace qrcodegen { /*---- Class BitBuffer ----*/ BitBuffer::BitBuffer() - : std::vector() {} + = default; - void BitBuffer::appendBits(std::uint32_t val, int len) { + void BitBuffer::appendBits(const std::uint32_t val, const int len) { if (len < 0 || len > 31 || val >> len != 0) throw std::domain_error("Value out of range"); for (int i = len - 1; i >= 0; i--) // Append bit by bit diff --git a/src/framework/stdext/qrcodegen.h b/src/framework/stdext/qrcodegen.h index 9a719165a7..4903230598 100644 --- a/src/framework/stdext/qrcodegen.h +++ b/src/framework/stdext/qrcodegen.h @@ -53,10 +53,10 @@ namespace qrcodegen { /*-- Constants --*/ public: static const Mode NUMERIC; - public: static const Mode ALPHANUMERIC; - public: static const Mode BYTE; - public: static const Mode KANJI; - public: static const Mode ECI; + static const Mode ALPHANUMERIC; + static const Mode BYTE; + static const Mode KANJI; + static const Mode ECI; /*-- Fields --*/ @@ -64,11 +64,11 @@ namespace qrcodegen { private: int modeBits; // Number of character count bits for three different version ranges. - private: int numBitsCharCount[3]; + int numBitsCharCount[3]; /*-- Constructor --*/ - private: Mode(int mode, int cc0, int cc1, int cc2); + Mode(int mode, int cc0, int cc1, int cc2); /*-- Methods --*/ @@ -81,7 +81,7 @@ namespace qrcodegen { * (Package-private) Returns the bit width of the character count field for a segment in * this mode in a QR Code at the given version number. The result is in the range [0, 16]. */ - public: int numCharCountBits(int ver) const; + int numCharCountBits(int ver) const; }; /*---- Static factory functions (mid level) ----*/ @@ -91,31 +91,31 @@ namespace qrcodegen { * byte mode. All input byte vectors are acceptable. Any text string * can be converted to UTF-8 bytes and encoded as a byte mode segment. */ - public: static QrSegment makeBytes(const std::vector& data); + static QrSegment makeBytes(const std::vector& data); /* * Returns a segment representing the given string of decimal digits encoded in numeric mode. */ - public: static QrSegment makeNumeric(const char* digits); + static QrSegment makeNumeric(const char* digits); /* * Returns a segment representing the given text string encoded in alphanumeric mode. * The characters allowed are: 0 to 9, A to Z (uppercase only), space, * dollar, percent, asterisk, plus, hyphen, period, slash, colon. */ - public: static QrSegment makeAlphanumeric(const char* text); + static QrSegment makeAlphanumeric(const char* text); /* * Returns a list of zero or more segments to represent the given text string. The result * may use various segment modes and switch modes to optimize the length of the bit stream. */ - public: static std::vector makeSegments(const char* text); + static std::vector makeSegments(const char* text); /* * Returns a segment representing an Extended Channel Interpretation * (ECI) designator with the given assignment value. */ - public: static QrSegment makeEci(long assignVal); + static QrSegment makeEci(long assignVal); /*---- Public static helper functions ----*/ @@ -123,14 +123,14 @@ namespace qrcodegen { * Tests whether the given string can be encoded as a segment in numeric mode. * A string is encodable iff each character is in the range 0 to 9. */ - public: static bool isNumeric(const char* text); + static bool isNumeric(const char* text); /* * Tests whether the given string can be encoded as a segment in alphanumeric mode. * A string is encodable iff each character is in the following set: 0 to 9, A to Z * (uppercase only), space, dollar, percent, asterisk, plus, hyphen, period, slash, colon. */ - public: static bool isAlphanumeric(const char* text); + static bool isAlphanumeric(const char* text); /*---- Instance fields ----*/ @@ -141,10 +141,10 @@ namespace qrcodegen { * numeric/alphanumeric/kanji mode, bytes for byte mode, and 0 for ECI mode. * Always zero or positive. Not the same as the data's bit length. * Accessed through getNumChars(). */ - private: int numChars; + int numChars; /* The data bits of this segment. Accessed through getData(). */ - private: std::vector data; + std::vector data; /*---- Constructors (low level) ----*/ @@ -160,29 +160,29 @@ namespace qrcodegen { * The character count (numCh) must agree with the mode and the bit buffer length, * but the constraint isn't checked. The given bit buffer is moved and stored. */ - public: QrSegment(const Mode& md, int numCh, std::vector&& dt); + QrSegment(const Mode& md, int numCh, std::vector&& dt); /*---- Methods ----*/ /* * Returns the mode field of this segment. */ - public: const Mode& getMode() const; + const Mode& getMode() const; /* * Returns the character count field of this segment. */ - public: int getNumChars() const; + int getNumChars() const; /* * Returns the data bits of this segment. */ - public: const std::vector& getData() const; + const std::vector& getData() const; // (Package-private) Calculates the number of bits needed to encode the given segments at // the given version. Returns a non-negative number if successful. Otherwise returns -1 if a // segment has too many characters to fit its length field, or the total bits exceeds INT_MAX. - public: static int getTotalBits(const std::vector& segs, int version); + static int getTotalBits(const std::vector& segs, int version); /*---- Private constant ----*/ @@ -242,7 +242,7 @@ namespace qrcodegen { * bytes allowed is 2953. The smallest possible QR Code version is automatically chosen for the output. * The ECC level of the result may be higher than the ecl argument if it can be done without increasing the version. */ - public: static QrCode encodeBinary(const std::vector& data, Ecc ecl); + static QrCode encodeBinary(const std::vector& data, Ecc ecl); /*---- Static factory functions (mid level) ----*/ @@ -257,8 +257,8 @@ namespace qrcodegen { * between modes (such as alphanumeric and byte) to encode text in less space. * This is a mid-level API; the high-level API is encodeText() and encodeBinary(). */ - public: static QrCode encodeSegments(const std::vector& segs, Ecc ecl, - int minVersion = 1, int maxVersion = 40, int mask = -1, bool boostEcl = true); // All optional parameters + static QrCode encodeSegments(const std::vector& segs, Ecc ecl, + int minVersion = 1, int maxVersion = 40, int mask = -1, bool boostEcl = true); // All optional parameters /*---- Instance fields ----*/ @@ -270,24 +270,24 @@ namespace qrcodegen { /* The width and height of this QR Code, measured in modules, between * 21 and 177 (inclusive). This is equal to version * 4 + 17. */ - private: int size; + int size; /* The error correction level used in this QR Code. */ - private: Ecc errorCorrectionLevel; + Ecc errorCorrectionLevel; /* The index of the mask pattern used in this QR Code, which is between 0 and 7 (inclusive). * Even if a QR Code is created with automatic masking requested (mask = -1), * the resulting object still has a mask value between 0 and 7. */ - private: int mask; + int mask; // Private grids of modules/pixels, with dimensions of size*size: // The modules of this QR Code (false = light, true = dark). // Immutable after constructor finishes. Accessed through getModule(). - private: std::vector > modules; + std::vector > modules; // Indicates function modules that are not subjected to masking. Discarded when constructor finishes. - private: std::vector > isFunction; + std::vector > isFunction; /*---- Constructor (low level) ----*/ @@ -304,29 +304,29 @@ namespace qrcodegen { /* * Returns this QR Code's version, in the range [1, 40]. */ - public: int getVersion() const; + int getVersion() const; /* * Returns this QR Code's size, in the range [21, 177]. */ - public: int getSize() const; + int getSize() const; /* * Returns this QR Code's error correction level. */ - public: Ecc getErrorCorrectionLevel() const; + Ecc getErrorCorrectionLevel() const; /* * Returns this QR Code's mask, in the range [0, 7]. */ - public: int getMask() const; + int getMask() const; /* * Returns the color of the module (pixel) at the given coordinates, which is false * for light or true for dark. The top left corner has the coordinates (x=0, y=0). * If the given coordinates are out of bounds, then false (light) is returned. */ - public: bool getModule(int x, int y) const; + bool getModule(int x, int y) const; /*---- Private helper methods for constructor: Drawing function modules ----*/ @@ -335,88 +335,88 @@ namespace qrcodegen { // Draws two copies of the format bits (with its own error correction code) // based on the given mask and this object's error correction level field. - private: void drawFormatBits(int msk); + void drawFormatBits(int msk); // Draws two copies of the version bits (with its own error correction code), // based on this object's version field, iff 7 <= version <= 40. - private: void drawVersion(); + void drawVersion(); // Draws a 9*9 finder pattern including the border separator, // with the center module at (x, y). Modules can be out of bounds. - private: void drawFinderPattern(int x, int y); + void drawFinderPattern(int x, int y); // Draws a 5*5 alignment pattern, with the center module // at (x, y). All modules must be in bounds. - private: void drawAlignmentPattern(int x, int y); + void drawAlignmentPattern(int x, int y); // Sets the color of a module and marks it as a function module. // Only used by the constructor. Coordinates must be in bounds. - private: void setFunctionModule(int x, int y, bool isDark); + void setFunctionModule(int x, int y, bool isDark); // Returns the color of the module at the given coordinates, which must be in range. - private: bool module(int x, int y) const; + bool module(int x, int y) const; /*---- Private helper methods for constructor: Codewords and masking ----*/ // Returns a new byte string representing the given data with the appropriate error correction // codewords appended to it, based on this object's version and error correction level. - private: std::vector addEccAndInterleave(const std::vector& data) const; + std::vector addEccAndInterleave(const std::vector& data) const; // Draws the given sequence of 8-bit codewords (data and error correction) onto the entire // data area of this QR Code. Function modules need to be marked off before this is called. - private: void drawCodewords(const std::vector& data); + void drawCodewords(const std::vector& data); // XORs the codeword modules in this QR Code with the given mask pattern. // The function modules must be marked and the codeword bits must be drawn // before masking. Due to the arithmetic of XOR, calling applyMask() with // the same mask value a second time will undo the mask. A final well-formed // QR Code needs exactly one (not zero, two, etc.) mask applied. - private: void applyMask(int msk); + void applyMask(int msk); // Calculates and returns the penalty score based on state of this QR Code's current modules. // This is used by the automatic mask choice algorithm to find the mask pattern that yields the lowest score. - private: long getPenaltyScore() const; + long getPenaltyScore() const; /*---- Private helper functions ----*/ // Returns an ascending list of positions of alignment patterns for this version number. // Each position is in the range [0,177), and are used on both the x and y axes. // This could be implemented as lookup table of 40 variable-length lists of unsigned bytes. - private: std::vector getAlignmentPatternPositions() const; + std::vector getAlignmentPatternPositions() const; // Returns the number of data bits that can be stored in a QR Code of the given version number, after // all function modules are excluded. This includes remainder bits, so it might not be a multiple of 8. // The result is in the range [208, 29648]. This could be implemented as a 40-entry lookup table. - private: static int getNumRawDataModules(int ver); + static int getNumRawDataModules(int ver); // Returns the number of 8-bit data (i.e. not error correction) codewords contained in any // QR Code of the given version number and error correction level, with remainder bits discarded. // This stateless pure function could be implemented as a (40*4)-cell lookup table. - private: static int getNumDataCodewords(int ver, Ecc ecl); + static int getNumDataCodewords(int ver, Ecc ecl); // Returns a Reed-Solomon ECC generator polynomial for the given degree. This could be // implemented as a lookup table over all possible parameter values, instead of as an algorithm. - private: static std::vector reedSolomonComputeDivisor(int degree); + static std::vector reedSolomonComputeDivisor(int degree); // Returns the Reed-Solomon error correction codeword for the given data and divisor polynomials. - private: static std::vector reedSolomonComputeRemainder(const std::vector& data, const std::vector& divisor); + static std::vector reedSolomonComputeRemainder(const std::vector& data, const std::vector& divisor); // Returns the product of the two given field elements modulo GF(2^8/0x11D). // All inputs are valid. This could be implemented as a 256*256 lookup table. - private: static std::uint8_t reedSolomonMultiply(std::uint8_t x, std::uint8_t y); + static std::uint8_t reedSolomonMultiply(std::uint8_t x, std::uint8_t y); // Can only be called immediately after a light run is added, and // returns either 0, 1, or 2. A helper function for getPenaltyScore(). - private: int finderPenaltyCountPatterns(const std::array& runHistory) const; + int finderPenaltyCountPatterns(const std::array& runHistory) const; // Must be called at the end of a line (row or column) of modules. A helper function for getPenaltyScore(). - private: int finderPenaltyTerminateAndCount(bool currentRunColor, int currentRunLength, std::array& runHistory) const; + int finderPenaltyTerminateAndCount(bool currentRunColor, int currentRunLength, std::array& runHistory) const; // Pushes the given value to the front and drops the last value. A helper function for getPenaltyScore(). - private: void finderPenaltyAddHistory(int currentRunLength, std::array& runHistory) const; + void finderPenaltyAddHistory(int currentRunLength, std::array& runHistory) const; // Returns true iff the i'th bit of x is set to 1. - private: static bool getBit(long x, int i); + static bool getBit(long x, int i); /*---- Constants and tables ----*/ @@ -424,16 +424,16 @@ namespace qrcodegen { public: static constexpr int MIN_VERSION = 1; // The maximum version number supported in the QR Code Model 2 standard. - public: static constexpr int MAX_VERSION = 40; + static constexpr int MAX_VERSION = 40; // For use in getPenaltyScore(), when evaluating which mask is best. private: static const int PENALTY_N1; - private: static const int PENALTY_N2; - private: static const int PENALTY_N3; - private: static const int PENALTY_N4; + static const int PENALTY_N2; + static const int PENALTY_N3; + static const int PENALTY_N4; - private: static const std::int8_t ECC_CODEWORDS_PER_BLOCK[4][41]; - private: static const std::int8_t NUM_ERROR_CORRECTION_BLOCKS[4][41]; + static const std::int8_t ECC_CODEWORDS_PER_BLOCK[4][41]; + static const std::int8_t NUM_ERROR_CORRECTION_BLOCKS[4][41]; }; /*---- Public exception class ----*/ @@ -449,7 +449,7 @@ namespace qrcodegen { * - Change the text to fit the character set of a particular segment mode (e.g. alphanumeric). * - Propagate the error upward to the caller/user. */ - class data_too_long : public std::length_error + class data_too_long final : public std::length_error { public: explicit data_too_long(const std::string& msg); }; @@ -468,6 +468,6 @@ namespace qrcodegen { // Appends the given number of low-order bits of the given value // to this buffer. Requires 0 <= len <= 31 and val < 2^len. - public: void appendBits(std::uint32_t val, int len); + void appendBits(std::uint32_t val, int len); }; } diff --git a/src/framework/stdext/stdext.h b/src/framework/stdext/stdext.h index e72f003c5b..9fa1c013a2 100644 --- a/src/framework/stdext/stdext.h +++ b/src/framework/stdext/stdext.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -35,8 +35,8 @@ #include "format.h" #include "hash.h" #include "math.h" +#include "qrcodegen.h" #include "storage.h" #include "string.h" -#include "time.h" -#include "qrcodegen.h" #include "thread.h" +#include "time.h" diff --git a/src/framework/stdext/storage.h b/src/framework/stdext/storage.h index f6a58e70b8..e5e4c84d87 100644 --- a/src/framework/stdext/storage.h +++ b/src/framework/stdext/storage.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -36,7 +36,7 @@ namespace stdext class Hash = phmap::priv::hash_default_hash, class Eq = phmap::priv::hash_default_eq, class Alloc = phmap::priv::Allocator> - using set = phmap::flat_hash_set; + using set = phmap::flat_hash_set; template concept OnlyEnum = std::is_enum_v; @@ -71,6 +71,6 @@ namespace stdext void clear() { m_data.clear(); } private: - stdext::map m_data; + map m_data; }; } diff --git a/src/framework/stdext/string.cpp b/src/framework/stdext/string.cpp index 49a8d7f6d2..8ec0b7de8c 100644 --- a/src/framework/stdext/string.cpp +++ b/src/framework/stdext/string.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,6 +21,7 @@ */ #include +#include #include #include "exception.h" @@ -33,7 +34,7 @@ namespace stdext { - std::string resolve_path(const std::string_view filePath, std::string_view sourcePath) + std::string resolve_path(const std::string_view filePath, const std::string_view sourcePath) { if (filePath.starts_with("/")) return filePath.data(); @@ -58,7 +59,7 @@ namespace stdext return std::string(date); } - std::string dec_to_hex(uint64_t num) + std::string dec_to_hex(const uint64_t num) { std::ostringstream o; o << std::hex << num; @@ -75,20 +76,20 @@ namespace stdext bool is_valid_utf8(const std::string_view src) { - int c, i, ix, n, j; + int i, ix, n; for (i = 0, ix = src.length(); i < ix; i++) { - c = (unsigned char)src[i]; + int c = static_cast(src[i]); //if (c==0x09 || c==0x0a || c==0x0d || (0x20 <= c && c <= 0x7e) ) n = 0; // is_printable_ascii if (0x00 <= c && c <= 0x7f) n = 0; // 0bbbbbbb else if ((c & 0xE0) == 0xC0) n = 1; // 110bbbbb - else if (c == 0xed && i < (ix - 1) && ((unsigned char)src[i + 1] & 0xa0) == 0xa0) return false; //U+d800 to U+dfff + else if (c == 0xed && i < (ix - 1) && (static_cast(src[i + 1]) & 0xa0) == 0xa0) return false; //U+d800 to U+dfff else if ((c & 0xF0) == 0xE0) n = 2; // 1110bbbb else if ((c & 0xF8) == 0xF0) n = 3; // 11110bbb //else if (($c & 0xFC) == 0xF8) n=4; // 111110bb //byte 5, unnecessary in 4 byte UTF-8 //else if (($c & 0xFE) == 0xFC) n=5; // 1111110b //byte 6, unnecessary in 4 byte UTF-8 else return false; - for (j = 0; j < n && i < ix; j++) { // n bytes matching 10bbbbbb follow ? - if ((++i == ix) || (((unsigned char)src[i] & 0xC0) != 0x80)) + for (int j = 0; j < n && i < ix; j++) { // n bytes matching 10bbbbbb follow ? + if ((++i == ix) || ((static_cast(src[i]) & 0xC0) != 0x80)) return false; } } @@ -139,18 +140,30 @@ namespace stdext std::wstring utf8_to_utf16(const std::string_view src) { +#ifndef BOT_PROTECTION + constexpr size_t BUFFER_SIZE = 65536; +#else + constexpr size_t BUFFER_SIZE = 4096; +#endif + std::wstring res; - wchar_t out[4096]; - if (MultiByteToWideChar(CP_UTF8, 0, src.data(), -1, out, 4096)) + wchar_t out[BUFFER_SIZE]; + if (MultiByteToWideChar(CP_UTF8, 0, src.data(), -1, out, BUFFER_SIZE)) res = out; return res; } std::string utf16_to_utf8(const std::wstring_view src) { +#ifndef BOT_PROTECTION + constexpr size_t BUFFER_SIZE = 65536; +#else + constexpr size_t BUFFER_SIZE = 4096; +#endif + std::string res; - char out[4096]; - if (WideCharToMultiByte(CP_UTF8, 0, src.data(), -1, out, 4096, nullptr, nullptr)) + char out[BUFFER_SIZE]; + if (WideCharToMultiByte(CP_UTF8, 0, src.data(), -1, out, BUFFER_SIZE, nullptr, nullptr)) res = out; return res; } @@ -168,24 +181,24 @@ namespace stdext void tolower(std::string& str) { - std::transform(str.begin(), str.end(), str.begin(), [](int c) -> char { return static_cast(::tolower(c)); }); + std::ranges::transform(str, str.begin(), [](const int c) -> char { return static_cast(::tolower(c)); }); } void toupper(std::string& str) { - std::transform(str.begin(), str.end(), str.begin(), [](int c) -> char { return static_cast(::toupper(c)); }); + std::ranges::transform(str, str.begin(), [](const int c) -> char { return static_cast(::toupper(c)); }); } void ltrim(std::string& s) { - s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](uint8_t ch) { + s.erase(s.begin(), std::ranges::find_if(s, [](const uint8_t ch) { return !std::isspace(ch); })); } void rtrim(std::string& s) { - s.erase(std::find_if(s.rbegin(), s.rend(), [](uint8_t ch) { + s.erase(std::ranges::find_if(std::ranges::reverse_view(s), [](const uint8_t ch) { return !std::isspace(ch); }).base(), s.end()); } diff --git a/src/framework/stdext/string.h b/src/framework/stdext/string.h index 85d04eb354..8348c0313d 100644 --- a/src/framework/stdext/string.h +++ b/src/framework/stdext/string.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -26,7 +26,6 @@ #include #include "cast.h" -#include "types.h" namespace stdext { @@ -34,12 +33,12 @@ namespace stdext template T from_string(const std::string_view str, T def = T()) { return unsafe_cast(str, def); } /// Resolve a file path by combining sourcePath with filePath - std::string resolve_path(const std::string_view filePath, std::string_view sourcePath); + std::string resolve_path(std::string_view filePath, std::string_view sourcePath); /// Get current date and time in a std::string std::string date_time_string(const char* format = "%b %d %Y %H:%M:%S"); std::string dec_to_hex(uint64_t num); - uint64_t hex_to_dec(const std::string_view str); + uint64_t hex_to_dec(std::string_view str); void tolower(std::string& str); void toupper(std::string& str); void ltrim(std::string& s); @@ -47,21 +46,21 @@ namespace stdext void trim(std::string& s); void ucwords(std::string& str); void eraseWhiteSpace(std::string& str); - void replace_all(std::string& str, const std::string_view search, const std::string_view replacement); + void replace_all(std::string& str, std::string_view search, std::string_view replacement); - bool is_valid_utf8(const std::string_view src); - std::string utf8_to_latin1(const std::string_view src); - std::string latin1_to_utf8(const std::string_view src); + bool is_valid_utf8(std::string_view src); + std::string utf8_to_latin1(std::string_view src); + std::string latin1_to_utf8(std::string_view src); #ifdef WIN32 - std::wstring utf8_to_utf16(const std::string_view src); - std::string utf16_to_utf8(const std::wstring_view src); - std::string utf16_to_latin1(const std::wstring_view src); - std::wstring latin1_to_utf16(const std::string_view src); + std::wstring utf8_to_utf16(std::string_view src); + std::string utf16_to_utf8(std::wstring_view src); + std::string utf16_to_latin1(std::wstring_view src); + std::wstring latin1_to_utf16(std::string_view src); #endif // always returns at least one element in vector - std::vector split(const std::string_view str, const std::string_view separators = " "); + std::vector split(std::string_view str, std::string_view separators = " "); template std::vector split(const std::string_view str, const std::string_view separators = " ") { const std::vector splitted = split(str, separators); diff --git a/src/framework/stdext/thread.h b/src/framework/stdext/thread.h index b529e636b2..b1140d5c2c 100644 --- a/src/framework/stdext/thread.h +++ b/src/framework/stdext/thread.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -22,14 +22,13 @@ #pragma once -#include "types.h" #include namespace stdext { inline int16_t getThreadId() { static std::atomic_int16_t lastId = -1; - thread_local static int16_t id = -1; + thread_local int16_t id = -1; if (id == -1) { lastId.fetch_add(1); diff --git a/src/framework/stdext/time.cpp b/src/framework/stdext/time.cpp index 68b272cf13..c410cf4598 100644 --- a/src/framework/stdext/time.cpp +++ b/src/framework/stdext/time.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -22,7 +22,6 @@ #include #include -#include #include #include "types.h" @@ -42,7 +41,7 @@ namespace stdext return std::chrono::duration_cast(std::chrono::high_resolution_clock::now() - startup_time).count(); } - void microsleep(size_t us) { std::this_thread::sleep_for(std::chrono::microseconds(us)); } + void microsleep(const size_t us) { std::this_thread::sleep_for(std::chrono::microseconds(us)); } - void millisleep(size_t ms) { std::this_thread::sleep_for(std::chrono::milliseconds(ms)); } + void millisleep(const size_t ms) { std::this_thread::sleep_for(std::chrono::milliseconds(ms)); } } \ No newline at end of file diff --git a/src/framework/stdext/time.h b/src/framework/stdext/time.h index fb0cda07fe..150b099a8b 100644 --- a/src/framework/stdext/time.h +++ b/src/framework/stdext/time.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -34,12 +34,11 @@ namespace stdext struct timer { - public: timer() { restart(); } float elapsed_seconds() const { return (micros() - m_start) / 1000000.f; } ticks_t elapsed_millis() const { return (micros() - m_start) / 1000; } ticks_t elapsed_micros() const { return micros() - m_start; } - void restart(int shift = 0) { m_start = micros() - shift; } + void restart(const int shift = 0) { m_start = micros() - shift; } private: ticks_t m_start{}; diff --git a/src/framework/stdext/traits.h b/src/framework/stdext/traits.h index 6580f5e2c8..d987e9ae9f 100644 --- a/src/framework/stdext/traits.h +++ b/src/framework/stdext/traits.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * 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/src/framework/stdext/types.h b/src/framework/stdext/types.h index 835367363f..ff3145889a 100644 --- a/src/framework/stdext/types.h +++ b/src/framework/stdext/types.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -26,10 +26,10 @@ #include #include -typedef unsigned char uchar; -typedef unsigned short ushort; -typedef unsigned int uint; -typedef unsigned long ulong; +using uchar = unsigned char; +using ushort = unsigned short; +using uint = unsigned int; +using ulong = unsigned long; using ticks_t = int64_t; using refcount_t = uint_fast32_t; diff --git a/src/framework/stdext/uri.cpp b/src/framework/stdext/uri.cpp index 5e4e92230b..acd6425d8c 100644 --- a/src/framework/stdext/uri.cpp +++ b/src/framework/stdext/uri.cpp @@ -3,31 +3,30 @@ #include "uri.h" -ParsedURI parseURI(const std::string &url) { - // Regular expression pattern to match URL components - static const std::regex PARSE_URL{ - R"((([httpsw]{2,5})://)?([^/ :]+)(:(\d+))?(/(.+)?))", - std::regex_constants::ECMAScript | std::regex_constants::icase}; +ParsedURI parseURI(const std::string& url) { + // Regular expression pattern to match URL components + static const std::regex PARSE_URL{ + R"((([httpsw]{2,5})://)?([^/ :]+)(:(\d+))?(/(.+)?))", + std::regex_constants::ECMAScript | std::regex_constants::icase }; - ParsedURI result; - std::smatch match; + ParsedURI result; + std::smatch match; - // Check if the URL matches the pattern and has the correct number of components - if (std::regex_match(url, match, PARSE_URL) && match.size() == 8) { - // Set protocol with default value "http" if not provided - result.protocol = (match[2].str().empty()) ? "http" : match[2].str(); + // Check if the URL matches the pattern and has the correct number of components + if (std::regex_match(url, match, PARSE_URL) && match.size() == 8) { + // Set protocol with default value "http" if not provided + result.protocol = (match[2].str().empty()) ? "http" : match[2].str(); - // Set domain - result.domain = match[3].str(); + // Set domain + result.domain = match[3].str(); - // Check if protocol is "https" or "wss" to determine default port - const bool isHttps = (result.protocol == "https" || result.protocol == "wss"); - result.port = (match[5].str().empty()) ? (isHttps) ? "443" : "80" : match[5].str(); + // Check if protocol is "https" or "wss" to determine default port + const bool isHttps = (result.protocol == "https" || result.protocol == "wss"); + result.port = (match[5].str().empty()) ? (isHttps) ? "443" : "80" : match[5].str(); - // Set query with default value "/" - result.query = (match[6].str().empty()) ? "/" : match[6].str(); - } - - return result; -} + // Set query with default value "/" + result.query = (match[6].str().empty()) ? "/" : match[6].str(); + } + return result; +} \ No newline at end of file diff --git a/src/framework/stdext/uri.h b/src/framework/stdext/uri.h index 3aa6c729e2..753f95b8fd 100644 --- a/src/framework/stdext/uri.h +++ b/src/framework/stdext/uri.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -24,11 +24,12 @@ #include -struct ParsedURI { - std::string protocol; - std::string domain; // only domain must be present - std::string port; - std::string query; // everything after '?', possibly nothing +struct ParsedURI +{ + std::string protocol; + std::string domain; // only domain must be present + std::string port; + std::string query; // everything after '?', possibly nothing }; ParsedURI parseURI(const std::string& url); \ No newline at end of file diff --git a/src/framework/ui/declarations.h b/src/framework/ui/declarations.h index ec7c1a3ae1..9a6d3405a3 100644 --- a/src/framework/ui/declarations.h +++ b/src/framework/ui/declarations.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * 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/src/framework/ui/ui.h b/src/framework/ui/ui.h index 99316b8cb2..de2324cf84 100644 --- a/src/framework/ui/ui.h +++ b/src/framework/ui/ui.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -28,7 +28,7 @@ #include "uilayout.h" #include "uimanager.h" #include "uiparticles.h" +#include "uiqrcode.h" #include "uitextedit.h" #include "uiverticallayout.h" #include "uiwidget.h" -#include "uiqrcode.h" diff --git a/src/framework/ui/uianchorlayout.cpp b/src/framework/ui/uianchorlayout.cpp index 065aae81b7..965ec5f553 100644 --- a/src/framework/ui/uianchorlayout.cpp +++ b/src/framework/ui/uianchorlayout.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -185,7 +185,8 @@ bool UIAnchorLayout::updateWidget(const UIWidgetPtr& widget, const UIAnchorGroup extraMarginTop += hookedWidget->getMarginBottom(); extraMarginBottom += hookedWidget->getMarginTop(); break; - } else if (anchor->getAnchoredEdge() == Fw::AnchorLeft && anchor->getHookedEdge() == Fw::AnchorRight) { + } + if (anchor->getAnchoredEdge() == Fw::AnchorLeft && anchor->getHookedEdge() == Fw::AnchorRight) { extraMarginTop -= hookedWidget->getMarginTop(); extraMarginBottom -= hookedWidget->getMarginBottom(); break; @@ -267,7 +268,7 @@ bool UIAnchorLayout::updateWidget(const UIWidgetPtr& widget, const UIAnchorGroup bool UIAnchorLayout::internalUpdate() { // reset all anchors groups update state - for (auto& it : m_anchorsGroups) + for (const auto& it : m_anchorsGroups) it.second->setUpdated(false); bool changed = false; diff --git a/src/framework/ui/uianchorlayout.h b/src/framework/ui/uianchorlayout.h index 064dfb6af0..1220abf4bf 100644 --- a/src/framework/ui/uianchorlayout.h +++ b/src/framework/ui/uianchorlayout.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -29,11 +29,12 @@ class UIAnchor : public std::enable_shared_from_this { public: - virtual ~UIAnchor() {} // fix clang warning + virtual ~UIAnchor() = default; // fix clang warning - UIAnchor(Fw::AnchorEdge anchoredEdge, std::string_view hookedWidgetId, Fw::AnchorEdge hookedEdge) : + UIAnchor(const Fw::AnchorEdge anchoredEdge, const std::string_view hookedWidgetId, const Fw::AnchorEdge hookedEdge) : m_anchoredEdge(anchoredEdge), m_hookedEdge(hookedEdge), m_hookedWidgetId(std::string{ hookedWidgetId }) - {} + { + } Fw::AnchorEdge getAnchoredEdge() const { return m_anchoredEdge; } Fw::AnchorEdge getHookedEdge() const { return m_hookedEdge; } @@ -55,7 +56,7 @@ class UIAnchorGroup : public std::enable_shared_from_this void addAnchor(const UIAnchorPtr& anchor); const UIAnchorList& getAnchors() { return m_anchors; } bool isUpdated() const { return m_updated; } - void setUpdated(bool updated) { m_updated = updated; } + void setUpdated(const bool updated) { m_updated = updated; } private: UIAnchorList m_anchors; @@ -69,11 +70,11 @@ class UIAnchorLayout : public UILayout UIAnchorLayout(UIWidgetPtr parentWidget) : UILayout(std::move(parentWidget)) {} void addAnchor(const UIWidgetPtr& anchoredWidget, Fw::AnchorEdge anchoredEdge, - const std::string_view hookedWidgetId, Fw::AnchorEdge hookedEdge); + std::string_view hookedWidgetId, Fw::AnchorEdge hookedEdge); void removeAnchors(const UIWidgetPtr& anchoredWidget); bool hasAnchors(const UIWidgetPtr& anchoredWidget) const; - void centerIn(const UIWidgetPtr& anchoredWidget, const std::string_view hookedWidgetId); - void fill(const UIWidgetPtr& anchoredWidget, const std::string_view hookedWidgetId); + void centerIn(const UIWidgetPtr& anchoredWidget, std::string_view hookedWidgetId); + void fill(const UIWidgetPtr& anchoredWidget, std::string_view hookedWidgetId); void addWidget(const UIWidgetPtr& widget) override; void removeWidget(const UIWidgetPtr& widget) override; diff --git a/src/framework/ui/uiboxlayout.cpp b/src/framework/ui/uiboxlayout.cpp index d0fe8be898..bc7185a11a 100644 --- a/src/framework/ui/uiboxlayout.cpp +++ b/src/framework/ui/uiboxlayout.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -22,8 +22,8 @@ #include "uiboxlayout.h" -#include #include "uiwidget.h" +#include UIBoxLayout::UIBoxLayout(UIWidgetPtr parentWidget) : UILayout(std::move(parentWidget)) {} diff --git a/src/framework/ui/uiboxlayout.h b/src/framework/ui/uiboxlayout.h index 867b5fe2d4..56d3ab8cdc 100644 --- a/src/framework/ui/uiboxlayout.h +++ b/src/framework/ui/uiboxlayout.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -34,12 +34,12 @@ class UIBoxLayout : public UILayout void addWidget(const UIWidgetPtr& /*widget*/) override { update(); } void removeWidget(const UIWidgetPtr& /*widget*/) override { update(); } - void setSpacing(uint8_t spacing) { m_spacing = spacing; update(); } - void setFitChildren(bool fitParent) { m_fitChildren = fitParent; update(); } + void setSpacing(const int8_t spacing) { m_spacing = spacing; update(); } + void setFitChildren(const bool fitParent) { m_fitChildren = fitParent; update(); } bool isUIBoxLayout() override { return true; } protected: bool m_fitChildren{ false }; - uint8_t m_spacing{ 0 }; + int8_t m_spacing{ 0 }; }; diff --git a/src/framework/ui/uigridlayout.cpp b/src/framework/ui/uigridlayout.cpp index 7292b9b5b3..f7e551ea57 100644 --- a/src/framework/ui/uigridlayout.cpp +++ b/src/framework/ui/uigridlayout.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * 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/src/framework/ui/uigridlayout.h b/src/framework/ui/uigridlayout.h index facd2285db..bd0f5eeaa9 100644 --- a/src/framework/ui/uigridlayout.h +++ b/src/framework/ui/uigridlayout.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -25,7 +25,7 @@ #include "uilayout.h" // @bindclass -class UIGridLayout : public UILayout +class UIGridLayout final : public UILayout { public: UIGridLayout(UIWidgetPtr parentWidget); @@ -35,14 +35,14 @@ class UIGridLayout : public UILayout void addWidget(const UIWidgetPtr& widget) override; void setCellSize(const Size& size) { m_cellSize = size; update(); } - void setCellWidth(int width) { m_cellSize.setWidth(width); update(); } - void setCellHeight(int height) { m_cellSize.setHeight(height); update(); } - void setCellSpacing(uint8_t spacing) { m_cellSpacing = spacing; update(); } - void setNumColumns(uint8_t columns) { m_numColumns = columns; update(); } - void setNumLines(uint16_t lines) { m_numLines = lines; update(); } - void setAutoSpacing(bool enable) { m_autoSpacing = enable; update(); } - void setFitChildren(bool enable) { m_fitChildren = enable; update(); } - void setFlow(bool enable) { m_flow = enable; update(); } + void setCellWidth(const int width) { m_cellSize.setWidth(width); update(); } + void setCellHeight(const int height) { m_cellSize.setHeight(height); update(); } + void setCellSpacing(const uint8_t spacing) { m_cellSpacing = spacing; update(); } + void setNumColumns(const uint8_t columns) { m_numColumns = columns; update(); } + void setNumLines(const uint16_t lines) { m_numLines = lines; update(); } + void setAutoSpacing(const bool enable) { m_autoSpacing = enable; update(); } + void setFitChildren(const bool enable) { m_fitChildren = enable; update(); } + void setFlow(const bool enable) { m_flow = enable; update(); } Size getCellSize() { return m_cellSize; } uint8_t getCellSpacing() { return m_cellSpacing; } diff --git a/src/framework/ui/uihorizontallayout.cpp b/src/framework/ui/uihorizontallayout.cpp index f634522802..b0598c7f7f 100644 --- a/src/framework/ui/uihorizontallayout.cpp +++ b/src/framework/ui/uihorizontallayout.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -22,7 +22,9 @@ #include "uihorizontallayout.h" #include + #include "uiwidget.h" +#include void UIHorizontalLayout::applyStyle(const OTMLNodePtr& styleNode) { @@ -81,8 +83,8 @@ bool UIHorizontalLayout::internalUpdate() }; if (m_alignRight) { - for (auto it = parentWidget->m_children.rbegin(); it != parentWidget->m_children.rend(); ++it) - action(*it); + for (auto& it : std::ranges::reverse_view(parentWidget->m_children)) + action(it); } else for (const auto& widget : parentWidget->m_children) action(widget); diff --git a/src/framework/ui/uihorizontallayout.h b/src/framework/ui/uihorizontallayout.h index 215d15f36c..95e3779871 100644 --- a/src/framework/ui/uihorizontallayout.h +++ b/src/framework/ui/uihorizontallayout.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -26,14 +26,14 @@ #include "uiboxlayout.h" -class UIHorizontalLayout : public UIBoxLayout +class UIHorizontalLayout final : public UIBoxLayout { public: UIHorizontalLayout(UIWidgetPtr parentWidget) : UIBoxLayout(std::move(parentWidget)) {} void applyStyle(const OTMLNodePtr& styleNode) override; - void setAlignRight(bool aliginRight) { m_alignRight = aliginRight; update(); } + void setAlignRight(const bool aliginRight) { m_alignRight = aliginRight; update(); } bool isUIHorizontalLayout() override { return true; } diff --git a/src/framework/ui/uilayout.cpp b/src/framework/ui/uilayout.cpp index 8e9b17501d..8ec9a7f4de 100644 --- a/src/framework/ui/uilayout.cpp +++ b/src/framework/ui/uilayout.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * 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/src/framework/ui/uilayout.h b/src/framework/ui/uilayout.h index bba2554a43..967e27f77d 100644 --- a/src/framework/ui/uilayout.h +++ b/src/framework/ui/uilayout.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -22,9 +22,9 @@ #pragma once +#include "declarations.h" #include #include -#include "declarations.h" #include @@ -32,7 +32,7 @@ class UILayout : public LuaObject { public: - UILayout(UIWidgetPtr parentWidget) : m_parentWidget(std::move(parentWidget)) { } + UILayout(UIWidgetPtr parentWidget) : m_parentWidget(std::move(parentWidget)) {} void update(); void updateLater(); diff --git a/src/framework/ui/uimanager.cpp b/src/framework/ui/uimanager.cpp index 99a1b59cd6..0bf4f70d27 100644 --- a/src/framework/ui/uimanager.cpp +++ b/src/framework/ui/uimanager.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -23,13 +23,14 @@ #include "uimanager.h" #include "ui.h" -#include #include +#include #include #include #include #include -#include + +#include "framework/graphics/graphics.h" UIManager g_ui; @@ -114,7 +115,7 @@ void UIManager::inputEvent(const InputEvent& event) // mouse release is always fired first on the pressed widget if (m_pressedWidget) { - const auto it = std::find(widgetList.begin(), widgetList.end(), m_pressedWidget); + const auto it = std::ranges::find(widgetList, m_pressedWidget); if (it != widgetList.end()) widgetList.erase(it); widgetList.emplace_front(m_pressedWidget); @@ -173,7 +174,7 @@ void UIManager::inputEvent(const InputEvent& event) } } -void UIManager::updatePressedWidget(const UIWidgetPtr& newPressedWidget, const Point& clickedPos, bool fireClicks) +void UIManager::updatePressedWidget(const UIWidgetPtr& newPressedWidget, const Point& clickedPos, const bool fireClicks) { const UIWidgetPtr oldPressedWidget = m_pressedWidget; m_pressedWidget = newPressedWidget; @@ -223,7 +224,7 @@ bool UIManager::updateDraggingWidget(const UIWidgetPtr& draggingWidget, const Po return accepted; } -void UIManager::updateHoveredWidget(bool now) +void UIManager::updateHoveredWidget(const bool now) { if (m_hoverUpdateScheduled && !now) return; @@ -322,7 +323,7 @@ void UIManager::clearStyles() m_styles.clear(); } -bool UIManager::importStyle(const std::string& fl, bool checkDeviceStyles) +bool UIManager::importStyle(const std::string& fl, const bool checkDeviceStyles) { const std::string file{ g_resources.guessFilePath(fl, "otui") }; try { @@ -337,13 +338,13 @@ bool UIManager::importStyle(const std::string& fl, bool checkDeviceStyles) if (checkDeviceStyles) { // check for device styles - auto fileName = fl.substr(0, fl.find(".")); + const auto fileName = fl.substr(0, fl.find(".")); - auto deviceName = g_platform.getDeviceShortName(); + const auto deviceName = g_platform.getDeviceShortName(); if (!deviceName.empty()) importStyle(deviceName + "." + fileName, false); - auto osName = g_platform.getOsShortName(); + const auto osName = g_platform.getOsShortName(); if (!osName.empty()) importStyle(osName + "." + fileName, false); } @@ -441,7 +442,6 @@ std::string UIManager::getStyleName(const std::string_view styleName) return ""; } - std::string UIManager::getStyleClass(const std::string_view styleName) { if (const auto& style = getStyle(styleName)) { @@ -466,10 +466,10 @@ OTMLNodePtr UIManager::findMainWidgetNode(const OTMLDocumentPtr& doc) return mainNode; } -OTMLNodePtr UIManager::loadDeviceUI(const std::string& file, Platform::OperatingSystem os) +OTMLNodePtr UIManager::loadDeviceUI(const std::string& file, const Platform::OperatingSystem os) { - auto rawName = file.substr(0, file.find(".")); - auto osName = g_platform.getOsShortName(os); + const auto rawName = file.substr(0, file.find(".")); + const auto osName = g_platform.getOsShortName(os); const auto& doc = OTMLDocument::parse(g_resources.guessFilePath(rawName + "." + osName, "otui")); if (doc) { @@ -480,10 +480,10 @@ OTMLNodePtr UIManager::loadDeviceUI(const std::string& file, Platform::Operating return nullptr; } -OTMLNodePtr UIManager::loadDeviceUI(const std::string& file, Platform::DeviceType deviceType) +OTMLNodePtr UIManager::loadDeviceUI(const std::string& file, const Platform::DeviceType deviceType) { - auto rawName = file.substr(0, file.find(".")); - auto deviceName = g_platform.getDeviceShortName(deviceType); + const auto rawName = file.substr(0, file.find(".")); + const auto deviceName = g_platform.getDeviceShortName(deviceType); const auto& doc = OTMLDocument::parse(g_resources.guessFilePath(rawName + "." + deviceName, "otui")); if (doc) { @@ -514,7 +514,7 @@ UIWidgetPtr UIManager::loadUI(const std::string& file, const UIWidgetPtr& parent } // load device styles and widget - auto device = g_platform.getDevice(); + const auto device = g_platform.getDevice(); try { const auto& deviceWidgetNode = loadDeviceUI(file, device.type); if (deviceWidgetNode) @@ -523,7 +523,7 @@ UIWidgetPtr UIManager::loadUI(const std::string& file, const UIWidgetPtr& parent g_logger.fine(stdext::format("no device ui found for '%s', reason: '%s'", file, e.what())); } try { - auto osWidgetNode = loadDeviceUI(file, device.os); + const auto osWidgetNode = loadDeviceUI(file, device.os); if (osWidgetNode) widgetNode = osWidgetNode; } catch (stdext::exception& e) { @@ -549,7 +549,7 @@ UIWidgetPtr UIManager::loadUIFromString(const std::string& data, const UIWidgetP sstream.clear(std::ios::goodbit); sstream.write(&data[0], data.length()); sstream.seekg(0, std::ios::beg); - OTMLDocumentPtr doc = OTMLDocument::parse(sstream, "(string)"); + const OTMLDocumentPtr doc = OTMLDocument::parse(sstream, "(string)"); UIWidgetPtr widget; for (const OTMLNodePtr& node : doc->children()) { std::string tag = node->tag(); diff --git a/src/framework/ui/uimanager.h b/src/framework/ui/uimanager.h index 29979fe6ce..145a5d6615 100644 --- a/src/framework/ui/uimanager.h +++ b/src/framework/ui/uimanager.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -22,10 +22,10 @@ #pragma once +#include "declarations.h" #include #include #include -#include "declarations.h" //@bindsingleton g_ui class UIManager @@ -46,9 +46,9 @@ class UIManager bool importStyle(const std::string& fl, bool checkDeviceStyles = true); void importStyleFromOTML(const OTMLNodePtr& styleNode); void importStyleFromOTML(const OTMLDocumentPtr& doc); - OTMLNodePtr getStyle(const std::string_view sn); - std::string getStyleName(const std::string_view styleName); - std::string getStyleClass(const std::string_view styleName); + OTMLNodePtr getStyle(std::string_view sn); + std::string getStyleName(std::string_view styleName); + std::string getStyleClass(std::string_view styleName); OTMLNodePtr findMainWidgetNode(const OTMLDocumentPtr& doc); UIWidgetPtr loadUI(const std::string& file, const UIWidgetPtr& parent); @@ -56,12 +56,12 @@ class UIManager OTMLNodePtr loadDeviceUI(const std::string& file, Platform::OperatingSystem os); OTMLNodePtr loadDeviceUI(const std::string& file, Platform::DeviceType deviceType); UIWidgetPtr displayUI(const std::string& file) { return loadUI(file, m_rootWidget); } - UIWidgetPtr createWidget(const std::string_view styleName, const UIWidgetPtr& parent); + UIWidgetPtr createWidget(std::string_view styleName, const UIWidgetPtr& parent); UIWidgetPtr createWidgetFromOTML(const OTMLNodePtr& widgetNode, const UIWidgetPtr& parent); void setMouseReceiver(const UIWidgetPtr& widget) { m_mouseReceiver = widget; } void setKeyboardReceiver(const UIWidgetPtr& widget) { m_keyboardReceiver = widget; } - void setDebugBoxesDrawing(bool enabled) { m_drawDebugBoxes = enabled; } + void setDebugBoxesDrawing(const bool enabled) { m_drawDebugBoxes = enabled; } void resetMouseReceiver() { m_mouseReceiver = m_rootWidget; } void resetKeyboardReceiver() { m_keyboardReceiver = m_rootWidget; } UIWidgetPtr getMouseReceiver() { return m_mouseReceiver; } diff --git a/src/framework/ui/uiparticles.cpp b/src/framework/ui/uiparticles.cpp index 325b3aa92e..b8060c424d 100644 --- a/src/framework/ui/uiparticles.cpp +++ b/src/framework/ui/uiparticles.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -26,7 +26,7 @@ #include "framework/graphics/particleeffect.h" -void UIParticles::drawSelf(DrawPoolType drawPane) +void UIParticles::drawSelf(const DrawPoolType drawPane) { if (drawPane != DrawPoolType::FOREGROUND) return; diff --git a/src/framework/ui/uiparticles.h b/src/framework/ui/uiparticles.h index 0579c473d1..2c88fd7d3d 100644 --- a/src/framework/ui/uiparticles.h +++ b/src/framework/ui/uiparticles.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -24,14 +24,14 @@ #include -class UIParticles : public UIWidget +class UIParticles final : public UIWidget { public: void drawSelf(DrawPoolType drawPane) override; - void addEffect(const std::string_view name); + void addEffect(std::string_view name); - void onStyleApply(const std::string_view styleName, const OTMLNodePtr& styleNode) override; + void onStyleApply(std::string_view styleName, const OTMLNodePtr& styleNode) override; void setReferencePos(const PointF& point) { m_referencePos = point; } PointF getReferencePos() { return m_referencePos; } diff --git a/src/framework/ui/uiqrcode.cpp b/src/framework/ui/uiqrcode.cpp index b1141edea7..8b65d716c9 100644 --- a/src/framework/ui/uiqrcode.cpp +++ b/src/framework/ui/uiqrcode.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -36,7 +36,7 @@ void UIQrCode::parseCustomStyle(const OTMLNodePtr& styleNode) } } -void UIQrCode::setCode(const std::string& code, int border) +void UIQrCode::setCode(const std::string& code, const int border) { if (code.empty()) { m_imageTexture = nullptr; @@ -45,7 +45,7 @@ void UIQrCode::setCode(const std::string& code, int border) } m_qrCode = code; - m_imageTexture = TexturePtr(new Texture(Image::fromQRCode(code, border))); + m_imageTexture = std::make_shared(Image::fromQRCode(code, border)); if (m_imageTexture && (!m_rect.isValid() || isImageAutoResize())) { const auto& imageSize = m_imageTexture->getSize(); @@ -59,4 +59,4 @@ void UIQrCode::setCode(const std::string& code, int border) setSize(size); } -} +} \ No newline at end of file diff --git a/src/framework/ui/uiqrcode.h b/src/framework/ui/uiqrcode.h index 0937138927..5d45fabff9 100644 --- a/src/framework/ui/uiqrcode.h +++ b/src/framework/ui/uiqrcode.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -22,16 +22,14 @@ #pragma once -#include "declarations.h" - #include "uiwidget.h" -// @bindclass -class UIQrCode : public UIWidget + // @bindclass +class UIQrCode final : public UIWidget { public: void setCode(const std::string& code, int border); - void setCodeBorder(int border) { m_qrCodeBorder = border; setCode(m_qrCode, border); } + void setCodeBorder(const int border) { m_qrCodeBorder = border; setCode(m_qrCode, border); } std::string getCode() { return m_qrCode; } int getCodeBorder() { return m_qrCodeBorder; } diff --git a/src/framework/ui/uitextedit.cpp b/src/framework/ui/uitextedit.cpp index c803fdb638..3e22c6a408 100644 --- a/src/framework/ui/uitextedit.cpp +++ b/src/framework/ui/uitextedit.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,7 +21,6 @@ */ #include "uitextedit.h" -#include #include #include #include @@ -33,16 +32,20 @@ #include "uitranslator.h" #include +#ifdef __EMSCRIPTEN__ +#include +#endif + UITextEdit::UITextEdit() { - setProp(Props::PropCursorInRange, true); - setProp(Props::PropCursorVisible, true); - setProp(Props::PropEditable, true); - setProp(Props::PropChangeCursorImage, true); - setProp(Props::PropUpdatesEnabled, true); - setProp(Props::PropAutoScroll, true); - setProp(Props::PropSelectable, true); - setProp(Props::PropGlyphsMustRecache, true); + setProp(PropCursorInRange, true); + setProp(PropCursorVisible, true); + setProp(PropEditable, true); + setProp(PropChangeCursorImage, true); + setProp(PropUpdatesEnabled, true); + setProp(PropAutoScroll, true); + setProp(PropSelectable, true); + setProp(PropGlyphsMustRecache, true); m_textAlign = Fw::AlignTopLeft; m_placeholder = ""; @@ -52,7 +55,7 @@ UITextEdit::UITextEdit() blinkCursor(); } -void UITextEdit::drawSelf(DrawPoolType drawPane) +void UITextEdit::drawSelf(const DrawPoolType drawPane) { if (drawPane != DrawPoolType::FOREGROUND) return; @@ -121,7 +124,7 @@ void UITextEdit::drawSelf(DrawPoolType drawPane) } } -void UITextEdit::update(bool focusCursor) +void UITextEdit::update(const bool focusCursor) { if (!getProp(PropUpdatesEnabled)) return; @@ -281,7 +284,7 @@ void UITextEdit::update(bool focusCursor) nextColorIndex = textLength; } - if (colorCoordsMap.find(curColorRgba) == colorCoordsMap.end()) { + if (!colorCoordsMap.contains(curColorRgba)) { colorCoordsMap.insert(std::make_pair(curColorRgba, std::make_shared())); } @@ -407,7 +410,7 @@ void UITextEdit::setSelection(int start, int end) repaint(); } -void UITextEdit::setTextHidden(bool hidden) +void UITextEdit::setTextHidden(const bool hidden) { if (getProp(PropTextHidden) == hidden) return; @@ -457,7 +460,7 @@ void UITextEdit::appendText(const std::string_view txt) } } -void UITextEdit::appendCharacter(char c) +void UITextEdit::appendCharacter(const char c) { if ((c == '\n' && !getProp(PropMultiline)) || c == '\r') return; @@ -482,7 +485,7 @@ void UITextEdit::appendCharacter(char c) setText(tmp2); } -void UITextEdit::removeCharacter(bool right) +void UITextEdit::removeCharacter(const bool right) { std::string tmp = m_text; if (static_cast(m_cursorPos) >= 0 && tmp.length() > 0) { @@ -516,7 +519,7 @@ void UITextEdit::deleteSelection() setText(tmp); } -void UITextEdit::del(bool right) +void UITextEdit::del(const bool right) { if (hasSelection()) { deleteSelection(); @@ -554,7 +557,7 @@ void UITextEdit::wrapText() setText(m_font->wrapText(m_text, getPaddingRect().width() - m_textOffset.x)); } -void UITextEdit::moveCursorHorizontally(bool right) +void UITextEdit::moveCursorHorizontally(const bool right) { if (right) { if (static_cast(m_cursorPos) + 1 <= m_text.length()) @@ -656,7 +659,7 @@ void UITextEdit::updateText() update(true); } -void UITextEdit::onHoverChange(bool hovered) +void UITextEdit::onHoverChange(const bool hovered) { if (getProp(PropChangeCursorImage)) { if (hovered && !g_mouse.isCursorChanged()) @@ -716,7 +719,7 @@ void UITextEdit::onGeometryChange(const Rect& oldRect, const Rect& newRect) UIWidget::onGeometryChange(oldRect, newRect); } -void UITextEdit::onFocusChange(bool focused, Fw::FocusReason reason) +void UITextEdit::onFocusChange(const bool focused, const Fw::FocusReason reason) { if (focused) { if (reason == Fw::KeyboardFocusReason) @@ -732,7 +735,7 @@ void UITextEdit::onFocusChange(bool focused, Fw::FocusReason reason) UIWidget::onFocusChange(focused, reason); } -bool UITextEdit::onKeyPress(uint8_t keyCode, int keyboardModifiers, int autoRepeatTicks) +bool UITextEdit::onKeyPress(const uint8_t keyCode, const int keyboardModifiers, const int autoRepeatTicks) { if (UIWidget::onKeyPress(keyCode, keyboardModifiers, autoRepeatTicks)) return true; @@ -879,7 +882,7 @@ bool UITextEdit::onKeyText(const std::string_view keyText) return false; } -bool UITextEdit::onMousePress(const Point& mousePos, Fw::MouseButton button) +bool UITextEdit::onMousePress(const Point& mousePos, const Fw::MouseButton button) { if (UIWidget::onMousePress(mousePos, button)) return true; @@ -894,12 +897,22 @@ bool UITextEdit::onMousePress(const Point& mousePos, Fw::MouseButton button) setSelection(pos, pos); } } +#ifdef __EMSCRIPTEN__ + if (g_window.isVisible()) { + MAIN_THREAD_ASYNC_EM_ASM({ + if (navigator && "virtualKeyboard" in navigator) { + document.getElementById("title-text").focus(); + navigator.virtualKeyboard.show(); + } + }); + } +#endif return true; } return false; } -bool UITextEdit::onMouseRelease(const Point& mousePos, Fw::MouseButton button) +bool UITextEdit::onMouseRelease(const Point& mousePos, const Fw::MouseButton button) { return UIWidget::onMouseRelease(mousePos, button); } @@ -939,4 +952,4 @@ void UITextEdit::onTextAreaUpdate(const Point& offset, const Size& visibleSize, void UITextEdit::setPlaceholderFont(const std::string_view fontName) { m_placeholderFont = g_fonts.getFont(fontName); -} +} \ No newline at end of file diff --git a/src/framework/ui/uitextedit.h b/src/framework/ui/uitextedit.h index 1334c8655c..2a23942e59 100644 --- a/src/framework/ui/uitextedit.h +++ b/src/framework/ui/uitextedit.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -25,7 +25,7 @@ #include "uiwidget.h" // @bindclass -class UITextEdit : public UIWidget +class UITextEdit final : public UIWidget { public: UITextEdit(); @@ -38,34 +38,34 @@ class UITextEdit : public UIWidget public: void setCursorPos(int pos); void setSelection(int start, int end); - void setCursorVisible(bool enable) { setProp(PropCursorVisible, enable); } - void setChangeCursorImage(bool enable) { setProp(PropChangeCursorImage, enable); } + void setCursorVisible(const bool enable) { setProp(PropCursorVisible, enable); } + void setChangeCursorImage(const bool enable) { setProp(PropChangeCursorImage, enable); } void setTextHidden(bool hidden); void setValidCharacters(const std::string_view validCharacters) { m_validCharacters = validCharacters; } - void setShiftNavigation(bool enable) { setProp(PropShiftNavigation, enable); } - void setMultiline(bool enable) { setProp(PropMultiline, enable); } - void setMaxLength(uint32_t maxLength) { m_maxLength = maxLength; } + void setShiftNavigation(const bool enable) { setProp(PropShiftNavigation, enable); } + void setMultiline(const bool enable) { setProp(PropMultiline, enable); } + void setMaxLength(const uint32_t maxLength) { m_maxLength = maxLength; } void setTextVirtualOffset(const Point& offset); - void setEditable(bool editable) { setProp(PropEditable, editable); } - void setSelectable(bool selectable) { setProp(PropSelectable, selectable); } + void setEditable(const bool editable) { setProp(PropEditable, editable); } + void setSelectable(const bool selectable) { setProp(PropSelectable, selectable); } void setSelectionColor(const Color& color) { m_selectionColor = color; } void setSelectionBackgroundColor(const Color& color) { m_selectionBackgroundColor = color; } - void setAutoScroll(bool autoScroll) { setProp(PropAutoScroll, autoScroll); } + void setAutoScroll(const bool autoScroll) { setProp(PropAutoScroll, autoScroll); } void setPlaceholder(std::string placeholder) { m_placeholder = placeholder; } void setPlaceholderColor(const Color& color) { m_placeholderColor = color; } - void setPlaceholderAlign(Fw::AlignmentFlag align) { m_placeholderAlign = align; } - void setPlaceholderFont(const std::string_view fontName); + void setPlaceholderAlign(const Fw::AlignmentFlag align) { m_placeholderAlign = align; } + void setPlaceholderFont(std::string_view fontName); void moveCursorHorizontally(bool right); void moveCursorVertically(bool up); - void appendText(const std::string_view text); + void appendText(std::string_view text); void appendCharacter(char c); void removeCharacter(bool right); void blinkCursor(); void deleteSelection(); void del(bool right = false); - void paste(const std::string_view text); + void paste(std::string_view text); std::string copy(); std::string cut(); void selectAll() { setSelection(0, m_text.length()); } @@ -98,10 +98,10 @@ class UITextEdit : public UIWidget void updateText() override; void onHoverChange(bool hovered) override; - void onStyleApply(const std::string_view styleName, const OTMLNodePtr& styleNode) override; + void onStyleApply(std::string_view styleName, const OTMLNodePtr& styleNode) override; void onGeometryChange(const Rect& oldRect, const Rect& newRect) override; void onFocusChange(bool focused, Fw::FocusReason reason) override; - bool onKeyText(const std::string_view keyText) override; + bool onKeyText(std::string_view keyText) override; bool onKeyPress(uint8_t keyCode, int keyboardModifiers, int autoRepeatTicks) override; bool onMousePress(const Point& mousePos, Fw::MouseButton button) override; bool onMouseRelease(const Point& mousePos, Fw::MouseButton button) override; @@ -140,8 +140,8 @@ class UITextEdit : public UIWidget ticks_t m_cursorTicks; uint32_t m_props{ 0 }; - void setProp(Props prop, bool v) { if (v) m_props |= prop; else m_props &= ~prop; } - bool getProp(Props prop) const { return m_props & prop; }; + void setProp(const Props prop, const bool v) { if (v) m_props |= prop; else m_props &= ~prop; } + bool getProp(const Props prop) const { return m_props & prop; }; int m_selectionReference{ 0 }; int m_selectionStart{ 0 }; diff --git a/src/framework/ui/uitranslator.cpp b/src/framework/ui/uitranslator.cpp index 54977ec082..ac210e763d 100644 --- a/src/framework/ui/uitranslator.cpp +++ b/src/framework/ui/uitranslator.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * 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/src/framework/ui/uitranslator.h b/src/framework/ui/uitranslator.h index 1b868a5ccc..4496a28ddc 100644 --- a/src/framework/ui/uitranslator.h +++ b/src/framework/ui/uitranslator.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -22,8 +22,8 @@ #pragma once -#include #include "../const.h" +#include namespace Fw { diff --git a/src/framework/ui/uiverticallayout.cpp b/src/framework/ui/uiverticallayout.cpp index c15ea46fb8..c5041f0d9d 100644 --- a/src/framework/ui/uiverticallayout.cpp +++ b/src/framework/ui/uiverticallayout.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -22,7 +22,9 @@ #include "uiverticallayout.h" #include + #include "uiwidget.h" +#include void UIVerticalLayout::applyStyle(const OTMLNodePtr& styleNode) { @@ -83,8 +85,8 @@ bool UIVerticalLayout::internalUpdate() }; if (m_alignBottom) { - for (auto it = parentWidget->m_children.rbegin(); it != parentWidget->m_children.rend(); ++it) - action(*it); + for (auto& it : std::ranges::reverse_view(parentWidget->m_children)) + action(it); } else for (const auto& widget : parentWidget->m_children) action(widget); @@ -99,4 +101,4 @@ bool UIVerticalLayout::internalUpdate() } return changed; -} +} \ No newline at end of file diff --git a/src/framework/ui/uiverticallayout.h b/src/framework/ui/uiverticallayout.h index 6f2b366396..8000817095 100644 --- a/src/framework/ui/uiverticallayout.h +++ b/src/framework/ui/uiverticallayout.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -27,14 +27,14 @@ #include "uiboxlayout.h" // @bindclass -class UIVerticalLayout : public UIBoxLayout +class UIVerticalLayout final : public UIBoxLayout { public: UIVerticalLayout(UIWidgetPtr parentWidget) : UIBoxLayout(std::move(parentWidget)) {} void applyStyle(const OTMLNodePtr& styleNode) override; - void setAlignBottom(bool aliginBottom) { m_alignBottom = aliginBottom; update(); } + void setAlignBottom(const bool aliginBottom) { m_alignBottom = aliginBottom; update(); } bool isAlignBottom() { return m_alignBottom; } bool isUIVerticalLayout() override { return true; } diff --git a/src/framework/ui/uiwidget.cpp b/src/framework/ui/uiwidget.cpp index 76f28c927a..5a6f862e0a 100644 --- a/src/framework/ui/uiwidget.cpp +++ b/src/framework/ui/uiwidget.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -25,11 +25,15 @@ #include "uimanager.h" #include "uitranslator.h" -#include #include #include #include #include + +#include + +#include + #include "framework/graphics/drawpoolmanager.h" #include "framework/graphics/shadermanager.h" @@ -66,7 +70,7 @@ UIWidget::~UIWidget() #endif } -void UIWidget::draw(const Rect& visibleRect, DrawPoolType drawPane) +void UIWidget::draw(const Rect& visibleRect, const DrawPoolType drawPane) { Rect oldClipRect; if (isClipping()) { @@ -96,7 +100,7 @@ void UIWidget::draw(const Rect& visibleRect, DrawPoolType drawPane) } } -void UIWidget::drawSelf(DrawPoolType drawPane) +void UIWidget::drawSelf(const DrawPoolType drawPane) { if (drawPane != DrawPoolType::FOREGROUND) return; @@ -120,7 +124,7 @@ void UIWidget::drawSelf(DrawPoolType drawPane) g_drawPool.resetShaderProgram(); } -void UIWidget::drawChildren(const Rect& visibleRect, DrawPoolType drawPane) +void UIWidget::drawChildren(const Rect& visibleRect, const DrawPoolType drawPane) { // draw children for (const auto& child : m_children) { @@ -224,7 +228,7 @@ void UIWidget::insertChild(int32_t index, const UIWidgetPtr& child) if (!(index >= 0 && index <= childrenSize)) { //g_logger.traceWarning("attempt to insert a child UIWidget into an invalid index, using nearest index..."); - index = std::clamp(index, 0, static_cast(childrenSize)); + index = std::clamp(index, 0, childrenSize); } // there was no change of index @@ -272,7 +276,7 @@ void UIWidget::removeChild(const UIWidgetPtr& child) if (isChildLocked(child)) unlockChild(child); - const auto it = std::find(m_children.begin(), m_children.end(), child); + const auto it = std::ranges::find(m_children, child); m_children.erase(it); m_childrenById.erase(child->getId()); @@ -310,7 +314,7 @@ void UIWidget::removeChild(const UIWidgetPtr& child) g_logger.traceError("attempt to remove an unknown child from a UIWidget"); } -void UIWidget::focusChild(const UIWidgetPtr& child, Fw::FocusReason reason) +void UIWidget::focusChild(const UIWidgetPtr& child, const Fw::FocusReason reason) { if (isDestroyed()) return; @@ -345,7 +349,7 @@ void UIWidget::focusChild(const UIWidgetPtr& child, Fw::FocusReason reason) onChildFocusChange(child, oldFocused, reason); } -void UIWidget::focusNextChild(Fw::FocusReason reason, bool rotate) +void UIWidget::focusNextChild(const Fw::FocusReason reason, const bool rotate) { if (isDestroyed()) return; @@ -355,9 +359,9 @@ void UIWidget::focusNextChild(Fw::FocusReason reason, bool rotate) UIWidgetList rotatedChildren(m_children); if (m_focusedChild) { - const auto focusedIt = std::find(rotatedChildren.begin(), rotatedChildren.end(), m_focusedChild); + const auto focusedIt = std::ranges::find(rotatedChildren, m_focusedChild); if (focusedIt != rotatedChildren.end()) { - std::rotate(rotatedChildren.begin(), focusedIt, rotatedChildren.end()); + std::ranges::rotate(rotatedChildren, focusedIt); rotatedChildren.pop_front(); } } @@ -372,7 +376,7 @@ void UIWidget::focusNextChild(Fw::FocusReason reason, bool rotate) } else { auto it = m_children.begin(); if (m_focusedChild) - it = std::find(m_children.begin(), m_children.end(), m_focusedChild); + it = std::ranges::find(m_children, m_focusedChild); for (; it != m_children.end(); ++it) { const auto& child = *it; @@ -387,7 +391,7 @@ void UIWidget::focusNextChild(Fw::FocusReason reason, bool rotate) focusChild(toFocus, reason); } -void UIWidget::focusPreviousChild(Fw::FocusReason reason, bool rotate) +void UIWidget::focusPreviousChild(const Fw::FocusReason reason, const bool rotate) { if (isDestroyed()) return; @@ -395,12 +399,12 @@ void UIWidget::focusPreviousChild(Fw::FocusReason reason, bool rotate) UIWidgetPtr toFocus; if (rotate) { UIWidgetList rotatedChildren(m_children); - std::reverse(rotatedChildren.begin(), rotatedChildren.end()); + std::ranges::reverse(rotatedChildren); if (m_focusedChild) { - const auto focusedIt = std::find(rotatedChildren.begin(), rotatedChildren.end(), m_focusedChild); + const auto focusedIt = std::ranges::find(rotatedChildren, m_focusedChild); if (focusedIt != rotatedChildren.end()) { - std::rotate(rotatedChildren.begin(), focusedIt, rotatedChildren.end()); + std::ranges::rotate(rotatedChildren, focusedIt); rotatedChildren.pop_front(); } } @@ -415,7 +419,7 @@ void UIWidget::focusPreviousChild(Fw::FocusReason reason, bool rotate) } else { auto it = m_children.rbegin(); if (m_focusedChild) - it = std::find(m_children.rbegin(), m_children.rend(), m_focusedChild); + it = std::ranges::find(std::ranges::reverse_view(m_children), m_focusedChild); for (; it != m_children.rend(); ++it) { const auto& child = *it; @@ -442,7 +446,7 @@ void UIWidget::lowerChild(const UIWidgetPtr& child) return; // remove and push child again - const auto it = std::find(m_children.begin(), m_children.end(), child); + const auto it = std::ranges::find(m_children, child); if (it == m_children.end()) { g_logger.traceError("cannot find child"); return; @@ -468,7 +472,7 @@ void UIWidget::raiseChild(const UIWidgetPtr& child) return; // remove and push child again - const auto it = std::find(m_children.begin(), m_children.end(), child); + const auto it = std::ranges::find(m_children, child); if (it == m_children.end()) { g_logger.traceError("cannot find child"); return; @@ -485,7 +489,7 @@ void UIWidget::raiseChild(const UIWidgetPtr& child) updateChildrenIndexStates(); } -void UIWidget::moveChildToIndex(const UIWidgetPtr& child, int index) +void UIWidget::moveChildToIndex(const UIWidgetPtr& child, const int index) { if (isDestroyed()) return; @@ -505,7 +509,7 @@ void UIWidget::moveChildToIndex(const UIWidgetPtr& child, int index) } // remove and push child again - const auto it = std::find(m_children.begin(), m_children.end(), child); + const auto it = std::ranges::find(m_children, child); if (it == m_children.end()) { g_logger.traceError("cannot find child"); return; @@ -536,8 +540,8 @@ void UIWidget::reorderChildren(const std::vector& childrens) { } m_children.clear(); - for (size_t i = 0; i < childrens.size(); ++i) { - m_children.push_back(childrens[i]); + for (const auto& children : childrens) { + m_children.push_back(children); } updateChildrenIndexStates(); @@ -589,7 +593,7 @@ void UIWidget::unlockChild(const UIWidgetPtr& child) return; } - const auto it = std::find(m_lockedChildren.begin(), m_lockedChildren.end(), child); + const auto it = std::ranges::find(m_lockedChildren, child); if (it == m_lockedChildren.end()) return; @@ -675,7 +679,7 @@ void UIWidget::applyStyle(const OTMLNodePtr& styleNode) setProp(PropLoadingStyle, false); } -void UIWidget::addAnchor(Fw::AnchorEdge anchoredEdge, const std::string_view hookedWidgetId, Fw::AnchorEdge hookedEdge) +void UIWidget::addAnchor(const Fw::AnchorEdge anchoredEdge, const std::string_view hookedWidgetId, const Fw::AnchorEdge hookedEdge) { if (isDestroyed()) return; @@ -686,7 +690,7 @@ void UIWidget::addAnchor(Fw::AnchorEdge anchoredEdge, const std::string_view hoo g_logger.traceError(stdext::format("cannot add anchors to widget '%s': the parent doesn't use anchors layout", m_id)); } -void UIWidget::removeAnchor(Fw::AnchorEdge anchoredEdge) +void UIWidget::removeAnchor(const Fw::AnchorEdge anchoredEdge) { addAnchor(anchoredEdge, "none", Fw::AnchorNone); } @@ -782,7 +786,7 @@ void UIWidget::focus() parent->focusChild(static_self_cast(), Fw::ActiveFocusReason); } -void UIWidget::recursiveFocus(Fw::FocusReason reason) +void UIWidget::recursiveFocus(const Fw::FocusReason reason) { if (isDestroyed()) return; @@ -937,7 +941,7 @@ void UIWidget::destroyChildren() void UIWidget::removeChildren() { - UILayoutPtr layout = getLayout(); + const UILayoutPtr layout = getLayout(); if (layout) layout->disableUpdates(); @@ -953,13 +957,13 @@ void UIWidget::removeChildren() void UIWidget::hideChildren() { - for (auto& child : m_children) + for (const auto& child : m_children) child->hide(); } void UIWidget::showChildren() { - for (auto& child : m_children) + for (const auto& child : m_children) child->show(); } @@ -1109,7 +1113,7 @@ void UIWidget::setStyleFromNode(const OTMLNodePtr& styleNode) updateStyle(); } -void UIWidget::setEnabled(bool enabled) +void UIWidget::setEnabled(const bool enabled) { if (hasProp(PropEnabled) == enabled) return; @@ -1122,7 +1126,7 @@ void UIWidget::setEnabled(bool enabled) callLuaField("onEnabled", enabled); } -void UIWidget::setVisible(bool visible) +void UIWidget::setVisible(const bool visible) { if (hasProp(PropVisible) == visible) return; @@ -1148,18 +1152,18 @@ void UIWidget::setVisible(bool visible) g_ui.onWidgetDisappear(static_self_cast()); } -void UIWidget::setOn(bool on) +void UIWidget::setOn(const bool on) { setState(Fw::OnState, on); } -void UIWidget::setChecked(bool checked) +void UIWidget::setChecked(const bool checked) { if (setState(Fw::CheckedState, checked)) callLuaField("onCheckChange", checked); } -void UIWidget::setFocusable(bool focusable) +void UIWidget::setFocusable(const bool focusable) { if (isFocusable() == focusable) return; @@ -1176,28 +1180,28 @@ void UIWidget::setFocusable(bool focusable) } } -void UIWidget::setPhantom(bool phantom) +void UIWidget::setPhantom(const bool phantom) { setProp(PropPhantom, phantom); } -void UIWidget::setDraggable(bool draggable) +void UIWidget::setDraggable(const bool draggable) { setProp(PropDraggable, draggable); } -void UIWidget::setFixedSize(bool fixed) +void UIWidget::setFixedSize(const bool fixed) { setProp(PropFixedSize, fixed); updateParentLayout(); } -void UIWidget::setLastFocusReason(Fw::FocusReason reason) +void UIWidget::setLastFocusReason(const Fw::FocusReason reason) { m_lastFocusReason = reason; } -void UIWidget::setAutoFocusPolicy(Fw::AutoFocusPolicy policy) +void UIWidget::setAutoFocusPolicy(const Fw::AutoFocusPolicy policy) { m_autoFocusPolicy = policy; } @@ -1221,13 +1225,13 @@ bool UIWidget::isAnchored() bool UIWidget::isChildLocked(const UIWidgetPtr& child) { - const auto it = std::find(m_lockedChildren.begin(), m_lockedChildren.end(), child); + const auto it = std::ranges::find(m_lockedChildren, child); return it != m_lockedChildren.end(); } bool UIWidget::hasChild(const UIWidgetPtr& child) { - const auto it = std::find(m_children.begin(), m_children.end(), child); + const auto it = std::ranges::find(m_children, child); if (it != m_children.end()) return true; @@ -1319,8 +1323,7 @@ UIWidgetPtr UIWidget::getChildByPos(const Point& childPos) if (!containsPaddingPoint(childPos)) return nullptr; - for (auto it = m_children.rbegin(); it != m_children.rend(); ++it) { - const auto& child = (*it); + for (auto& child : std::ranges::reverse_view(m_children)) { if (child->isExplicitlyVisible() && child->containsPoint(childPos)) return child; } @@ -1337,10 +1340,9 @@ UIWidgetPtr UIWidget::getChildByIndex(int index) return nullptr; } -UIWidgetPtr UIWidget::getChildByState(Fw::WidgetState state) +UIWidgetPtr UIWidget::getChildByState(const Fw::WidgetState state) { - for (auto it = m_children.rbegin(); it != m_children.rend(); ++it) { - const auto& child = (*it); + for (auto& child : std::ranges::reverse_view(m_children)) { if (child->hasState(state)) return child; } @@ -1362,14 +1364,12 @@ UIWidgetPtr UIWidget::recursiveGetChildById(const std::string_view id) return nullptr; } -UIWidgetPtr UIWidget::recursiveGetChildByPos(const Point& childPos, bool wantsPhantom) +UIWidgetPtr UIWidget::recursiveGetChildByPos(const Point& childPos, const bool wantsPhantom) { if (!containsPaddingPoint(childPos)) return nullptr; - for (auto it = m_children.rbegin(); it != m_children.rend(); ++it) { - const auto& child = (*it); - + for (auto& child : std::ranges::reverse_view(m_children)) { if (child->isExplicitlyVisible() && child->containsPoint(childPos)) { if (const auto& subChild = child->recursiveGetChildByPos(childPos, wantsPhantom)) return subChild; @@ -1381,11 +1381,9 @@ UIWidgetPtr UIWidget::recursiveGetChildByPos(const Point& childPos, bool wantsPh return nullptr; } -UIWidgetPtr UIWidget::recursiveGetChildByState(Fw::WidgetState state, bool wantsPhantom) +UIWidgetPtr UIWidget::recursiveGetChildByState(const Fw::WidgetState state, const bool wantsPhantom) { - for (auto it = m_children.rbegin(); it != m_children.rend(); ++it) { - const auto& child = (*it); - + for (auto& child : std::ranges::reverse_view(m_children)) { if (child->hasState(state)) { if (const auto& subChild = child->recursiveGetChildByState(state, wantsPhantom)) return subChild; @@ -1416,9 +1414,7 @@ UIWidgetList UIWidget::recursiveGetChildrenByPos(const Point& childPos) return {}; UIWidgetList children; - for (auto it = m_children.rbegin(); it != m_children.rend(); ++it) { - const auto& child = (*it); - + for (auto& child : std::ranges::reverse_view(m_children)) { if (child->isExplicitlyVisible() && child->containsPoint(childPos)) { if (const UIWidgetList& subChildren = child->recursiveGetChildrenByPos(childPos); !subChildren.empty()) children.insert(children.end(), subChildren.begin(), subChildren.end()); @@ -1436,8 +1432,7 @@ UIWidgetList UIWidget::recursiveGetChildrenByMarginPos(const Point& childPos) if (!containsPaddingPoint(childPos)) return children; - for (auto it = m_children.rbegin(); it != m_children.rend(); ++it) { - const auto& child = (*it); + for (auto& child : std::ranges::reverse_view(m_children)) { if (child->isExplicitlyVisible() && child->containsMarginPoint(childPos)) { UIWidgetList subChildren = child->recursiveGetChildrenByMarginPos(childPos); if (!subChildren.empty()) @@ -1449,19 +1444,17 @@ UIWidgetList UIWidget::recursiveGetChildrenByMarginPos(const Point& childPos) } UIWidgetPtr UIWidget::getChildByStyleName(const std::string_view styleName) { - for (auto it = m_children.rbegin(); it != m_children.rend(); ++it) { - const auto& child = (*it); + for (auto& child : std::ranges::reverse_view(m_children)) { if (child->getStyleName() == styleName) return child; } return nullptr; } -UIWidgetList UIWidget::recursiveGetChildrenByState(Fw::WidgetState state) +UIWidgetList UIWidget::recursiveGetChildrenByState(const Fw::WidgetState state) { UIWidgetList children; - for (auto it = m_children.rbegin(); it != m_children.rend(); ++it) { - const auto& child = (*it); + for (auto& child : std::ranges::reverse_view(m_children)) { if (child->hasState(state)) { UIWidgetList subChildren = child->recursiveGetChildrenByState(state); if (!subChildren.empty()) @@ -1497,7 +1490,7 @@ UIWidgetPtr UIWidget::backwardsGetWidgetById(const std::string_view id) return widget; } -void UIWidget::setProp(FlagProp prop, bool v, bool callEvent) +void UIWidget::setProp(const FlagProp prop, const bool v, const bool callEvent) { // Note: Be aware that setProp is called many times, there will be a cost, // so only call this event if it is really necessary. @@ -1511,7 +1504,7 @@ void UIWidget::setProp(FlagProp prop, bool v, bool callEvent) if (v) m_flagsProp |= prop; else m_flagsProp &= ~prop; } -bool UIWidget::setState(Fw::WidgetState state, bool on) +bool UIWidget::setState(const Fw::WidgetState state, const bool on) { if (state == Fw::InvalidState) return false; @@ -1529,7 +1522,7 @@ bool UIWidget::setState(Fw::WidgetState state, bool on) return true; } -bool UIWidget::hasState(Fw::WidgetState state) +bool UIWidget::hasState(const Fw::WidgetState state) { if (state == Fw::InvalidState) return false; @@ -1537,7 +1530,7 @@ bool UIWidget::hasState(Fw::WidgetState state) return (m_states & state); } -void UIWidget::updateState(Fw::WidgetState state) +void UIWidget::updateState(const Fw::WidgetState state) { if (isDestroyed()) return; @@ -1750,22 +1743,22 @@ void UIWidget::onLayoutUpdate() callLuaField("onLayoutUpdate"); } -void UIWidget::onFocusChange(bool focused, Fw::FocusReason reason) +void UIWidget::onFocusChange(const bool focused, const Fw::FocusReason reason) { callLuaField("onFocusChange", focused, reason); } -void UIWidget::onChildFocusChange(const UIWidgetPtr& focusedChild, const UIWidgetPtr& unfocusedChild, Fw::FocusReason reason) +void UIWidget::onChildFocusChange(const UIWidgetPtr& focusedChild, const UIWidgetPtr& unfocusedChild, const Fw::FocusReason reason) { callLuaField("onChildFocusChange", focusedChild, unfocusedChild, reason); } -void UIWidget::onHoverChange(bool hovered) +void UIWidget::onHoverChange(const bool hovered) { callLuaField("onHoverChange", hovered); } -void UIWidget::onVisibilityChange(bool visible) +void UIWidget::onVisibilityChange(const bool visible) { if (!isAnchored()) bindRectToParent(); @@ -1777,7 +1770,7 @@ bool UIWidget::onDragEnter(const Point& mousePos) return callLuaField("onDragEnter", mousePos); } -bool UIWidget::onDragLeave(UIWidgetPtr droppedWidget, const Point& mousePos) +bool UIWidget::onDragLeave(const UIWidgetPtr droppedWidget, const Point& mousePos) { return callLuaField("onDragLeave", droppedWidget, mousePos); } @@ -1787,7 +1780,7 @@ bool UIWidget::onDragMove(const Point& mousePos, const Point& mouseMoved) return callLuaField("onDragMove", mousePos, mouseMoved); } -bool UIWidget::onDrop(UIWidgetPtr draggedWidget, const Point& mousePos) +bool UIWidget::onDrop(const UIWidgetPtr draggedWidget, const Point& mousePos) { return callLuaField("onDrop", draggedWidget, mousePos); } @@ -1797,22 +1790,22 @@ bool UIWidget::onKeyText(const std::string_view keyText) return callLuaField("onKeyText", keyText); } -bool UIWidget::onKeyDown(uint8_t keyCode, int keyboardModifiers) +bool UIWidget::onKeyDown(const uint8_t keyCode, const int keyboardModifiers) { return callLuaField("onKeyDown", keyCode, keyboardModifiers); } -bool UIWidget::onKeyPress(uint8_t keyCode, int keyboardModifiers, int autoRepeatTicks) +bool UIWidget::onKeyPress(const uint8_t keyCode, const int keyboardModifiers, const int autoRepeatTicks) { return callLuaField("onKeyPress", keyCode, keyboardModifiers, autoRepeatTicks); } -bool UIWidget::onKeyUp(uint8_t keyCode, int keyboardModifiers) +bool UIWidget::onKeyUp(const uint8_t keyCode, const int keyboardModifiers) { return callLuaField("onKeyUp", keyCode, keyboardModifiers); } -bool UIWidget::onMousePress(const Point& mousePos, Fw::MouseButton button) +bool UIWidget::onMousePress(const Point& mousePos, const Fw::MouseButton button) { if (button == Fw::MouseLeftButton) { if (m_clickTimer.running() && m_clickTimer.ticksElapsed() <= 200) { @@ -1827,7 +1820,7 @@ bool UIWidget::onMousePress(const Point& mousePos, Fw::MouseButton button) return callLuaField("onMousePress", mousePos, button); } -bool UIWidget::onMouseRelease(const Point& mousePos, Fw::MouseButton button) +bool UIWidget::onMouseRelease(const Point& mousePos, const Fw::MouseButton button) { return callLuaField("onMouseRelease", mousePos, button); } @@ -1837,7 +1830,7 @@ bool UIWidget::onMouseMove(const Point& mousePos, const Point& mouseMoved) return callLuaField("onMouseMove", mousePos, mouseMoved); } -bool UIWidget::onMouseWheel(const Point& mousePos, Fw::MouseWheelDirection direction) +bool UIWidget::onMouseWheel(const Point& mousePos, const Fw::MouseWheelDirection direction) { return callLuaField("onMouseWheel", mousePos, direction); } @@ -1880,7 +1873,7 @@ bool UIWidget::propagateOnKeyText(const std::string_view keyText) return onKeyText(keyText); } -bool UIWidget::propagateOnKeyDown(uint8_t keyCode, int keyboardModifiers) +bool UIWidget::propagateOnKeyDown(const uint8_t keyCode, const int keyboardModifiers) { // do a backup of children list, because it may change while looping it UIWidgetList children; @@ -1902,7 +1895,7 @@ bool UIWidget::propagateOnKeyDown(uint8_t keyCode, int keyboardModifiers) return onKeyDown(keyCode, keyboardModifiers); } -bool UIWidget::propagateOnKeyPress(uint8_t keyCode, int keyboardModifiers, int autoRepeatTicks) +bool UIWidget::propagateOnKeyPress(const uint8_t keyCode, const int keyboardModifiers, const int autoRepeatTicks) { // do a backup of children list, because it may change while looping it UIWidgetList children; @@ -1926,7 +1919,7 @@ bool UIWidget::propagateOnKeyPress(uint8_t keyCode, int keyboardModifiers, int a return false; } -bool UIWidget::propagateOnKeyUp(uint8_t keyCode, int keyboardModifiers) +bool UIWidget::propagateOnKeyUp(const uint8_t keyCode, const int keyboardModifiers) { // do a backup of children list, because it may change while looping it UIWidgetList children; @@ -1952,9 +1945,7 @@ bool UIWidget::propagateOnMouseEvent(const Point& mousePos, UIWidgetList& widget { bool ret = false; if (containsPaddingPoint(mousePos)) { - for (auto it = m_children.rbegin(); it != m_children.rend(); ++it) { - const auto& child = *it; - + for (auto& child : std::ranges::reverse_view(m_children)) { if (child->isExplicitlyEnabled() && child->isExplicitlyVisible() && child->containsPoint(mousePos)) { if (child->propagateOnMouseEvent(mousePos, widgetList)) { ret = true; @@ -2039,7 +2030,7 @@ void UIWidget::removeOnDestroyCallback(const std::string& id) if (hasProp(PropDestroyed)) return; - auto it = m_onDestroyCallbacks.find(id); + const auto it = m_onDestroyCallbacks.find(id); if (it != m_onDestroyCallbacks.end()) m_onDestroyCallbacks.erase(it); } \ No newline at end of file diff --git a/src/framework/ui/uiwidget.h b/src/framework/ui/uiwidget.h index f8316b3c20..742953260e 100644 --- a/src/framework/ui/uiwidget.h +++ b/src/framework/ui/uiwidget.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -31,8 +31,8 @@ #include #include -#include "framework/graphics/texture.h" #include "framework/graphics/drawpool.h" +#include "framework/graphics/texture.h" template struct EdgeGroup @@ -132,10 +132,10 @@ class UIWidget : public LuaObject void unlockChild(const UIWidgetPtr& child); void mergeStyle(const OTMLNodePtr& styleNode); void applyStyle(const OTMLNodePtr& styleNode); - void addAnchor(Fw::AnchorEdge anchoredEdge, const std::string_view hookedWidgetId, Fw::AnchorEdge hookedEdge); + void addAnchor(Fw::AnchorEdge anchoredEdge, std::string_view hookedWidgetId, Fw::AnchorEdge hookedEdge); void removeAnchor(Fw::AnchorEdge anchoredEdge); - void fill(const std::string_view hookedWidgetId); - void centerIn(const std::string_view hookedWidgetId); + void fill(std::string_view hookedWidgetId); + void centerIn(std::string_view hookedWidgetId); void breakAnchors(); void updateParentLayout(); void updateLayout(); @@ -156,11 +156,11 @@ class UIWidget : public LuaObject void hideChildren(); void showChildren(); - void setId(const std::string_view id); + void setId(std::string_view id); void setParent(const UIWidgetPtr& parent); void setLayout(const UILayoutPtr& layout); bool setRect(const Rect& rect); - void setStyle(const std::string_view styleName); + void setStyle(std::string_view styleName); void setStyleFromNode(const OTMLNodePtr& styleNode); void setEnabled(bool enabled); void setVisible(bool visible); @@ -170,13 +170,13 @@ class UIWidget : public LuaObject void setPhantom(bool phantom); void setDraggable(bool draggable); void setFixedSize(bool fixed); - void setClipping(bool clipping) { setProp(PropClipping, clipping); } + void setClipping(const bool clipping) { setProp(PropClipping, clipping); } void setLastFocusReason(Fw::FocusReason reason); void setAutoFocusPolicy(Fw::AutoFocusPolicy policy); - void setAutoRepeatDelay(int delay) { m_autoRepeatDelay = delay; } + void setAutoRepeatDelay(const int delay) { m_autoRepeatDelay = delay; } void setVirtualOffset(const Point& offset); - void setOnHtml(bool v) { setProp(PropOnHTML, v); } + void setOnHtml(const bool v) { setProp(PropOnHTML, v); } bool isOnHtml() { return hasProp(PropOnHTML); } bool isAnchored(); @@ -200,36 +200,36 @@ class UIWidget : public LuaObject UIWidgetPtr getChildAfter(const UIWidgetPtr& relativeChild); UIWidgetPtr getChildBefore(const UIWidgetPtr& relativeChild); - UIWidgetPtr getChildById(const std::string_view childId); + UIWidgetPtr getChildById(std::string_view childId); UIWidgetPtr getChildByPos(const Point& childPos); UIWidgetPtr getChildByIndex(int index); UIWidgetPtr getChildByState(Fw::WidgetState state); - UIWidgetPtr getChildByStyleName(const std::string_view styleName); - UIWidgetPtr recursiveGetChildById(const std::string_view id); + UIWidgetPtr getChildByStyleName(std::string_view styleName); + UIWidgetPtr recursiveGetChildById(std::string_view id); UIWidgetPtr recursiveGetChildByPos(const Point& childPos, bool wantsPhantom); UIWidgetPtr recursiveGetChildByState(Fw::WidgetState state, bool wantsPhantom); UIWidgetList recursiveGetChildren(); UIWidgetList recursiveGetChildrenByPos(const Point& childPos); UIWidgetList recursiveGetChildrenByMarginPos(const Point& childPos); UIWidgetList recursiveGetChildrenByState(Fw::WidgetState state); - UIWidgetList recursiveGetChildrenByStyleName(const std::string_view styleName); - UIWidgetPtr backwardsGetWidgetById(const std::string_view id); + UIWidgetList recursiveGetChildrenByStyleName(std::string_view styleName); + UIWidgetPtr backwardsGetWidgetById(std::string_view id); - void setShader(const std::string_view name); + void setShader(std::string_view name); bool hasShader() { return m_shader != nullptr; } void setProp(FlagProp prop, bool v, bool callEvent = false); - bool hasProp(FlagProp prop) { return (m_flagsProp & prop); } + bool hasProp(const FlagProp prop) { return (m_flagsProp & prop); } void disableUpdateTemporarily(); void addOnDestroyCallback(const std::string& id, const std::function&& callback); void removeOnDestroyCallback(const std::string&); - void setBackgroundDrawOrder(uint8_t order) { m_backgroundDrawConductor.order = std::min(order, DrawOrder::LAST - 1); } - void setImageDrawOrder(uint8_t order) { m_imageDrawConductor.order = std::min(order, DrawOrder::LAST - 1); } - void setIconDrawOrder(uint8_t order) { m_iconDrawConductor.order = std::min(order, DrawOrder::LAST - 1); } - void setTextDrawOrder(uint8_t order) { m_textDrawConductor.order = std::min(order, DrawOrder::LAST - 1); } - void setBorderDrawOrder(uint8_t order) { m_borderDrawConductor.order = std::min(order, DrawOrder::LAST - 1); } + void setBackgroundDrawOrder(const uint8_t order) { m_backgroundDrawConductor.order = std::min(order, LAST - 1); } + void setImageDrawOrder(const uint8_t order) { m_imageDrawConductor.order = std::min(order, LAST - 1); } + void setIconDrawOrder(const uint8_t order) { m_iconDrawConductor.order = std::min(order, LAST - 1); } + void setTextDrawOrder(const uint8_t order) { m_textDrawConductor.order = std::min(order, LAST - 1); } + void setBorderDrawOrder(const uint8_t order) { m_borderDrawConductor.order = std::min(order, LAST - 1); } private: uint32_t m_flagsProp{ 0 }; @@ -258,7 +258,7 @@ class UIWidget : public LuaObject // event processing protected: - virtual void onStyleApply(const std::string_view styleName, const OTMLNodePtr& styleNode); + virtual void onStyleApply(std::string_view styleName, const OTMLNodePtr& styleNode); virtual void onGeometryChange(const Rect& oldRect, const Rect& newRect); virtual void onLayoutUpdate(); virtual void onFocusChange(bool focused, Fw::FocusReason reason); @@ -269,7 +269,7 @@ class UIWidget : public LuaObject virtual bool onDragLeave(UIWidgetPtr droppedWidget, const Point& mousePos); virtual bool onDragMove(const Point& mousePos, const Point& mouseMoved); virtual bool onDrop(UIWidgetPtr draggedWidget, const Point& mousePos); - virtual bool onKeyText(const std::string_view keyText); + virtual bool onKeyText(std::string_view keyText); virtual bool onKeyDown(uint8_t keyCode, int keyboardModifiers); virtual bool onKeyPress(uint8_t keyCode, int keyboardModifiers, int autoRepeatTicks); virtual bool onKeyUp(uint8_t keyCode, int keyboardModifiers); @@ -282,7 +282,7 @@ class UIWidget : public LuaObject friend class UILayout; - bool propagateOnKeyText(const std::string_view keyText); + bool propagateOnKeyText(std::string_view keyText); bool propagateOnKeyDown(uint8_t keyCode, int keyboardModifiers); bool propagateOnKeyPress(uint8_t keyCode, int keyboardModifiers, int autoRepeatTicks); bool propagateOnKeyUp(uint8_t keyCode, int keyboardModifiers); @@ -291,9 +291,9 @@ class UIWidget : public LuaObject // function shortcuts public: - void resize(int width, int height) { setRect(Rect(getPosition(), Size(width, height))); } + void resize(const int width, const int height) { setRect(Rect(getPosition(), Size(width, height))); } void move(int x, int y); - void rotate(float degrees) { setRotation(degrees); } + void rotate(const float degrees) { setRotation(degrees); } void hide() { setVisible(false); } void show() { setVisible(true); } void disable() { setEnabled(false); } @@ -303,7 +303,7 @@ class UIWidget : public LuaObject bool isEnabled() { return !hasState(Fw::DisabledState); } bool isDisabled() { return hasState(Fw::DisabledState); } bool isFocused() { return hasState(Fw::FocusState); } - bool isHovered(bool orChild = false) { return hasState(Fw::HoverState) || (orChild && isChildHovered()); } + bool isHovered(const bool orChild = false) { return hasState(Fw::HoverState) || (orChild && isChildHovered()); } bool isChildHovered() { return getHoveredChild() != nullptr; } bool isPressed() { return hasState(Fw::PressedState); } bool isFirst() { return hasState(Fw::FirstState); } @@ -374,9 +374,9 @@ class UIWidget : public LuaObject Rect m_iconClipRect; Fw::AlignmentFlag m_iconAlign{ Fw::AlignNone }; EdgeGroup m_borderColor; - EdgeGroup m_borderWidth; - EdgeGroup m_margin; - EdgeGroup m_padding; + EdgeGroup<> m_borderWidth; + EdgeGroup<> m_margin; + EdgeGroup<> m_padding; float m_opacity{ 1.f }; float m_rotation{ 0.f }; uint16_t m_autoRepeatDelay{ 500 }; @@ -385,64 +385,64 @@ class UIWidget : public LuaObject DrawConductor m_textDrawConductor; public: - void setX(int x) { move(x, getY()); } - void setY(int y) { move(getX(), y); } - void setWidth(int width) { resize(width, getHeight()); } - void setHeight(int height) { resize(getWidth(), height); } + void setX(const int x) { move(x, getY()); } + void setY(const int y) { move(getX(), y); } + void setWidth(const int width) { resize(width, getHeight()); } + void setHeight(const int height) { resize(getWidth(), height); } void setSize(const Size& size) { resize(size.width(), size.height()); } - void setMinWidth(int minWidth) { m_minSize.setWidth(minWidth); setRect(m_rect); } - void setMaxWidth(int maxWidth) { m_maxSize.setWidth(maxWidth); setRect(m_rect); } - void setMinHeight(int minHeight) { m_minSize.setHeight(minHeight); setRect(m_rect); } - void setMaxHeight(int maxHeight) { m_maxSize.setHeight(maxHeight); setRect(m_rect); } + void setMinWidth(const int minWidth) { m_minSize.setWidth(minWidth); setRect(m_rect); } + void setMaxWidth(const int maxWidth) { m_maxSize.setWidth(maxWidth); setRect(m_rect); } + void setMinHeight(const int minHeight) { m_minSize.setHeight(minHeight); setRect(m_rect); } + void setMaxHeight(const int maxHeight) { m_maxSize.setHeight(maxHeight); setRect(m_rect); } void setMinSize(const Size& minSize) { m_minSize = minSize; setRect(m_rect); } void setMaxSize(const Size& maxSize) { m_maxSize = maxSize; setRect(m_rect); } void setPosition(const Point& pos) { move(pos.x, pos.y); } void setColor(const Color& color) { m_color = color; repaint(); } void setBackgroundColor(const Color& color) { m_backgroundColor = color; repaint(); } - void setBackgroundOffsetX(int x) { m_backgroundRect.setX(x); repaint(); } - void setBackgroundOffsetY(int y) { m_backgroundRect.setX(y); repaint(); } + void setBackgroundOffsetX(const int x) { m_backgroundRect.setX(x); repaint(); } + void setBackgroundOffsetY(const int y) { m_backgroundRect.setX(y); repaint(); } void setBackgroundOffset(const Point& pos) { m_backgroundRect.move(pos); repaint(); } - void setBackgroundWidth(int width) { m_backgroundRect.setWidth(width); repaint(); } - void setBackgroundHeight(int height) { m_backgroundRect.setHeight(height); repaint(); } + void setBackgroundWidth(const int width) { m_backgroundRect.setWidth(width); repaint(); } + void setBackgroundHeight(const int height) { m_backgroundRect.setHeight(height); repaint(); } void setBackgroundSize(const Size& size) { m_backgroundRect.resize(size); repaint(); } void setBackgroundRect(const Rect& rect) { m_backgroundRect = rect; repaint(); } void setIcon(const std::string& iconFile); void setIconColor(const Color& color) { m_iconColor = color; repaint(); } - void setIconOffsetX(int x) { m_iconOffset.x = x; repaint(); } - void setIconOffsetY(int y) { m_iconOffset.y = y; repaint(); } + void setIconOffsetX(const int x) { m_iconOffset.x = x; repaint(); } + void setIconOffsetY(const int y) { m_iconOffset.y = y; repaint(); } void setIconOffset(const Point& pos) { m_iconOffset = pos; repaint(); } - void setIconWidth(int width) { m_iconRect.setWidth(width); repaint(); } - void setIconHeight(int height) { m_iconRect.setHeight(height); repaint(); } + void setIconWidth(const int width) { m_iconRect.setWidth(width); repaint(); } + void setIconHeight(const int height) { m_iconRect.setHeight(height); repaint(); } void setIconSize(const Size& size) { m_iconRect.resize(size); repaint(); } void setIconRect(const Rect& rect) { m_iconRect = rect; repaint(); } void setIconClip(const Rect& rect) { m_iconClipRect = rect; repaint(); } - void setIconAlign(Fw::AlignmentFlag align) { m_iconAlign = align; repaint(); } - void setBorderWidth(int width) { m_borderWidth.set(width); updateLayout(); } - void setBorderWidthTop(int width) { m_borderWidth.top = width; repaint(); } - void setBorderWidthRight(int width) { m_borderWidth.right = width; repaint(); } - void setBorderWidthBottom(int width) { m_borderWidth.bottom = width; repaint(); } - void setBorderWidthLeft(int width) { m_borderWidth.left = width; repaint(); } + void setIconAlign(const Fw::AlignmentFlag align) { m_iconAlign = align; repaint(); } + void setBorderWidth(const int width) { m_borderWidth.set(width); updateLayout(); } + void setBorderWidthTop(const int width) { m_borderWidth.top = width; repaint(); } + void setBorderWidthRight(const int width) { m_borderWidth.right = width; repaint(); } + void setBorderWidthBottom(const int width) { m_borderWidth.bottom = width; repaint(); } + void setBorderWidthLeft(const int width) { m_borderWidth.left = width; repaint(); } void setBorderColor(const Color& color) { m_borderColor.set(color); updateLayout(); } void setBorderColorTop(const Color& color) { m_borderColor.top = color; repaint(); } void setBorderColorRight(const Color& color) { m_borderColor.right = color; repaint(); } void setBorderColorBottom(const Color& color) { m_borderColor.bottom = color; repaint(); } void setBorderColorLeft(const Color& color) { m_borderColor.left = color; repaint(); } - void setMargin(int margin) { m_margin.set(margin); updateParentLayout(); } - void setMarginHorizontal(int margin) { m_margin.right = m_margin.left = margin; updateParentLayout(); } - void setMarginVertical(int margin) { m_margin.bottom = m_margin.top = margin; updateParentLayout(); } - void setMarginTop(int margin) { m_margin.top = margin; updateParentLayout(); } - void setMarginRight(int margin) { m_margin.right = margin; updateParentLayout(); } - void setMarginBottom(int margin) { m_margin.bottom = margin; updateParentLayout(); } - void setMarginLeft(int margin) { m_margin.left = margin; updateParentLayout(); } - void setPadding(int padding) { m_padding.top = m_padding.right = m_padding.bottom = m_padding.left = padding; updateLayout(); } - void setPaddingHorizontal(int padding) { m_padding.right = m_padding.left = padding; updateLayout(); } - void setPaddingVertical(int padding) { m_padding.bottom = m_padding.top = padding; updateLayout(); } - void setPaddingTop(int padding) { m_padding.top = padding; updateLayout(); } - void setPaddingRight(int padding) { m_padding.right = padding; updateLayout(); } - void setPaddingBottom(int padding) { m_padding.bottom = padding; updateLayout(); } - void setPaddingLeft(int padding) { m_padding.left = padding; updateLayout(); } - void setOpacity(float opacity) { m_opacity = std::clamp(opacity, 0.0f, 1.0f); repaint(); } - void setRotation(float degrees) { m_rotation = degrees; repaint(); } + void setMargin(const int margin) { m_margin.set(margin); updateParentLayout(); } + void setMarginHorizontal(const int margin) { m_margin.right = m_margin.left = margin; updateParentLayout(); } + void setMarginVertical(const int margin) { m_margin.bottom = m_margin.top = margin; updateParentLayout(); } + void setMarginTop(const int margin) { m_margin.top = margin; updateParentLayout(); } + void setMarginRight(const int margin) { m_margin.right = margin; updateParentLayout(); } + void setMarginBottom(const int margin) { m_margin.bottom = margin; updateParentLayout(); } + void setMarginLeft(const int margin) { m_margin.left = margin; updateParentLayout(); } + void setPadding(const int padding) { m_padding.top = m_padding.right = m_padding.bottom = m_padding.left = padding; updateLayout(); } + void setPaddingHorizontal(const int padding) { m_padding.right = m_padding.left = padding; updateLayout(); } + void setPaddingVertical(const int padding) { m_padding.bottom = m_padding.top = padding; updateLayout(); } + void setPaddingTop(const int padding) { m_padding.top = padding; updateLayout(); } + void setPaddingRight(const int padding) { m_padding.right = padding; updateLayout(); } + void setPaddingBottom(const int padding) { m_padding.bottom = padding; updateLayout(); } + void setPaddingLeft(const int padding) { m_padding.left = padding; updateLayout(); } + void setOpacity(const float opacity) { m_opacity = std::clamp(opacity, 0.0f, 1.0f); repaint(); } + void setRotation(const float degrees) { m_rotation = degrees; repaint(); } int getX() { return m_rect.x(); } int getY() { return m_rect.y(); } @@ -493,7 +493,7 @@ class UIWidget : public LuaObject int getPaddingRight() { return m_padding.right; } int getPaddingBottom() { return m_padding.bottom; } int getPaddingLeft() { return m_padding.left; } - Size getPaddingSize() { return Size(m_padding.left + m_padding.right, m_padding.top + m_padding.bottom); } + Size getPaddingSize() { return { m_padding.left + m_padding.right, m_padding.top + m_padding.bottom }; } float getOpacity() { return m_opacity; } float getRotation() { return m_rotation; } @@ -521,29 +521,29 @@ class UIWidget : public LuaObject Timer m_imageAnimatorTimer; uint32_t m_currentFrame{ 0 }; - EdgeGroup m_imageBorder; + EdgeGroup<> m_imageBorder; public: - void setImageSource(const std::string_view source, bool base64); + void setImageSource(std::string_view source, bool base64); void setImageClip(const Rect& clipRect) { m_imageClipRect = clipRect; updateImageCache(); } - void setImageOffsetX(int x) { m_imageRect.setX(x); updateImageCache(); } - void setImageOffsetY(int y) { m_imageRect.setY(y); updateImageCache(); } + void setImageOffsetX(const int x) { m_imageRect.setX(x); updateImageCache(); } + void setImageOffsetY(const int y) { m_imageRect.setY(y); updateImageCache(); } void setImageOffset(const Point& pos) { m_imageRect.move(pos); updateImageCache(); } - void setImageWidth(int width) { m_imageRect.setWidth(width); updateImageCache(); } - void setImageHeight(int height) { m_imageRect.setHeight(height); updateImageCache(); } + void setImageWidth(const int width) { m_imageRect.setWidth(width); updateImageCache(); } + void setImageHeight(const int height) { m_imageRect.setHeight(height); updateImageCache(); } void setImageSize(const Size& size) { m_imageRect.resize(size); updateImageCache(); } void setImageRect(const Rect& rect) { m_imageRect = rect; updateImageCache(); } void setImageColor(const Color& color) { m_imageColor = color; updateImageCache(); } - void setImageFixedRatio(bool fixedRatio) { setProp(PropImageFixedRatio, fixedRatio); updateImageCache(); } - void setImageRepeated(bool repeated) { setProp(PropImageRepeated, repeated); updateImageCache(); } - void setImageSmooth(bool smooth) { setProp(PropImageSmooth, smooth); } - void setImageAutoResize(bool autoResize) { setProp(PropImageAutoResize, autoResize); } - void setImageIndividualAnimation(bool v) { setProp(PropImageIndividualAnimation, v); } - void setImageBorderTop(int border) { m_imageBorder.top = border; configureBorderImage(); } - void setImageBorderRight(int border) { m_imageBorder.right = border; configureBorderImage(); } - void setImageBorderBottom(int border) { m_imageBorder.bottom = border; configureBorderImage(); } - void setImageBorderLeft(int border) { m_imageBorder.left = border; configureBorderImage(); } - void setImageBorder(int border) { m_imageBorder.set(border); configureBorderImage(); } + void setImageFixedRatio(const bool fixedRatio) { setProp(PropImageFixedRatio, fixedRatio); updateImageCache(); } + void setImageRepeated(const bool repeated) { setProp(PropImageRepeated, repeated); updateImageCache(); } + void setImageSmooth(const bool smooth) { setProp(PropImageSmooth, smooth); } + void setImageAutoResize(const bool autoResize) { setProp(PropImageAutoResize, autoResize); } + void setImageIndividualAnimation(const bool v) { setProp(PropImageIndividualAnimation, v); } + void setImageBorderTop(const int border) { m_imageBorder.top = border; configureBorderImage(); } + void setImageBorderRight(const int border) { m_imageBorder.right = border; configureBorderImage(); } + void setImageBorderBottom(const int border) { m_imageBorder.bottom = border; configureBorderImage(); } + void setImageBorderLeft(const int border) { m_imageBorder.left = border; configureBorderImage(); } + void setImageBorder(const int border) { m_imageBorder.set(border); configureBorderImage(); } std::string getImageSource() { return m_imageSource; } Rect getImageClip() { return m_imageClipRect; } @@ -579,8 +579,8 @@ class UIWidget : public LuaObject virtual void updateText(); void drawText(const Rect& screenCoords); - virtual void onTextChange(const std::string_view text, const std::string_view oldText); - virtual void onFontChange(const std::string_view font); + virtual void onTextChange(std::string_view text, std::string_view oldText); + virtual void onFontChange(std::string_view font); std::string m_text; std::string m_drawText; @@ -600,17 +600,17 @@ class UIWidget : public LuaObject void resizeToText(); void clearText() { setText(""); } - void setText(const std::string_view text, bool dontFireLuaCall = false); - void setColoredText(const std::string_view coloredText, bool dontFireLuaCall = false); - void setTextAlign(Fw::AlignmentFlag align) { m_textAlign = align; updateText(); } + void setText(std::string_view text, bool dontFireLuaCall = false); + void setColoredText(std::string_view coloredText, bool dontFireLuaCall = false); + void setTextAlign(const Fw::AlignmentFlag align) { m_textAlign = align; updateText(); } void setTextOffset(const Point& offset) { m_textOffset = offset; updateText(); } - void setTextWrap(bool textWrap) { setProp(PropTextWrap, textWrap); updateText(); } - void setTextAutoResize(bool textAutoResize) { setProp(PropTextHorizontalAutoResize, textAutoResize); setProp(PropTextVerticalAutoResize, textAutoResize); updateText(); } - void setTextHorizontalAutoResize(bool textAutoResize) { setProp(PropTextHorizontalAutoResize, textAutoResize); updateText(); } - void setTextVerticalAutoResize(bool textAutoResize) { setProp(PropTextVerticalAutoResize, textAutoResize); updateText(); } - void setTextOnlyUpperCase(bool textOnlyUpperCase) { setProp(PropTextOnlyUpperCase, textOnlyUpperCase); setText(m_text); } - void setFont(const std::string_view fontName); - void setFontScale(float scale) { m_fontScale = scale; m_textCachedScreenCoords = {}; updateText(); } + void setTextWrap(const bool textWrap) { setProp(PropTextWrap, textWrap); updateText(); } + void setTextAutoResize(const bool textAutoResize) { setProp(PropTextHorizontalAutoResize, textAutoResize); setProp(PropTextVerticalAutoResize, textAutoResize); updateText(); } + void setTextHorizontalAutoResize(const bool textAutoResize) { setProp(PropTextHorizontalAutoResize, textAutoResize); updateText(); } + void setTextVerticalAutoResize(const bool textAutoResize) { setProp(PropTextVerticalAutoResize, textAutoResize); updateText(); } + void setTextOnlyUpperCase(const bool textOnlyUpperCase) { setProp(PropTextOnlyUpperCase, textOnlyUpperCase); setText(m_text); } + void setFont(std::string_view fontName); + void setFontScale(const float scale) { m_fontScale = scale; m_textCachedScreenCoords = {}; updateText(); } std::string getText() { return m_text; } std::string getDrawText() { return m_drawText; } diff --git a/src/framework/ui/uiwidgetbasestyle.cpp b/src/framework/ui/uiwidgetbasestyle.cpp index 61fcdd067b..9f5c7ac813 100644 --- a/src/framework/ui/uiwidgetbasestyle.cpp +++ b/src/framework/ui/uiwidgetbasestyle.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -28,7 +28,6 @@ #include "uiwidget.h" #include -#include #include #include @@ -412,7 +411,7 @@ void UIWidget::drawIcon(const Rect& screenCoords) const void UIWidget::setIcon(const std::string& iconFile) { - g_dispatcher.addEvent([&, iconFile = iconFile]() { + g_dispatcher.addEvent([&, iconFile = iconFile] { m_icon = iconFile.empty() ? nullptr : g_textures.getTexture(iconFile); if (m_icon && !m_iconClipRect.isValid()) { m_iconClipRect = Rect(0, 0, m_icon->getSize()); diff --git a/src/framework/ui/uiwidgetimage.cpp b/src/framework/ui/uiwidgetimage.cpp index 1444d76e42..c96ebc9779 100644 --- a/src/framework/ui/uiwidgetimage.cpp +++ b/src/framework/ui/uiwidgetimage.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -20,14 +20,11 @@ * THE SOFTWARE. */ -#include -#include +#include "framework/graphics/drawpoolmanager.h" +#include "uiwidget.h" #include -#include #include #include -#include "uiwidget.h" -#include "framework/graphics/drawpoolmanager.h" #include void UIWidget::initImage() {} @@ -37,8 +34,8 @@ void UIWidget::parseImageStyle(const OTMLNodePtr& styleNode) for (const auto& node : styleNode->children()) { if (node->tag() == "image-source") { auto split = stdext::split(node->value(), ":"); - if (split.size() == 0) split.push_back("none"); - bool base64 = split.size() > 1 && split[0] == "base64"; + if (split.size() == 0) split.emplace_back("none"); + const bool base64 = split.size() > 1 && split[0] == "base64"; auto& value = split.size() > 1 ? split[1] : split[0]; if (value == "" || value == "none") { @@ -188,7 +185,7 @@ void UIWidget::drawImage(const Rect& screenCoords) } } -void UIWidget::setImageSource(const std::string_view source, bool base64) +void UIWidget::setImageSource(const std::string_view source, const bool base64) { updateImageCache(); diff --git a/src/framework/ui/uiwidgettext.cpp b/src/framework/ui/uiwidgettext.cpp index d5695441a4..e80fd325dc 100644 --- a/src/framework/ui/uiwidgettext.cpp +++ b/src/framework/ui/uiwidgettext.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -20,12 +20,11 @@ * THE SOFTWARE. */ -#include +#include "uitranslator.h" +#include "uiwidget.h" #include #include #include -#include "uitranslator.h" -#include "uiwidget.h" void UIWidget::initText() { @@ -139,7 +138,7 @@ void UIWidget::onTextChange(const std::string_view text, const std::string_view void UIWidget::onFontChange(const std::string_view font) { callLuaField("onFontChange", font); } -void UIWidget::setText(const std::string_view text, bool dontFireLuaCall) +void UIWidget::setText(const std::string_view text, const bool dontFireLuaCall) { std::string _text{ text.data() }; if (hasProp(PropTextOnlyUpperCase)) @@ -168,7 +167,7 @@ void UIWidget::setColoredText(const std::string_view coloredText, bool dontFireL m_colorCoordsBuffer.clear(); m_coordsBuffer->clear(); - std::regex exp("\\{([^\\}]+),[ ]*([^\\}]+)\\}"); + std::regex exp(R"(\{([^\}]+),[ ]*([^\}]+)\})"); std::string _text{ coloredText.data() }; @@ -178,17 +177,17 @@ void UIWidget::setColoredText(const std::string_view coloredText, bool dontFireL while (std::regex_search(_text, res, exp)) { std::string prefix = res.prefix().str(); if (prefix.size() > 0) { - m_textColors.push_back(std::make_pair(text.size(), baseColor)); + m_textColors.emplace_back(text.size(), baseColor); text = text + prefix; } auto color = Color(res[2].str()); - m_textColors.push_back(std::make_pair(text.size(), color)); + m_textColors.emplace_back(text.size(), color); text = text + res[1].str(); _text = res.suffix(); } if (_text.size() > 0) { - m_textColors.push_back(std::make_pair(text.size(), baseColor)); + m_textColors.emplace_back(text.size(), baseColor); text = text + _text; } diff --git a/src/framework/util/BS_thread_pool.hpp b/src/framework/util/BS_thread_pool.hpp index 984fc3664a..626718f018 100644 --- a/src/framework/util/BS_thread_pool.hpp +++ b/src/framework/util/BS_thread_pool.hpp @@ -101,9 +101,9 @@ namespace this_thread { /** * @brief A helper class to store information about the index of the current thread. */ - class [[nodiscard]] thread_info_index + class thread_info_index { - friend class BS::thread_pool; + friend class thread_pool; public: /** @@ -111,7 +111,7 @@ namespace this_thread { * * @return An `std::optional` object, optionally containing a thread index. Unless you are 100% sure this thread is in a pool, first use `std::optional::has_value()` to check if it contains a value, and if so, use `std::optional::value()` to obtain that value. */ - [[nodiscard]] optional_index operator()() const + optional_index operator()() const { return index; } @@ -126,9 +126,9 @@ namespace this_thread { /** * @brief A helper class to store information about the thread pool that owns the current thread. */ - class [[nodiscard]] thread_info_pool + class thread_info_pool { - friend class BS::thread_pool; + friend class thread_pool; public: /** @@ -136,7 +136,7 @@ namespace this_thread { * * @return An `std::optional` object, optionally containing a pointer to a thread pool. Unless you are 100% sure this thread is in a pool, first use `std::optional::has_value()` to check if it contains a value, and if so, use `std::optional::value()` to obtain that value. */ - [[nodiscard]] optional_pool operator()() const + optional_pool operator()() const { return pool; } @@ -165,7 +165,7 @@ namespace this_thread { * @tparam T The return type of the futures. */ template -class [[nodiscard]] multi_future : public std::vector> +class multi_future : public std::vector> { public: // Inherit all constructors from the base class `std::vector`. @@ -184,7 +184,7 @@ class [[nodiscard]] multi_future : public std::vector> * * @return If the futures return `void`, this function returns `void` as well. Otherwise, it returns a vector containing the results. */ - [[nodiscard]] std::conditional_t, void, std::vector> get() + std::conditional_t, void, std::vector> get() { if constexpr (std::is_void_v) { @@ -207,7 +207,7 @@ class [[nodiscard]] multi_future : public std::vector> * * @return The number of ready futures. */ - [[nodiscard]] size_t ready_count() const + size_t ready_count() const { size_t count = 0; for (const std::future& future : *this) @@ -223,7 +223,7 @@ class [[nodiscard]] multi_future : public std::vector> * * @return `true` if all futures are valid, `false` if at least one of the futures is not valid. */ - [[nodiscard]] bool valid() const + bool valid() const { bool is_valid = true; for (const std::future& future : *this) @@ -285,7 +285,7 @@ class [[nodiscard]] multi_future : public std::vector> /** * @brief A fast, lightweight, and easy-to-use C++17 thread pool class. */ -class [[nodiscard]] thread_pool +class thread_pool { public: // ============================ @@ -347,7 +347,7 @@ class [[nodiscard]] thread_pool * * @return The native thread handles. */ - [[nodiscard]] std::vector get_native_handles() const + std::vector get_native_handles() const { std::vector native_handles(thread_count); for (concurrency_t i = 0; i < thread_count; ++i) @@ -363,7 +363,7 @@ class [[nodiscard]] thread_pool * * @return The number of queued tasks. */ - [[nodiscard]] size_t get_tasks_queued() const + size_t get_tasks_queued() const { const std::scoped_lock tasks_lock(tasks_mutex); return tasks.size(); @@ -374,7 +374,7 @@ class [[nodiscard]] thread_pool * * @return The number of running tasks. */ - [[nodiscard]] size_t get_tasks_running() const + size_t get_tasks_running() const { const std::scoped_lock tasks_lock(tasks_mutex); return tasks_running; @@ -385,7 +385,7 @@ class [[nodiscard]] thread_pool * * @return The total number of tasks. */ - [[nodiscard]] size_t get_tasks_total() const + size_t get_tasks_total() const { const std::scoped_lock tasks_lock(tasks_mutex); return tasks_running + tasks.size(); @@ -396,7 +396,7 @@ class [[nodiscard]] thread_pool * * @return The number of threads. */ - [[nodiscard]] concurrency_t get_thread_count() const + concurrency_t get_thread_count() const { return thread_count; } @@ -406,7 +406,7 @@ class [[nodiscard]] thread_pool * * @return The unique thread identifiers. */ - [[nodiscard]] std::vector get_thread_ids() const + std::vector get_thread_ids() const { std::vector thread_ids(thread_count); for (concurrency_t i = 0; i < thread_count; ++i) @@ -422,7 +422,7 @@ class [[nodiscard]] thread_pool * * @return `true` if the pool is paused, `false` if it is not paused. */ - [[nodiscard]] bool is_paused() const + bool is_paused() const { const std::scoped_lock tasks_lock(tasks_mutex); return paused; @@ -602,7 +602,7 @@ class [[nodiscard]] thread_pool * @return A future to be used later to wait for the function to finish executing and/or obtain its returned value if it has one. */ template >> - [[nodiscard]] std::future submit_task(F&& task BS_THREAD_POOL_PRIORITY_INPUT) + std::future submit_task(F&& task BS_THREAD_POOL_PRIORITY_INPUT) { const std::shared_ptr> task_promise = std::make_shared>(); detach_task( @@ -652,7 +652,7 @@ class [[nodiscard]] thread_pool * @return A `multi_future` that can be used to wait for all the blocks to finish. If the block function returns a value, the `multi_future` can also be used to obtain the values returned by each block. */ template , T, T>> - [[nodiscard]] multi_future submit_blocks(const T first_index, const T index_after_last, F&& block, const size_t num_blocks = 0 BS_THREAD_POOL_PRIORITY_INPUT) + multi_future submit_blocks(const T first_index, const T index_after_last, F&& block, const size_t num_blocks = 0 BS_THREAD_POOL_PRIORITY_INPUT) { if (index_after_last > first_index) { @@ -683,7 +683,7 @@ class [[nodiscard]] thread_pool * @return A `multi_future` that can be used to wait for all the blocks to finish. */ template - [[nodiscard]] multi_future submit_loop(const T first_index, const T index_after_last, F&& loop, const size_t num_blocks = 0 BS_THREAD_POOL_PRIORITY_INPUT) + multi_future submit_loop(const T first_index, const T index_after_last, F&& loop, const size_t num_blocks = 0 BS_THREAD_POOL_PRIORITY_INPUT) { if (index_after_last > first_index) { @@ -715,7 +715,7 @@ class [[nodiscard]] thread_pool * @return A `multi_future` that can be used to wait for all the tasks to finish. If the sequence function returns a value, the `multi_future` can also be used to obtain the values returned by each task. */ template , T>> - [[nodiscard]] multi_future submit_sequence(const T first_index, const T index_after_last, F&& sequence BS_THREAD_POOL_PRIORITY_INPUT) + multi_future submit_sequence(const T first_index, const T index_after_last, F&& sequence BS_THREAD_POOL_PRIORITY_INPUT) { if (index_after_last > first_index) { @@ -889,7 +889,7 @@ class [[nodiscard]] thread_pool * @param num_threads The parameter passed to the constructor or `reset()`. If the parameter is a positive number, then the pool will be created with this number of threads. If the parameter is non-positive, or a parameter was not supplied (in which case it will have the default value of 0), then the pool will be created with the total number of hardware threads available, as obtained from `std::thread::hardware_concurrency()`. If the latter returns zero for some reason, then the pool will be created with just one thread. * @return The number of threads to use for constructing the pool. */ - [[nodiscard]] static concurrency_t determine_thread_count(const concurrency_t num_threads) + static concurrency_t determine_thread_count(const concurrency_t num_threads) { if (num_threads > 0) return num_threads; @@ -952,7 +952,7 @@ class [[nodiscard]] thread_pool * @tparam T The type of the indices. Should be a signed or unsigned integer. */ template - class [[nodiscard]] blocks + class blocks { public: /** @@ -966,7 +966,7 @@ class [[nodiscard]] thread_pool { if (index_after_last > first_index) { - const size_t total_size = static_cast(index_after_last - first_index); + const auto total_size = static_cast(index_after_last - first_index); if (num_blocks > total_size) num_blocks = total_size; block_size = total_size / num_blocks; @@ -989,7 +989,7 @@ class [[nodiscard]] thread_pool * @param block The block number. * @return The first index. */ - [[nodiscard]] T start(const size_t block) const + T start(const size_t block) const { return first_index + static_cast(block * block_size) + static_cast(block < remainder ? block : remainder); } @@ -1000,7 +1000,7 @@ class [[nodiscard]] thread_pool * @param block The block number. * @return The index after the last index. */ - [[nodiscard]] T end(const size_t block) const + T end(const size_t block) const { return (block == num_blocks - 1) ? index_after_last : start(block + 1); } @@ -1010,7 +1010,7 @@ class [[nodiscard]] thread_pool * * @return The number of blocks. */ - [[nodiscard]] size_t get_num_blocks() const + size_t get_num_blocks() const { return num_blocks; } @@ -1046,7 +1046,7 @@ class [[nodiscard]] thread_pool /** * @brief A helper class to store a task with an assigned priority. */ - class [[nodiscard]] pr_task + class pr_task { friend class thread_pool; @@ -1074,7 +1074,7 @@ class [[nodiscard]] thread_pool * @param rhs The second task. * @return `true` if the first task has a lower priority than the second task, `false` otherwise. */ - [[nodiscard]] friend bool operator<(const pr_task& lhs, const pr_task& rhs) + friend bool operator<(const pr_task& lhs, const pr_task& rhs) { return lhs.priority < rhs.priority; } diff --git a/src/framework/util/color.cpp b/src/framework/util/color.cpp index d16ba78278..bf1913f377 100644 --- a/src/framework/util/color.cpp +++ b/src/framework/util/color.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -24,6 +24,8 @@ #include #include +#include "framework/stdext/string.h" + // NOTE: AABBGGRR order const Color Color::alpha = 0x00000000U; const Color Color::white = 0xffffffffU; diff --git a/src/framework/util/color.h b/src/framework/util/color.h index 97e39f1ef9..ec945aa271 100644 --- a/src/framework/util/color.h +++ b/src/framework/util/color.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -23,14 +23,13 @@ #pragma once #include "../stdext/cast.h" -#include "../stdext/string.h" #include "../stdext/types.h" class Color { public: - Color() { m_hash = Color::white.hash(); }; - Color(const std::string_view coltext); + Color() { m_hash = white.hash(); }; + Color(std::string_view coltext); Color(const uint32_t rgba) { setRGBA(rgba); } Color(const int r, const int g, const int b, const int a = 0xFF) : m_r(r / 255.f), m_g(g / 255.f), m_b(b / 255.f), m_a(a / 255.f) { update(); } Color(const float r, const float g, const float b, const float a = 1.0f) : m_r(r), m_g(g), m_b(b), m_a(a) { update(); } @@ -49,7 +48,7 @@ class Color } Color(const Color& color) = default; - Color(const Color& color, float a) { + Color(const Color& color, const float a) { m_r = color.m_r; m_g = color.m_g; m_b = color.m_b; @@ -89,8 +88,8 @@ class Color Color operator*(const float v) const { return Color(m_r * v, m_g * v, m_b * v, m_a * v); } Color operator/(const float v) const { return Color(m_r / v, m_g / v, m_b / v, m_a / v); } - Color& operator=(uint32_t rgba) { setRGBA(rgba); return *this; } - bool operator==(uint32_t rgba) const { return this->rgba() == rgba; } + Color& operator=(const uint32_t rgba) { setRGBA(rgba); return *this; } + bool operator==(const uint32_t rgba) const { return this->rgba() == rgba; } Color& operator=(const Color& other) = default; bool operator==(const Color& other) const { return other.hash() == hash(); } @@ -117,7 +116,7 @@ class Color static Color from8bit(const int color, const float brightness = 1.0f) { if (color >= 216 || color <= 0) - return Color::alpha; + return alpha; const int r = static_cast((color / 36 % 6 * 51) * brightness); const int g = static_cast((color / 6 % 6 * 51) * brightness); diff --git a/src/framework/util/crypt.cpp b/src/framework/util/crypt.cpp index b8d3630ac8..2850ba1cf9 100644 --- a/src/framework/util/crypt.cpp +++ b/src/framework/util/crypt.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,9 +21,9 @@ */ #include "crypt.h" +#include "framework/core/application.h" #include #include -#include "framework/core/application.h" #include #include @@ -34,8 +34,12 @@ #endif #include +#include + +#include "framework/core/graphicalapplication.h" + static constexpr std::string_view base64_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; -static inline bool is_base64(uint8_t c) { return (isalnum(c) || (c == '+') || (c == '/')); } +static inline bool is_base64(const uint8_t c) { return (isalnum(c) || (c == '+') || (c == '/')); } Crypt g_crypt; @@ -167,8 +171,8 @@ std::string Crypt::xorCrypt(const std::string& buffer, const std::string& key) std::string Crypt::genUUID() { std::random_device rd; - auto seed_data = std::array {}; - std::generate(std::begin(seed_data), std::end(seed_data), std::ref(rd)); + auto seed_data = std::array{}; + std::ranges::generate(seed_data, std::ref(rd)); std::seed_seq seq(std::begin(seed_data), std::end(seed_data)); std::mt19937 generator(seq); @@ -194,8 +198,8 @@ std::string Crypt::getMachineUUID() { if (m_machineUUID.is_nil()) { std::random_device rd; - auto seed_data = std::array {}; - std::generate(std::begin(seed_data), std::end(seed_data), std::ref(rd)); + auto seed_data = std::array{}; + std::ranges::generate(seed_data, std::ref(rd)); std::seed_seq seq(std::begin(seed_data), std::end(seed_data)); std::mt19937 generator(seq); @@ -204,7 +208,7 @@ std::string Crypt::getMachineUUID() return _encrypt(to_string(m_machineUUID), false); } -std::string Crypt::getCryptKey(bool useMachineUUID) const +std::string Crypt::getCryptKey(const bool useMachineUUID) const { constexpr std::hash uuid_hasher; const uuids::uuid uuid = useMachineUUID ? m_machineUUID : uuids::uuid(); @@ -217,7 +221,7 @@ std::string Crypt::getCryptKey(bool useMachineUUID) const return key; } -std::string Crypt::_encrypt(const std::string& decrypted_string, bool useMachineUUID) +std::string Crypt::_encrypt(const std::string& decrypted_string, const bool useMachineUUID) { const uint32_t sum = stdext::adler32((const uint8_t*)decrypted_string.c_str(), decrypted_string.size()); @@ -228,7 +232,7 @@ std::string Crypt::_encrypt(const std::string& decrypted_string, bool useMachine return encrypted; } -std::string Crypt::_decrypt(const std::string& encrypted_string, bool useMachineUUID) +std::string Crypt::_decrypt(const std::string& encrypted_string, const bool useMachineUUID) { const auto& decoded = base64Decode(encrypted_string); const auto& tmp = xorCrypt(decoded, getCryptKey(useMachineUUID)); @@ -364,15 +368,15 @@ int Crypt::rsaGetSize() #endif } -std::string Crypt::crc32(const std::string& decoded_string, bool upperCase) +std::string Crypt::crc32(const std::string& decoded_string, const bool upperCase) { - uint32_t crc = ::crc32(0, Z_NULL, 0); + uint32_t crc = ::crc32(0, nullptr, 0); crc = ::crc32(crc, (const Bytef*)decoded_string.c_str(), decoded_string.size()); std::string result = stdext::dec_to_hex(crc); if (upperCase) - std::transform(result.begin(), result.end(), result.begin(), toupper); + std::ranges::transform(result, result.begin(), toupper); else - std::transform(result.begin(), result.end(), result.begin(), tolower); + std::ranges::transform(result, result.begin(), tolower); return result; } @@ -391,7 +395,7 @@ std::string Crypt::sha1Encrpyt(const std::string& input) uint32_t length_low = 0; uint32_t length_high = 0; - for (char ch : input) { + for (const char ch : input) { messageBlock[index++] = ch; length_low += 8; @@ -433,7 +437,7 @@ std::string Crypt::sha1Encrpyt(const std::string& input) sha1Block(messageBlock, H); char hexstring[41]; - static const char hexDigits[] = {"0123456789abcdef"}; + static constexpr char hexDigits[] = { "0123456789abcdef" }; for (int hashByte = 20; --hashByte >= 0;) { const uint8_t byte = H[hashByte >> 2] >> (((3 - hashByte) & 3) << 3); index = hashByte << 1; @@ -443,7 +447,7 @@ std::string Crypt::sha1Encrpyt(const std::string& input) return std::string(hexstring, 40); } -void Crypt::sha1Block(uint8_t* block, uint32_t* H) +void Crypt::sha1Block(const uint8_t* block, uint32_t* H) { uint32_t W[80]; for (int i = 0; i < 16; ++i) { @@ -482,4 +486,4 @@ void Crypt::sha1Block(uint8_t* block, uint32_t* H) H[2] += C; H[3] += D; H[4] += E; -} +} \ No newline at end of file diff --git a/src/framework/util/crypt.h b/src/framework/util/crypt.h index fd02c335e5..f5f429da35 100644 --- a/src/framework/util/crypt.h +++ b/src/framework/util/crypt.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -24,8 +24,8 @@ #include "../global.h" -#include #include +#include #ifdef USE_GMP #include @@ -58,7 +58,7 @@ class Crypt std::string sha1Encrpyt(const std::string& input); protected: - void sha1Block(uint8_t* block, uint32_t* H); + void sha1Block(const uint8_t* block, uint32_t* H); private: std::string _encrypt(const std::string& decrypted_string, bool useMachineUUID); diff --git a/src/framework/util/matrix.h b/src/framework/util/matrix.h index 960614ce0a..27deeed166 100644 --- a/src/framework/util/matrix.h +++ b/src/framework/util/matrix.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -30,7 +30,7 @@ class Matrix public: Matrix() { setIdentity(); } Matrix(int) {} // construct without initializing identity matrix - Matrix(const Matrix& other) = default; + Matrix(const Matrix& other) = default; template Matrix(const std::initializer_list& values) { *this = values; } template @@ -48,22 +48,22 @@ class Matrix T* data() { return m[0]; } const T* data() const { return m[0]; } - T& operator()(int row, int column) { return m[row - 1][column - 1]; } - T operator()(int row, int column) const { return m[row - 1][column - 1]; } + T& operator()(const int row, const int column) { return m[row - 1][column - 1]; } + T operator()(const int row, const int column) const { return m[row - 1][column - 1]; } - Matrix& operator=(const Matrix& other) = default; + Matrix& operator=(const Matrix& other) = default; template - Matrix& operator=(const std::initializer_list& values); + Matrix& operator=(const std::initializer_list& values); template - Matrix& operator=(const U* values); - Matrix& operator+=(const Matrix& other); - Matrix& operator-=(const Matrix& other); - Matrix& operator*=(T factor); - Matrix& operator/=(T divisor); - bool operator==(const Matrix& other) const; - bool operator!=(const Matrix& other) const; - - Matrix& generateHash() + Matrix& operator=(const U* values); + Matrix& operator+=(const Matrix& other); + Matrix& operator-=(const Matrix& other); + Matrix& operator*=(T factor); + Matrix& operator/=(T divisor); + bool operator==(const Matrix& other) const; + bool operator!=(const Matrix& other) const; + + Matrix& generateHash() { m_hash = 0; for (int i = -1; ++i < N;) @@ -143,7 +143,7 @@ Matrix& Matrix::operator=(const U* values) } template -Matrix& Matrix::operator+=(const Matrix& other) +Matrix& Matrix::operator+=(const Matrix& other) { for (int i = 0; i < N; ++i) for (int j = 0; j < M; ++j) @@ -152,7 +152,7 @@ Matrix& Matrix::operator+=(const Matrix& other) } template -Matrix& Matrix::operator-=(const Matrix& other) +Matrix& Matrix::operator-=(const Matrix& other) { for (int i = 0; i < N; ++i) for (int j = 0; j < M; ++j) @@ -180,13 +180,13 @@ Matrix& Matrix::operator/=(T divisor) } template -bool Matrix::operator==(const Matrix& other) const +bool Matrix::operator==(const Matrix& other) const { return hash() == other.hash(); } template -bool Matrix::operator!=(const Matrix& other) const +bool Matrix::operator!=(const Matrix& other) const { return !(*this == other); } diff --git a/src/framework/util/point.h b/src/framework/util/point.h index fcd49dfcd0..0c5bf72a84 100644 --- a/src/framework/util/point.h +++ b/src/framework/util/point.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -22,10 +22,8 @@ #pragma once -#include #include #include -#include "../stdext/types.h" template class TSize; @@ -37,13 +35,13 @@ class TPoint TPoint() : x(0), y(0) {} TPoint(T xy) : x(xy), y(xy) {} TPoint(T x, T y) : x(x), y(y) {} - TPoint(const TPoint& other) : x(other.x), y(other.y) {} + TPoint(const TPoint& other) : x(other.x), y(other.y) {} bool isNull() const { return x == 0 && y == 0; } TSize toSize() const { return TSize(x, y); } - TPoint translated(T dx, T dy) const { TPoint point = *this; point.x += dx; point.y += dy; return point; } + TPoint translated(T dx, T dy) const { TPoint point = *this; point.x += dx; point.y += dy; return point; } - TPoint scale(float v) { + TPoint scale(const float v) { if (v != 1.f) { float factor = (1.f - (1.f / v)); x -= x * factor; @@ -52,42 +50,42 @@ class TPoint return *this; } - TPoint operator-() const { return TPoint(-x, -y); } - - TPoint operator+(const TPoint& other) const { return TPoint(x + other.x, y + other.y); } - TPoint& operator+=(const TPoint& other) { x += other.x; y += other.y; return *this; } - TPoint operator-(const TPoint& other) const { return TPoint(x - other.x, y - other.y); } - TPoint& operator-=(const TPoint& other) { x -= other.x; y -= other.y; return *this; } - TPoint operator*(const TPoint& other) const { return TPoint(x * other.x, y * other.y); } - TPoint& operator*=(const TPoint& other) { x *= other.x; y *= other.y; return *this; } - TPoint operator/(const TPoint& other) const { return TPoint(x / other.x, y / other.y); } - TPoint& operator/=(const TPoint& other) { x /= other.x; y /= other.y; return *this; } - - TPoint operator+(T other) const { return TPoint(x + other, y + other); } - TPoint& operator+=(T other) { x += other; y += other; return *this; } - TPoint operator-(T other) const { return TPoint(x - other, y - other); } - TPoint& operator-=(T other) { x -= other; y -= other; return *this; } - TPoint operator*(float v) const { return TPoint(x * v, y * v); } - TPoint& operator*=(float v) { x *= v; y *= v; return *this; } - TPoint operator/(float v) const { return TPoint(x / v, y / v); } - TPoint& operator/=(float v) { x /= v; y /= v; return *this; } - - TPoint operator&(int a) { return TPoint(x & a, y & a); } - TPoint& operator&=(int a) { x &= a; y &= a; return *this; } - - bool operator<=(const TPoint& other) const { return x <= other.x && y <= other.y; } - bool operator>=(const TPoint& other) const { return x >= other.x && y >= other.y; } - bool operator<(const TPoint& other) const { return x < other.x && y < other.y; } - bool operator>(const TPoint& other) const { return x > other.x && y > other.y; } - - TPoint& operator=(const TPoint& other) { x = other.x; y = other.y; return *this; } - bool operator==(const TPoint& other) const { return other.x == x && other.y == y; } - bool operator!=(const TPoint& other) const { return other.x != x || other.y != y; } + TPoint operator-() const { return TPoint(-x, -y); } + + TPoint operator+(const TPoint& other) const { return TPoint(x + other.x, y + other.y); } + TPoint& operator+=(const TPoint& other) { x += other.x; y += other.y; return *this; } + TPoint operator-(const TPoint& other) const { return TPoint(x - other.x, y - other.y); } + TPoint& operator-=(const TPoint& other) { x -= other.x; y -= other.y; return *this; } + TPoint operator*(const TPoint& other) const { return TPoint(x * other.x, y * other.y); } + TPoint& operator*=(const TPoint& other) { x *= other.x; y *= other.y; return *this; } + TPoint operator/(const TPoint& other) const { return TPoint(x / other.x, y / other.y); } + TPoint& operator/=(const TPoint& other) { x /= other.x; y /= other.y; return *this; } + + TPoint operator+(T other) const { return TPoint(x + other, y + other); } + TPoint& operator+=(T other) { x += other; y += other; return *this; } + TPoint operator-(T other) const { return TPoint(x - other, y - other); } + TPoint& operator-=(T other) { x -= other; y -= other; return *this; } + TPoint operator*(float v) const { return TPoint(x * v, y * v); } + TPoint& operator*=(float v) { x *= v; y *= v; return *this; } + TPoint operator/(float v) const { return TPoint(x / v, y / v); } + TPoint& operator/=(float v) { x /= v; y /= v; return *this; } + + TPoint operator&(int a) { return TPoint(x & a, y & a); } + TPoint& operator&=(int a) { x &= a; y &= a; return *this; } + + bool operator<=(const TPoint& other) const { return x <= other.x && y <= other.y; } + bool operator>=(const TPoint& other) const { return x >= other.x && y >= other.y; } + bool operator<(const TPoint& other) const { return x < other.x && y < other.y; } + bool operator>(const TPoint& other) const { return x > other.x && y > other.y; } + + TPoint& operator=(const TPoint& other) = default; + bool operator==(const TPoint& other) const { return other.x == x && other.y == y; } + bool operator!=(const TPoint& other) const { return other.x != x || other.y != y; } float length() const { return sqrt(static_cast(x * x + y * y)); } T manhattanLength() const { return std::abs(x) + std::abs(y); } - float distanceFrom(const TPoint& other) const { return TPoint(x - other.x, y - other.y).length(); } + float distanceFrom(const TPoint& other) const { return TPoint(x - other.x, y - other.y).length(); } std::size_t hash() const { return (7 * 15 + x) * 15 + y; } diff --git a/src/framework/util/rect.h b/src/framework/util/rect.h index 3dbf2d9af1..417306c5d0 100644 --- a/src/framework/util/rect.h +++ b/src/framework/util/rect.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -37,7 +37,7 @@ class TRect TRect() : x1(0), y1(0), x2(-1), y2(-1) {} TRect(T x, T y, T width, T height) : x1(x), y1(y), x2(x + width - 1), y2(y + height - 1) {} TRect(const TPoint& topLeft, const TPoint& bottomRight) : x1(topLeft.x), y1(topLeft.y), x2(bottomRight.x), y2(bottomRight.y) {} - TRect(const TRect& other) : x1(other.x1), y1(other.y1), x2(other.x2), y2(other.y2) {} + TRect(const TRect& other) : x1(other.x1), y1(other.y1), x2(other.x2), y2(other.y2) {} TRect(T x, T y, const TSize& size) : x1(x), y1(y), x2(x + size.width() - 1), y2(y + size.height() - 1) {} TRect(const TPoint& topLeft, const TSize& size) : x1(topLeft.x), y1(topLeft.y), x2(x1 + size.width() - 1), y2(y1 + size.height() - 1) {} TRect(const TPoint& topLeft, int width, int height) : x1(topLeft.x), y1(topLeft.y), x2(x1 + width - 1), y2(y1 + height - 1) {} @@ -111,13 +111,13 @@ class TRect void moveCenterLeft(const TPoint& p) { moveLeft(p.x); moveVerticalCenter(p.y); } void moveCenterRight(const TPoint& p) { moveRight(p.x); moveVerticalCenter(p.y); } - TRect translated(int x, int y) const { return TRect(TPoint(x1 + x, y1 + y), TPoint(x2 + x, y2 + y)); } - TRect translated(const TPoint& p) const { return TRect(TPoint(x1 + p.x, y1 + p.y), TPoint(x2 + p.x, y2 + p.y)); } + TRect translated(int x, int y) const { return TRect(TPoint(x1 + x, y1 + y), TPoint(x2 + x, y2 + y)); } + TRect translated(const TPoint& p) const { return TRect(TPoint(x1 + p.x, y1 + p.y), TPoint(x2 + p.x, y2 + p.y)); } - TRect expanded(T add) const { return TRect(TPoint(x1 - add, y1 - add), TPoint(x2 + add, y2 + add)); } + TRect expanded(T add) const { return TRect(TPoint(x1 - add, y1 - add), TPoint(x2 + add, y2 + add)); } - TRect clamp(const TSize& min, const TSize& max) const { - return TRect(x1, y1, + TRect clamp(const TSize& min, const TSize& max) const { + return TRect(x1, y1, std::min(max.width(), std::max(min.width(), width())), std::min(max.height(), std::max(min.height(), height()))); } @@ -152,7 +152,7 @@ class TRect y2 = y1 + h; } - bool contains(const TPoint& p, bool insideOnly = false) const + bool contains(const TPoint& p, const bool insideOnly = false) const { T l, r; if (x2 < x1 - 1) { @@ -187,14 +187,14 @@ class TRect return true; } - bool contains(const TRect& r, bool insideOnly = false) const + bool contains(const TRect& r, const bool insideOnly = false) const { if (contains(r.topLeft(), insideOnly) && contains(r.bottomRight(), insideOnly)) return true; return false; } - bool intersects(const TRect& r) const + bool intersects(const TRect& r) const { if (isNull() || r.isNull()) return false; @@ -236,9 +236,9 @@ class TRect return true; } - TRect united(const TRect& r) const + TRect united(const TRect& r) const { - TRect tmp; + TRect tmp; tmp.x1 = std::min(x1, r.x1); tmp.x2 = std::max(x2, r.x2); tmp.y1 = std::min(y1, r.y1); @@ -246,7 +246,7 @@ class TRect return tmp; } - TRect intersection(const TRect& r) const + TRect intersection(const TRect& r) const { if (isNull()) return r; @@ -281,7 +281,7 @@ class TRect else b2 = r.y2; - TRect tmp; + TRect tmp; tmp.x1 = std::max(l1, l2); tmp.x2 = std::min(r1, r2); tmp.y1 = std::max(t1, t2); @@ -289,7 +289,7 @@ class TRect return tmp; } - void bind(const TRect& r) + void bind(const TRect& r) { if (isNull() || r.isNull()) return; @@ -304,7 +304,7 @@ class TRect moveTop(r.top()); } - void alignIn(const TRect& r, Fw::AlignmentFlag align) + void alignIn(const TRect& r, const Fw::AlignmentFlag align) { if (align == Fw::AlignTopLeft) moveTopLeft(r.topLeft()); @@ -326,12 +326,12 @@ class TRect moveCenterRight(r.centerRight()); } - TRect& operator=(const TRect& other) { x1 = other.x1; y1 = other.y1; x2 = other.x2; y2 = other.y2; return *this; } - bool operator==(const TRect& other) const { return (x1 == other.x1 && y1 == other.y1 && x2 == other.x2 && y2 == other.y2); } - bool operator!=(const TRect& other) const { return (x1 != other.x1 || y1 != other.y1 || x2 != other.x2 || y2 != other.y2); } + TRect& operator=(const TRect& other) = default; + bool operator==(const TRect& other) const { return (x1 == other.x1 && y1 == other.y1 && x2 == other.x2 && y2 == other.y2); } + bool operator!=(const TRect& other) const { return (x1 != other.x1 || y1 != other.y1 || x2 != other.x2 || y2 != other.y2); } - TRect& operator|=(const TRect& other) { *this = united(other); return *this; } - TRect& operator&=(const TRect& other) { *this = intersection(other); return *this; } + TRect& operator|=(const TRect& other) { *this = united(other); return *this; } + TRect& operator&=(const TRect& other) { *this = intersection(other); return *this; } private: T x1, y1, x2, y2; diff --git a/src/framework/util/size.h b/src/framework/util/size.h index 6171583313..1ec4abcacd 100644 --- a/src/framework/util/size.h +++ b/src/framework/util/size.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -22,8 +22,8 @@ #pragma once -#include "point.h" #include "../const.h" +#include "point.h" template class TSize @@ -32,7 +32,7 @@ class TSize TSize() : wd(-1), ht(-1) {}; TSize(T widthHeight) : wd(widthHeight), ht(widthHeight) {}; TSize(T width, T height) : wd(width), ht(height) {}; - TSize(const TSize& other) : wd(other.wd), ht(other.ht) {}; + TSize(const TSize& other) : wd(other.wd), ht(other.ht) {}; TPoint toPoint() const { return TPoint(wd, ht); } @@ -48,42 +48,42 @@ class TSize void setWidth(T w) { wd = w; } void setHeight(T h) { ht = h; } - TSize operator-() const { return TSize(-wd, -ht); } - TSize operator+(const TSize& other) const { return TSize(wd + other.wd, ht + other.ht); } - TSize& operator+=(const TSize& other) { wd += other.wd; ht += other.ht; return *this; } - TSize operator-(const TSize& other) const { return TSize(wd - other.wd, ht - other.ht); } - TSize& operator-=(const TSize& other) { wd -= other.wd; ht -= other.ht; return *this; } - TSize operator*(const TSize& other) const { return TSize(static_cast(other.wd) * wd, static_cast(ht) * other.ht); } - TSize& operator*=(const TSize& other) { wd = static_cast(other.wd) * wd; ht = static_cast(ht) * other.ht; return *this; } - TSize operator/(const TSize& other) const { return TSize(static_cast(wd) / other.wd, static_cast(ht) / other.ht); } - TSize& operator/=(const TSize& other) { static_cast(wd) /= other.wd; static_cast(ht) /= other.ht; return *this; } - TSize operator*(const float v) const { return TSize(static_cast(wd) * v, static_cast(ht) * v); } - TSize& operator*=(const float v) { wd = static_cast(wd) * v; ht = static_cast(ht) * v; return *this; } - TSize operator/(const float v) const { return TSize(static_cast(wd) / v, static_cast(ht) / v); } - TSize& operator/=(const float v) { wd /= v; ht /= v; return *this; } - - bool operator<=(const TSize& other) const { return wd <= other.wd || ht <= other.ht; } - bool operator>=(const TSize& other) const { return wd >= other.wd || ht >= other.ht; } - bool operator<(const TSize& other) const { return wd < other.wd || ht < other.ht; } - bool operator>(const TSize& other) const { return wd > other.wd || ht > other.ht; } - - TSize& operator=(const TSize& other) { wd = other.wd; ht = other.ht; return *this; } - bool operator==(const TSize& other) const { return other.wd == wd && other.ht == ht; } - bool operator!=(const TSize& other) const { return other.wd != wd || other.ht != ht; } + TSize operator-() const { return TSize(-wd, -ht); } + TSize operator+(const TSize& other) const { return TSize(wd + other.wd, ht + other.ht); } + TSize& operator+=(const TSize& other) { wd += other.wd; ht += other.ht; return *this; } + TSize operator-(const TSize& other) const { return TSize(wd - other.wd, ht - other.ht); } + TSize& operator-=(const TSize& other) { wd -= other.wd; ht -= other.ht; return *this; } + TSize operator*(const TSize& other) const { return TSize(static_cast(other.wd) * wd, static_cast(ht) * other.ht); } + TSize& operator*=(const TSize& other) { wd = static_cast(other.wd) * wd; ht = static_cast(ht) * other.ht; return *this; } + TSize operator/(const TSize& other) const { return TSize(static_cast(wd) / other.wd, static_cast(ht) / other.ht); } + TSize& operator/=(const TSize& other) { static_cast(wd) /= other.wd; static_cast(ht) /= other.ht; return *this; } + TSize operator*(const float v) const { return TSize(static_cast(wd) * v, static_cast(ht) * v); } + TSize& operator*=(const float v) { wd = static_cast(wd) * v; ht = static_cast(ht) * v; return *this; } + TSize operator/(const float v) const { return TSize(static_cast(wd) / v, static_cast(ht) / v); } + TSize& operator/=(const float v) { wd /= v; ht /= v; return *this; } + + bool operator<=(const TSize& other) const { return wd <= other.wd || ht <= other.ht; } + bool operator>=(const TSize& other) const { return wd >= other.wd || ht >= other.ht; } + bool operator<(const TSize& other) const { return wd < other.wd || ht < other.ht; } + bool operator>(const TSize& other) const { return wd > other.wd || ht > other.ht; } + + TSize& operator=(const TSize& other) = default; + bool operator==(const TSize& other) const { return other.wd == wd && other.ht == ht; } + bool operator!=(const TSize& other) const { return other.wd != wd || other.ht != ht; } bool operator<=(const T other) const { return wd <= other || ht <= other; } bool operator>=(const T other) const { return wd >= other || ht >= other; } bool operator<(const T other) const { return wd < other || ht < other; } bool operator>(const T other) const { return wd > other || ht > other; } - TSize& operator=(const T other) { wd = other; ht = other; return *this; } + TSize& operator=(const T other) { wd = other; ht = other; return *this; } bool operator==(const T other) const { return other == wd && other == ht; } bool operator!=(const T other) const { return other != wd || other != ht; } - TSize expandedTo(const TSize& other) const { return TSize(std::max(wd, other.wd), std::max(ht, other.ht)); } - TSize boundedTo(const TSize& other) const { return TSize(std::min(wd, other.wd), std::min(ht, other.ht)); } + TSize expandedTo(const TSize& other) const { return TSize(std::max(wd, other.wd), std::max(ht, other.ht)); } + TSize boundedTo(const TSize& other) const { return TSize(std::min(wd, other.wd), std::min(ht, other.ht)); } - void scale(const TSize& s, Fw::AspectRatioMode mode) + void scale(const TSize& s, const Fw::AspectRatioMode mode) { if (mode == Fw::IgnoreAspectRatio || wd == 0 || ht == 0) { wd = s.wd; @@ -107,7 +107,7 @@ class TSize } } - void scale(int w, int h, Fw::AspectRatioMode mode) { scale(TSize(w, h), mode); } + void scale(int w, int h, const Fw::AspectRatioMode mode) { scale(TSize(w, h), mode); } T smaller() const { return std::min(ht, wd); } T bigger() const { return std::max(ht, wd); } diff --git a/src/main.cpp b/src/main.cpp index f397572b00..696a53aefa 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2022 OTClient + * Copyright (c) 2010-2024 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -22,7 +22,6 @@ #include #include -#include #include #include #include @@ -42,7 +41,7 @@ extern "C" { #endif - int main(int argc, const char* argv[]) + int main(const int argc, const char* argv[]) { std::vector args(argv, argv + argc); diff --git a/src/protobuf/CMakeLists.txt b/src/protobuf/CMakeLists.txt index 3f350eaee9..645fd2d2d4 100644 --- a/src/protobuf/CMakeLists.txt +++ b/src/protobuf/CMakeLists.txt @@ -44,5 +44,9 @@ if(PROTOBUF_FOUND) target_compile_definitions(${PROJECT_NAME} PUBLIC _DISABLE_VECTOR_ANNOTATION _DISABLE_STRING_ANNOTATION) target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_BINARY_DIR}) + if(CMAKE_BASE_NAME STREQUAL "em++") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread") + endif() + protobuf_generate(TARGET ${PROJECT_NAME} LANGUAGE cpp) endif(PROTOBUF_FOUND) diff --git a/tools/api/status.php b/tools/api/status.php index b6d97cc863..c464acb8f9 100644 --- a/tools/api/status.php +++ b/tools/api/status.php @@ -136,7 +136,7 @@ echo json_encode($response); // EnterGame.postShowCreatureBoost() -} elseif ($requestType === 'Creatureboost') { +} elseif ($requestType === 'boostedcreature') { $response = array( diff --git a/vc17/otclient.vcxproj b/vc17/otclient.vcxproj index e4f4c43891..a97426b99c 100644 --- a/vc17/otclient.vcxproj +++ b/vc17/otclient.vcxproj @@ -408,6 +408,8 @@ + + @@ -573,6 +575,8 @@ + + @@ -614,7 +618,6 @@ - @@ -631,34 +634,34 @@ true - false + false - $(ProjectDir)vcpkg_installed\$(VcpkgTriplet)\tools\protobuf\protoc - $(SourcePath)protobuf + $(ProjectDir)vcpkg_installed\$(VcpkgTriplet)\tools\protobuf\protoc + $(SourcePath)protobuf - $(ProjectDir)vcpkg_installed\$(VcpkgTriplet)\tools\protobuf\protoc - $(GITHUB_WORKSPACE)\src\protobuf + $(ProjectDir)vcpkg_installed\$(VcpkgTriplet)\tools\protobuf\protoc + $(GITHUB_WORKSPACE)\src\protobuf - + - - - - - false - NotUsing - - - false - NotUsing - - + + + + + false + NotUsing + + + false + NotUsing + + - \ No newline at end of file + diff --git a/vc17/otclient.vcxproj.filters b/vc17/otclient.vcxproj.filters index 22c3296ac5..b2a2d1917c 100644 --- a/vc17/otclient.vcxproj.filters +++ b/vc17/otclient.vcxproj.filters @@ -522,9 +522,6 @@ Source Files\framework\graphics - - Source Files\protobuf - Source Files\client @@ -570,6 +567,12 @@ Source Files\client + + Source Files + + + Source Files + @@ -1091,9 +1094,6 @@ Header Files\framework\net - - Header Files\framework\util - Header Files\framework\sound @@ -1109,6 +1109,12 @@ Header Files\client + + Header Files + + + Header Files + diff --git a/vc17/settings.props b/vc17/settings.props index 3d429b7b6f..c33ea7994e 100644 --- a/vc17/settings.props +++ b/vc17/settings.props @@ -17,6 +17,7 @@ advapi32.lib; + avrt.lib; crypt32.lib; dbghelp.lib; gdi32.lib; @@ -44,6 +45,7 @@ advapi32.lib; + avrt.lib; discord-rpc.lib; dbghelp.lib; gdi32.lib; diff --git a/vcpkg.json b/vcpkg.json index e067becf35..c5fcec74db 100644 --- a/vcpkg.json +++ b/vcpkg.json @@ -18,9 +18,10 @@ "pugixml", "stduuid", "zlib", + "bshoshany-thread-pool", { "name": "luajit", - "platform": "!android" + "platform": "!android & !wasm32" }, { "name": "opengl", @@ -35,5 +36,5 @@ "platform": "windows" } ], - "builtin-baseline":"c82f74667287d3dc386bce81e44964370c91a289" + "builtin-baseline":"b322364f06308bdd24823f9d8f03fe0cc86fd46f" }