diff --git a/src/creatures/players/player.cpp b/src/creatures/players/player.cpp index 305fe6ee8..ab2032d11 100644 --- a/src/creatures/players/player.cpp +++ b/src/creatures/players/player.cpp @@ -861,12 +861,13 @@ void Player::addStorageValue(const uint32_t key, const int32_t value, const bool } if (value != -1) { + int32_t oldValue = getStorageValue(key); storageMap[key] = value; if (!isLogin) { auto currentFrameTime = g_dispatcher().getDispatcherCycle(); - g_events().eventOnStorageUpdate(static_self_cast(), key, value, getStorageValue(key), currentFrameTime); - g_callbacks().executeCallback(EventCallback_t::playerOnStorageUpdate, &EventCallback::playerOnStorageUpdate, getPlayer(), key, value, getStorageValue(key), currentFrameTime); + g_events().eventOnStorageUpdate(static_self_cast(), key, value, oldValue, currentFrameTime); + g_callbacks().executeCallback(EventCallback_t::playerOnStorageUpdate, &EventCallback::playerOnStorageUpdate, getPlayer(), key, value, oldValue, currentFrameTime); } } else { storageMap.erase(key); diff --git a/src/creatures/players/wheel/player_wheel.cpp b/src/creatures/players/wheel/player_wheel.cpp index 6890f7b4e..dc7d0ee77 100644 --- a/src/creatures/players/wheel/player_wheel.cpp +++ b/src/creatures/players/wheel/player_wheel.cpp @@ -83,7 +83,6 @@ namespace { { 43949, "wheel.scroll.extended", 13 }, { 43950, "wheel.scroll.advanced", 20 }, }; - } // namespace PlayerWheel::PlayerWheel(Player &initPlayer) : @@ -784,7 +783,8 @@ void PlayerWheel::saveSlotPointsOnPressSaveButton(NetworkMessage &msg) { return; } - auto startSaveTime = OTSYS_TIME(); + Benchmark bm_saveSlot; + if (!canOpenWheel()) { return; } @@ -849,7 +849,7 @@ void PlayerWheel::saveSlotPointsOnPressSaveButton(NetworkMessage &msg) { initializePlayerData(); registerPlayerBonusData(); - g_logger().debug("Player: {} is saved the all slots info in: {} seconds", m_player.getName(), (OTSYS_TIME() - startSaveTime) / (1000.)); + g_logger().debug("Player: {} is saved the all slots info in: {} seconds", m_player.getName(), bm_saveSlot.duration()); } /* diff --git a/src/game/game.cpp b/src/game/game.cpp index 6db6a0687..c89e438fb 100644 --- a/src/game/game.cpp +++ b/src/game/game.cpp @@ -960,8 +960,8 @@ bool Game::removeCreature(std::shared_ptr creature, bool isLogout /* = void Game::executeDeath(uint32_t creatureId) { std::shared_ptr creature = getCreatureByID(creatureId); if (creature && !creature->isRemoved()) { - creature->onDeath(); afterCreatureZoneChange(creature, creature->getZones(), {}); + creature->onDeath(); } } @@ -5715,6 +5715,7 @@ void Game::checkCreatures(size_t index) { creature->onAttacking(EVENT_CREATURE_THINK_INTERVAL); creature->executeConditions(EVENT_CREATURE_THINK_INTERVAL); } else { + afterCreatureZoneChange(creature, creature->getZones(), {}); creature->onDeath(); } ++it; diff --git a/src/game/zones/zone.cpp b/src/game/zones/zone.cpp index 40ec4e018..a000c45d5 100644 --- a/src/game/zones/zone.cpp +++ b/src/game/zones/zone.cpp @@ -268,3 +268,24 @@ void Zone::itemRemoved(const std::shared_ptr &item) { } itemsCache.erase(item); } + +void Zone::refresh() { + creaturesCache.clear(); + monstersCache.clear(); + npcsCache.clear(); + playersCache.clear(); + itemsCache.clear(); + + for (const auto &position : positions) { + const auto tile = g_game().map.getTile(position); + if (!tile) { + continue; + } + for (const auto &item : *tile->getItemList()) { + itemAdded(item); + } + for (const auto &creature : *tile->getCreatures()) { + creatureAdded(creature); + } + } +} diff --git a/src/game/zones/zone.hpp b/src/game/zones/zone.hpp index f2f9545e8..0aa5e76fd 100644 --- a/src/game/zones/zone.hpp +++ b/src/game/zones/zone.hpp @@ -117,6 +117,8 @@ class Zone { void removeMonsters() const; void removeNpcs() const; + void refresh(); + static std::shared_ptr addZone(const std::string &name); static std::shared_ptr getZone(const std::string &name); static phmap::parallel_flat_hash_set> getZones(const Position position); diff --git a/src/io/iomap.cpp b/src/io/iomap.cpp index 923511179..72eaed123 100644 --- a/src/io/iomap.cpp +++ b/src/io/iomap.cpp @@ -38,7 +38,7 @@ */ void IOMap::loadMap(Map* map, const Position &pos) { - const int64_t start = OTSYS_TIME(); + Benchmark bm_mapLoad; const auto &fileByte = mio::mmap_source(map->path.string()); @@ -77,7 +77,7 @@ void IOMap::loadMap(Map* map, const Position &pos) { map->flush(); - g_logger().info("Map Loaded {} ({}x{}) in {} seconds", map->path.filename().string(), map->width, map->height, static_cast(OTSYS_TIME() - start) / 1000.f); + g_logger().info("Map Loaded {} ({}x{}) in {} seconds", map->path.filename().string(), map->width, map->height, bm_mapLoad.duration()); } void IOMap::parseMapDataAttributes(FileStream &stream, Map* map) { diff --git a/src/io/iomapserialize.cpp b/src/io/iomapserialize.cpp index dba8214a6..94531a612 100644 --- a/src/io/iomapserialize.cpp +++ b/src/io/iomapserialize.cpp @@ -15,7 +15,7 @@ #include "items/bed.hpp" void IOMapSerialize::loadHouseItems(Map* map) { - int64_t start = OTSYS_TIME(); + Benchmark bm_context; DBResult_ptr result = Database::getInstance().storeQuery("SELECT `data` FROM `tile_store`"); if (!result) { @@ -49,7 +49,7 @@ void IOMapSerialize::loadHouseItems(Map* map) { loadItem(propStream, tile, true); } } while (result->next()); - g_logger().info("Loaded house items in {} seconds", (OTSYS_TIME() - start) / (1000.)); + g_logger().info("Loaded house items in {} seconds", bm_context.duration()); } bool IOMapSerialize::saveHouseItems() { bool success = DBTransaction::executeWithinTransaction([]() { @@ -64,7 +64,8 @@ bool IOMapSerialize::saveHouseItems() { } bool IOMapSerialize::SaveHouseItemsGuard() { - int64_t start = OTSYS_TIME(); + Benchmark bm_context; + Database &db = Database::getInstance(); std::ostringstream query; @@ -97,7 +98,7 @@ bool IOMapSerialize::SaveHouseItemsGuard() { return false; } - g_logger().info("Saved house items in {} seconds", (OTSYS_TIME() - start) / (1000.)); + g_logger().info("Saved house items in {} seconds", bm_context.duration()); return true; } diff --git a/src/lua/functions/core/game/zone_functions.cpp b/src/lua/functions/core/game/zone_functions.cpp index 9aa000caf..a624f36fe 100644 --- a/src/lua/functions/core/game/zone_functions.cpp +++ b/src/lua/functions/core/game/zone_functions.cpp @@ -330,3 +330,14 @@ int ZoneFunctions::luaZoneGetAll(lua_State* L) { } return 1; } + +int ZoneFunctions::luaZoneRefresh(lua_State* L) { + // Zone:refresh() + auto zone = getUserdataShared(L, 1); + if (!zone) { + reportErrorFunc(getErrorDesc(LUA_ERROR_ZONE_NOT_FOUND)); + return 1; + } + zone->refresh(); + return 1; +} diff --git a/src/lua/functions/core/game/zone_functions.hpp b/src/lua/functions/core/game/zone_functions.hpp index feb9f2ca3..c8ce215f6 100644 --- a/src/lua/functions/core/game/zone_functions.hpp +++ b/src/lua/functions/core/game/zone_functions.hpp @@ -26,6 +26,7 @@ class ZoneFunctions final : LuaScriptInterface { registerMethod(L, "Zone", "removePlayers", ZoneFunctions::luaZoneRemovePlayers); registerMethod(L, "Zone", "removeMonsters", ZoneFunctions::luaZoneRemoveMonsters); registerMethod(L, "Zone", "removeNpcs", ZoneFunctions::luaZoneRemoveNpcs); + registerMethod(L, "Zone", "refresh", ZoneFunctions::luaZoneRefresh); // static methods registerMethod(L, "Zone", "getByPosition", ZoneFunctions::luaZoneGetByPosition); diff --git a/src/pch.hpp b/src/pch.hpp index 899d986e9..1c6100611 100644 --- a/src/pch.hpp +++ b/src/pch.hpp @@ -14,6 +14,7 @@ // -------------------- // Utils +#include "utils/benchmark.hpp" #include "utils/definitions.hpp" #include "utils/simd.hpp" diff --git a/src/server/network/protocol/protocol.cpp b/src/server/network/protocol/protocol.cpp index 895780b3f..05a6d1451 100644 --- a/src/server/network/protocol/protocol.cpp +++ b/src/server/network/protocol/protocol.cpp @@ -14,18 +14,9 @@ #include "security/rsa.hpp" #include "game/scheduling/dispatcher.hpp" -Protocol::~Protocol() { - if (compreesionEnabled) { - deflateEnd(defStream.get()); - } -} - void Protocol::onSendMessage(const OutputMessage_ptr &msg) { if (!rawMessages) { - uint32_t sendMessageChecksum = 0; - if (compreesionEnabled && msg->getLength() >= 128 && compression(*msg)) { - sendMessageChecksum = (1U << 31); - } + const uint32_t sendMessageChecksum = msg->getLength() >= 128 && compression(*msg) ? (1U << 31) : 0; msg->writeMessageLength(); @@ -208,54 +199,41 @@ uint32_t Protocol::getIP() const { return 0; } -void Protocol::enableCompression() { - if (compreesionEnabled) { - return; - } - - int32_t compressionLevel = g_configManager().getNumber(COMPRESSION_LEVEL); - if (compressionLevel <= 0) { - return; +bool Protocol::compression(OutputMessage &msg) const { + if (checksumMethod != CHECKSUM_METHOD_SEQUENCE) { + return false; } - defStream = std::make_unique(); - defStream->zalloc = nullptr; - defStream->zfree = nullptr; - defStream->opaque = nullptr; - - compreesionEnabled = deflateInit2(defStream.get(), compressionLevel, Z_DEFLATED, -15, 9, Z_DEFAULT_STRATEGY) == Z_OK; - - if (!compreesionEnabled) { - defStream.reset(); - g_logger().error("[Protocol::enableCompression()] - Zlib deflateInit2 error: {}", (defStream->msg ? defStream->msg : " unknown error")); + static const thread_local auto &compress = std::make_unique(); + if (!compress->stream) { + return false; } -} -bool Protocol::compression(OutputMessage &msg) const { - auto outputMessageSize = msg.getLength(); + const auto outputMessageSize = msg.getLength(); if (outputMessageSize > NETWORKMESSAGE_MAXSIZE) { g_logger().error("[NetworkMessage::compression] - Exceded NetworkMessage max size: {}, actually size: {}", NETWORKMESSAGE_MAXSIZE, outputMessageSize); return false; } - static thread_local std::array defBuffer; - defStream->next_in = msg.getOutputBuffer(); - defStream->avail_in = outputMessageSize; - defStream->next_out = (Bytef*)defBuffer.data(); - defStream->avail_out = NETWORKMESSAGE_MAXSIZE; + compress->stream->next_in = msg.getOutputBuffer(); + compress->stream->avail_in = outputMessageSize; + compress->stream->next_out = reinterpret_cast(compress->buffer.data()); + compress->stream->avail_out = NETWORKMESSAGE_MAXSIZE; - if (int32_t ret = deflate(defStream.get(), Z_FINISH); - ret != Z_OK && ret != Z_STREAM_END) { + const int32_t ret = deflate(compress->stream.get(), Z_FINISH); + if (ret != Z_OK && ret != Z_STREAM_END) { return false; } - auto totalSize = static_cast(defStream->total_out); - deflateReset(defStream.get()); + + const auto totalSize = compress->stream->total_out; + deflateReset(compress->stream.get()); + if (totalSize == 0) { return false; } msg.reset(); - auto charData = static_cast(static_cast(defBuffer.data())); - msg.addBytes(charData, static_cast(totalSize)); + msg.addBytes(compress->buffer.data(), totalSize); + return true; } diff --git a/src/server/network/protocol/protocol.hpp b/src/server/network/protocol/protocol.hpp index b209c3069..6f9252285 100644 --- a/src/server/network/protocol/protocol.hpp +++ b/src/server/network/protocol/protocol.hpp @@ -17,7 +17,7 @@ class Protocol : public std::enable_shared_from_this { explicit Protocol(Connection_ptr initConnection) : connectionPtr(initConnection) { } - virtual ~Protocol(); + virtual ~Protocol() = default; // non-copyable Protocol(const Protocol &) = delete; @@ -71,7 +71,6 @@ class Protocol : public std::enable_shared_from_this { void setChecksumMethod(ChecksumMethods_t method) { checksumMethod = method; } - void enableCompression(); static bool RSA_decrypt(NetworkMessage &msg); @@ -82,12 +81,37 @@ class Protocol : public std::enable_shared_from_this { virtual void release() { } private: + struct ZStream { + ZStream() noexcept { + const int32_t compressionLevel = g_configManager().getNumber(COMPRESSION_LEVEL); + if (compressionLevel <= 0) { + return; + } + + stream = std::make_unique(); + stream->zalloc = nullptr; + stream->zfree = nullptr; + stream->opaque = nullptr; + + if (deflateInit2(stream.get(), compressionLevel, Z_DEFLATED, -15, 9, Z_DEFAULT_STRATEGY) != Z_OK) { + stream.reset(); + g_logger().error("[Protocol::enableCompression()] - Zlib deflateInit2 error: {}", (stream->msg ? stream->msg : " unknown error")); + } + } + + ~ZStream() { + deflateEnd(stream.get()); + } + + std::unique_ptr stream; + std::array buffer {}; + }; + void XTEA_encrypt(OutputMessage &msg) const; bool XTEA_decrypt(NetworkMessage &msg) const; bool compression(OutputMessage &msg) const; OutputMessage_ptr outputBuffer; - std::unique_ptr defStream; const ConnectionWeak_ptr connectionPtr; std::array key = {}; @@ -96,7 +120,6 @@ class Protocol : public std::enable_shared_from_this { std::underlying_type_t checksumMethod = CHECKSUM_METHOD_NONE; bool encryptionEnabled = false; bool rawMessages = false; - bool compreesionEnabled = false; friend class Connection; }; diff --git a/src/server/network/protocol/protocolgame.cpp b/src/server/network/protocol/protocolgame.cpp index ac3d2e979..c6a9ac453 100644 --- a/src/server/network/protocol/protocolgame.cpp +++ b/src/server/network/protocol/protocolgame.cpp @@ -675,7 +675,6 @@ void ProtocolGame::onRecvFirstMessage(NetworkMessage &msg) { setChecksumMethod(CHECKSUM_METHOD_ADLER32); } else if (operatingSystem <= CLIENTOS_OTCLIENT_MAC) { setChecksumMethod(CHECKSUM_METHOD_SEQUENCE); - enableCompression(); } clientVersion = static_cast(msg.get()); diff --git a/src/utils/benchmark.hpp b/src/utils/benchmark.hpp new file mode 100644 index 000000000..8d968ca70 --- /dev/null +++ b/src/utils/benchmark.hpp @@ -0,0 +1,87 @@ +/** + * Canary - A free and open-source MMORPG server emulator + * Copyright (©) 2019-2022 OpenTibiaBR + * Repository: https://github.com/opentibiabr/canary + * License: https://github.com/opentibiabr/canary/blob/main/LICENSE + * Contributors: https://github.com/opentibiabr/canary/graphs/contributors + * Website: https://docs.opentibiabr.com/ + */ + +#pragma once + +#include +#include +#include + +class Benchmark { +public: + Benchmark() noexcept { + start(); + } + + void start() noexcept { + startTime = time(); + } + + void end() noexcept { + if (startTime == -1) { + return; + } + + last = static_cast(time() - startTime) / 1000.f; + + startTime = -1; + + if (minTime == -1 || minTime > last) { + minTime = last; + } + + if (maxTime == -1 || maxTime < last) { + maxTime = last; + } + + total += last; + ++totalExecs; + } + + double duration() noexcept { + if (startTime > -1) { + end(); + } + + return last; + } + + double min() const noexcept { + return minTime; + } + + double max() const noexcept { + return maxTime; + } + + double avg() const noexcept { + return total / totalExecs; + } + + void reset() noexcept { + startTime = -1; + minTime = -1; + maxTime = -1; + last = -1; + total = 0; + totalExecs = 0; + } + +private: + int64_t time() const noexcept { + return std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(); + } + + int64_t startTime = -1; + double minTime = -1; + double maxTime = -1; + double last = -1; + double total = 0; + uint_fast32_t totalExecs = 0; +}; diff --git a/vcproj/otxserver.vcxproj b/vcproj/otxserver.vcxproj index cdf4fc3f7..7d41505c8 100644 --- a/vcproj/otxserver.vcxproj +++ b/vcproj/otxserver.vcxproj @@ -211,6 +211,7 @@ +