diff --git a/CMakeLists.txt b/CMakeLists.txt index 9c8ffef6c0a..e4093f4de2d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,7 +8,7 @@ cmake_minimum_required(VERSION 3.22 FATAL_ERROR) # VCPKG # cmake -DCMAKE_TOOLCHAIN_FILE=/opt/workspace/vcpkg/scripts/buildsystems/vcpkg.cmake .. # Needed libs is in file vcpkg.json -# Windows required libs: .\vcpkg install --triplet x64-windows asio pugixml spdlog curl jsoncpp protobuf parallel-hashmap magic-enum mio luajit libmariadb mpir abseil +# Windows required libs: .\vcpkg install --triplet x64-windows asio pugixml spdlog curl protobuf parallel-hashmap magic-enum mio luajit libmariadb mpir abseil if(DEFINED ENV{VCPKG_ROOT} AND NOT DEFINED CMAKE_TOOLCHAIN_FILE) set(CMAKE_TOOLCHAIN_FILE "$ENV{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake" CACHE STRING "") @@ -48,11 +48,18 @@ include(LoggingHelper) option(OPTIONS_ENABLE_CCACHE "Enable ccache" OFF) option(OPTIONS_ENABLE_SCCACHE "Use sccache to speed up compilation process" OFF) option(OPTIONS_ENABLE_IPO "Check and Enable interprocedural optimization (IPO/LTO)" ON) +option(FEATURE_METRICS "Enable metrics feature" OFF) # ***************************************************************************** # Options Code # ***************************************************************************** +if(FEATURE_METRIC) + log_option_enabled("metrics") +else () + log_option_disabled("metrics") +endif () + # === CCACHE === if(OPTIONS_ENABLE_CCACHE) find_program(CCACHE ccache) diff --git a/cmake/modules/BaseConfig.cmake b/cmake/modules/BaseConfig.cmake index 6f58a2eebdb..7e3f6404b3f 100644 --- a/cmake/modules/BaseConfig.cmake +++ b/cmake/modules/BaseConfig.cmake @@ -31,10 +31,11 @@ find_package(ZLIB REQUIRED) find_package(absl CONFIG REQUIRED) find_package(asio CONFIG REQUIRED) find_package(eventpp CONFIG REQUIRED) -find_package(jsoncpp CONFIG REQUIRED) find_package(magic_enum CONFIG REQUIRED) -find_package(opentelemetry-cpp CONFIG REQUIRED) -find_package(prometheus-cpp CONFIG REQUIRED) +if(FEATURE_METRICS) + find_package(opentelemetry-cpp CONFIG REQUIRED) + find_package(prometheus-cpp CONFIG REQUIRED) +endif() find_package(mio REQUIRED) find_package(pugixml CONFIG REQUIRED) find_package(spdlog REQUIRED) diff --git a/cmake/modules/CanaryLib.cmake b/cmake/modules/CanaryLib.cmake index 4838935f19e..a3f5410b9d8 100644 --- a/cmake/modules/CanaryLib.cmake +++ b/cmake/modules/CanaryLib.cmake @@ -105,17 +105,25 @@ target_link_libraries(${PROJECT_NAME}_lib unofficial::argon2::libargon2 unofficial::libmariadb unofficial::mariadbclient - opentelemetry-cpp::common - opentelemetry-cpp::metrics - opentelemetry-cpp::api - opentelemetry-cpp::ext - opentelemetry-cpp::sdk - opentelemetry-cpp::logs - opentelemetry-cpp::ostream_metrics_exporter - opentelemetry-cpp::prometheus_exporter protobuf ) +if(FEATURE_METRICS) + add_definitions(-DFEATURE_METRICS) + + target_link_libraries(${PROJECT_NAME}_lib + PUBLIC + opentelemetry-cpp::common + opentelemetry-cpp::metrics + opentelemetry-cpp::api + opentelemetry-cpp::ext + opentelemetry-cpp::sdk + opentelemetry-cpp::logs + opentelemetry-cpp::ostream_metrics_exporter + opentelemetry-cpp::prometheus_exporter + ) +endif() + if(CMAKE_BUILD_TYPE MATCHES Debug) target_link_libraries(${PROJECT_NAME}_lib PUBLIC ${ZLIB_LIBRARY_DEBUG}) else() @@ -124,16 +132,14 @@ endif() if (MSVC) if(BUILD_STATIC_LIBRARY) - target_link_libraries(${PROJECT_NAME}_lib PUBLIC jsoncpp_static) set(VCPKG_TARGET_TRIPLET "x64-windows-static" CACHE STRING "") else() - target_link_libraries(${PROJECT_NAME}_lib PUBLIC jsoncpp_lib) set(VCPKG_TARGET_TRIPLET "x64-windows" CACHE STRING "") endif() target_link_libraries(${PROJECT_NAME}_lib PUBLIC ${CMAKE_THREAD_LIBS_INIT} ${MYSQL_CLIENT_LIBS}) else() - target_link_libraries(${PROJECT_NAME}_lib PUBLIC jsoncpp_static Threads::Threads) + target_link_libraries(${PROJECT_NAME}_lib PUBLIC Threads::Threads) endif (MSVC) # === OpenMP === diff --git a/config.lua.dist b/config.lua.dist index a5bb3d73ca5..0507b652e29 100644 --- a/config.lua.dist +++ b/config.lua.dist @@ -212,6 +212,8 @@ wheelAtelierRevealGreaterCost = 6000000 familiarTime = 30 partyAutoShareExperience = true +-- partyShareRangeMultiplier: the range of the party share experience, default 3/2 (1.5) +partyShareRangeMultiplier = 1.5 partyShareLootBoosts = false partyShareLootBoostsDimishingFactor = 0.7 @@ -239,6 +241,7 @@ onlyPremiumAccount = false -- NOTE: enablePlayerPutItemInAmmoSlot = true, will enable players to put any items on ammo slot, more used in custom shopping system -- NOTE: startStreakLevel will make a reward streak level for new players who never logged in -- NOTE: if showLootsInBestiary is true, will cause all loots to be shown in the bestiary even if the player has not reached the required number of kills +-- NOTE: minTownIdToBankTransfer blocks towns less than defined from receiving money transfers stashMoving = false depotChest = 4 autoLoot = false @@ -257,6 +260,7 @@ storeInboxMaxLimit = 2000 enablePlayerPutItemInAmmoSlot = false startStreakLevel = 0 showLootsInBestiary = false +minTownIdToBankTransfer = 3 -- Teleport summon -- Set to true will never remove the summon diff --git a/data-otservbr-global/lib/core/storages.lua b/data-otservbr-global/lib/core/storages.lua index 50d4d409379..87588037ac7 100644 --- a/data-otservbr-global/lib/core/storages.lua +++ b/data-otservbr-global/lib/core/storages.lua @@ -106,7 +106,6 @@ Storage = { -- unused ExerciseDummyExhaust = 30029, SamsOldBackpack = 30030, SamsOldBackpackDoor = 30031, - StrawberryCupcake = 30032, ChayenneReward = 30033, SwampDiggingTimeout = 30034, HydraEggQuest = 30035, @@ -125,8 +124,6 @@ Storage = { Navigator = 30048, DwarvenLegs = 30049, PrinceDrazzakTime = 30050, - LemonCupcake = 30052, - BlueberryCupcake = 30053, -- Reserved in Global.Storage.FamiliarSummonEvent10 = 30054 -- Reserved in Global.Storage.FamiliarSummonEvent60 = 30055 ChayenneKeyTime = 30056, diff --git a/data-otservbr-global/npc/asnarus.lua b/data-otservbr-global/npc/asnarus.lua index a733d90834b..3992d513e9b 100644 --- a/data-otservbr-global/npc/asnarus.lua +++ b/data-otservbr-global/npc/asnarus.lua @@ -56,7 +56,7 @@ npcConfig.shop = { { itemName = "animate dead rune", clientId = 3203, buy = 375 }, { itemName = "arrow", clientId = 3447, buy = 2 }, { itemName = "blue quiver", clientId = 35848, buy = 400 }, - { itemName = "bolt", clientId = 3483, buy = 4 }, + { itemName = "bolt", clientId = 3446, buy = 4 }, { itemName = "bow", clientId = 3350, buy = 400, sell = 100 }, { itemName = "bowl of terror sweat", clientId = 20204, sell = 500 }, { itemName = "broken visor", clientId = 20184, sell = 1900 }, diff --git a/data-otservbr-global/npc/hireling.lua b/data-otservbr-global/npc/hireling.lua index 145d846bd7e..aad7785079d 100644 --- a/data-otservbr-global/npc/hireling.lua +++ b/data-otservbr-global/npc/hireling.lua @@ -228,7 +228,7 @@ function createHirelingType(HirelingName) }, ["distance"] = { { itemName = "arrow", clientId = 3447, buy = 2 }, - { itemName = "bolt", clientId = 3483, buy = 4 }, + { itemName = "bolt", clientId = 3446, buy = 4 }, { itemName = "bow", clientId = 3350, buy = 400, sell = 100 }, { itemName = "crossbow", clientId = 3349, buy = 500, sell = 120 }, { itemName = "crystalline arrow", clientId = 15793, buy = 450 }, diff --git a/data-otservbr-global/scripts/actions/other/cup_cakes.lua b/data-otservbr-global/scripts/actions/other/cup_cakes.lua deleted file mode 100644 index a9d94dbaacd..00000000000 --- a/data-otservbr-global/scripts/actions/other/cup_cakes.lua +++ /dev/null @@ -1,51 +0,0 @@ -local data = { - [28484] = { - Type = "mana", - ExhaustStor = Storage.BlueberryCupcake, - timestamp = 10, - }, - [28485] = { - Type = "health", - ExhaustStor = Storage.StrawberryCupcake, - timestamp = 10, - }, - [28486] = { - Type = "skill", - ExhaustStor = Storage.LemonCupcake, - timestamp = 10, - }, -} - -local lemon = Condition(CONDITION_ATTRIBUTES) -lemon:setParameter(CONDITION_PARAM_TICKS, 60 * 60 * 1000) -lemon:setParameter(CONDITION_PARAM_SKILL_DISTANCE, 10) - -local cupCakes = Action() - -function cupCakes.onUse(player, item, fromPos, itemEx, toPos) - local foundItem = data[item.itemid] - if not foundItem then - return - end - if (player:getStorageValue(foundItem.ExhaustStor)) < os.time() then - if foundItem.Type == "mana" then - player:addMana(player:getMaxMana()) - player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "Your mana has been refilled.") - elseif foundItem.Type == "health" then - player:addHealth(player:getMaxHealth()) - player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "Your health has been refilled.") - elseif foundItem.Type == "skill" then - player:addCondition(lemon) - player:sendTextMessage(MESSAGE_FAILURE, "You feel more focused.") - end - player:say("Mmmm.", TALKTYPE_MONSTER_SAY) - item:remove(1) - player:setStorageValue(foundItem.ExhaustStor, os.time() + (foundItem.timestamp * 60)) - else - player:sendTextMessage(MESSAGE_FAILURE, "You need to wait before using it again.") - end - return true -end - -cupCakes:id(28484, 28485, 28486) -cupCakes:register() diff --git a/data/items/items.xml b/data/items/items.xml index b1a1c6b003f..765c6e9db51 100644 --- a/data/items/items.xml +++ b/data/items/items.xml @@ -34797,7 +34797,7 @@ - + diff --git a/data/modules/scripts/daily_reward/daily_reward.lua b/data/modules/scripts/daily_reward/daily_reward.lua index 815a7e2611c..1f0e805704c 100644 --- a/data/modules/scripts/daily_reward/daily_reward.lua +++ b/data/modules/scripts/daily_reward/daily_reward.lua @@ -462,14 +462,12 @@ function Player.selectDailyReward(self, msg) local description = "" for k, v in ipairs(items) do if dailyTable.itemCharges then - for i = 1, rewardCount do - local inboxItem = inbox:addItem(v.itemId, dailyTable.itemCharges) -- adding charges for each item - if inboxItem then - inboxItem:setAttribute(ITEM_ATTRIBUTE_STORE, systemTime()) - end + local inboxItem = inbox:addItem(v.itemId, dailyTable.itemCharges) -- adding charges for each item + if inboxItem then + inboxItem:setAttribute(ITEM_ATTRIBUTE_STORE, systemTime()) end else - local inboxItem = inbox:addItem(v.itemId, rewardCount) -- adding single item w/o charges + local inboxItem = inbox:addItem(v.itemId, v.count) -- adding single item w/o charges if inboxItem then inboxItem:setAttribute(ITEM_ATTRIBUTE_STORE, systemTime()) end diff --git a/data/modules/scripts/gamestore/init.lua b/data/modules/scripts/gamestore/init.lua index a927715cd93..6146f562307 100644 --- a/data/modules/scripts/gamestore/init.lua +++ b/data/modules/scripts/gamestore/init.lua @@ -402,7 +402,7 @@ function parseBuyStoreOffer(playerId, msg) -- All guarding conditions under which the offer should not be processed must be included here if - (table.contains(GameStore.OfferTypes, offer.type) == false) -- we've got an invalid offer type + not table.contains(GameStore.OfferTypes, offer.type) -- we've got an invalid offer type or not player or (player:getVocation():getId() == 0) and (not GameStore.haveOfferRook(id)) -- we don't have such offer or not offer @@ -620,7 +620,7 @@ end function Player.canBuyOffer(self, offer) local playerId = self:getId() local disabled, disabledReason = 0, "" - if offer.disabled == true or not offer.type then + if offer.disabled or not offer.type then disabled = 1 end @@ -692,8 +692,7 @@ function Player.canBuyOffer(self, offer) disabledReason = "The offer is fake." end elseif offer.type == GameStore.OfferTypes.OFFER_TYPE_MOUNT then - local hasMount = self:hasMount(offer.id) - if hasMount == true then + if self:hasMount(offer.id) then disabled = 1 disabledReason = "You already have this mount." end @@ -723,12 +722,11 @@ function Player.canBuyOffer(self, offer) disabledReason = "You already have 3 slots released." end elseif offer.type == GameStore.OfferTypes.OFFER_TYPE_EXPBOOST then - local remainingBoost = self:getExpBoostStamina() if self:getStorageValue(GameStore.Storages.expBoostCount) == 6 then disabled = 1 disabledReason = "You can't buy XP Boost for today." end - if remainingBoost > 0 then + if self:getExpBoostStamina() > 0 then disabled = 1 disabledReason = "You already have an active XP boost." end @@ -786,9 +784,9 @@ function Player.canReceiveStoreItems(self, offerId, offerCount) local inboxItems = inbox:getItems(true) local slotsOccupied = #inboxItems local maxCapacity = inbox:getMaxCapacity() - local slotsAvailable = maxCapacity - slotsOccupied if slotsOccupied + slotsNeeded > maxCapacity then + local slotsAvailable = maxCapacity - slotsOccupied return false, string.format("Not enough free slots in your store inbox. You need %d more slot(s). Currently occupied: %d/%d", slotsNeeded - slotsAvailable, slotsOccupied, maxCapacity) end @@ -1104,14 +1102,16 @@ function sendStoreTransactionHistory(playerId, page, entriesPerPage) if not player then return false end - local oldProtocol = player:getClient().version < 1200 - local totalEntries = GameStore.retrieveHistoryTotalPages(player:getAccountId()) - local totalPages = math.ceil(totalEntries / entriesPerPage) + local entries = GameStore.retrieveHistoryEntries(player:getAccountId(), page, entriesPerPage) -- this makes everything easy! if #entries == 0 then return addPlayerEvent(sendStoreError, 250, playerId, GameStore.StoreErrors.STORE_ERROR_HISTORY, "You don't have any entries yet.") end + local oldProtocol = player:getClient().version < 1200 + local totalEntries = GameStore.retrieveHistoryTotalPages(player:getAccountId()) + local totalPages = math.ceil(totalEntries / entriesPerPage) + local msg = NetworkMessage() msg:addByte(GameStore.SendingPackets.S_OpenTransactionHistory) msg:addU32(totalPages > 0 and page - 1 or 0x0) -- current page @@ -1165,10 +1165,8 @@ function sendStoreError(playerId, errorType, message) local msg = NetworkMessage() msg:addByte(GameStore.SendingPackets.S_StoreError) - msg:addByte(errorType) msg:addString(message, "sendStoreError - message") - msg:sendToPlayer(player) end @@ -1183,7 +1181,7 @@ function sendStoreBalanceUpdating(playerId, updating) msg:addByte(0x00) msg:sendToPlayer(player) - if updating == true then + if updating then sendUpdatedStoreBalances(playerId) end end @@ -1194,7 +1192,6 @@ function sendUpdatedStoreBalances(playerId) return false end - local oldProtocol = player:getClient().version < 1200 local msg = NetworkMessage() msg:addByte(GameStore.SendingPackets.S_CoinBalanceUpdating) msg:addByte(0x01) @@ -1205,6 +1202,8 @@ function sendUpdatedStoreBalances(playerId) -- Send total of coins (transferable and normal coin) msg:addU32(player:getTibiaCoins()) msg:addU32(player:getTransferableCoins()) -- How many are Transferable + + local oldProtocol = player:getClient().version < 1200 if not oldProtocol then -- How many are reserved for a Character Auction -- We currently do not have this system implemented, so we will send 0 @@ -1346,7 +1345,7 @@ end GameStore.retrieveHistoryTotalPages = function(accountId) local resultId = db.storeQuery("SELECT count(id) as total FROM store_history WHERE account_id = " .. accountId) - if resultId == false then + if not resultId then return 0 end @@ -1360,7 +1359,7 @@ GameStore.retrieveHistoryEntries = function(accountId, currentPage, entriesPerPa local offset = currentPage > 1 and entriesPerPage * (currentPage - 1) or 0 local resultId = db.storeQuery("SELECT * FROM `store_history` WHERE `account_id` = " .. accountId .. " ORDER BY `time` DESC LIMIT " .. offset .. ", " .. entriesPerPage .. ";") - if resultId ~= false then + if resultId then repeat local entry = { mode = Result.getNumber(resultId, "mode"), @@ -1602,7 +1601,7 @@ function GameStore.processStackablePurchase(player, offerId, offerCount, offerNa local countToAdd = math.min(remainingCount, stackSize) local inboxItem = inbox:addItem(offerId, countToAdd) if inboxItem then - if movable ~= true then + if not movable then inboxItem:setAttribute(ITEM_ATTRIBUTE_STORE, systemTime()) end else @@ -1631,21 +1630,32 @@ function GameStore.processHouseRelatedPurchase(player, offer) local inbox = player:getStoreInbox() if inbox then for _, itemId in ipairs(itemIds) do - for i = 1, offer.count do + if isCaskItem(itemId) then local decoKit = inbox:addItem(ITEM_DECORATION_KIT, 1) if decoKit then decoKit:setAttribute(ITEM_ATTRIBUTE_DESCRIPTION, "You bought this item in the Store.\nUnwrap it in your own house to create a <" .. ItemType(itemId):getName() .. ">.") decoKit:setCustomAttribute("unWrapId", itemId) - if isCaskItem(itemId) then - decoKit:setAttribute(ITEM_ATTRIBUTE_DATE, offer.count) - end + decoKit:setAttribute(ITEM_ATTRIBUTE_DATE, offer.count) - if offer.movable ~= true then + if not offer.movable then decoKit:setAttribute(ITEM_ATTRIBUTE_STORE, systemTime()) end end + player:sendUpdateContainer(inbox) + else + for i = 1, offer.count do + local decoKit = inbox:addItem(ITEM_DECORATION_KIT, 1) + if decoKit then + decoKit:setAttribute(ITEM_ATTRIBUTE_DESCRIPTION, "You bought this item in the Store.\nUnwrap it in your own house to create a <" .. ItemType(itemId):getName() .. ">.") + decoKit:setCustomAttribute("unWrapId", itemId) + + if not offer.movable then + decoKit:setAttribute(ITEM_ATTRIBUTE_STORE, systemTime()) + end + end + player:sendUpdateContainer(inbox) + end end - player:sendUpdateContainer(inbox) end end end @@ -1689,8 +1699,6 @@ function GameStore.processMountPurchase(player, offerId) end function GameStore.processNameChangePurchase(player, offer, productType, newName) - local playerId = player:getId() - if productType == GameStore.ClientOfferTypes.CLIENT_STORE_OFFER_NAMECHANGE then local tile = Tile(player:getPosition()) if tile then @@ -1720,11 +1728,11 @@ function GameStore.processNameChangePurchase(player, offer, productType, newName else message = "Your character has been renamed successfully." end - addPlayerEvent(sendStorePurchaseSuccessful, 500, playerId, message) + addPlayerEvent(sendStorePurchaseSuccessful, 500, player:getId(), message) player:changeName(newName) else - return addPlayerEvent(sendRequestPurchaseData, 250, playerId, offer.id, GameStore.ClientOfferTypes.CLIENT_STORE_OFFER_NAMECHANGE) + return addPlayerEvent(sendRequestPurchaseData, 250, player:getId(), offer.id, GameStore.ClientOfferTypes.CLIENT_STORE_OFFER_NAMECHANGE) end end @@ -1780,9 +1788,6 @@ function GameStore.processTempleTeleportPurchase(player) end function GameStore.processHirelingPurchase(player, offer, productType, hirelingName, chosenSex) - local playerId = player:getId() - local offerId = offer.id - if player:getClient().version < 1200 then return error({ code = 1, message = "You cannot buy hirelings on client 10, please relog on client 12 and try again." }) end @@ -1804,7 +1809,7 @@ function GameStore.processHirelingPurchase(player, offer, productType, hirelingN player:makeCoinTransaction(offer, hirelingName) local message = "You have successfully bought " .. hirelingName - return addPlayerEvent(sendStorePurchaseSuccessful, 650, playerId, message) + return addPlayerEvent(sendStorePurchaseSuccessful, 650, player:getId(), message) -- If not, we ask him to do! else if player:getHirelingsCount() >= 10 then @@ -1812,14 +1817,50 @@ function GameStore.processHirelingPurchase(player, offer, productType, hirelingN end -- TODO: Use the correct dialog (byte 0xDB) on client 1205+ -- for compatibility, request name using the change name dialog - return addPlayerEvent(sendRequestPurchaseData, 250, playerId, offerId, GameStore.ClientOfferTypes.CLIENT_STORE_OFFER_HIRELING) + return addPlayerEvent(sendRequestPurchaseData, 250, player:getId(), offer.id, GameStore.ClientOfferTypes.CLIENT_STORE_OFFER_HIRELING) end end -function GameStore.processHirelingChangeNamePurchase(player, offer, productType, newHirelingName) - local playerId = player:getId() - local offerId = offer.id +-- Hireling Helpers +local function HandleHirelingNameChange(playerId, offer, newHirelingName) + local player = Player(playerId) + if not player then + return + end + + local functionCallback = function(playerIdInFunction, data, hireling) + local playerInFunction = Player(playerIdInFunction) + if not playerInFunction then + return + end + + if not hireling then + return playerInFunction:showInfoModal("Error", "Your must select a hireling.") + end + if hireling.active > 0 then + return playerInFunction:showInfoModal("Error", "Your hireling must be inside his/her lamp.") + end + + local oldName = hireling.name + hireling.name = data.newHirelingName + + if not playerInFunction:makeCoinTransaction(data.offer, oldName .. " to " .. hireling.name) then + return playerInFunction:showInfoModal("Error", "Transaction error") + end + + local lamp = playerInFunction:findHirelingLamp(hireling:getId()) + if lamp then + lamp:setAttribute(ITEM_ATTRIBUTE_DESCRIPTION, "This mysterious lamp summons your very own personal hireling.\nThis item cannot be traded.\nThis magic lamp is the home of " .. hireling:getName() .. ".") + end + logger.debug("{} has been renamed to {}", oldName, hireling.name) + sendUpdatedStoreBalances(playerIdInFunction) + end + + player:sendHirelingSelectionModal("Choose a Hireling", "Select a hireling below", functionCallback, { offer = offer, newHirelingName = newHirelingName }) +end + +function GameStore.processHirelingChangeNamePurchase(player, offer, productType, newHirelingName) if player:getClient().version < 1200 then return error({ code = 1, @@ -1838,17 +1879,60 @@ function GameStore.processHirelingChangeNamePurchase(player, offer, productType, end) local message = "Close the store window to select which hireling should be renamed to " .. newHirelingName + local playerId = player:getId() addPlayerEvent(sendStorePurchaseSuccessful, 200, playerId, message) - addPlayerEvent(HandleHirelingNameChange, 550, playerId, offer, newHirelingName) else - return addPlayerEvent(sendRequestPurchaseData, 250, playerId, offerId, GameStore.ClientOfferTypes.CLIENT_STORE_OFFER_NAMECHANGE) + return addPlayerEvent(sendRequestPurchaseData, 250, player:getId(), offer.id, GameStore.ClientOfferTypes.CLIENT_STORE_OFFER_NAMECHANGE) end end -function GameStore.processHirelingChangeSexPurchase(player, offer) - local playerId = player:getId() +local function HandleHirelingSexChange(playerId, offer) + local player = Player(playerId) + if not player then + return + end + + local functionCallback = function(playerIdInFunction, data, hireling) + local playerInFunction = Player(playerIdInFunction) + if not playerInFunction then + return + end + + if not hireling then + return playerInFunction:showInfoModal("Error", "Your must select a hireling.") + end + if hireling.active > 0 then + return playerInFunction:showInfoModal("Error", "Your hireling must be inside his/her lamp.") + end + + if not playerInFunction:makeCoinTransaction(data.offer, hireling:getName()) then + return playerInFunction:showInfoModal("Error", "Transaction error") + end + + local changeTo, sexString, lookType + if hireling.sex == HIRELING_SEX.FEMALE then + changeTo = HIRELING_SEX.MALE + sexString = "male" + lookType = HIRELING_OUTFIT_DEFAULT.male + else + changeTo = HIRELING_SEX.FEMALE + sexString = "female" + lookType = HIRELING_OUTFIT_DEFAULT.female + end + + hireling.sex = changeTo + hireling.looktype = lookType + + logger.debug("{} sex was changed to {}", hireling:getName(), sexString) + sendUpdatedStoreBalances(playerIdInFunction) + end + + player:sendHirelingSelectionModal("Choose a Hireling", "Select a hireling below", functionCallback, { offer = offer }) +end + +function GameStore.processHirelingChangeSexPurchase(player, offer) if player:getClient().version < 1200 then return error({ code = 1, @@ -1857,8 +1941,8 @@ function GameStore.processHirelingChangeSexPurchase(player, offer) end local message = "Close the store window to select which hireling should have the sex changed." + local playerId = player:getId() addPlayerEvent(sendStorePurchaseSuccessful, 200, playerId, message) - addPlayerEvent(HandleHirelingSexChange, 550, playerId, offer) end @@ -2154,75 +2238,3 @@ function Player:openStore(serviceName) --exporting the method so other scripts c addPlayerEvent(sendShowStoreOffers, 50, playerId, category) end end - --- Hireling Helpers -function HandleHirelingNameChange(playerId, offer, newHirelingName) - local player = Player(playerId) - - local cb = function(playerId, data, hireling) - local offer = data.offer - local newHirelingName = data.newHirelingName - local player = Player(playerId) - if not hireling then - return player:showInfoModal("Error", "Your must select a hireling.") - end - - if hireling.active > 0 then - return player:showInfoModal("Error", "Your hireling must be inside his/her lamp.") - end - - local oldName = hireling.name - hireling.name = newHirelingName - - if not player:makeCoinTransaction(data.offer, oldName .. " to " .. newHirelingName) then - return player:showInfoModal("Error", "Transaction error") - end - - local lamp = player:findHirelingLamp(hireling:getId()) - if lamp then - lamp:setAttribute(ITEM_ATTRIBUTE_DESCRIPTION, "This mysterious lamp summons your very own personal hireling.\nThis item cannot be traded.\nThis magic lamp is the home of " .. hireling:getName() .. ".") - end - logger.debug("{} has been renamed to {}", oldName, newHirelingName) - sendUpdatedStoreBalances(playerId) - end - - player:sendHirelingSelectionModal("Choose a Hireling", "Select a hireling below", cb, { offer = offer, newHirelingName = newHirelingName }) -end - -function HandleHirelingSexChange(playerId, offer) - local player = Player(playerId) - - local cb = function(playerId, data, hireling) - local player = Player(playerId) - if not hireling then - return player:showInfoModal("Error", "Your must select a hireling.") - end - - if hireling.active > 0 then - return player:showInfoModal("Error", "Your hireling must be inside his/her lamp.") - end - - if not player:makeCoinTransaction(data.offer, hireling:getName()) then - return player:showInfoModal("Error", "Transaction error") - end - - local changeTo, sexString, lookType - if hireling.sex == HIRELING_SEX.FEMALE then - changeTo = HIRELING_SEX.MALE - sexString = "male" - lookType = HIRELING_OUTFIT_DEFAULT.male - else - changeTo = HIRELING_SEX.FEMALE - sexString = "female" - lookType = HIRELING_OUTFIT_DEFAULT.female - end - - hireling.sex = changeTo - hireling.looktype = lookType - - logger.debug("{} sex was changed to {}", hireling:getName(), sexString) - sendUpdatedStoreBalances(playerId) - end - - player:sendHirelingSelectionModal("Choose a Hireling", "Select a hireling below", cb, { offer = offer }) -end diff --git a/data/scripts/actions/items/blueberry_cupcake.lua b/data/scripts/actions/items/blueberry_cupcake.lua new file mode 100644 index 00000000000..f645e852101 --- /dev/null +++ b/data/scripts/actions/items/blueberry_cupcake.lua @@ -0,0 +1,18 @@ +local blueberryCupcake = Action() + +function blueberryCupcake.onUse(player, item, fromPosition, target, toPosition, isHotkey) + if player:hasExhaustion("blueberry-cupcake-cooldown") then + player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "You need to wait before using it again.") + return true + end + + player:addMana(player:getMaxMana()) + player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "Your mana has been refilled.") + player:say("Mmmm.", TALKTYPE_MONSTER_SAY) + player:setExhaustion("blueberry-cupcake-cooldown", 10 * 60) + item:remove(1) + return true +end + +blueberryCupcake:id(28484) +blueberryCupcake:register() diff --git a/data/scripts/actions/items/lemon_cupcake.lua b/data/scripts/actions/items/lemon_cupcake.lua new file mode 100644 index 00000000000..3cf085d8ad8 --- /dev/null +++ b/data/scripts/actions/items/lemon_cupcake.lua @@ -0,0 +1,24 @@ +local distanceCondition = Condition(CONDITION_ATTRIBUTES) +distanceCondition:setParameter(CONDITION_PARAM_BUFF_SPELL, 1) +distanceCondition:setParameter(CONDITION_PARAM_TICKS, 60 * 60 * 1000) +distanceCondition:setParameter(CONDITION_PARAM_SKILL_DISTANCE, 10) +distanceCondition:setParameter(CONDITION_PARAM_FORCEUPDATE, true) + +local lemonCupcake = Action() + +function lemonCupcake.onUse(player, item, fromPosition, target, toPosition, isHotkey) + if player:hasExhaustion("lemon-cupcake-cooldown") then + player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "You need to wait before using it again.") + return true + end + + player:addCondition(distanceCondition) + player:sendTextMessage(MESSAGE_FAILURE, "You feel more focused.") + player:say("Mmmm.", TALKTYPE_MONSTER_SAY) + player:setExhaustion("lemon-cupcake-cooldown", 10 * 60) + item:remove(1) + return true +end + +lemonCupcake:id(28486) +lemonCupcake:register() diff --git a/data/scripts/actions/items/potions.lua b/data/scripts/actions/items/potions.lua index 02e92349363..473796d79df 100644 --- a/data/scripts/actions/items/potions.lua +++ b/data/scripts/actions/items/potions.lua @@ -89,10 +89,13 @@ function flaskPotion.onUse(player, item, fromPosition, target, toPosition, isHot local deactivatedFlasks = player:kv():get("talkaction.potions.flask") or false if not deactivatedFlasks then local container = Container(item:getParent().uid) - local inbox = player:getSlotItem(CONST_SLOT_STORE_INBOX) - - if fromPosition.x == CONTAINER_POSITION and container ~= inbox and container:getEmptySlots() ~= 0 then - container:addItem(potion.flask, 1) + if container then + local storeInbox = player:getSlotItem(CONST_SLOT_STORE_INBOX) + if fromPosition.x == CONTAINER_POSITION and container ~= storeInbox and container:getEmptySlots() ~= 0 then + container:addItem(potion.flask, 1) + else + player:addItem(potion.flask, 1) + end else Game.createItem(potion.flask, 1, fromPosition) end diff --git a/data/scripts/actions/items/strawberry_cupcake.lua b/data/scripts/actions/items/strawberry_cupcake.lua new file mode 100644 index 00000000000..7ee7ec75764 --- /dev/null +++ b/data/scripts/actions/items/strawberry_cupcake.lua @@ -0,0 +1,18 @@ +local strawberryCupcake = Action() + +function strawberryCupcake.onUse(player, item, fromPosition, target, toPosition, isHotkey) + if player:hasExhaustion("strawberry-cupcake-cooldown") then + player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "You need to wait before using it again.") + return true + end + + player:addHealth(player:getMaxHealth()) + player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "Your health has been refilled.") + player:say("Mmmm.", TALKTYPE_MONSTER_SAY) + player:setExhaustion("strawberry-cupcake-cooldown", 10 * 60) + item:remove(1) + return true +end + +strawberryCupcake:id(28485) +strawberryCupcake:register() diff --git a/data/scripts/creaturescripts/player/offline_training.lua b/data/scripts/creaturescripts/player/offline_training.lua index abfb0b94b3d..4466c6ee0e3 100644 --- a/data/scripts/creaturescripts/player/offline_training.lua +++ b/data/scripts/creaturescripts/player/offline_training.lua @@ -12,7 +12,7 @@ function offlineTraining.onLogin(player) player:setOfflineTrainingSkill(SKILL_NONE) if offlineTime < 600 then - player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "You must be logged out for more than 10 minutes to start offline training.") + player:sendTextMessage(MESSAGE_OFFLINE_TRAINING, "You must be logged out for more than 10 minutes to start offline training.") return true end @@ -50,15 +50,15 @@ function offlineTraining.onLogin(player) end text = string.format("%s.", text) - player:sendTextMessage(MESSAGE_EVENT_ADVANCE, text) + player:sendTextMessage(MESSAGE_OFFLINE_TRAINING, text) local vocation = player:getVocation() local promotion = vocation:getPromotion() local topVocation = not promotion and vocation or promotion - local updateSkills = false + if table.contains({ SKILL_CLUB, SKILL_SWORD, SKILL_AXE, SKILL_DISTANCE }, offlineTrainingSkill) then - local modifier = topVocation:getBaseAttackSpeed() / 1000 + local modifier = topVocation:getBaseAttackSpeed() / 1000 / configManager.getFloat(configKeys.RATE_OFFLINE_TRAINING_SPEED) updateSkills = player:addOfflineTrainingTries(offlineTrainingSkill, (trainingTime / modifier) / (offlineTrainingSkill == SKILL_DISTANCE and 4 or 2)) elseif offlineTrainingSkill == SKILL_MAGLEVEL then local gainTicks = topVocation:getManaGainTicks() * 2 diff --git a/data/scripts/spells/conjuring/conjure_diamond_arrow.lua b/data/scripts/spells/conjuring/conjure_diamond_arrow.lua deleted file mode 100644 index 2ab4bbe0647..00000000000 --- a/data/scripts/spells/conjuring/conjure_diamond_arrow.lua +++ /dev/null @@ -1,21 +0,0 @@ -local spell = Spell("instant") - -function spell.onCastSpell(creature, variant) - return creature:conjureItem(0, 25757, 100, CONST_ME_MAGIC_BLUE) -end - -spell:group("support") -spell:id(192) -spell:name("Conjure Diamond Arrow") -spell:words("exevo gran con hur") -spell:cooldown(2 * 1000) -spell:groupCooldown(2 * 1000) -spell:level(150) -spell:mana(1000) -spell:soul(0) -spell:isPremium(true) -spell:isSelfTarget(true) -spell:isAggressive(false) -spell:vocation("paladin;true", "royal paladin;true") -spell:needLearn(false) -spell:register() diff --git a/data/scripts/spells/conjuring/conjure_spectral_bolt.lua b/data/scripts/spells/conjuring/conjure_spectral_bolt.lua deleted file mode 100644 index 336eb423139..00000000000 --- a/data/scripts/spells/conjuring/conjure_spectral_bolt.lua +++ /dev/null @@ -1,21 +0,0 @@ -local spell = Spell("instant") - -function spell.onCastSpell(creature, variant) - return creature:conjureItem(0, 35902, 100, CONST_ME_MAGIC_BLUE) -end - -spell:group("support") -spell:id(193) -spell:name("Conjure Spectral Bolt") -spell:words("exevo gran con vis") -spell:cooldown(2 * 1000) -spell:groupCooldown(2 * 1000) -spell:level(150) -spell:mana(1000) -spell:soul(0) -spell:isPremium(true) -spell:isSelfTarget(true) -spell:isAggressive(false) -spell:vocation("paladin;true", "royal paladin;true") -spell:needLearn(false) -spell:register() diff --git a/src/canary_server.cpp b/src/canary_server.cpp index 56cd53bf567..0961bc93fde 100644 --- a/src/canary_server.cpp +++ b/src/canary_server.cpp @@ -61,6 +61,7 @@ int CanaryServer::run() { loadConfigLua(); logger.info("Server protocol: {}.{}{}", CLIENT_VERSION_UPPER, CLIENT_VERSION_LOWER, g_configManager().getBoolean(OLD_PROTOCOL, __FUNCTION__) ? " and 10x allowed!" : ""); +#ifdef FEATURE_METRICS metrics::Options metricsOptions; metricsOptions.enablePrometheusExporter = g_configManager().getBoolean(METRICS_ENABLE_PROMETHEUS, __FUNCTION__); if (metricsOptions.enablePrometheusExporter) { @@ -71,7 +72,7 @@ int CanaryServer::run() { metricsOptions.ostreamOptions.export_interval_millis = std::chrono::milliseconds(g_configManager().getNumber(METRICS_OSTREAM_INTERVAL, __FUNCTION__)); } g_metrics().init(metricsOptions); - +#endif rsa.start(); initializeDatabase(); loadModules(); diff --git a/src/config/config_enums.hpp b/src/config/config_enums.hpp index b9b857f435c..4abf29c04cb 100644 --- a/src/config/config_enums.hpp +++ b/src/config/config_enums.hpp @@ -36,10 +36,10 @@ enum ConfigKey_t : uint16_t { CLASSIC_ATTACK_SPEED, CLEAN_PROTECTION_ZONES, COMBAT_CHAIN_DELAY, - COMBAT_CHAIN_TARGETS, COMBAT_CHAIN_SKILL_FORMULA_AXE, COMBAT_CHAIN_SKILL_FORMULA_CLUB, COMBAT_CHAIN_SKILL_FORMULA_SWORD, + COMBAT_CHAIN_TARGETS, COMPRESSION_LEVEL, CONVERT_UNSAFE_SCRIPTS, CORE_DIRECTORY, @@ -155,6 +155,7 @@ enum ConfigKey_t : uint16_t { METRICS_PROMETHEUS_ADDRESS, MIN_DELAY_BETWEEN_CONDITIONS, MIN_ELEMENTAL_RESISTANCE, + MIN_TOWN_ID_TO_BANK_TRANSFER, MOMENTUM_CHANCE_FORMULA_A, MOMENTUM_CHANCE_FORMULA_B, MOMENTUM_CHANCE_FORMULA_C, @@ -178,6 +179,7 @@ enum ConfigKey_t : uint16_t { OWNER_NAME, PARALLELISM, PARTY_AUTO_SHARE_EXPERIENCE, + PARTY_SHARE_RANGE_MULTIPLIER, PARTY_LIST_MAX_DISTANCE, PARTY_SHARE_LOOT_BOOSTS_DIMINISHING_FACTOR, PARTY_SHARE_LOOT_BOOSTS, diff --git a/src/config/configmanager.cpp b/src/config/configmanager.cpp index c1702672e71..8d4ba7a77da 100644 --- a/src/config/configmanager.cpp +++ b/src/config/configmanager.cpp @@ -166,6 +166,9 @@ bool ConfigManager::load() { loadBoolConfig(L, XP_DISPLAY_MODE, "experienceDisplayRates", true); loadFloatConfig(L, BESTIARY_RATE_CHARM_SHOP_PRICE, "bestiaryRateCharmShopPrice", 1.0); + loadFloatConfig(L, COMBAT_CHAIN_SKILL_FORMULA_AXE, "combatChainSkillFormulaAxe", 0.9); + loadFloatConfig(L, COMBAT_CHAIN_SKILL_FORMULA_CLUB, "combatChainSkillFormulaClub", 0.7); + loadFloatConfig(L, COMBAT_CHAIN_SKILL_FORMULA_SWORD, "combatChainSkillFormulaSword", 1.1); loadFloatConfig(L, FORGE_AMOUNT_MULTIPLIER, "forgeAmountMultiplier", 3.0); loadFloatConfig(L, HAZARD_EXP_BONUS_MULTIPLIER, "hazardExpBonusMultiplier", 2.0); loadFloatConfig(L, LOYALTY_BONUS_PERCENTAGE_MULTIPLIER, "loyaltyBonusPercentageMultiplier", 1.0); @@ -218,9 +221,6 @@ bool ConfigManager::load() { loadIntConfig(L, CHECK_EXPIRED_MARKET_OFFERS_EACH_MINUTES, "checkExpiredMarketOffersEachMinutes", 60); loadIntConfig(L, COMBAT_CHAIN_DELAY, "combatChainDelay", 50); loadIntConfig(L, COMBAT_CHAIN_TARGETS, "combatChainTargets", 5); - loadFloatConfig(L, COMBAT_CHAIN_SKILL_FORMULA_AXE, "combatChainSkillFormulaAxe", 0.9); - loadFloatConfig(L, COMBAT_CHAIN_SKILL_FORMULA_CLUB, "combatChainSkillFormulaClub", 0.7); - loadFloatConfig(L, COMBAT_CHAIN_SKILL_FORMULA_SWORD, "combatChainSkillFormulaSword", 1.1); loadIntConfig(L, COMPRESSION_LEVEL, "packetCompressionLevel", 6); loadIntConfig(L, CRITICALCHANCE, "criticalChance", 10); loadIntConfig(L, DAY_KILLS_TO_RED, "dayKillsToRedSkull", 3); @@ -287,6 +287,7 @@ bool ConfigManager::load() { loadIntConfig(L, METRICS_OSTREAM_INTERVAL, "metricsOstreamInterval", 1000); loadIntConfig(L, MIN_DELAY_BETWEEN_CONDITIONS, "minDelayBetweenConditions", 0); loadIntConfig(L, MIN_ELEMENTAL_RESISTANCE, "minElementalResistance", -200); + loadIntConfig(L, MIN_TOWN_ID_TO_BANK_TRANSFER, "minTownIdToBankTransfer", 3); loadIntConfig(L, MONTH_KILLS_TO_RED, "monthKillsToRedSkull", 10); loadIntConfig(L, MULTIPLIER_ATTACKONFIST, "multiplierSpeedOnFist", 5); loadIntConfig(L, ORANGE_SKULL_DURATION, "orangeSkullDuration", 7); @@ -317,6 +318,7 @@ bool ConfigManager::load() { loadIntConfig(L, STAMINA_PZ_GAIN, "staminaPzGain", 1); loadIntConfig(L, STAMINA_TRAINER_DELAY, "staminaTrainerDelay", 5); loadIntConfig(L, STAMINA_TRAINER_GAIN, "staminaTrainerGain", 1); + loadFloatConfig(L, PARTY_SHARE_RANGE_MULTIPLIER, "partyShareRangeMultiplier", 1.5f); loadIntConfig(L, START_STREAK_LEVEL, "startStreakLevel", 0); loadIntConfig(L, STATUSQUERY_TIMEOUT, "statusTimeout", 5000); loadIntConfig(L, STORE_COIN_PACKET, "coinPacketSize", 25); diff --git a/src/creatures/combat/condition.cpp b/src/creatures/combat/condition.cpp index d54a3deb1d0..9d0f6962884 100644 --- a/src/creatures/combat/condition.cpp +++ b/src/creatures/combat/condition.cpp @@ -2041,7 +2041,11 @@ bool ConditionFeared::executeCondition(std::shared_ptr creature, int32 } if (getFleePath(creature, currentPos, listDir)) { - g_dispatcher().addEvent(std::bind(&Game::forcePlayerAutoWalk, &g_game(), creature->getID(), listDir.data()), "ConditionFeared::executeCondition"); + g_dispatcher().addEvent([id = creature->getID(), listDir = listDir.data()] { + g_game().forcePlayerAutoWalk(id, listDir); + }, + "ConditionFeared::executeCondition"); + g_logger().debug("[ConditionFeared::executeCondition] Walking Scheduled"); } } diff --git a/src/creatures/creature.cpp b/src/creatures/creature.cpp index d17ee454402..6101ff0473d 100644 --- a/src/creatures/creature.cpp +++ b/src/creatures/creature.cpp @@ -258,8 +258,8 @@ void Creature::addEventWalk(bool firstStep) { } self->eventWalk = g_dispatcher().scheduleEvent( - static_cast(ticks), std::bind(&Game::checkCreatureWalk, &g_game(), self->getID()), - "Creature::checkCreatureWalk" + static_cast(ticks), + [creatureId = self->getID()] { g_game().checkCreatureWalk(creatureId); }, "Creature::checkCreatureWalk" ); }); } @@ -600,7 +600,7 @@ void Creature::onCreatureMove(const std::shared_ptr &creature, const s if (followCreature && (creature == getCreature() || creature == followCreature)) { if (hasFollowPath) { isUpdatingPath = true; - g_dispatcher().addEvent(std::bind(&Game::updateCreatureWalk, &g_game(), getID()), "Game::updateCreatureWalk"); + g_dispatcher().addEvent([creatureId = getID()] { g_game().updateCreatureWalk(creatureId); }, "Game::updateCreatureWalk"); } if (newPos.z != oldPos.z || !canSee(followCreature->getPosition())) { @@ -615,7 +615,7 @@ void Creature::onCreatureMove(const std::shared_ptr &creature, const s } else { if (hasExtraSwing()) { // our target is moving lets see if we can get in hit - g_dispatcher().addEvent(std::bind(&Game::checkCreatureAttack, &g_game(), getID()), "Game::checkCreatureAttack"); + g_dispatcher().addEvent([creatureId = getID()] { g_game().checkCreatureAttack(creatureId); }, "Game::checkCreatureAttack"); } if (newTile->getZoneType() != oldTile->getZoneType()) { @@ -813,11 +813,21 @@ bool Creature::dropCorpse(std::shared_ptr lastHitCreature, std::shared player->sendLootMessage(lootMessage.str()); } - if (player->checkAutoLoot(monster->isRewardBoss()) && corpseContainer && mostDamageCreature->getPlayer()) { - g_dispatcher().addEvent( - std::bind(&Game::playerQuickLootCorpse, &g_game(), player, corpseContainer, corpse->getPosition()), - "Game::playerQuickLootCorpse" - ); + stdext::arraylist dirList(128); + FindPathParams fpp; + fpp.minTargetDist = 0; + fpp.maxTargetDist = 1; + fpp.fullPathSearch = true; + fpp.clearSight = true; + fpp.maxSearchDist = 0; + + auto isReachable = g_game().map.getPathMatching(player->getPosition(), dirList, FrozenPathingConditionCall(corpse->getPosition()), fpp); + + if (player->checkAutoLoot(monster->isRewardBoss()) && corpseContainer && mostDamageCreature->getPlayer() && isReachable) { + g_dispatcher().addEvent([player, corpseContainer, corpsePosition = corpse->getPosition()] { + g_game().playerQuickLootCorpse(player, corpseContainer, corpsePosition); + }, + "Game::playerQuickLootCorpse"); } } } @@ -861,7 +871,7 @@ void Creature::changeHealth(int32_t healthChange, bool sendHealthChange /* = tru g_game().addCreatureHealth(static_self_cast()); } if (health <= 0) { - g_dispatcher().addEvent(std::bind(&Game::executeDeath, &g_game(), getID()), "Game::executeDeath"); + g_dispatcher().addEvent([creatureId = getID()] { g_game().executeDeath(creatureId); }, "Game::executeDeath"); } } @@ -1401,9 +1411,7 @@ void Creature::removeCondition(ConditionType_t conditionType, ConditionId_t cond int32_t walkDelay = getWalkDelay(); if (walkDelay > 0) { g_dispatcher().scheduleEvent( - walkDelay, - std::bind(&Game::forceRemoveCondition, &g_game(), getID(), conditionType, conditionId), - "Game::forceRemoveCondition" + walkDelay, [creatureId = getID(), conditionType, conditionId] { g_game().forceRemoveCondition(creatureId, conditionType, conditionId); }, "Game::forceRemoveCondition" ); return; } diff --git a/src/creatures/interactions/chat.cpp b/src/creatures/interactions/chat.cpp index f30c3f219e3..e16af670fcc 100644 --- a/src/creatures/interactions/chat.cpp +++ b/src/creatures/interactions/chat.cpp @@ -81,7 +81,9 @@ bool ChatChannel::addUser(const std::shared_ptr &player) { if (id == CHANNEL_GUILD) { const auto guild = player->getGuild(); if (guild && !guild->getMotd().empty()) { - g_dispatcher().scheduleEvent(150, std::bind(&Game::sendGuildMotd, &g_game(), player->getID()), "Game::sendGuildMotd"); + g_dispatcher().scheduleEvent( + 150, [playerId = player->getID()] { g_game().sendGuildMotd(playerId); }, "Game::sendGuildMotd" + ); } } diff --git a/src/creatures/monsters/monster.cpp b/src/creatures/monsters/monster.cpp index 5f31c67aa72..f15616d6af5 100644 --- a/src/creatures/monsters/monster.cpp +++ b/src/creatures/monsters/monster.cpp @@ -668,7 +668,7 @@ bool Monster::selectTarget(const std::shared_ptr &creature) { if (isHostile() || isSummon()) { if (setAttackedCreature(creature)) { - g_dispatcher().addEvent(std::bind(&Game::checkCreatureAttack, &g_game(), getID()), "Game::checkCreatureAttack"); + g_dispatcher().addEvent([creatureId = getID()] { g_game().checkCreatureAttack(creatureId); }, "Game::checkCreatureAttack"); } } return setFollowCreature(creature); diff --git a/src/creatures/monsters/spawns/spawn_monster.cpp b/src/creatures/monsters/spawns/spawn_monster.cpp index aec222d723a..21eab1a7c0b 100644 --- a/src/creatures/monsters/spawns/spawn_monster.cpp +++ b/src/creatures/monsters/spawns/spawn_monster.cpp @@ -141,7 +141,9 @@ bool SpawnsMonster::isInZone(const Position ¢erPos, int32_t radius, const Po void SpawnMonster::startSpawnMonsterCheck() { if (checkSpawnMonsterEvent == 0) { - checkSpawnMonsterEvent = g_dispatcher().scheduleEvent(getInterval(), std::bind(&SpawnMonster::checkSpawnMonster, this), "SpawnMonster::checkSpawnMonster"); + checkSpawnMonsterEvent = g_dispatcher().scheduleEvent( + getInterval(), [this] { checkSpawnMonster(); }, "SpawnMonster::checkSpawnMonster" + ); } } @@ -178,6 +180,7 @@ bool SpawnMonster::spawnMonster(uint32_t spawnMonsterId, spawnBlock_t &sb, const return false; } } else { + g_logger().debug("[SpawnMonster] Spawning {} at {}", monsterType->name, sb.pos.toString()); if (!g_game().placeCreature(monster, sb.pos, false, true)) { return false; } @@ -225,7 +228,7 @@ void SpawnMonster::startup(bool delayed) { continue; } if (delayed) { - g_dispatcher().addEvent(std::bind(&SpawnMonster::scheduleSpawn, this, spawnMonsterId, sb, mType, 0, true), "SpawnMonster::startup"); + g_dispatcher().addEvent([this, spawnMonsterId, &sb, mType] { scheduleSpawn(spawnMonsterId, sb, mType, 0, true); }, "SpawnMonster::startup"); } else { scheduleSpawn(spawnMonsterId, sb, mType, 0, true); } @@ -258,14 +261,16 @@ void SpawnMonster::checkSpawnMonster() { } if (mType->info.isBlockable) { - spawnMonster(spawnMonsterId, sb, mType, true); + spawnMonster(spawnMonsterId, sb, mType); } else { scheduleSpawn(spawnMonsterId, sb, mType, 3 * NONBLOCKABLE_SPAWN_MONSTER_INTERVAL); } } if (spawnedMonsterMap.size() < spawnMonsterMap.size()) { - checkSpawnMonsterEvent = g_dispatcher().scheduleEvent(getInterval(), std::bind(&SpawnMonster::checkSpawnMonster, this), "SpawnMonster::checkSpawnMonster"); + checkSpawnMonsterEvent = g_dispatcher().scheduleEvent( + getInterval(), [this] { checkSpawnMonster(); }, "SpawnMonster::checkSpawnMonster" + ); } } @@ -274,7 +279,9 @@ void SpawnMonster::scheduleSpawn(uint32_t spawnMonsterId, spawnBlock_t &sb, cons spawnMonster(spawnMonsterId, sb, mType, startup); } else { g_game().addMagicEffect(sb.pos, CONST_ME_TELEPORT); - g_dispatcher().scheduleEvent(NONBLOCKABLE_SPAWN_MONSTER_INTERVAL, std::bind(&SpawnMonster::scheduleSpawn, this, spawnMonsterId, sb, mType, interval - NONBLOCKABLE_SPAWN_MONSTER_INTERVAL, startup), "SpawnMonster::scheduleSpawn"); + g_dispatcher().scheduleEvent( + NONBLOCKABLE_SPAWN_MONSTER_INTERVAL, [=, this, &sb] { scheduleSpawn(spawnMonsterId, sb, mType, interval - NONBLOCKABLE_SPAWN_MONSTER_INTERVAL, startup); }, "SpawnMonster::scheduleSpawn" + ); } } diff --git a/src/creatures/npcs/npc.cpp b/src/creatures/npcs/npc.cpp index 0f9f60cec9b..d347ec6b66c 100644 --- a/src/creatures/npcs/npc.cpp +++ b/src/creatures/npcs/npc.cpp @@ -351,7 +351,9 @@ void Npc::onPlayerSellAllLoot(uint32_t playerId, uint16_t itemId, bool ignore, u return; } if (hasMore) { - g_dispatcher().scheduleEvent(SCHEDULER_MINTICKS, std::bind(&Npc::onPlayerSellAllLoot, this, player->getID(), itemId, ignore, totalPrice), __FUNCTION__); + g_dispatcher().scheduleEvent( + SCHEDULER_MINTICKS, [this, playerId = player->getID(), itemId, ignore, totalPrice] { onPlayerSellAllLoot(playerId, itemId, ignore, totalPrice); }, __FUNCTION__ + ); return; } ss << "You sold all of the items from your loot pouch for "; @@ -366,7 +368,9 @@ void Npc::onPlayerSellItem(std::shared_ptr player, uint16_t itemId, uint return; } if (itemId == ITEM_GOLD_POUCH) { - g_dispatcher().scheduleEvent(SCHEDULER_MINTICKS, std::bind(&Npc::onPlayerSellAllLoot, this, player->getID(), itemId, ignore, 0), __FUNCTION__); + g_dispatcher().scheduleEvent( + SCHEDULER_MINTICKS, [this, playerId = player->getID(), itemId, ignore] { onPlayerSellAllLoot(playerId, itemId, ignore, 0); }, __FUNCTION__ + ); return; } diff --git a/src/creatures/npcs/spawns/spawn_npc.cpp b/src/creatures/npcs/spawns/spawn_npc.cpp index 7fd99d6c37f..968deca5331 100644 --- a/src/creatures/npcs/spawns/spawn_npc.cpp +++ b/src/creatures/npcs/spawns/spawn_npc.cpp @@ -131,7 +131,9 @@ bool SpawnsNpc::isInZone(const Position ¢erPos, int32_t radius, const Positi void SpawnNpc::startSpawnNpcCheck() { if (checkSpawnNpcEvent == 0) { - checkSpawnNpcEvent = g_dispatcher().scheduleEvent(getInterval(), std::bind(&SpawnNpc::checkSpawnNpc, this), "SpawnNpc::checkSpawnNpc"); + checkSpawnNpcEvent = g_dispatcher().scheduleEvent( + getInterval(), [this] { checkSpawnNpc(); }, "SpawnNpc::checkSpawnNpc" + ); } } @@ -217,7 +219,9 @@ void SpawnNpc::checkSpawnNpc() { } if (spawnedNpcMap.size() < spawnNpcMap.size()) { - checkSpawnNpcEvent = g_dispatcher().scheduleEvent(getInterval(), std::bind(&SpawnNpc::checkSpawnNpc, this), __FUNCTION__); + checkSpawnNpcEvent = g_dispatcher().scheduleEvent( + getInterval(), [this] { checkSpawnNpc(); }, __FUNCTION__ + ); } } @@ -226,7 +230,9 @@ void SpawnNpc::scheduleSpawnNpc(uint32_t spawnId, spawnBlockNpc_t &sb, uint16_t spawnNpc(spawnId, sb.npcType, sb.pos, sb.direction); } else { g_game().addMagicEffect(sb.pos, CONST_ME_TELEPORT); - g_dispatcher().scheduleEvent(1400, std::bind(&SpawnNpc::scheduleSpawnNpc, this, spawnId, sb, interval - NONBLOCKABLE_SPAWN_NPC_INTERVAL), __FUNCTION__); + g_dispatcher().scheduleEvent( + 1400, [=, this, &sb] { scheduleSpawnNpc(spawnId, sb, interval - NONBLOCKABLE_SPAWN_NPC_INTERVAL); }, __FUNCTION__ + ); } } diff --git a/src/creatures/players/grouping/party.cpp b/src/creatures/players/grouping/party.cpp index 880fc77594f..c7d6fd48363 100644 --- a/src/creatures/players/grouping/party.cpp +++ b/src/creatures/players/grouping/party.cpp @@ -491,6 +491,10 @@ SharedExpStatus_t Party::getMemberSharedExperienceStatus(std::shared_ptr return SHAREDEXP_OK; } +float Party::shareRangeMultiplier() const { + return g_configManager().getFloat(PARTY_SHARE_RANGE_MULTIPLIER, __FUNCTION__); +} + uint32_t Party::getHighestLevel() { auto leader = getLeader(); if (!leader) { @@ -507,7 +511,7 @@ uint32_t Party::getHighestLevel() { } uint32_t Party::getMinLevel() { - return static_cast(std::ceil((static_cast(getHighestLevel()) * 2) / 3)); + return static_cast(std::ceil(static_cast(getHighestLevel()) / shareRangeMultiplier())); } uint32_t Party::getLowestLevel() { @@ -525,7 +529,7 @@ uint32_t Party::getLowestLevel() { } uint32_t Party::getMaxLevel() { - return static_cast(std::floor((static_cast(getLowestLevel()) * 3) / 2)); + return static_cast(std::floor(static_cast(getLowestLevel()) * shareRangeMultiplier())); } bool Party::isPlayerActive(std::shared_ptr player) { @@ -533,7 +537,6 @@ bool Party::isPlayerActive(std::shared_ptr player) { if (it == ticksMap.end()) { return false; } - uint64_t timeDiff = OTSYS_TIME() - it->second; return timeDiff <= 2 * 60 * 1000; } diff --git a/src/creatures/players/grouping/party.hpp b/src/creatures/players/grouping/party.hpp index a356d1a032b..5da0f4e0647 100644 --- a/src/creatures/players/grouping/party.hpp +++ b/src/creatures/players/grouping/party.hpp @@ -133,6 +133,7 @@ class Party : public SharedObject { uint32_t getLowestLevel(); uint32_t getMinLevel(); uint32_t getMaxLevel(); + float shareRangeMultiplier() const; std::map ticksMap; diff --git a/src/creatures/players/player.cpp b/src/creatures/players/player.cpp index 874089e5602..75e5b5ef2af 100644 --- a/src/creatures/players/player.cpp +++ b/src/creatures/players/player.cpp @@ -1934,7 +1934,7 @@ void Player::onCreatureMove(const std::shared_ptr &creature, const std const auto &followCreature = getFollowCreature(); if (hasFollowPath && (creature == followCreature || (creature.get() == this && followCreature))) { isUpdatingPath = false; - g_dispatcher().addEvent(std::bind(&Game::updateCreatureWalk, &g_game(), getID()), "Game::updateCreatureWalk"); + g_dispatcher().addEvent([creatureId = getID()] { g_game().updateCreatureWalk(creatureId); }, "Game::updateCreatureWalk"); } if (creature != getPlayer()) { @@ -4245,7 +4245,7 @@ bool Player::updateSaleShopList(std::shared_ptr item) { return true; } - g_dispatcher().addEvent(std::bind(&Game::updatePlayerSaleItems, &g_game(), getID()), "updatePlayerSaleItems"); + g_dispatcher().addEvent([creatureId = getID()] { g_game().updatePlayerSaleItems(creatureId); }, "Game::updatePlayerSaleItems"); scheduledSaleUpdate = true; return true; } @@ -4316,7 +4316,7 @@ bool Player::setAttackedCreature(std::shared_ptr creature) { } if (creature) { - g_dispatcher().addEvent(std::bind(&Game::checkCreatureAttack, &g_game(), getID()), "Game::checkCreatureAttack"); + g_dispatcher().addEvent([creatureId = getID()] { g_game().checkCreatureAttack(creatureId); }, "Game::checkCreatureAttack"); } return true; } @@ -4376,7 +4376,11 @@ void Player::doAttacking(uint32_t) { result = Weapon::useFist(static_self_cast(), attackedCreature); } - std::shared_ptr task = createPlayerTask(std::max(SCHEDULER_MINTICKS, delay), std::bind(&Game::checkCreatureAttack, &g_game(), getID()), "Game::checkCreatureAttack"); + const auto &task = createPlayerTask( + std::max(SCHEDULER_MINTICKS, delay), + [playerId = getID()] { g_game().checkCreatureAttack(playerId); }, "Game::checkCreatureAttack" + ); + if (!classicSpeed) { setNextActionTask(task, false); } else { @@ -6448,7 +6452,7 @@ void Player::stowItem(std::shared_ptr item, uint32_t count, bool allItems) // Stow locker items std::shared_ptr depotLocker = getDepotLocker(getLastDepotId()); auto [itemVector, itemMap] = requestLockerItems(depotLocker); - for (auto lockerItem : itemVector) { + for (const auto &lockerItem : itemVector) { if (lockerItem == nullptr) { break; } @@ -6459,7 +6463,7 @@ void Player::stowItem(std::shared_ptr item, uint32_t count, bool allItems) } } else if (item->getContainer()) { itemDict = item->getContainer()->getStowableItems(); - for (std::shared_ptr containerItem : item->getContainer()->getItems(true)) { + for (const std::shared_ptr &containerItem : item->getContainer()->getItems(true)) { uint32_t depotChest = g_configManager().getNumber(DEPOTCHEST, __FUNCTION__); bool validDepot = depotChest > 0 && depotChest < 21; if (g_configManager().getBoolean(STASH_MOVING, __FUNCTION__) && containerItem && !containerItem->isStackable() && validDepot) { @@ -6469,10 +6473,10 @@ void Player::stowItem(std::shared_ptr item, uint32_t count, bool allItems) } } } else { - itemDict.push_back(std::pair, uint32_t>(item, count)); + itemDict.emplace_back(item, count); } - if (itemDict.size() == 0) { + if (itemDict.empty()) { sendCancelMessage("There is no stowable items on this container."); return; } @@ -7776,7 +7780,7 @@ bool Player::canAutoWalk(const Position &toPosition, const std::function // Check if can walk to the toPosition and send event to use function stdext::arraylist listDir(128); if (getPathTo(toPosition, listDir, 0, 1, true, true)) { - g_dispatcher().addEvent(std::bind(&Game::playerAutoWalk, &g_game(), getID(), listDir.data()), __FUNCTION__); + g_dispatcher().addEvent([creatureId = getID(), dirs = listDir.data()] { g_game().playerAutoWalk(creatureId, dirs); }, __FUNCTION__); std::shared_ptr task = createPlayerTask(delay, function, __FUNCTION__); setNextWalkActionTask(task); diff --git a/src/creatures/players/player.hpp b/src/creatures/players/player.hpp index 592db179071..855b48a782b 100644 --- a/src/creatures/players/player.hpp +++ b/src/creatures/players/player.hpp @@ -657,6 +657,11 @@ class Player final : public Creature, public Cylinder, public Bankable { return loginPosition; } const Position &getTemplePosition() const { + if (!town) { + static auto emptyPosition = Position(); + return emptyPosition; + } + return town->getTemplePosition(); } std::shared_ptr getTown() const { diff --git a/src/game/bank/bank.cpp b/src/game/bank/bank.cpp index 30345e0495b..d9a056396ce 100644 --- a/src/game/bank/bank.cpp +++ b/src/game/bank/bank.cpp @@ -80,18 +80,18 @@ const std::set deniedNames = { "paladinsample" }; -const uint32_t minTownId = 3; - bool Bank::transferTo(const std::shared_ptr destination, uint64_t amount) { if (!destination) { g_logger().error("Bank::transferTo: destination is nullptr"); return false; } + auto bankable = getBankable(); if (!bankable) { g_logger().error("Bank::transferTo: bankable is nullptr"); return false; } + auto destinationBankable = destination->getBankable(); if (!destinationBankable) { g_logger().error("Bank::transferTo: destinationBankable is nullptr"); @@ -102,11 +102,13 @@ bool Bank::transferTo(const std::shared_ptr destination, uint64_t amount) if (destinationPlayer != nullptr) { auto name = asLowerCaseString(destinationPlayer->getName()); replaceString(name, " ", ""); + if (deniedNames.contains(name)) { g_logger().warn("Bank::transferTo: denied name: {}", name); return false; } - if (destinationPlayer->getTown()->getID() < minTownId) { + + if (destinationPlayer->getTown()->getID() < g_configManager().getNumber(MIN_TOWN_ID_TO_BANK_TRANSFER, __FUNCTION__)) { g_logger().warn("Bank::transferTo: denied town: {}", destinationPlayer->getTown()->getID()); return false; } diff --git a/src/game/game.cpp b/src/game/game.cpp index 7adaf196dff..cac0b596ebf 100644 --- a/src/game/game.cpp +++ b/src/game/game.cpp @@ -207,6 +207,8 @@ Game::Game() { // Create instance of IOWheel to Game class m_IOWheel = std::make_unique(); + wildcardTree = std::make_shared(false); + m_highscoreCategoriesNames = { { static_cast(HighscoreCategories_t::ACHIEVEMENTS), "Achievement Points" }, { static_cast(HighscoreCategories_t::AXE_FIGHTING), "Axe Fighting" }, @@ -342,17 +344,30 @@ void Game::start(ServiceManager* manager) { int minutes = tms->tm_min; lightHour = (minutes * LIGHT_DAY_LENGTH) / 60; - g_dispatcher().scheduleEvent(EVENT_MS + 1000, std::bind_front(&Game::createFiendishMonsters, this), "Game::createFiendishMonsters"); - g_dispatcher().scheduleEvent(EVENT_MS + 1000, std::bind_front(&Game::createInfluencedMonsters, this), "Game::createInfluencedMonsters"); - - g_dispatcher().cycleEvent(EVENT_MS, std::bind_front(&Game::updateForgeableMonsters, this), "Game::updateForgeableMonsters"); - g_dispatcher().cycleEvent(EVENT_LIGHTINTERVAL_MS, std::bind(&Game::checkLight, this), "Game::checkLight"); - g_dispatcher().cycleEvent(EVENT_CHECK_CREATURE_INTERVAL, std::bind(&Game::checkCreatures, this), "Game::checkCreatures"); - g_dispatcher().cycleEvent(EVENT_IMBUEMENT_INTERVAL, std::bind(&Game::checkImbuements, this), "Game::checkImbuements"); + g_dispatcher().scheduleEvent( + EVENT_MS + 1000, [this] { createFiendishMonsters(); }, "Game::createFiendishMonsters" + ); + g_dispatcher().scheduleEvent( + EVENT_MS + 1000, [this] { createInfluencedMonsters(); }, "Game::createInfluencedMonsters" + ); + g_dispatcher().cycleEvent( + EVENT_MS, [this] { updateForgeableMonsters(); }, "Game::updateForgeableMonsters" + ); + g_dispatcher().cycleEvent( + EVENT_LIGHTINTERVAL_MS, [this] { checkLight(); }, "Game::checkLight" + ); + g_dispatcher().cycleEvent( + EVENT_CHECK_CREATURE_INTERVAL, [this] { checkCreatures(); }, "Game::checkCreatures" + ); + g_dispatcher().cycleEvent( + EVENT_IMBUEMENT_INTERVAL, [this] { checkImbuements(); }, "Game::checkImbuements" + ); g_dispatcher().cycleEvent( EVENT_LUA_GARBAGE_COLLECTION, [this] { g_luaEnvironment().collectGarbage(); }, "Calling GC" ); - g_dispatcher().cycleEvent(EVENT_REFRESH_MARKET_PRICES, std::bind_front(&Game::loadItemsPrice, this), "Game::loadItemsPrice"); + g_dispatcher().cycleEvent( + EVENT_REFRESH_MARKET_PRICES, [this] { loadItemsPrice(); }, "Game::loadItemsPrice" + ); } GameState_t Game::getGameState() const { @@ -418,7 +433,7 @@ void Game::setGameState(GameState_t newState) { saveMotdNum(); g_saveManager().saveAll(); - g_dispatcher().addEvent(std::bind(&Game::shutdown, this), "Game::shutdown"); + g_dispatcher().addEvent([this] { shutdown(); }, "Game::shutdown"); break; } @@ -873,7 +888,7 @@ ReturnValue Game::getPlayerByNameWildcard(const std::string &s, std::shared_ptr< if (s.back() == '~') { const std::string &query = asLowerCaseString(s.substr(0, strlen - 1)); std::string result; - ReturnValue ret = wildcardTree.findOne(query, result); + ReturnValue ret = wildcardTree->findOne(query, result); if (ret != RETURNVALUE_NOERROR) { return ret; } @@ -1165,9 +1180,11 @@ void Game::playerMoveThing(uint32_t playerId, const Position &fromPos, uint16_t } if (Position::areInRange<1, 1, 0>(movingCreature->getPosition(), player->getPosition())) { - std::shared_ptr task = createPlayerTask( + const auto &task = createPlayerTask( g_configManager().getNumber(PUSH_DELAY, __FUNCTION__), - std::bind(&Game::playerMoveCreatureByID, this, player->getID(), movingCreature->getID(), movingCreature->getPosition(), tile->getPosition()), + [this, player, movingCreature, tile] { + playerMoveCreatureByID(player->getID(), movingCreature->getID(), movingCreature->getPosition(), tile->getPosition()); + }, "Game::playerMoveCreatureByID" ); player->setNextActionPushTask(task); @@ -1208,8 +1225,9 @@ void Game::playerMoveCreatureByID(uint32_t playerId, uint32_t movingCreatureId, void Game::playerMoveCreature(std::shared_ptr player, std::shared_ptr movingCreature, const Position &movingCreatureOrigPos, std::shared_ptr toTile) { metrics::method_latency measure(__METHOD_NAME__); if (!player->canDoAction()) { - uint32_t delay = 600; - std::shared_ptr task = createPlayerTask(delay, std::bind(&Game::playerMoveCreatureByID, this, player->getID(), movingCreature->getID(), movingCreatureOrigPos, toTile->getPosition()), "Game::playerMoveCreatureByID"); + const auto &task = createPlayerTask( + 600, [this, player, movingCreature, toTile, movingCreatureOrigPos] { playerMoveCreatureByID(player->getID(), movingCreature->getID(), movingCreatureOrigPos, toTile->getPosition()); }, "Game::playerMoveCreatureByID" + ); player->setNextActionPushTask(task); return; @@ -1221,10 +1239,10 @@ void Game::playerMoveCreature(std::shared_ptr player, std::shared_ptr listDir(128); if (player->getPathTo(movingCreatureOrigPos, listDir, 0, 1, true, true)) { - g_dispatcher().addEvent(std::bind(&Game::playerAutoWalk, this, player->getID(), listDir.data()), "Game::playerAutoWalk"); - - std::shared_ptr task = createPlayerTask(600, std::bind(&Game::playerMoveCreatureByID, this, player->getID(), movingCreature->getID(), movingCreatureOrigPos, toTile->getPosition()), "Game::playerMoveCreatureByID"); - + g_dispatcher().addEvent([this, playerId = player->getID(), listDir = listDir.data()] { playerAutoWalk(playerId, listDir); }, "Game::playerAutoWalk"); + const auto &task = createPlayerTask( + 600, [this, player, movingCreature, toTile, movingCreatureOrigPos] { playerMoveCreatureByID(player->getID(), movingCreature->getID(), movingCreatureOrigPos, toTile->getPosition()); }, "Game::playerMoveCreatureByID" + ); player->pushEvent(true); player->setNextActionPushTask(task); } else { @@ -1424,7 +1442,12 @@ void Game::playerMoveItemByPlayerID(uint32_t playerId, const Position &fromPos, void Game::playerMoveItem(std::shared_ptr player, const Position &fromPos, uint16_t itemId, uint8_t fromStackPos, const Position &toPos, uint8_t count, std::shared_ptr item, std::shared_ptr toCylinder) { if (!player->canDoAction()) { uint32_t delay = player->getNextActionTime(); - std::shared_ptr task = createPlayerTask(delay, std::bind(&Game::playerMoveItemByPlayerID, this, player->getID(), fromPos, itemId, fromStackPos, toPos, count), "Game::playerMoveItemByPlayerID"); + std::shared_ptr task = createPlayerTask( + delay, [this, playerId = player->getID(), fromPos, itemId, fromStackPos, toPos, count] { + playerMoveItemByPlayerID(playerId, fromPos, itemId, fromStackPos, toPos, count); + }, + "Game::playerMoveItemByPlayerID" + ); player->setNextActionTask(task); return; } @@ -1497,16 +1520,6 @@ void Game::playerMoveItem(std::shared_ptr player, const Position &fromPo return; } - if (isTryingToStow(toPos, toCylinder)) { - player->stowItem(item, count, false); - return; - } - - if (!item->isPushable() || item->hasAttribute(ItemAttribute_t::UNIQUEID)) { - player->sendCancelMessage(RETURNVALUE_NOTMOVABLE); - return; - } - const Position &playerPos = player->getPosition(); auto cylinderTile = fromCylinder->getTile(); const Position &mapFromPos = cylinderTile ? cylinderTile->getPosition() : item->getPosition(); @@ -1519,9 +1532,14 @@ void Game::playerMoveItem(std::shared_ptr player, const Position &fromPo // need to walk to the item first before using it stdext::arraylist listDir(128); if (player->getPathTo(item->getPosition(), listDir, 0, 1, true, true)) { - g_dispatcher().addEvent(std::bind(&Game::playerAutoWalk, this, player->getID(), listDir.data()), "Game::playerAutoWalk"); + g_dispatcher().addEvent([this, playerId = player->getID(), listDir = listDir.data()] { playerAutoWalk(playerId, listDir); }, "Game::playerAutoWalk"); - std::shared_ptr task = createPlayerTask(400, std::bind(&Game::playerMoveItemByPlayerID, this, player->getID(), fromPos, itemId, fromStackPos, toPos, count), "Game::playerMoveItemByPlayerID"); + std::shared_ptr task = createPlayerTask( + 400, [this, playerId = player->getID(), fromPos, itemId, fromStackPos, toPos, count] { + playerMoveItemByPlayerID(playerId, fromPos, itemId, fromStackPos, toPos, count); + }, + "Game::playerMoveItemByPlayerID" + ); player->setNextWalkActionTask(task); } else { player->sendCancelMessage(RETURNVALUE_THEREISNOWAY); @@ -1576,9 +1594,14 @@ void Game::playerMoveItem(std::shared_ptr player, const Position &fromPo stdext::arraylist listDir(128); if (player->getPathTo(walkPos, listDir, 0, 0, true, true)) { - g_dispatcher().addEvent(std::bind(&Game::playerAutoWalk, this, player->getID(), listDir.data()), "Game::playerAutoWalk"); - - std::shared_ptr task = createPlayerTask(400, std::bind(&Game::playerMoveItemByPlayerID, this, player->getID(), itemPos, itemId, itemStackPos, toPos, count), "Game::playerMoveItemByPlayerID"); + g_dispatcher().addEvent([this, playerId = player->getID(), listDir = listDir.data()] { playerAutoWalk(playerId, listDir); }, "Game::playerAutoWalk"); + + std::shared_ptr task = createPlayerTask( + 400, [this, playerId = player->getID(), itemPos, itemId, itemStackPos, toPos, count] { + playerMoveItemByPlayerID(playerId, itemPos, itemId, itemStackPos, toPos, count); + }, + "Game::playerMoveItemByPlayerID" + ); player->setNextWalkActionTask(task); } else { player->sendCancelMessage(RETURNVALUE_THEREISNOWAY); @@ -1624,6 +1647,16 @@ void Game::playerMoveItem(std::shared_ptr player, const Position &fromPo } } + if (isTryingToStow(toPos, toCylinder)) { + player->stowItem(item, count, false); + return; + } + + if (!item->isPushable() || item->hasAttribute(ItemAttribute_t::UNIQUEID)) { + player->sendCancelMessage(RETURNVALUE_NOTMOVABLE); + return; + } + ReturnValue ret = internalMoveItem(fromCylinder, toCylinder, toIndex, item, count, nullptr, 0, player); if (ret != RETURNVALUE_NOERROR) { player->sendCancelMessage(ret); @@ -2583,12 +2616,10 @@ std::shared_ptr Game::transformItem(std::shared_ptr item, uint16_t n auto decaying = item->getDecaying(); // If the item is decaying, we need to transform it to the new item - if (decaying > DECAYING_FALSE && item->getDuration() <= 1) { + if (decaying > DECAYING_FALSE && item->getDuration() <= 1 && newType.decayTo) { g_logger().debug("Decay duration old type {}, transformEquipTo {}, transformDeEquipTo {}", curType.decayTo, curType.transformEquipTo, curType.transformDeEquipTo); - g_logger().debug("Decay duration new type, decayTo {}, transformEquipTo {}, transformDeEquipTo {}", newType.decayTo, newType.transformEquipTo, newType.transformDeEquipTo); - if (newType.decayTo) { - itemId = newType.decayTo; - } + g_logger().debug("Decay duration new type decayTo {}, transformEquipTo {}, transformDeEquipTo {}", newType.decayTo, newType.transformEquipTo, newType.transformDeEquipTo); + itemId = newType.decayTo; } else if (curType.id != newType.id) { if (newType.group != curType.group) { item->setDefaultSubtype(); @@ -3484,9 +3515,11 @@ void Game::playerUseItemEx(uint32_t playerId, const Position &fromPos, uint8_t f stdext::arraylist listDir(128); if (player->getPathTo(walkToPos, listDir, 0, 1, true, true)) { - g_dispatcher().addEvent(std::bind(&Game::playerAutoWalk, this, player->getID(), listDir.data()), "Game::playerAutoWalk"); + g_dispatcher().addEvent([this, playerId = player->getID(), listDir = listDir.data()] { playerAutoWalk(playerId, listDir); }, "Game::playerAutoWalk"); - std::shared_ptr task = createPlayerTask(400, std::bind(&Game::playerUseItemEx, this, playerId, itemPos, itemStackPos, fromItemId, toPos, toStackPos, toItemId), "Game::playerUseItemEx"); + std::shared_ptr task = createPlayerTask( + 400, [this, playerId, itemPos, itemStackPos, fromItemId, toPos, toStackPos, toItemId] { playerUseItemEx(playerId, itemPos, itemStackPos, fromItemId, toPos, toStackPos, toItemId); }, "Game::playerUseItemEx" + ); if (it.isRune() || it.type == ITEM_TYPE_POTION) { player->setNextPotionActionTask(task); } else { @@ -3512,7 +3545,9 @@ void Game::playerUseItemEx(uint32_t playerId, const Position &fromPos, uint8_t f if (it.isRune() || it.type == ITEM_TYPE_POTION) { delay = player->getNextPotionActionTime(); } - std::shared_ptr task = createPlayerTask(delay, std::bind(&Game::playerUseItemEx, this, playerId, fromPos, fromStackPos, fromItemId, toPos, toStackPos, toItemId), "Game::playerUseItemEx"); + std::shared_ptr task = createPlayerTask( + delay, [this, playerId, fromPos, fromStackPos, fromItemId, toPos, toStackPos, toItemId] { playerUseItemEx(playerId, fromPos, fromStackPos, fromItemId, toPos, toStackPos, toItemId); }, "Game::playerUseItemEx" + ); if (it.isRune() || it.type == ITEM_TYPE_POTION) { player->setNextPotionActionTask(task); } else { @@ -3594,9 +3629,11 @@ void Game::playerUseItem(uint32_t playerId, const Position &pos, uint8_t stackPo if (ret == RETURNVALUE_TOOFARAWAY) { stdext::arraylist listDir(128); if (player->getPathTo(pos, listDir, 0, 1, true, true)) { - g_dispatcher().addEvent(std::bind(&Game::playerAutoWalk, this, player->getID(), listDir.data()), "Game::playerAutoWalk"); + g_dispatcher().addEvent([this, playerId = player->getID(), listDir = listDir.data()] { playerAutoWalk(playerId, listDir); }, "Game::playerAutoWalk"); - std::shared_ptr task = createPlayerTask(400, std::bind(&Game::playerUseItem, this, playerId, pos, stackPos, index, itemId), "Game::playerUseItem"); + std::shared_ptr task = createPlayerTask( + 400, [this, playerId, pos, stackPos, index, itemId] { playerUseItem(playerId, pos, stackPos, index, itemId); }, "Game::playerUseItem" + ); if (it.isRune() || it.type == ITEM_TYPE_POTION) { player->setNextPotionActionTask(task); } else { @@ -3622,7 +3659,9 @@ void Game::playerUseItem(uint32_t playerId, const Position &pos, uint8_t stackPo if (it.isRune() || it.type == ITEM_TYPE_POTION) { delay = player->getNextPotionActionTime(); } - std::shared_ptr task = createPlayerTask(delay, std::bind(&Game::playerUseItem, this, playerId, pos, stackPos, index, itemId), "Game::playerUseItem"); + std::shared_ptr task = createPlayerTask( + delay, [this, playerId, pos, stackPos, index, itemId] { playerUseItem(playerId, pos, stackPos, index, itemId); }, "Game::playerUseItem" + ); if (it.isRune() || it.type == ITEM_TYPE_POTION) { player->setNextPotionActionTask(task); } else { @@ -3734,9 +3773,14 @@ void Game::playerUseWithCreature(uint32_t playerId, const Position &fromPos, uin stdext::arraylist listDir(128); if (player->getPathTo(walkToPos, listDir, 0, 1, true, true)) { - g_dispatcher().addEvent(std::bind(&Game::playerAutoWalk, this, player->getID(), listDir.data()), "Game::playerAutoWalk"); - - std::shared_ptr task = createPlayerTask(400, std::bind(&Game::playerUseWithCreature, this, playerId, itemPos, itemStackPos, creatureId, itemId), "Game::playerUseWithCreature"); + g_dispatcher().addEvent([this, playerId = player->getID(), listDir = listDir.data()] { playerAutoWalk(playerId, listDir); }, "Game::playerAutoWalk"); + + std::shared_ptr task = createPlayerTask( + 400, [this, playerId, itemPos, itemStackPos, creatureId, itemId] { + playerUseWithCreature(playerId, itemPos, itemStackPos, creatureId, itemId); + }, + "Game::playerUseWithCreature" + ); if (it.isRune() || it.type == ITEM_TYPE_POTION) { player->setNextPotionActionTask(task); } else { @@ -3762,7 +3806,9 @@ void Game::playerUseWithCreature(uint32_t playerId, const Position &fromPos, uin if (it.isRune() || it.type == ITEM_TYPE_POTION) { delay = player->getNextPotionActionTime(); } - std::shared_ptr task = createPlayerTask(delay, std::bind(&Game::playerUseWithCreature, this, playerId, fromPos, fromStackPos, creatureId, itemId), "Game::playerUseWithCreature"); + std::shared_ptr task = createPlayerTask( + delay, [this, playerId, fromPos, fromStackPos, creatureId, itemId] { playerUseWithCreature(playerId, fromPos, fromStackPos, creatureId, itemId); }, "Game::playerUseWithCreature" + ); if (it.isRune() || it.type == ITEM_TYPE_POTION) { player->setNextPotionActionTask(task); @@ -3888,9 +3934,14 @@ void Game::playerRotateItem(uint32_t playerId, const Position &pos, uint8_t stac if (pos.x != 0xFFFF && !Position::areInRange<1, 1, 0>(pos, player->getPosition())) { stdext::arraylist listDir(128); if (player->getPathTo(pos, listDir, 0, 1, true, true)) { - g_dispatcher().addEvent(std::bind(&Game::playerAutoWalk, this, player->getID(), listDir.data()), "Game::playerAutoWalk"); + g_dispatcher().addEvent([this, playerId = player->getID(), listDir = listDir.data()] { playerAutoWalk(playerId, listDir); }, "Game::playerAutoWalk"); - std::shared_ptr task = createPlayerTask(400, std::bind(&Game::playerRotateItem, this, playerId, pos, stackPos, itemId), "Game::playerRotateItem"); + std::shared_ptr task = createPlayerTask( + 400, [this, playerId, pos, stackPos, itemId] { + playerRotateItem(playerId, pos, stackPos, itemId); + }, + "Game::playerRotateItem" + ); player->setNextWalkActionTask(task); } else { player->sendCancelMessage(RETURNVALUE_THEREISNOWAY); @@ -3939,12 +3990,16 @@ void Game::playerConfigureShowOffSocket(uint32_t playerId, const Position &pos, if (!Position::areInRange<1, 1, 0>(pos, player->getPosition())) { stdext::arraylist listDir(128); if (player->getPathTo(pos, listDir, 0, 1, true, false)) { - g_dispatcher().addEvent(std::bind(&Game::playerAutoWalk, this, player->getID(), listDir.data()), "Game::playerAutoWalk"); + g_dispatcher().addEvent([this, playerId = player->getID(), listDir = listDir.data()] { playerAutoWalk(playerId, listDir); }, "Game::playerAutoWalk"); std::shared_ptr task; if (isPodiumOfRenown) { - task = createPlayerTask(400, std::bind_front(&Player::sendPodiumWindow, player, item, pos, itemId, stackPos), "Game::playerConfigureShowOffSocket"); + task = createPlayerTask( + 400, [player, item, pos, itemId, stackPos] { player->sendPodiumWindow(item, pos, itemId, stackPos); }, "Game::playerConfigureShowOffSocket" + ); } else { - task = createPlayerTask(400, std::bind_front(&Player::sendMonsterPodiumWindow, player, item, pos, itemId, stackPos), "Game::playerConfigureShowOffSocket"); + task = createPlayerTask( + 400, [player, item, pos, itemId, stackPos] { player->sendMonsterPodiumWindow(item, pos, itemId, stackPos); }, "Game::playerConfigureShowOffSocket" + ); } player->setNextWalkActionTask(task); } else { @@ -3996,8 +4051,10 @@ void Game::playerSetShowOffSocket(uint32_t playerId, Outfit_t &outfit, const Pos if (!Position::areInRange<1, 1, 0>(pos, player->getPosition())) { stdext::arraylist listDir(128); if (player->getPathTo(pos, listDir, 0, 1, true, false)) { - g_dispatcher().addEvent(std::bind(&Game::playerAutoWalk, this, player->getID(), listDir.data()), "Game::playerAutoWalk"); - std::shared_ptr task = createPlayerTask(400, std::bind(&Game::playerBrowseField, this, playerId, pos), "Game::playerBrowseField"); + g_dispatcher().addEvent([this, playerId = player->getID(), listDir = listDir.data()] { playerAutoWalk(playerId, listDir); }, "Game::playerAutoWalk"); + std::shared_ptr task = createPlayerTask( + 400, [this, playerId, pos] { playerBrowseField(playerId, pos); }, "Game::playerBrowseField" + ); player->setNextWalkActionTask(task); } else { player->sendCancelMessage(RETURNVALUE_THEREISNOWAY); @@ -4135,9 +4192,11 @@ void Game::playerWrapableItem(uint32_t playerId, const Position &pos, uint8_t st if (pos.x != 0xFFFF && !Position::areInRange<1, 1, 0>(pos, player->getPosition())) { stdext::arraylist listDir(128); if (player->getPathTo(pos, listDir, 0, 1, true, true)) { - g_dispatcher().addEvent(std::bind(&Game::playerAutoWalk, this, player->getID(), listDir.data()), "Game::playerAutoWalk"); + g_dispatcher().addEvent([this, playerId = player->getID(), listDir = listDir.data()] { playerAutoWalk(playerId, listDir); }, "Game::playerAutoWalk"); - std::shared_ptr task = createPlayerTask(400, std::bind(&Game::playerWrapableItem, this, playerId, pos, stackPos, itemId), "Game::playerWrapableItem"); + std::shared_ptr task = createPlayerTask( + 400, [this, playerId, pos, stackPos, itemId] { playerWrapableItem(playerId, pos, stackPos, itemId); }, "Game::playerWrapableItem" + ); player->setNextWalkActionTask(task); } else { player->sendCancelMessage(RETURNVALUE_THEREISNOWAY); @@ -4314,8 +4373,10 @@ void Game::playerBrowseField(uint32_t playerId, const Position &pos) { if (!Position::areInRange<1, 1>(playerPos, pos)) { stdext::arraylist listDir(128); if (player->getPathTo(pos, listDir, 0, 1, true, true)) { - g_dispatcher().addEvent(std::bind(&Game::playerAutoWalk, this, player->getID(), listDir.data()), "Game::playerAutoWalk"); - std::shared_ptr task = createPlayerTask(400, std::bind(&Game::playerBrowseField, this, playerId, pos), "Game::playerBrowseField"); + g_dispatcher().addEvent([this, playerId = player->getID(), listDir = listDir.data()] { playerAutoWalk(playerId, listDir); }, "Game::playerAutoWalk"); + std::shared_ptr task = createPlayerTask( + 400, [this, playerId, pos] { playerBrowseField(playerId, pos); }, "Game::playerBrowseField" + ); player->setNextWalkActionTask(task); } else { player->sendCancelMessage(RETURNVALUE_THEREISNOWAY); @@ -4575,9 +4636,11 @@ void Game::playerRequestTrade(uint32_t playerId, const Position &pos, uint8_t st if (!Position::areInRange<1, 1>(tradeItemPosition, playerPosition)) { stdext::arraylist listDir(128); if (player->getPathTo(pos, listDir, 0, 1, true, true)) { - g_dispatcher().addEvent(std::bind(&Game::playerAutoWalk, this, player->getID(), listDir.data()), "Game::playerAutoWalk"); + g_dispatcher().addEvent([this, playerId = player->getID(), listDir = listDir.data()] { playerAutoWalk(playerId, listDir); }, "Game::playerAutoWalk"); - std::shared_ptr task = createPlayerTask(400, std::bind(&Game::playerRequestTrade, this, playerId, pos, stackPos, tradePlayerId, itemId), "Game::playerRequestTrade"); + std::shared_ptr task = createPlayerTask( + 400, [this, playerId, pos, stackPos, tradePlayerId, itemId] { playerRequestTrade(playerId, pos, stackPos, tradePlayerId, itemId); }, "Game::playerRequestTrade" + ); player->setNextWalkActionTask(task); } else { player->sendCancelMessage(RETURNVALUE_THEREISNOWAY); @@ -5120,7 +5183,12 @@ void Game::playerQuickLoot(uint32_t playerId, const Position &pos, uint16_t item if (!autoLoot && !player->canDoAction()) { uint32_t delay = player->getNextActionTime(); - std::shared_ptr task = createPlayerTask(delay, std::bind(&Game::playerQuickLoot, this, player->getID(), pos, itemId, stackPos, defaultItem, lootAllCorpses, autoLoot), "Game::playerQuickLoot"); + std::shared_ptr task = createPlayerTask( + delay, [this, playerId = player->getID(), pos, itemId, stackPos, defaultItem, lootAllCorpses, autoLoot] { + playerQuickLoot(playerId, pos, itemId, stackPos, defaultItem, lootAllCorpses, autoLoot); + }, + "Game::playerQuickLoot" + ); player->setNextActionTask(task); return; } @@ -5130,8 +5198,13 @@ void Game::playerQuickLoot(uint32_t playerId, const Position &pos, uint16_t item // need to walk to the corpse first before looting it stdext::arraylist listDir(128); if (player->getPathTo(pos, listDir, 0, 1, true, true)) { - g_dispatcher().addEvent(std::bind(&Game::playerAutoWalk, this, player->getID(), listDir.data()), "Game::playerAutoWalk"); - std::shared_ptr task = createPlayerTask(0, std::bind(&Game::playerQuickLoot, this, player->getID(), pos, itemId, stackPos, defaultItem, lootAllCorpses, autoLoot), "Game::playerQuickLoot"); + g_dispatcher().addEvent([this, playerId = player->getID(), listDir = listDir.data()] { playerAutoWalk(playerId, listDir); }, "Game::playerAutoWalk"); + std::shared_ptr task = createPlayerTask( + 0, [this, playerId = player->getID(), pos, itemId, stackPos, defaultItem, lootAllCorpses, autoLoot] { + playerQuickLoot(playerId, pos, itemId, stackPos, defaultItem, lootAllCorpses, autoLoot); + }, + "Game::playerQuickLoot" + ); player->setNextWalkActionTask(task); } else { player->sendCancelMessage(RETURNVALUE_THEREISNOWAY); @@ -5494,7 +5567,7 @@ void Game::playerSetAttackedCreature(uint32_t playerId, uint32_t creatureId) { } player->setAttackedCreature(attackCreature); - g_dispatcher().addEvent(std::bind(&Game::updateCreatureWalk, this, player->getID()), "Game::updateCreatureWalk"); + g_dispatcher().addEvent([this, plyerId = player->getID()] { updateCreatureWalk(plyerId); }, "Game::updateCreatureWalk"); } void Game::playerFollowCreature(uint32_t playerId, uint32_t creatureId) { @@ -5504,7 +5577,7 @@ void Game::playerFollowCreature(uint32_t playerId, uint32_t creatureId) { } player->setAttackedCreature(nullptr); - g_dispatcher().addEvent(std::bind(&Game::updateCreatureWalk, this, player->getID()), "Game::updateCreatureWalk"); + g_dispatcher().addEvent([this, plyerId = player->getID()] { updateCreatureWalk(plyerId); }, "Game::updateCreatureWalk"); player->setFollowCreature(getCreatureByID(creatureId)); } @@ -6252,7 +6325,6 @@ bool Game::combatBlockHit(CombatDamage &damage, std::shared_ptr attack std::shared_ptr targetPlayer = target->getPlayer(); if (damage.primary.type != COMBAT_NONE) { - damage.primary.value = -damage.primary.value; // Damage healing primary if (attacker) { @@ -9330,8 +9402,10 @@ void Game::playerSetMonsterPodium(uint32_t playerId, uint32_t monsterRaceId, con if (!Position::areInRange<1, 1, 0>(pos, player->getPosition())) { if (stdext::arraylist listDir(128); player->getPathTo(pos, listDir, 0, 1, true, false)) { - g_dispatcher().addEvent(std::bind_front(&Game::playerAutoWalk, this, player->getID(), listDir.data()), "Game::playerAutoWalk"); - std::shared_ptr task = createPlayerTask(400, std::bind_front(&Game::playerBrowseField, this, playerId, pos), "Game::playerBrowseField"); + g_dispatcher().addEvent([this, playerId = player->getID(), listDir = listDir.data()] { playerAutoWalk(playerId, listDir); }, "Game::playerAutoWalk"); + std::shared_ptr task = createPlayerTask( + 400, [this, playerId, pos] { playerBrowseField(playerId, pos); }, "Game::playerBrowseField" + ); player->setNextWalkActionTask(task); } else { player->sendCancelMessage(RETURNVALUE_THEREISNOWAY); @@ -9428,9 +9502,13 @@ void Game::playerRotatePodium(uint32_t playerId, const Position &pos, uint8_t st if (pos.x != 0xFFFF && !Position::areInRange<1, 1, 0>(pos, player->getPosition())) { if (stdext::arraylist listDir(128); player->getPathTo(pos, listDir, 0, 1, true, true)) { - g_dispatcher().addEvent(std::bind_front(&Game::playerAutoWalk, this, player->getID(), listDir.data()), "Game::playerAutoWalk"); - - std::shared_ptr task = createPlayerTask(400, std::bind_front(&Game::playerRotatePodium, this, playerId, pos, stackPos, itemId), "Game::playerRotatePodium"); + g_dispatcher().addEvent([this, playerId = player->getID(), listDir = listDir.data()] { playerAutoWalk(playerId, listDir); }, "Game::playerAutoWalk"); + std::shared_ptr task = createPlayerTask( + 400, [this, playerId, pos, stackPos, itemId] { + playerRotatePodium(playerId, pos, stackPos, itemId); + }, + "Game::playerRotatePodium" + ); player->setNextWalkActionTask(task); } else { player->sendCancelMessage(RETURNVALUE_THEREISNOWAY); @@ -9611,14 +9689,14 @@ void Game::updatePlayerSaleItems(uint32_t playerId) { void Game::addPlayer(std::shared_ptr player) { const std::string &lowercase_name = asLowerCaseString(player->getName()); mappedPlayerNames[lowercase_name] = player; - wildcardTree.insert(lowercase_name); + wildcardTree->insert(lowercase_name); players[player->getID()] = player; } void Game::removePlayer(std::shared_ptr player) { const std::string &lowercase_name = asLowerCaseString(player->getName()); mappedPlayerNames.erase(lowercase_name); - wildcardTree.remove(lowercase_name); + wildcardTree->remove(lowercase_name); players.erase(player->getID()); } @@ -9947,7 +10025,7 @@ uint32_t Game::makeFiendishMonster(uint32_t forgeableMonsterId /* = 0*/, bool cr auto schedulerTask = createPlayerTask( finalTime, - std::bind_front(&Game::updateFiendishMonsterStatus, this, monster->getID(), monster->getName()), + [this, monster] { updateFiendishMonsterStatus(monster->getID(), monster->getName()); }, "Game::updateFiendishMonsterStatus" ); forgeMonsterEventIds[monster->getID()] = g_dispatcher().scheduleEvent(schedulerTask); @@ -9986,7 +10064,9 @@ bool Game::removeInfluencedMonster(uint32_t id, bool create /* = false*/) { influencedMonsters.erase(find); if (create) { - g_dispatcher().scheduleEvent(200 * 1000, std::bind_front(&Game::makeInfluencedMonster, this), "Game::makeInfluencedMonster"); + g_dispatcher().scheduleEvent( + 200 * 1000, [this] { makeInfluencedMonster(); }, "Game::makeInfluencedMonster" + ); } } else { g_logger().warn("[Game::removeInfluencedMonster] - Failed to remove a Influenced Monster, error code: monster id not exist in the influenced monsters map"); @@ -10002,7 +10082,9 @@ bool Game::removeFiendishMonster(uint32_t id, bool create /* = true*/) { checkForgeEventId(id); if (create) { - g_dispatcher().scheduleEvent(300 * 1000, std::bind_front(&Game::makeFiendishMonster, this, 0, false), "Game::makeFiendishMonster"); + g_dispatcher().scheduleEvent( + 300 * 1000, [this] { makeFiendishMonster(0, false); }, "Game::makeFiendishMonster" + ); } } else { g_logger().warn("[Game::removeFiendishMonster] - Failed to remove a Fiendish Monster, error code: monster id not exist in the fiendish monsters map"); @@ -10200,7 +10282,9 @@ void Game::playerCheckActivity(const std::string &playerName, int interval) { } } - g_dispatcher().scheduleEvent(1000, std::bind(&Game::playerCheckActivity, this, playerName, interval), "Game::playerCheckActivity"); + g_dispatcher().scheduleEvent( + 1000, [this, playerName, interval] { playerCheckActivity(playerName, interval); }, "Game::playerCheckActivity" + ); } void Game::playerRewardChestCollect(uint32_t playerId, const Position &pos, uint16_t itemId, uint8_t stackPos, uint32_t maxMoveItems /* = 0*/) { @@ -10221,8 +10305,11 @@ void Game::playerRewardChestCollect(uint32_t playerId, const Position &pos, uint return; } - if (auto function = std::bind(&Game::playerRewardChestCollect, this, player->getID(), pos, itemId, stackPos, maxMoveItems); - player->canAutoWalk(item->getPosition(), function)) { + const auto &function = [this, playerId = player->getID(), pos, itemId, stackPos, maxMoveItems] { + playerRewardChestCollect(playerId, pos, itemId, stackPos, maxMoveItems); + }; + + if (player->canAutoWalk(item->getPosition(), function)) { return; } diff --git a/src/game/game.hpp b/src/game/game.hpp index d70263c1775..708aa4b1782 100644 --- a/src/game/game.hpp +++ b/src/game/game.hpp @@ -840,7 +840,7 @@ class Game { size_t lastBucket = 0; size_t lastImbuedBucket = 0; - WildcardTreeNode wildcardTree { false }; + std::shared_ptr wildcardTree; std::map> npcs; std::map> monsters; diff --git a/src/io/iologindata.cpp b/src/io/iologindata.cpp index 7e113ef901e..4c6b95dc32e 100644 --- a/src/io/iologindata.cpp +++ b/src/io/iologindata.cpp @@ -172,6 +172,9 @@ bool IOLoginData::loadPlayer(std::shared_ptr player, DBResult_ptr result // Load task hunting class IOLoginDataLoad::loadPlayerTaskHuntingClass(player, result); + // Load instant spells list + IOLoginDataLoad::loadPlayerInstantSpellList(player, result); + if (disableIrrelevantInfo) { return true; } diff --git a/src/items/bed.cpp b/src/items/bed.cpp index 4ce4a1e0edd..d093dcc5fd9 100644 --- a/src/items/bed.cpp +++ b/src/items/bed.cpp @@ -165,7 +165,9 @@ bool BedItem::sleep(std::shared_ptr player) { g_game().addMagicEffect(player->getPosition(), CONST_ME_SLEEP); // logout player after he sees himself walk onto the bed and it change id - g_dispatcher().scheduleEvent(SCHEDULER_MINTICKS, std::bind(&ProtocolGame::logout, player->client, false, false), "ProtocolGame::logout"); + g_dispatcher().scheduleEvent( + SCHEDULER_MINTICKS, [client = player->client] { client->logout(false, false); }, "ProtocolGame::logout" + ); // change self and partner's appearance updateAppearance(player); diff --git a/src/items/decay/decay.cpp b/src/items/decay/decay.cpp index 27ae7b6b485..848acffbf68 100644 --- a/src/items/decay/decay.cpp +++ b/src/items/decay/decay.cpp @@ -47,11 +47,15 @@ void Decay::startDecay(std::shared_ptr item) { int64_t timestamp = OTSYS_TIME() + duration; if (decayMap.empty()) { - eventId = g_dispatcher().scheduleEvent(std::max(SCHEDULER_MINTICKS, duration), std::bind(&Decay::checkDecay, this), "Decay::checkDecay"); + eventId = g_dispatcher().scheduleEvent( + std::max(SCHEDULER_MINTICKS, duration), [this] { checkDecay(); }, "Decay::checkDecay" + ); } else { if (timestamp < decayMap.begin()->first) { g_dispatcher().stopEvent(eventId); - eventId = g_dispatcher().scheduleEvent(std::max(SCHEDULER_MINTICKS, duration), std::bind(&Decay::checkDecay, this), "Decay::checkDecay"); + eventId = g_dispatcher().scheduleEvent( + std::max(SCHEDULER_MINTICKS, duration), [this] { checkDecay(); }, "Decay::checkDecay" + ); } } @@ -138,7 +142,9 @@ void Decay::checkDecay() { } if (it != end) { - eventId = g_dispatcher().scheduleEvent(std::max(SCHEDULER_MINTICKS, static_cast(it->first - timestamp)), std::bind(&Decay::checkDecay, this), "Decay::checkDecay"); + eventId = g_dispatcher().scheduleEvent( + std::max(SCHEDULER_MINTICKS, static_cast(it->first - timestamp)), [this] { checkDecay(); }, "Decay::checkDecay" + ); } } diff --git a/src/lib/CMakeLists.txt b/src/lib/CMakeLists.txt index 402c6a34a79..55709c59ac3 100644 --- a/src/lib/CMakeLists.txt +++ b/src/lib/CMakeLists.txt @@ -1,6 +1,9 @@ target_sources(${PROJECT_NAME}_lib PRIVATE di/soft_singleton.cpp logging/log_with_spd_log.cpp - metrics/metrics.cpp thread/thread_pool.cpp ) + +if(FEATURE_METRICS) + target_sources(${PROJECT_NAME}_lib PRIVATE metrics/metrics.cpp) +endif() diff --git a/src/lib/metrics/metrics.cpp b/src/lib/metrics/metrics.cpp index 2a65e9a7d5d..cf11060125a 100644 --- a/src/lib/metrics/metrics.cpp +++ b/src/lib/metrics/metrics.cpp @@ -1,3 +1,4 @@ +#ifdef FEATURE_METRICS /** * Canary - A free and open-source MMORPG server emulator * Copyright (©) 2019-2024 OpenTibiaBR @@ -7,8 +8,8 @@ * Website: https://docs.opentibiabr.com/ */ -#include "metrics.hpp" -#include "lib/di/container.hpp" + #include "metrics.hpp" + #include "lib/di/container.hpp" using namespace metrics; @@ -41,7 +42,7 @@ void Metrics::init(Options opts) { initHistograms(); } -void Metrics ::initHistograms() { +void Metrics::initHistograms() { for (auto name : latencyNames) { auto instrumentSelector = metrics_sdk::InstrumentSelectorFactory::Create(metrics_sdk::InstrumentType::kHistogram, name, "us"); auto meterSelector = metrics_sdk::MeterSelectorFactory::Create("performance", otelVersion, otelSchema); @@ -108,3 +109,5 @@ void ScopedLatency::stop() { auto attrskv = opentelemetry::common::KeyValueIterableView { attrs }; histogram->Record(elapsed, attrskv, context); } + +#endif // FEATURE_METRICS diff --git a/src/lib/metrics/metrics.hpp b/src/lib/metrics/metrics.hpp index 0d8c291dfbe..279ea5f91c5 100644 --- a/src/lib/metrics/metrics.hpp +++ b/src/lib/metrics/metrics.hpp @@ -9,43 +9,29 @@ #pragma once -#include "game/scheduling/dispatcher.hpp" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#ifdef FEATURE_METRICS + #include "game/scheduling/dispatcher.hpp" + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include namespace metrics_sdk = opentelemetry::sdk::metrics; namespace common = opentelemetry::common; namespace metrics_exporter = opentelemetry::exporter::metrics; namespace metrics_api = opentelemetry::metrics; -constexpr std::string_view methodName(const char* s) { - std::string_view prettyFunction(s); - size_t bracket = prettyFunction.rfind("("); - size_t space = prettyFunction.rfind(" ", bracket) + 1; - return prettyFunction.substr(space, bracket - space); -} - -#if defined(__GNUC__) || defined(__clang__) - #define __METHOD_NAME__ methodName(__PRETTY_FUNCTION__) -#elif defined(_MSC_VER) - #define __METHOD_NAME__ methodName(__FUNCSIG__) -#else - #error "Compiler not supported" -#endif - namespace metrics { using Meter = opentelemetry::nostd::shared_ptr; @@ -85,12 +71,12 @@ namespace metrics { bool stopped { false }; }; -#define DEFINE_LATENCY_CLASS(class_name, histogram_name, category) \ - class class_name##_latency final : public ScopedLatency { \ - public: \ - class_name##_latency(std::string_view name) : \ - ScopedLatency(name, histogram_name "_latency", category) { } \ - } + #define DEFINE_LATENCY_CLASS(class_name, histogram_name, category) \ + class class_name##_latency final : public ScopedLatency { \ + public: \ + class_name##_latency(std::string_view name) : \ + ScopedLatency(name, histogram_name "_latency", category) { } \ + } DEFINE_LATENCY_CLASS(method, "method", "method"); DEFINE_LATENCY_CLASS(lua, "lua", "scope"); @@ -170,3 +156,70 @@ namespace metrics { constexpr auto g_metrics = metrics::Metrics::getInstance; + +#else // FEATURE_METRICS + + #include "lib/di/container.hpp" + +struct Options { + bool enablePrometheusExporter; + bool enableOStreamExporter; +}; + +class ScopedLatency { +public: + explicit ScopedLatency([[maybe_unused]] std::string_view name, [[maybe_unused]] const std::string &histogramName, [[maybe_unused]] const std::string &scopeKey) {}; + explicit ScopedLatency([[maybe_unused]] std::string_view name, [[maybe_unused]] std::set &histogram, [[maybe_unused]] const std::map &attrs = {}, [[maybe_unused]] const std::string &context = std::string()) {}; + + void stop() {}; + + ~ScopedLatency() = default; +}; + +namespace metrics { + #define DEFINE_LATENCY_CLASS(class_name, histogram_name, category) \ + class class_name##_latency final : public ScopedLatency { \ + public: \ + class_name##_latency(std::string_view name) : \ + ScopedLatency(name, histogram_name "_latency", category) { } \ + } + + DEFINE_LATENCY_CLASS(method, "method", "method"); + DEFINE_LATENCY_CLASS(lua, "lua", "scope"); + DEFINE_LATENCY_CLASS(query, "query", "truncated_query"); + DEFINE_LATENCY_CLASS(task, "task", "task"); + DEFINE_LATENCY_CLASS(lock, "lock", "scope"); + + const std::vector latencyNames { + "method_latency", + "lua_latency", + "query_latency", + "task_latency", + "lock_latency", + }; + + class Metrics final { + public: + Metrics() = default; + ~Metrics() = default; + + void init([[maybe_unused]] Options opts) {}; + void initHistograms() {}; + void shutdown() {}; + + static Metrics &getInstance() { + return inject(); + }; + + void addCounter([[maybe_unused]] std::string_view name, [[maybe_unused]] double value, [[maybe_unused]] const std::map &attrs = {}) { } + + void addUpDownCounter([[maybe_unused]] std::string_view name, [[maybe_unused]] int value, [[maybe_unused]] const std::map &attrs = {}) { } + + friend class ScopedLatency; + }; +} + +constexpr auto g_metrics + = metrics::Metrics::getInstance; + +#endif // FEATURE_METRICS diff --git a/src/lua/creature/raids.cpp b/src/lua/creature/raids.cpp index f0d7cecf402..a4500d126ba 100644 --- a/src/lua/creature/raids.cpp +++ b/src/lua/creature/raids.cpp @@ -102,7 +102,9 @@ bool Raids::startup() { setLastRaidEnd(OTSYS_TIME()); - checkRaidsEvent = g_dispatcher().scheduleEvent(CHECK_RAIDS_INTERVAL * 1000, std::bind(&Raids::checkRaids, this), "Raids::checkRaids"); + checkRaidsEvent = g_dispatcher().scheduleEvent( + CHECK_RAIDS_INTERVAL * 1000, [this] { checkRaids(); }, "Raids::checkRaids" + ); started = true; return started; @@ -134,7 +136,9 @@ void Raids::checkRaids() { } } - checkRaidsEvent = g_dispatcher().scheduleEvent(CHECK_RAIDS_INTERVAL * 1000, std::bind(&Raids::checkRaids, this), "Raids::checkRaids"); + checkRaidsEvent = g_dispatcher().scheduleEvent( + CHECK_RAIDS_INTERVAL * 1000, [this] { checkRaids(); }, "Raids::checkRaids" + ); } void Raids::clear() { @@ -216,7 +220,9 @@ void Raid::startRaid() { const auto raidEvent = getNextRaidEvent(); if (raidEvent) { state = RAIDSTATE_EXECUTING; - nextEventEvent = g_dispatcher().scheduleEvent(raidEvent->getDelay(), std::bind(&Raid::executeRaidEvent, this, raidEvent), "Raid::executeRaidEvent"); + nextEventEvent = g_dispatcher().scheduleEvent( + raidEvent->getDelay(), [this, raidEvent] { executeRaidEvent(raidEvent); }, "Raid::executeRaidEvent" + ); } else { g_logger().warn("[raids] Raid {} has no events", name); resetRaid(); @@ -230,7 +236,9 @@ void Raid::executeRaidEvent(const std::shared_ptr raidEvent) { if (newRaidEvent) { uint32_t ticks = static_cast(std::max(RAID_MINTICKS, newRaidEvent->getDelay() - raidEvent->getDelay())); - nextEventEvent = g_dispatcher().scheduleEvent(ticks, std::bind(&Raid::executeRaidEvent, this, newRaidEvent), __FUNCTION__); + nextEventEvent = g_dispatcher().scheduleEvent( + ticks, [this, newRaidEvent] { executeRaidEvent(newRaidEvent); }, __FUNCTION__ + ); } else { resetRaid(); } diff --git a/src/lua/functions/core/game/global_functions.cpp b/src/lua/functions/core/game/global_functions.cpp index cbb133211f8..0403e88dd95 100644 --- a/src/lua/functions/core/game/global_functions.cpp +++ b/src/lua/functions/core/game/global_functions.cpp @@ -664,7 +664,7 @@ int GlobalFunctions::luaAddEvent(lua_State* L) { auto &lastTimerEventId = g_luaEnvironment().lastEventTimerId; eventDesc.eventId = g_dispatcher().scheduleEvent( delay, - std::bind(&LuaEnvironment::executeTimerEvent, &g_luaEnvironment(), lastTimerEventId), + [lastTimerEventId] { g_luaEnvironment().executeTimerEvent(lastTimerEventId); }, "LuaEnvironment::executeTimerEvent" ); diff --git a/src/lua/global/globalevent.cpp b/src/lua/global/globalevent.cpp index 62650b429a9..9626173dc9f 100644 --- a/src/lua/global/globalevent.cpp +++ b/src/lua/global/globalevent.cpp @@ -35,7 +35,9 @@ bool GlobalEvents::registerLuaEvent(const std::shared_ptr globalEve auto result = timerMap.emplace(globalEvent->getName(), globalEvent); if (result.second) { if (timerEventId == 0) { - timerEventId = g_dispatcher().scheduleEvent(SCHEDULER_MINTICKS, std::bind(&GlobalEvents::timer, this), "GlobalEvents::timer"); + timerEventId = g_dispatcher().scheduleEvent( + SCHEDULER_MINTICKS, [this] { timer(); }, "GlobalEvents::timer" + ); } return true; } @@ -99,7 +101,9 @@ void GlobalEvents::timer() { } if (nextScheduledTime != std::numeric_limits::max()) { - timerEventId = g_dispatcher().scheduleEvent(std::max(1000, nextScheduledTime * 1000), std::bind(&GlobalEvents::timer, this), __FUNCTION__); + timerEventId = g_dispatcher().scheduleEvent( + std::max(1000, nextScheduledTime * 1000), [this] { timer(); }, __FUNCTION__ + ); } } @@ -136,7 +140,9 @@ void GlobalEvents::think() { if (nextScheduledTime != std::numeric_limits::max()) { auto delay = static_cast(nextScheduledTime); - thinkEventId = g_dispatcher().scheduleEvent(delay, std::bind(&GlobalEvents::think, this), "GlobalEvents::think"); + thinkEventId = g_dispatcher().scheduleEvent( + delay, [this] { think(); }, "GlobalEvents::think" + ); } } diff --git a/src/pch.hpp b/src/pch.hpp index 522411b5621..e69c27016a4 100644 --- a/src/pch.hpp +++ b/src/pch.hpp @@ -45,6 +45,7 @@ #include #include #include +#include // -------------------- // System Includes @@ -95,9 +96,6 @@ struct fmt::formatter, char>> : formatter< // GMP #include -// JSON -#include - // LUA #if __has_include("luajit/lua.hpp") #include @@ -172,3 +170,18 @@ struct fmt::formatter, char>> : formatter< #include #include "lua/global/shared_object.hpp" + +constexpr std::string_view methodName(const char* s) { + std::string_view prettyFunction(s); + size_t bracket = prettyFunction.rfind('('); + size_t space = prettyFunction.rfind(' ', bracket) + 1; + return prettyFunction.substr(space, bracket - space); +} + +#if defined(__GNUC__) || defined(__clang__) + #define __METHOD_NAME__ methodName(__PRETTY_FUNCTION__) +#elif defined(_MSC_VER) + #define __METHOD_NAME__ methodName(__FUNCSIG__) +#else + #error "Compiler not supported" +#endif diff --git a/src/server/network/connection/connection.cpp b/src/server/network/connection/connection.cpp index 41789b88387..cc27eb0e9eb 100644 --- a/src/server/network/connection/connection.cpp +++ b/src/server/network/connection/connection.cpp @@ -62,7 +62,7 @@ void Connection::close(bool force) { connectionState = CONNECTION_STATE_CLOSED; if (protocol) { - g_dispatcher().addEvent(std::bind_front(&Protocol::release, protocol), "Protocol::release", std::chrono::milliseconds(CONNECTION_WRITE_TIMEOUT * 1000).count()); + g_dispatcher().addEvent([protocol = protocol] { protocol->release(); }, "Protocol::release", std::chrono::milliseconds(CONNECTION_WRITE_TIMEOUT * 1000).count()); } if (messageQueue.empty() || force) { @@ -98,19 +98,23 @@ void Connection::closeSocket() { void Connection::accept(Protocol_ptr protocolPtr) { connectionState = CONNECTION_STATE_IDENTIFYING; protocol = std::move(protocolPtr); - g_dispatcher().addEvent(std::bind_front(&Protocol::onConnect, protocol), "Protocol::onConnect", std::chrono::milliseconds(CONNECTION_WRITE_TIMEOUT * 1000).count()); + g_dispatcher().addEvent([protocol = protocol] { protocol->onConnect(); }, "Protocol::onConnect", std::chrono::milliseconds(CONNECTION_WRITE_TIMEOUT * 1000).count()); acceptInternal(false); } void Connection::acceptInternal(bool toggleParseHeader) { readTimer.expires_from_now(std::chrono::seconds(CONNECTION_READ_TIMEOUT)); - readTimer.async_wait(std::bind(&Connection::handleTimeout, std::weak_ptr(shared_from_this()), std::placeholders::_1)); + readTimer.async_wait([self = shared_from_this()](const std::error_code &error) { Connection::handleTimeout(std::weak_ptr(self), error); }); try { - auto readCallback = toggleParseHeader ? std::bind(&Connection::parseHeader, shared_from_this(), std::placeholders::_1) - : std::bind(&Connection::parseProxyIdentification, shared_from_this(), std::placeholders::_1); - asio::async_read(socket, asio::buffer(msg.getBuffer(), HEADER_LENGTH), readCallback); + asio::async_read(socket, asio::buffer(msg.getBuffer(), HEADER_LENGTH), [self = shared_from_this(), toggleParseHeader](const std::error_code &error, std::size_t N) { + if (toggleParseHeader) { + self->parseHeader(error); + } else { + self->parseProxyIdentification(error); + } + }); } catch (const std::system_error &e) { g_logger().error("[Connection::acceptInternal] - Exception in async_read: {}", e.what()); close(FORCE_CLOSE); @@ -143,10 +147,10 @@ void Connection::parseProxyIdentification(const std::error_code &error) { connectionState = CONNECTION_STATE_READINGS; try { readTimer.expires_from_now(std::chrono::seconds(CONNECTION_READ_TIMEOUT)); - readTimer.async_wait(std::bind(&Connection::handleTimeout, std::weak_ptr(shared_from_this()), std::placeholders::_1)); + readTimer.async_wait([self = shared_from_this()](const std::error_code &error) { Connection::handleTimeout(std::weak_ptr(self), error); }); // Read the remainder of proxy identification - asio::async_read(socket, asio::buffer(msg.getBuffer(), remainder), std::bind(&Connection::parseProxyIdentification, shared_from_this(), std::placeholders::_1)); + asio::async_read(socket, asio::buffer(msg.getBuffer(), remainder), [self = shared_from_this()](const std::error_code &error, std::size_t N) { self->parseProxyIdentification(error); }); } catch (const std::system_error &e) { g_logger().error("Connection::parseProxyIdentification] - error: {}", e.what()); close(FORCE_CLOSE); @@ -204,11 +208,12 @@ void Connection::parseHeader(const std::error_code &error) { try { readTimer.expires_from_now(std::chrono::seconds(CONNECTION_READ_TIMEOUT)); - readTimer.async_wait(std::bind(&Connection::handleTimeout, std::weak_ptr(shared_from_this()), std::placeholders::_1)); + readTimer.async_wait([self = shared_from_this()](const std::error_code &error) { Connection::handleTimeout(std::weak_ptr(self), error); }); // Read packet content msg.setLength(size + HEADER_LENGTH); - asio::async_read(socket, asio::buffer(msg.getBodyBuffer(), size), std::bind(&Connection::parsePacket, shared_from_this(), std::placeholders::_1)); + // Read the remainder of proxy identification + asio::async_read(socket, asio::buffer(msg.getBodyBuffer(), size), [self = shared_from_this()](const std::error_code &error, std::size_t N) { self->parsePacket(error); }); } catch (const std::system_error &e) { g_logger().error("[Connection::parseHeader] - error: {}", e.what()); close(FORCE_CLOSE); @@ -270,11 +275,11 @@ void Connection::parsePacket(const std::error_code &error) { try { readTimer.expires_from_now(std::chrono::seconds(CONNECTION_READ_TIMEOUT)); - readTimer.async_wait(std::bind(&Connection::handleTimeout, std::weak_ptr(shared_from_this()), std::placeholders::_1)); + readTimer.async_wait([self = shared_from_this()](const std::error_code &error) { Connection::handleTimeout(std::weak_ptr(self), error); }); if (!skipReadingNextPacket) { // Wait to the next packet - asio::async_read(socket, asio::buffer(msg.getBuffer(), HEADER_LENGTH), std::bind(&Connection::parseHeader, shared_from_this(), std::placeholders::_1)); + asio::async_read(socket, asio::buffer(msg.getBuffer(), HEADER_LENGTH), [self = shared_from_this()](const std::error_code &error, std::size_t N) { self->parseHeader(error); }); } } catch (const std::system_error &e) { g_logger().error("[Connection::parsePacket] - error: {}", e.what()); @@ -284,10 +289,10 @@ void Connection::parsePacket(const std::error_code &error) { void Connection::resumeWork() { readTimer.expires_from_now(std::chrono::seconds(CONNECTION_READ_TIMEOUT)); - readTimer.async_wait(std::bind(&Connection::handleTimeout, std::weak_ptr(shared_from_this()), std::placeholders::_1)); + readTimer.async_wait([self = shared_from_this()](const std::error_code &error) { Connection::handleTimeout(std::weak_ptr(self), error); }); try { - asio::async_read(socket, asio::buffer(msg.getBuffer(), HEADER_LENGTH), std::bind(&Connection::parseHeader, shared_from_this(), std::placeholders::_1)); + asio::async_read(socket, asio::buffer(msg.getBuffer(), HEADER_LENGTH), [self = shared_from_this()](const std::error_code &error, std::size_t N) { self->parseHeader(error); }); } catch (const std::system_error &e) { g_logger().error("[Connection::resumeWork] - Exception in async_read: {}", e.what()); close(FORCE_CLOSE); @@ -306,7 +311,7 @@ void Connection::send(const OutputMessage_ptr &outputMessage) { if (noPendingWrite) { if (socket.is_open()) { try { - asio::post(socket.get_executor(), std::bind(&Connection::internalWorker, shared_from_this())); + asio::post(socket.get_executor(), [self = shared_from_this()] { self->internalWorker(); }); } catch (const std::system_error &e) { g_logger().error("[Connection::send] - Exception in posting write operation: {}", e.what()); close(FORCE_CLOSE); @@ -353,10 +358,10 @@ uint32_t Connection::getIP() { void Connection::internalSend(const OutputMessage_ptr &outputMessage) { writeTimer.expires_from_now(std::chrono::seconds(CONNECTION_WRITE_TIMEOUT)); - writeTimer.async_wait(std::bind(&Connection::handleTimeout, std::weak_ptr(shared_from_this()), std::placeholders::_1)); + readTimer.async_wait([self = shared_from_this()](const std::error_code &error) { Connection::handleTimeout(std::weak_ptr(self), error); }); try { - asio::async_write(socket, asio::buffer(outputMessage->getOutputBuffer(), outputMessage->getLength()), std::bind(&Connection::onWriteOperation, shared_from_this(), std::placeholders::_1)); + asio::async_write(socket, asio::buffer(outputMessage->getOutputBuffer(), outputMessage->getLength()), [self = shared_from_this()](const std::error_code &error, std::size_t N) { self->onWriteOperation(error); }); } catch (const std::system_error &e) { g_logger().error("[Connection::internalSend] - Exception in async_write: {}", e.what()); close(FORCE_CLOSE); diff --git a/src/server/network/message/outputmessage.cpp b/src/server/network/message/outputmessage.cpp index 6ede36da406..efed7fe8367 100644 --- a/src/server/network/message/outputmessage.cpp +++ b/src/server/network/message/outputmessage.cpp @@ -16,8 +16,9 @@ const std::chrono::milliseconds OUTPUTMESSAGE_AUTOSEND_DELAY { 10 }; void OutputMessagePool::scheduleSendAll() { - auto function = std::bind_front(&OutputMessagePool::sendAll, this); - g_dispatcher().scheduleEvent(OUTPUTMESSAGE_AUTOSEND_DELAY.count(), function, "OutputMessagePool::sendAll"); + g_dispatcher().scheduleEvent( + OUTPUTMESSAGE_AUTOSEND_DELAY.count(), [this] { sendAll(); }, "OutputMessagePool::sendAll" + ); } void OutputMessagePool::sendAll() { diff --git a/src/server/network/protocol/protocolgame.cpp b/src/server/network/protocol/protocolgame.cpp index 5398155067e..0d0d8e79f17 100644 --- a/src/server/network/protocol/protocolgame.cpp +++ b/src/server/network/protocol/protocolgame.cpp @@ -248,16 +248,6 @@ ProtocolGame::ProtocolGame(Connection_ptr initConnection) : version = CLIENT_VERSION; } -template -void ProtocolGame::addGameTask(Callable function, Args &&... args) { - g_dispatcher().addEvent(std::bind(function, &g_game(), std::forward(args)...), "ProtocolGame::addGameTask"); -} - -template -void ProtocolGame::addGameTaskTimed(uint32_t delay, std::string_view context, Callable function, Args &&... args) { - g_dispatcher().addEvent(std::bind(function, &g_game(), std::forward(args)...), context, delay); -} - void ProtocolGame::AddItem(NetworkMessage &msg, uint16_t id, uint8_t count, uint8_t tier) { const ItemType &it = Item::items[id]; @@ -629,7 +619,10 @@ void ProtocolGame::login(const std::string &name, uint32_t accountId, OperatingS foundPlayer->disconnect(); foundPlayer->isConnecting = true; - eventConnect = g_dispatcher().scheduleEvent(1000, std::bind(&ProtocolGame::connect, getThis(), foundPlayer->getName(), operatingSystem), "ProtocolGame::connect"); + eventConnect = g_dispatcher().scheduleEvent( + 1000, + [self = getThis(), playerName = foundPlayer->getName(), operatingSystem] { self->connect(playerName, operatingSystem); }, "ProtocolGame::connect" + ); } else { connect(foundPlayer->getName(), operatingSystem); } @@ -842,11 +835,13 @@ void ProtocolGame::onRecvFirstMessage(NetworkMessage &msg) { output->addByte(0x14); output->addString(ss.str(), "ProtocolGame::onRecvFirstMessage - ss.str()"); send(output); - g_dispatcher().scheduleEvent(1000, std::bind(&ProtocolGame::disconnect, getThis()), "ProtocolGame::disconnect"); + g_dispatcher().scheduleEvent( + 1000, [self = getThis()] { self->disconnect(); }, "ProtocolGame::disconnect" + ); return; } - g_dispatcher().addEvent(std::bind(&ProtocolGame::login, getThis(), characterName, accountId, operatingSystem), "ProtocolGame::login"); + g_dispatcher().addEvent([self = getThis(), characterName, accountId, operatingSystem] { self->login(characterName, accountId, operatingSystem); }, "ProtocolGame::login"); } void ProtocolGame::onConnect() { @@ -907,20 +902,20 @@ void ProtocolGame::parsePacket(NetworkMessage &msg) { if (player->isDead() || player->getHealth() <= 0) { // Check player activity on death screen if (m_playerDeathTime == 0) { - addGameTask(&Game::playerCheckActivity, player->getName(), 1000); + g_game().playerCheckActivity(player->getName(), 1000); m_playerDeathTime++; } - g_dispatcher().addEvent(std::bind(&ProtocolGame::parsePacketDead, getThis(), recvbyte), "ProtocolGame::parsePacketDead"); + parsePacketDead(recvbyte); return; } // Modules system if (player && recvbyte != 0xD3) { - g_dispatcher().addEvent(std::bind(&Modules::executeOnRecvbyte, &g_modules(), player->getID(), msg, recvbyte), "Modules::executeOnRecvbyte"); + g_modules().executeOnRecvbyte(player->getID(), msg, recvbyte); } - g_dispatcher().addEvent(std::bind(&ProtocolGame::parsePacketFromDispatcher, getThis(), msg, recvbyte), "ProtocolGame::parsePacketFromDispatcher"); + parsePacketFromDispatcher(msg, recvbyte); } void ProtocolGame::parsePacketDead(uint8_t recvbyte) { @@ -930,7 +925,7 @@ void ProtocolGame::parsePacketDead(uint8_t recvbyte) { g_game().removePlayerUniqueLogin(player->getName()); } disconnect(); - g_dispatcher().addEvent(std::bind(&IOLoginData::updateOnlineStatus, player->getGUID(), false), "IOLoginData::updateOnlineStatus"); + IOLoginData::updateOnlineStatus(player->getGUID(), false); return; } @@ -939,23 +934,27 @@ void ProtocolGame::parsePacketDead(uint8_t recvbyte) { return; } - g_dispatcher().scheduleEvent(100, std::bind(&ProtocolGame::sendPing, getThis()), "ProtocolGame::sendPing"); + g_dispatcher().scheduleEvent( + 100, [self = getThis()] { self->sendPing(); }, "ProtocolGame::sendPing" + ); if (!player->spawn()) { disconnect(); - addGameTask(&Game::removeCreature, player, true); + g_game().removeCreature(player, true); return; } - g_dispatcher().addEvent(std::bind(&ProtocolGame::sendAddCreature, getThis(), player, player->getPosition(), 0, false), "ProtocolGame::sendAddCreature"); - g_dispatcher().addEvent(std::bind(&ProtocolGame::addBless, getThis()), "ProtocolGame::addBless"); + sendAddCreature(player, player->getPosition(), 0, false); + addBless(); resetPlayerDeathTime(); return; } if (recvbyte == 0x1D) { // keep the connection alive - g_dispatcher().scheduleEvent(100, std::bind(&ProtocolGame::sendPingBack, getThis()), "ProtocolGame::sendPingBack"); + g_dispatcher().scheduleEvent( + 100, [self = getThis()] { self->sendPingBack(); }, "ProtocolGame::sendPingBack" + ); return; } } @@ -978,13 +977,13 @@ void ProtocolGame::parsePacketFromDispatcher(NetworkMessage msg, uint8_t recvbyt switch (recvbyte) { case 0x14: - g_dispatcher().addEvent(std::bind(&ProtocolGame::logout, getThis(), true, false), "ProtocolGame::logout"); + logout(true, false); break; case 0x1D: - addGameTask(&Game::playerReceivePingBack, player->getID()); + g_game().playerReceivePingBack(player->getID()); break; case 0x1E: - addGameTask(&Game::playerReceivePing, player->getID()); + g_game().playerReceivePing(player->getID()); break; case 0x2a: parseCyclopediaMonsterTracker(msg); @@ -1020,43 +1019,43 @@ void ProtocolGame::parsePacketFromDispatcher(NetworkMessage msg, uint8_t recvbyt parseAutoWalk(msg); break; case 0x65: - addGameTask(&Game::playerMove, player->getID(), DIRECTION_NORTH); + g_game().playerMove(player->getID(), DIRECTION_NORTH); break; case 0x66: - addGameTask(&Game::playerMove, player->getID(), DIRECTION_EAST); + g_game().playerMove(player->getID(), DIRECTION_EAST); break; case 0x67: - addGameTask(&Game::playerMove, player->getID(), DIRECTION_SOUTH); + g_game().playerMove(player->getID(), DIRECTION_SOUTH); break; case 0x68: - addGameTask(&Game::playerMove, player->getID(), DIRECTION_WEST); + g_game().playerMove(player->getID(), DIRECTION_WEST); break; case 0x69: - addGameTask(&Game::playerStopAutoWalk, player->getID()); + g_game().playerStopAutoWalk(player->getID()); break; case 0x6A: - addGameTask(&Game::playerMove, player->getID(), DIRECTION_NORTHEAST); + g_game().playerMove(player->getID(), DIRECTION_NORTHEAST); break; case 0x6B: - addGameTask(&Game::playerMove, player->getID(), DIRECTION_SOUTHEAST); + g_game().playerMove(player->getID(), DIRECTION_SOUTHEAST); break; case 0x6C: - addGameTask(&Game::playerMove, player->getID(), DIRECTION_SOUTHWEST); + g_game().playerMove(player->getID(), DIRECTION_SOUTHWEST); break; case 0x6D: - addGameTask(&Game::playerMove, player->getID(), DIRECTION_NORTHWEST); + g_game().playerMove(player->getID(), DIRECTION_NORTHWEST); break; case 0x6F: - addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, "Game::playerTurn", &Game::playerTurn, player->getID(), DIRECTION_NORTH); + g_game().playerTurn(player->getID(), DIRECTION_NORTH); break; case 0x70: - addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, "Game::playerTurn", &Game::playerTurn, player->getID(), DIRECTION_EAST); + g_game().playerTurn(player->getID(), DIRECTION_EAST); break; case 0x71: - addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, "Game::playerTurn", &Game::playerTurn, player->getID(), DIRECTION_SOUTH); + g_game().playerTurn(player->getID(), DIRECTION_SOUTH); break; case 0x72: - addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, "Game::playerTurn", &Game::playerTurn, player->getID(), DIRECTION_WEST); + g_game().playerTurn(player->getID(), DIRECTION_WEST); break; case 0x73: parseTeleport(msg); @@ -1077,7 +1076,7 @@ void ProtocolGame::parsePacketFromDispatcher(NetworkMessage msg, uint8_t recvbyt parsePlayerSellOnShop(msg); break; case 0x7C: - addGameTask(&Game::playerCloseShop, player->getID()); + g_game().playerCloseShop(player->getID()); break; case 0x7D: parseRequestTrade(msg); @@ -1086,10 +1085,10 @@ void ProtocolGame::parsePacketFromDispatcher(NetworkMessage msg, uint8_t recvbyt parseLookInTrade(msg); break; case 0x7F: - addGameTask(&Game::playerAcceptTrade, player->getID()); + g_game().playerAcceptTrade(player->getID()); break; case 0x80: - addGameTask(&Game::playerCloseTrade, player->getID()); + g_game().playerCloseTrade(player->getID()); break; case 0x82: parseUseItem(msg); @@ -1154,7 +1153,7 @@ void ProtocolGame::parsePacketFromDispatcher(NetworkMessage msg, uint8_t recvbyt parseSay(msg); break; case 0x97: - addGameTask(&Game::playerRequestChannels, player->getID()); + g_game().playerRequestChannels(player->getID()); break; case 0x98: parseOpenChannel(msg); @@ -1166,7 +1165,7 @@ void ProtocolGame::parsePacketFromDispatcher(NetworkMessage msg, uint8_t recvbyt parseOpenPrivateChannel(msg); break; case 0x9E: - addGameTask(&Game::playerCloseNpcChannel, player->getID()); + g_game().playerCloseNpcChannel(player->getID()); break; case 0x9F: parseSetMonsterPodium(msg); @@ -1193,13 +1192,13 @@ void ProtocolGame::parsePacketFromDispatcher(NetworkMessage msg, uint8_t recvbyt parsePassPartyLeadership(msg); break; case 0xA7: - addGameTask(&Game::playerLeaveParty, player->getID()); + g_game().playerLeaveParty(player->getID()); break; case 0xA8: parseEnableSharedPartyExperience(msg); break; case 0xAA: - addGameTask(&Game::playerCreatePrivateChannel, player->getID()); + g_game().playerCreatePrivateChannel(player->getID()); break; case 0xAB: parseChannelInvite(msg); @@ -1223,7 +1222,7 @@ void ProtocolGame::parsePacketFromDispatcher(NetworkMessage msg, uint8_t recvbyt parseTaskHuntingAction(msg); break; case 0xBE: - addGameTask(&Game::playerCancelAttackAndFollow, player->getID()); + g_game().playerCancelAttackAndFollow(player->getID()); break; case 0xBF: parseForgeEnter(msg); @@ -1246,11 +1245,10 @@ void ProtocolGame::parsePacketFromDispatcher(NetworkMessage msg, uint8_t recvbyt parseInspectionObject(msg); break; case 0xD2: - addGameTask(&Game::playerRequestOutfit, player->getID()); + g_game().playerRequestOutfit(player->getID()); break; - // g_dispatcher().addEvent(std::bind(&Modules::executeOnRecvbyte, g_modules, player, msg, recvbyte)); case 0xD3: - g_dispatcher().addEvent(std::bind(&ProtocolGame::parseSetOutfit, getThis(), msg), "ProtocolGame::parseSetOutfit"); + parseSetOutfit(msg); break; case 0xD4: parseToggleMount(msg); @@ -1309,7 +1307,7 @@ void ProtocolGame::parsePacketFromDispatcher(NetworkMessage msg, uint8_t recvbyt // Premium coins transfer // case 0xEF: parseCoinTransfer(msg); break; case 0xF0: - addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, "Game::playerShowQuestLog", &Game::playerShowQuestLog, player->getID()); + g_game().playerShowQuestLog(player->getID()); break; case 0xF1: parseQuestLine(msg); @@ -1360,7 +1358,7 @@ void ProtocolGame::parseHotkeyEquip(NetworkMessage &msg) { uint16_t itemId = msg.get(); uint8_t tier = msg.get(); - addGameTask(&Game::playerEquipItem, player->getID(), itemId, Item::items[itemId].upgradeClassification > 0, tier); + g_game().playerEquipItem(player->getID(), itemId, Item::items[itemId].upgradeClassification > 0, tier); } void ProtocolGame::GetTileDescription(std::shared_ptr tile, NetworkMessage &msg) { @@ -1563,27 +1561,27 @@ bool ProtocolGame::canSee(int32_t x, int32_t y, int32_t z) const { // Parse methods void ProtocolGame::parseChannelInvite(NetworkMessage &msg) { const std::string name = msg.getString(); - addGameTask(&Game::playerChannelInvite, player->getID(), name); + g_game().playerChannelInvite(player->getID(), name); } void ProtocolGame::parseChannelExclude(NetworkMessage &msg) { const std::string name = msg.getString(); - addGameTask(&Game::playerChannelExclude, player->getID(), name); + g_game().playerChannelExclude(player->getID(), name); } void ProtocolGame::parseOpenChannel(NetworkMessage &msg) { uint16_t channelId = msg.get(); - addGameTask(&Game::playerOpenChannel, player->getID(), channelId); + g_game().playerOpenChannel(player->getID(), channelId); } void ProtocolGame::parseCloseChannel(NetworkMessage &msg) { uint16_t channelId = msg.get(); - addGameTask(&Game::playerCloseChannel, player->getID(), channelId); + g_game().playerCloseChannel(player->getID(), channelId); } void ProtocolGame::parseOpenPrivateChannel(NetworkMessage &msg) { - const std::string receiver = msg.getString(); - addGameTask(&Game::playerOpenPrivateChannel, player->getID(), receiver); + std::string receiver = msg.getString(); + g_game().playerOpenPrivateChannel(player->getID(), receiver); } void ProtocolGame::parseAutoWalk(NetworkMessage &msg) { @@ -1631,7 +1629,7 @@ void ProtocolGame::parseAutoWalk(NetworkMessage &msg) { return; } - addGameTask(&Game::playerAutoWalk, player->getID(), path.data()); + g_game().playerAutoWalk(player->getID(), path.data()); } void ProtocolGame::parseSetOutfit(NetworkMessage &msg) { @@ -1688,23 +1686,23 @@ void ProtocolGame::parseSetOutfit(NetworkMessage &msg) { void ProtocolGame::parseToggleMount(NetworkMessage &msg) { bool mount = msg.getByte() != 0; - addGameTask(&Game::playerToggleMount, player->getID(), mount); + g_game().playerToggleMount(player->getID(), mount); } void ProtocolGame::parseApplyImbuement(NetworkMessage &msg) { uint8_t slot = msg.getByte(); uint32_t imbuementId = msg.get(); bool protectionCharm = msg.getByte() != 0x00; - addGameTask(&Game::playerApplyImbuement, player->getID(), imbuementId, slot, protectionCharm); + g_game().playerApplyImbuement(player->getID(), imbuementId, slot, protectionCharm); } void ProtocolGame::parseClearImbuement(NetworkMessage &msg) { uint8_t slot = msg.getByte(); - addGameTask(&Game::playerClearImbuement, player->getID(), slot); + g_game().playerClearImbuement(player->getID(), slot); } void ProtocolGame::parseCloseImbuementWindow(NetworkMessage &) { - addGameTask(&Game::playerCloseImbuementWindow, player->getID()); + g_game().playerCloseImbuementWindow(player->getID()); } void ProtocolGame::parseUseItem(NetworkMessage &msg) { @@ -1712,7 +1710,7 @@ void ProtocolGame::parseUseItem(NetworkMessage &msg) { uint16_t itemId = msg.get(); uint8_t stackpos = msg.getByte(); uint8_t index = msg.getByte(); - addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, "Game::playerUseItem", &Game::playerUseItem, player->getID(), pos, stackpos, index, itemId); + g_game().playerUseItem(player->getID(), pos, stackpos, index, itemId); } void ProtocolGame::parseUseItemEx(NetworkMessage &msg) { @@ -1722,7 +1720,7 @@ void ProtocolGame::parseUseItemEx(NetworkMessage &msg) { Position toPos = msg.getPosition(); uint16_t toItemId = msg.get(); uint8_t toStackPos = msg.getByte(); - addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, "Game::playerUseItemEx", &Game::playerUseItemEx, player->getID(), fromPos, fromStackPos, fromItemId, toPos, toStackPos, toItemId); + g_game().playerUseItemEx(player->getID(), fromPos, fromStackPos, fromItemId, toPos, toStackPos, toItemId); } void ProtocolGame::parseUseWithCreature(NetworkMessage &msg) { @@ -1730,27 +1728,27 @@ void ProtocolGame::parseUseWithCreature(NetworkMessage &msg) { uint16_t itemId = msg.get(); uint8_t fromStackPos = msg.getByte(); uint32_t creatureId = msg.get(); - addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, "Game::playerUseWithCreature", &Game::playerUseWithCreature, player->getID(), fromPos, fromStackPos, creatureId, itemId); + g_game().playerUseWithCreature(player->getID(), fromPos, fromStackPos, creatureId, itemId); } void ProtocolGame::parseCloseContainer(NetworkMessage &msg) { uint8_t cid = msg.getByte(); - addGameTask(&Game::playerCloseContainer, player->getID(), cid); + g_game().playerCloseContainer(player->getID(), cid); } void ProtocolGame::parseUpArrowContainer(NetworkMessage &msg) { uint8_t cid = msg.getByte(); - addGameTask(&Game::playerMoveUpContainer, player->getID(), cid); + g_game().playerMoveUpContainer(player->getID(), cid); } void ProtocolGame::parseUpdateContainer(NetworkMessage &msg) { uint8_t cid = msg.getByte(); - addGameTask(&Game::playerUpdateContainer, player->getID(), cid); + g_game().playerUpdateContainer(player->getID(), cid); } void ProtocolGame::parseTeleport(NetworkMessage &msg) { Position newPosition = msg.getPosition(); - addGameTask(&Game::playerTeleport, player->getID(), newPosition); + g_game().playerTeleport(player->getID(), newPosition); } void ProtocolGame::parseThrow(NetworkMessage &msg) { @@ -1761,7 +1759,7 @@ void ProtocolGame::parseThrow(NetworkMessage &msg) { uint8_t count = msg.getByte(); if (toPos != fromPos) { - addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, "Game::playerMoveThing", &Game::playerMoveThing, player->getID(), fromPos, itemId, fromStackpos, toPos, count); + g_game().playerMoveThing(player->getID(), fromPos, itemId, fromStackpos, toPos, count); } } @@ -1769,12 +1767,12 @@ void ProtocolGame::parseLookAt(NetworkMessage &msg) { Position pos = msg.getPosition(); uint16_t itemId = msg.get(); uint8_t stackpos = msg.getByte(); - addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, "Game::playerLookAt", &Game::playerLookAt, player->getID(), itemId, pos, stackpos); + g_game().playerLookAt(player->getID(), itemId, pos, stackpos); } void ProtocolGame::parseLookInBattleList(NetworkMessage &msg) { uint32_t creatureId = msg.get(); - addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, "Game::playerLookInBattleList", &Game::playerLookInBattleList, player->getID(), creatureId); + g_game().playerLookInBattleList(player->getID(), creatureId); } void ProtocolGame::parseQuickLoot(NetworkMessage &msg) { @@ -1787,7 +1785,7 @@ void ProtocolGame::parseQuickLoot(NetworkMessage &msg) { uint8_t stackpos = msg.getByte(); bool lootAllCorpses = msg.getByte(); bool autoLoot = msg.getByte(); - addGameTask(&Game::playerQuickLoot, player->getID(), pos, itemId, stackpos, nullptr, lootAllCorpses, autoLoot); + g_game().playerQuickLoot(player->getID(), pos, itemId, stackpos, nullptr, lootAllCorpses, autoLoot); } void ProtocolGame::parseLootContainer(NetworkMessage &msg) { @@ -1801,29 +1799,29 @@ void ProtocolGame::parseLootContainer(NetworkMessage &msg) { Position pos = msg.getPosition(); uint16_t itemId = msg.get(); uint8_t stackpos = msg.getByte(); - addGameTask(&Game::playerSetManagedContainer, player->getID(), category, pos, itemId, stackpos, true); + g_game().playerSetManagedContainer(player->getID(), category, pos, itemId, stackpos, true); } else if (action == 1) { ObjectCategory_t category = (ObjectCategory_t)msg.getByte(); - addGameTask(&Game::playerClearManagedContainer, player->getID(), category, true); + g_game().playerClearManagedContainer(player->getID(), category, true); } else if (action == 2) { ObjectCategory_t category = (ObjectCategory_t)msg.getByte(); - addGameTask(&Game::playerOpenManagedContainer, player->getID(), category, true); + g_game().playerOpenManagedContainer(player->getID(), category, true); } else if (action == 3) { bool useMainAsFallback = msg.getByte() == 1; - addGameTask(&Game::playerSetQuickLootFallback, player->getID(), useMainAsFallback); + g_game().playerSetQuickLootFallback(player->getID(), useMainAsFallback); } else if (action == 4) { ObjectCategory_t category = (ObjectCategory_t)msg.getByte(); Position pos = msg.getPosition(); uint16_t itemId = msg.get(); uint8_t stackpos = msg.getByte(); g_logger().debug("[{}] action {}, category {}, pos {}, itemId {}, stackPos {}", __FUNCTION__, action, static_cast(category), pos.toString(), itemId, stackpos); - addGameTask(&Game::playerSetManagedContainer, player->getID(), category, pos, itemId, stackpos, false); + g_game().playerSetManagedContainer(player->getID(), category, pos, itemId, stackpos, false); } else if (action == 5) { ObjectCategory_t category = (ObjectCategory_t)msg.getByte(); - addGameTask(&Game::playerClearManagedContainer, player->getID(), category, false); + g_game().playerClearManagedContainer(player->getID(), category, false); } else if (action == 6) { ObjectCategory_t category = (ObjectCategory_t)msg.getByte(); - addGameTask(&Game::playerOpenManagedContainer, player->getID(), category, false); + g_game().playerOpenManagedContainer(player->getID(), category, false); } g_logger().debug("[{}] action type {}", __FUNCTION__, action); @@ -1844,7 +1842,7 @@ void ProtocolGame::parseQuickLootBlackWhitelist(NetworkMessage &msg) { listedItems.push_back(msg.get()); } - addGameTask(&Game::playerQuickLootBlackWhitelist, player->getID(), filter, listedItems); + g_game().playerQuickLootBlackWhitelist(player->getID(), filter, listedItems); } void ProtocolGame::parseSay(NetworkMessage &msg) { @@ -1874,7 +1872,7 @@ void ProtocolGame::parseSay(NetworkMessage &msg) { return; } - addGameTask(&Game::playerSay, player->getID(), channelId, type, receiver, text); + g_game().playerSay(player->getID(), channelId, type, receiver, text); } void ProtocolGame::parseFightModes(NetworkMessage &msg) { @@ -1892,38 +1890,38 @@ void ProtocolGame::parseFightModes(NetworkMessage &msg) { fightMode = FIGHTMODE_DEFENSE; } - addGameTask(&Game::playerSetFightModes, player->getID(), fightMode, rawChaseMode != 0, rawSecureMode != 0); + g_game().playerSetFightModes(player->getID(), fightMode, rawChaseMode != 0, rawSecureMode != 0); } void ProtocolGame::parseAttack(NetworkMessage &msg) { uint32_t creatureId = msg.get(); // msg.get(); creatureId (same as above) - addGameTask(&Game::playerSetAttackedCreature, player->getID(), creatureId); + g_game().playerSetAttackedCreature(player->getID(), creatureId); } void ProtocolGame::parseFollow(NetworkMessage &msg) { uint32_t creatureId = msg.get(); // msg.get(); creatureId (same as above) - addGameTask(&Game::playerFollowCreature, player->getID(), creatureId); + g_game().playerFollowCreature(player->getID(), creatureId); } void ProtocolGame::parseTextWindow(NetworkMessage &msg) { uint32_t windowTextId = msg.get(); const std::string newText = msg.getString(); - addGameTask(&Game::playerWriteItem, player->getID(), windowTextId, newText); + g_game().playerWriteItem(player->getID(), windowTextId, newText); } void ProtocolGame::parseHouseWindow(NetworkMessage &msg) { uint8_t doorId = msg.getByte(); uint32_t id = msg.get(); const std::string text = msg.getString(); - addGameTask(&Game::playerUpdateHouseWindow, player->getID(), doorId, id, text); + g_game().playerUpdateHouseWindow(player->getID(), doorId, id, text); } void ProtocolGame::parseLookInShop(NetworkMessage &msg) { uint16_t id = msg.get(); uint8_t count = msg.getByte(); - addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, "Game::playerLookInShop", &Game::playerLookInShop, player->getID(), id, count); + g_game().playerLookInShop(player->getID(), id, count); } void ProtocolGame::parsePlayerBuyOnShop(NetworkMessage &msg) { @@ -1932,7 +1930,7 @@ void ProtocolGame::parsePlayerBuyOnShop(NetworkMessage &msg) { uint16_t amount = oldProtocol ? static_cast(msg.getByte()) : msg.get(); bool ignoreCap = msg.getByte() != 0; bool inBackpacks = msg.getByte() != 0; - addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, "Game::playerBuyItem", &Game::playerBuyItem, player->getID(), id, count, amount, ignoreCap, inBackpacks); + g_game().playerBuyItem(player->getID(), id, count, amount, ignoreCap, inBackpacks); } void ProtocolGame::parsePlayerSellOnShop(NetworkMessage &msg) { @@ -1941,7 +1939,7 @@ void ProtocolGame::parsePlayerSellOnShop(NetworkMessage &msg) { uint16_t amount = oldProtocol ? static_cast(msg.getByte()) : msg.get(); bool ignoreEquipped = msg.getByte() != 0; - addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, "Game::playerSellItem", &Game::playerSellItem, player->getID(), id, count, amount, ignoreEquipped); + g_game().playerSellItem(player->getID(), id, count, amount, ignoreEquipped); } void ProtocolGame::parseRequestTrade(NetworkMessage &msg) { @@ -1949,23 +1947,23 @@ void ProtocolGame::parseRequestTrade(NetworkMessage &msg) { uint16_t itemId = msg.get(); uint8_t stackpos = msg.getByte(); uint32_t playerId = msg.get(); - addGameTask(&Game::playerRequestTrade, player->getID(), pos, stackpos, playerId, itemId); + g_game().playerRequestTrade(player->getID(), pos, stackpos, playerId, itemId); } void ProtocolGame::parseLookInTrade(NetworkMessage &msg) { bool counterOffer = (msg.getByte() == 0x01); uint8_t index = msg.getByte(); - addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, "Game::playerLookInTrade", &Game::playerLookInTrade, player->getID(), counterOffer, index); + g_game().playerLookInTrade(player->getID(), counterOffer, index); } void ProtocolGame::parseAddVip(NetworkMessage &msg) { const std::string name = msg.getString(); - addGameTask(&Game::playerRequestAddVip, player->getID(), name); + g_game().playerRequestAddVip(player->getID(), name); } void ProtocolGame::parseRemoveVip(NetworkMessage &msg) { uint32_t guid = msg.get(); - addGameTask(&Game::playerRequestRemoveVip, player->getID(), guid); + g_game().playerRequestRemoveVip(player->getID(), guid); } void ProtocolGame::parseEditVip(NetworkMessage &msg) { @@ -1973,7 +1971,7 @@ void ProtocolGame::parseEditVip(NetworkMessage &msg) { const std::string description = msg.getString(); uint32_t icon = std::min(10, msg.get()); // 10 is max icon in 9.63 bool notify = msg.getByte() != 0; - addGameTask(&Game::playerRequestEditVip, player->getID(), guid, description, icon, notify); + g_game().playerRequestEditVip(player->getID(), guid, description, icon, notify); } void ProtocolGame::parseRotateItem(NetworkMessage &msg) { @@ -1982,9 +1980,9 @@ void ProtocolGame::parseRotateItem(NetworkMessage &msg) { uint8_t stackpos = msg.getByte(); const auto &itemType = Item::items[itemId]; if (itemType.isPodium) { - addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, "Game::playerRotatePodium", &Game::playerRotatePodium, player->getID(), pos, stackpos, itemId); + g_game().playerRotatePodium(player->getID(), pos, stackpos, itemId); } else { - addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, "Game::playerRotateItem", &Game::playerRotateItem, player->getID(), pos, stackpos, itemId); + g_game().playerRotateItem(player->getID(), pos, stackpos, itemId); } } @@ -1992,7 +1990,7 @@ void ProtocolGame::parseWrapableItem(NetworkMessage &msg) { Position pos = msg.getPosition(); uint16_t itemId = msg.get(); uint8_t stackpos = msg.getByte(); - addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, "Game::playerWrapableItem", &Game::playerWrapableItem, player->getID(), pos, stackpos, itemId); + g_game().playerWrapableItem(player->getID(), pos, stackpos, itemId); } void ProtocolGame::parseInspectionObject(NetworkMessage &msg) { @@ -2106,7 +2104,7 @@ void ProtocolGame::parseTaskHuntingAction(NetworkMessage &msg) { return; } - addGameTask(&Game::playerTaskHuntingAction, player->getID(), slot, action, upgrade, raceId); + g_game().playerTaskHuntingAction(player->getID(), slot, action, upgrade, raceId); } void ProtocolGame::sendHighscoresNoData() { @@ -2220,7 +2218,7 @@ void ProtocolGame::parseRuleViolationReport(NetworkMessage &msg) { msg.get(); // statement id, used to get whatever player have said, we don't log that. } - addGameTask(&Game::playerReportRuleViolationReport, player->getID(), targetName, reportType, reportReason, comment, translation); + g_game().playerReportRuleViolationReport(player->getID(), targetName, reportType, reportReason, comment, translation); } void ProtocolGame::parseBestiarysendRaces() { @@ -2942,12 +2940,12 @@ void ProtocolGame::parseBugReport(NetworkMessage &msg) { position = msg.getPosition(); } - addGameTask(&Game::playerReportBug, player->getID(), message, position, category); + g_game().playerReportBug(player->getID(), message, position, category); } void ProtocolGame::parseGreet(NetworkMessage &msg) { uint32_t npcId = msg.get(); - addGameTask(&Game::playerNpcGreet, player->getID(), npcId); + g_game().playerNpcGreet(player->getID(), npcId); } void ProtocolGame::parseDebugAssert(NetworkMessage &msg) { @@ -2961,7 +2959,7 @@ void ProtocolGame::parseDebugAssert(NetworkMessage &msg) { std::string date = msg.getString(); std::string description = msg.getString(); std::string comment = msg.getString(); - addGameTask(&Game::playerDebugAssert, player->getID(), assertLine, date, description, comment); + g_game().playerDebugAssert(player->getID(), assertLine, date, description, comment); } void ProtocolGame::parsePreyAction(NetworkMessage &msg) { @@ -2982,7 +2980,7 @@ void ProtocolGame::parsePreyAction(NetworkMessage &msg) { return; } - addGameTask(&Game::playerPreyAction, player->getID(), slot, action, option, index, raceId); + g_game().playerPreyAction(player->getID(), slot, action, option, index, raceId); } void ProtocolGame::parseSendResourceBalance() { @@ -3001,52 +2999,52 @@ void ProtocolGame::parseSendResourceBalance() { void ProtocolGame::parseInviteToParty(NetworkMessage &msg) { uint32_t targetId = msg.get(); - addGameTask(&Game::playerInviteToParty, player->getID(), targetId); + g_game().playerInviteToParty(player->getID(), targetId); } void ProtocolGame::parseJoinParty(NetworkMessage &msg) { uint32_t targetId = msg.get(); - addGameTask(&Game::playerJoinParty, player->getID(), targetId); + g_game().playerJoinParty(player->getID(), targetId); } void ProtocolGame::parseRevokePartyInvite(NetworkMessage &msg) { uint32_t targetId = msg.get(); - addGameTask(&Game::playerRevokePartyInvitation, player->getID(), targetId); + g_game().playerRevokePartyInvitation(player->getID(), targetId); } void ProtocolGame::parsePassPartyLeadership(NetworkMessage &msg) { uint32_t targetId = msg.get(); - addGameTask(&Game::playerPassPartyLeadership, player->getID(), targetId); + g_game().playerPassPartyLeadership(player->getID(), targetId); } void ProtocolGame::parseEnableSharedPartyExperience(NetworkMessage &msg) { bool sharedExpActive = msg.getByte() == 1; - addGameTask(&Game::playerEnableSharedPartyExperience, player->getID(), sharedExpActive); + g_game().playerEnableSharedPartyExperience(player->getID(), sharedExpActive); } void ProtocolGame::parseQuestLine(NetworkMessage &msg) { uint16_t questId = msg.get(); - addGameTask(&Game::playerShowQuestLine, player->getID(), questId); + g_game().playerShowQuestLine(player->getID(), questId); } void ProtocolGame::parseMarketLeave() { - addGameTask(&Game::playerLeaveMarket, player->getID()); + g_game().playerLeaveMarket(player->getID()); } void ProtocolGame::parseMarketBrowse(NetworkMessage &msg) { uint16_t browseId = oldProtocol ? msg.get() : static_cast(msg.getByte()); if ((oldProtocol && browseId == MARKETREQUEST_OWN_OFFERS_OLD) || (!oldProtocol && browseId == MARKETREQUEST_OWN_OFFERS)) { - addGameTask(&Game::playerBrowseMarketOwnOffers, player->getID()); + g_game().playerBrowseMarketOwnOffers(player->getID()); } else if ((oldProtocol && browseId == MARKETREQUEST_OWN_HISTORY_OLD) || (!oldProtocol && browseId == MARKETREQUEST_OWN_HISTORY)) { - addGameTask(&Game::playerBrowseMarketOwnHistory, player->getID()); + g_game().playerBrowseMarketOwnHistory(player->getID()); } else if (!oldProtocol) { uint16_t itemId = msg.get(); uint8_t tier = msg.get(); player->sendMarketEnter(player->getLastDepotId()); - addGameTask(&Game::playerBrowseMarket, player->getID(), itemId, tier); + g_game().playerBrowseMarket(player->getID(), itemId, tier); } else { - addGameTask(&Game::playerBrowseMarket, player->getID(), browseId, 0); + g_game().playerBrowseMarket(player->getID(), browseId, 0); } } @@ -3062,7 +3060,7 @@ void ProtocolGame::parseMarketCreateOffer(NetworkMessage &msg) { uint64_t price = oldProtocol ? static_cast(msg.get()) : msg.get(); bool anonymous = (msg.getByte() != 0); if (amount > 0 && price > 0) { - addGameTask(&Game::playerCreateMarketOffer, player->getID(), type, itemId, amount, price, itemTier, anonymous); + g_game().playerCreateMarketOffer(player->getID(), type, itemId, amount, price, itemTier, anonymous); } } @@ -3070,7 +3068,7 @@ void ProtocolGame::parseMarketCancelOffer(NetworkMessage &msg) { uint32_t timestamp = msg.get(); uint16_t counter = msg.get(); if (counter > 0) { - addGameTask(&Game::playerCancelMarketOffer, player->getID(), timestamp, counter); + g_game().playerCancelMarketOffer(player->getID(), timestamp, counter); } updateCoinBalance(); @@ -3081,7 +3079,7 @@ void ProtocolGame::parseMarketAcceptOffer(NetworkMessage &msg) { uint16_t counter = msg.get(); uint16_t amount = msg.get(); if (amount > 0 && counter > 0) { - addGameTask(&Game::playerAcceptMarketOffer, player->getID(), timestamp, counter, amount); + g_game().playerAcceptMarketOffer(player->getID(), timestamp, counter, amount); } updateCoinBalance(); @@ -3091,7 +3089,7 @@ void ProtocolGame::parseModalWindowAnswer(NetworkMessage &msg) { uint32_t id = msg.get(); uint8_t button = msg.getByte(); uint8_t choice = msg.getByte(); - addGameTask(&Game::playerAnswerModalWindow, player->getID(), id, button, choice); + g_game().playerAnswerModalWindow(player->getID(), id, button, choice); } void ProtocolGame::parseRewardChestCollect(NetworkMessage &msg) { @@ -3106,19 +3104,19 @@ void ProtocolGame::parseRewardChestCollect(NetworkMessage &msg) { } auto maxCollectItems = g_configManager().getNumber(REWARD_CHEST_MAX_COLLECT_ITEMS, __FUNCTION__); - addGameTask(&Game::playerRewardChestCollect, player->getID(), position, itemId, stackPosition, maxCollectItems); + g_game().playerRewardChestCollect(player->getID(), position, itemId, stackPosition, maxCollectItems); } void ProtocolGame::parseBrowseField(NetworkMessage &msg) { const Position &pos = msg.getPosition(); - addGameTask(&Game::playerBrowseField, player->getID(), pos); + g_game().playerBrowseField(player->getID(), pos); } void ProtocolGame::parseSeekInContainer(NetworkMessage &msg) { uint8_t containerId = msg.getByte(); uint16_t index = msg.get(); auto primaryType = msg.getByte(); - addGameTask(&Game::playerSeekInContainer, player->getID(), containerId, index, primaryType); + g_game().playerSeekInContainer(player->getID(), containerId, index, primaryType); } // Send methods @@ -4660,23 +4658,18 @@ void ProtocolGame::updateCoinBalance() { return; } - g_dispatcher().addEvent( - std::bind( - [](uint32_t playerId) { - auto threadPlayer = g_game().getPlayerByID(playerId); - if (threadPlayer && threadPlayer->getAccount()) { - auto [coins, errCoin] = threadPlayer->getAccount()->getCoins(enumToValue(CoinType::Normal)); - auto [transferCoins, errTCoin] = threadPlayer->getAccount()->getCoins(enumToValue(CoinType::Transferable)); + g_dispatcher().addEvent([playerId = player->getID()] { + const auto &threadPlayer = g_game().getPlayerByID(playerId); + if (threadPlayer && threadPlayer->getAccount()) { + const auto [coins, errCoin] = threadPlayer->getAccount()->getCoins(enumToValue(CoinType::Normal)); + const auto [transferCoins, errTCoin] = threadPlayer->getAccount()->getCoins(enumToValue(CoinType::Transferable)); - threadPlayer->coinBalance = coins; - threadPlayer->coinTransferableBalance = transferCoins; - threadPlayer->sendCoinBalance(); - } - }, - player->getID() - ), - "ProtocolGame::updateCoinBalance" - ); + threadPlayer->coinBalance = coins; + threadPlayer->coinTransferableBalance = transferCoins; + threadPlayer->sendCoinBalance(); + } + }, + "ProtocolGame::updateCoinBalance"); } void ProtocolGame::sendMarketLeave() { @@ -5028,7 +5021,7 @@ void ProtocolGame::sendOpenForge() { getForgeInfoMap(item, receiveTierItemMap); } if (itemClassification == 4) { - getForgeInfoMap(item, convergenceItemsMap[item->getSlotPosition()]); + getForgeInfoMap(item, convergenceItemsMap[item->getClassification()]); } } } @@ -5224,11 +5217,11 @@ void ProtocolGame::parseForgeEnter(NetworkMessage &msg) { bool usedCore = msg.getByte(); bool reduceTierLoss = msg.getByte(); if (actionType == ForgeAction_t::FUSION) { - addGameTask(&Game::playerForgeFuseItems, player->getID(), actionType, firstItem, tier, secondItem, usedCore, reduceTierLoss, convergence); + g_game().playerForgeFuseItems(player->getID(), actionType, firstItem, tier, secondItem, usedCore, reduceTierLoss, convergence); } else if (actionType == ForgeAction_t::TRANSFER) { - addGameTask(&Game::playerForgeTransferItemTier, player->getID(), actionType, firstItem, tier, secondItem, convergence); + g_game().playerForgeTransferItemTier(player->getID(), actionType, firstItem, tier, secondItem, convergence); } else if (actionType <= ForgeAction_t::INCREASELIMIT) { - addGameTask(&Game::playerForgeResourceConversion, player->getID(), actionType); + g_game().playerForgeResourceConversion(player->getID(), actionType); } } @@ -5237,7 +5230,7 @@ void ProtocolGame::parseForgeBrowseHistory(NetworkMessage &msg) { return; } - addGameTask(&Game::playerBrowseForgeHistory, player->getID(), msg.getByte()); + g_game().playerBrowseForgeHistory(player->getID(), msg.getByte()); } void ProtocolGame::sendForgeResult(ForgeAction_t actionType, uint16_t leftItemId, uint8_t leftTier, uint16_t rightItemId, uint8_t rightTier, bool success, uint8_t bonus, uint8_t coreCount, bool convergence) { @@ -7884,7 +7877,7 @@ void ProtocolGame::parseExtendedOpcode(NetworkMessage &msg) { const std::string &buffer = msg.getString(); // process additional opcodes via lua script event - addGameTask(&Game::parsePlayerExtendedOpcode, player->getID(), opcode, buffer); + g_game().parsePlayerExtendedOpcode(player->getID(), opcode, buffer); } // OTCv8 @@ -7917,7 +7910,7 @@ void ProtocolGame::parseInventoryImbuements(NetworkMessage &msg) { } bool isTrackerOpen = msg.getByte(); // Window is opened or closed - addGameTask(&Game::playerRequestInventoryImbuements, player->getID(), isTrackerOpen); + g_game().playerRequestInventoryImbuements(player->getID(), isTrackerOpen); } void ProtocolGame::sendInventoryImbuements(const std::map> items) { @@ -8082,28 +8075,28 @@ void ProtocolGame::parseStashWithdraw(NetworkMessage &msg) { uint16_t itemId = msg.get(); uint8_t stackpos = msg.getByte(); uint32_t count = msg.getByte(); - addGameTask(&Game::playerStowItem, player->getID(), pos, itemId, stackpos, count, false); + g_game().playerStowItem(player->getID(), pos, itemId, stackpos, count, false); break; } case SUPPLY_STASH_ACTION_STOW_CONTAINER: { Position pos = msg.getPosition(); uint16_t itemId = msg.get(); uint8_t stackpos = msg.getByte(); - addGameTask(&Game::playerStowItem, player->getID(), pos, itemId, stackpos, 0, false); + g_game().playerStowItem(player->getID(), pos, itemId, stackpos, 0, false); break; } case SUPPLY_STASH_ACTION_STOW_STACK: { Position pos = msg.getPosition(); uint16_t itemId = msg.get(); uint8_t stackpos = msg.getByte(); - addGameTask(&Game::playerStowItem, player->getID(), pos, itemId, stackpos, 0, true); + g_game().playerStowItem(player->getID(), pos, itemId, stackpos, 0, true); break; } case SUPPLY_STASH_ACTION_WITHDRAW: { uint16_t itemId = msg.get(); uint32_t count = msg.get(); uint8_t stackpos = msg.getByte(); - addGameTask(&Game::playerStashWithdraw, player->getID(), itemId, count, stackpos); + g_game().playerStashWithdraw(player->getID(), itemId, count, stackpos); break; } default: @@ -8196,7 +8189,7 @@ void ProtocolGame::parseOpenDepotSearch() { return; } - addGameTask(&Game::playerRequestDepotItems, player->getID()); + g_game().playerRequestDepotItems(player->getID()); } void ProtocolGame::parseCloseDepotSearch() { @@ -8204,7 +8197,7 @@ void ProtocolGame::parseCloseDepotSearch() { return; } - addGameTask(&Game::playerRequestCloseDepotSearch, player->getID()); + g_game().playerRequestCloseDepotSearch(player->getID()); } void ProtocolGame::parseDepotSearchItemRequest(NetworkMessage &msg) { @@ -8218,7 +8211,7 @@ void ProtocolGame::parseDepotSearchItemRequest(NetworkMessage &msg) { itemTier = msg.getByte(); } - addGameTask(&Game::playerRequestDepotSearchItem, player->getID(), itemId, itemTier); + g_game().playerRequestDepotSearchItem(player->getID(), itemId, itemTier); } void ProtocolGame::parseRetrieveDepotSearch(NetworkMessage &msg) { @@ -8233,7 +8226,7 @@ void ProtocolGame::parseRetrieveDepotSearch(NetworkMessage &msg) { } uint8_t type = msg.getByte(); - addGameTask(&Game::playerRequestDepotSearchRetrieve, player->getID(), itemId, itemTier, type); + g_game().playerRequestDepotSearchRetrieve(player->getID(), itemId, itemTier, type); } void ProtocolGame::parseOpenParentContainer(NetworkMessage &msg) { @@ -8242,7 +8235,7 @@ void ProtocolGame::parseOpenParentContainer(NetworkMessage &msg) { } Position pos = msg.getPosition(); - addGameTask(&Game::playerRequestOpenContainerFromDepotSearch, player->getID(), pos); + g_game().playerRequestOpenContainerFromDepotSearch(player->getID(), pos); } void ProtocolGame::sendUpdateCreature(std::shared_ptr creature) { @@ -8530,7 +8523,7 @@ void ProtocolGame::parseBosstiarySlot(NetworkMessage &msg) { uint8_t slotBossId = msg.getByte(); uint32_t selectedBossId = msg.get(); - addGameTask(&Game::playerBosstiarySlot, player->getID(), slotBossId, selectedBossId); + g_game().playerBosstiarySlot(player->getID(), slotBossId, selectedBossId); } void ProtocolGame::sendPodiumDetails(NetworkMessage &msg, const std::vector &toSendMonsters, bool isBoss) const { @@ -8745,7 +8738,7 @@ void ProtocolGame::parseOpenWheel(NetworkMessage &msg) { } auto ownerId = msg.get(); - addGameTask(&Game::playerOpenWheel, player->getID(), ownerId); + g_game().playerOpenWheel(player->getID(), ownerId); } void ProtocolGame::parseWheelGemAction(NetworkMessage &msg) { @@ -8753,7 +8746,7 @@ void ProtocolGame::parseWheelGemAction(NetworkMessage &msg) { return; } - addGameTask(&Game::playerWheelGemAction, player->getID(), msg); + g_game().playerWheelGemAction(player->getID(), msg); } void ProtocolGame::sendOpenWheelWindow(uint32_t ownerId) { @@ -8771,7 +8764,7 @@ void ProtocolGame::parseSaveWheel(NetworkMessage &msg) { return; } - addGameTask(&Game::playerSaveWheel, player->getID(), msg); + g_game().playerSaveWheel(player->getID(), msg); } void ProtocolGame::sendDisableLoginMusic() { diff --git a/src/server/network/protocol/protocolgame.hpp b/src/server/network/protocol/protocolgame.hpp index 61c3aa19af0..306bb873f25 100644 --- a/src/server/network/protocol/protocolgame.hpp +++ b/src/server/network/protocol/protocolgame.hpp @@ -73,12 +73,6 @@ class ProtocolGame final : public Protocol { } private: - // Helpers so we don't need to bind every time - template - void addGameTask(Callable function, Args &&... args); - template - void addGameTaskTimed(uint32_t delay, std::string_view context, Callable function, Args &&... args); - ProtocolGame_ptr getThis() { return std::static_pointer_cast(shared_from_this()); } diff --git a/src/server/network/protocol/protocollogin.cpp b/src/server/network/protocol/protocollogin.cpp index 4e38a7503c7..b59a3704429 100644 --- a/src/server/network/protocol/protocollogin.cpp +++ b/src/server/network/protocol/protocollogin.cpp @@ -174,6 +174,8 @@ void ProtocolLogin::onRecvFirstMessage(NetworkMessage &msg) { return; } - auto thisPtr = std::static_pointer_cast(shared_from_this()); - g_dispatcher().addEvent(std::bind(&ProtocolLogin::getCharacterList, thisPtr, accountDescriptor, password), "ProtocolLogin::getCharacterList"); + g_dispatcher().addEvent([self = std::static_pointer_cast(shared_from_this()), accountDescriptor, password] { + self->getCharacterList(accountDescriptor, password); + }, + "ProtocolLogin::getCharacterList"); } diff --git a/src/server/network/protocol/protocolstatus.cpp b/src/server/network/protocol/protocolstatus.cpp index 8d9f245f5df..a4dfe1651d6 100644 --- a/src/server/network/protocol/protocolstatus.cpp +++ b/src/server/network/protocol/protocolstatus.cpp @@ -44,7 +44,10 @@ void ProtocolStatus::onRecvFirstMessage(NetworkMessage &msg) { // XML info protocol case 0xFF: { if (msg.getString(4) == "info") { - g_dispatcher().addEvent(std::bind(&ProtocolStatus::sendStatusString, std::static_pointer_cast(shared_from_this())), "ProtocolStatus::sendStatusString"); + g_dispatcher().addEvent([self = std::static_pointer_cast(shared_from_this())] { + self->sendStatusString(); + }, + "ProtocolStatus::sendStatusString"); return; } break; @@ -57,7 +60,11 @@ void ProtocolStatus::onRecvFirstMessage(NetworkMessage &msg) { if (requestedInfo & REQUEST_PLAYER_STATUS_INFO) { characterName = msg.getString(); } - g_dispatcher().addEvent(std::bind(&ProtocolStatus::sendInfo, std::static_pointer_cast(shared_from_this()), requestedInfo, characterName), "ProtocolStatus::sendInfo"); + g_dispatcher().addEvent([self = std::static_pointer_cast(shared_from_this()), requestedInfo, characterName] { + self->sendInfo(requestedInfo, characterName); + }, + "ProtocolStatus::sendInfo"); + return; } diff --git a/src/server/server.cpp b/src/server/server.cpp index 2968033bafa..fc8690468fe 100644 --- a/src/server/server.cpp +++ b/src/server/server.cpp @@ -47,7 +47,7 @@ void ServiceManager::stop() { for (auto &servicePortIt : acceptors) { try { - io_service.post(std::bind_front(&ServicePort::onStopServer, servicePortIt.second)); + io_service.post([servicePort = servicePortIt.second] { servicePort->onStopServer(); }); } catch (const std::system_error &e) { g_logger().warn("[ServiceManager::stop] - Network error: {}", e.what()); } @@ -56,7 +56,9 @@ void ServiceManager::stop() { acceptors.clear(); death_timer.expires_from_now(std::chrono::seconds(3)); - death_timer.async_wait(std::bind(&ServiceManager::die, this)); + death_timer.async_wait([this](const std::error_code &err) { + die(); + }); } ServicePort::~ServicePort() { @@ -87,7 +89,7 @@ void ServicePort::accept() { } auto connection = ConnectionManager::getInstance().createConnection(io_service, shared_from_this()); - acceptor->async_accept(connection->getSocket(), std::bind(&ServicePort::onAccept, shared_from_this(), connection, std::placeholders::_1)); + acceptor->async_accept(connection->getSocket(), [self = shared_from_this(), connection](const std::error_code &error) { self->onAccept(connection, error); }); } void ServicePort::onAccept(Connection_ptr connection, const std::error_code &error) { @@ -113,7 +115,9 @@ void ServicePort::onAccept(Connection_ptr connection, const std::error_code &err if (!pendingStart) { close(); pendingStart = true; - g_dispatcher().scheduleEvent(15000, std::bind_front(&ServicePort::openAcceptor, std::weak_ptr(shared_from_this()), serverPort), "ServicePort::openAcceptor"); + g_dispatcher().scheduleEvent( + 15000, [self = shared_from_this(), serverPort = serverPort] { ServicePort::openAcceptor(std::weak_ptr(self), serverPort); }, "ServicePort::openAcceptor" + ); } } } @@ -162,7 +166,10 @@ void ServicePort::open(uint16_t port) { g_logger().warn("[ServicePort::open] - Error code: {}", e.what()); pendingStart = true; - g_dispatcher().scheduleEvent(15000, std::bind_front(&ServicePort::openAcceptor, std::weak_ptr(shared_from_this()), port), "ServicePort::openAcceptor"); + g_dispatcher().scheduleEvent( + 15000, + [self = shared_from_this(), port] { ServicePort::openAcceptor(std::weak_ptr(self), port); }, "ServicePort::openAcceptor" + ); } } diff --git a/src/utils/wildcardtree.cpp b/src/utils/wildcardtree.cpp index 1e91b9b4169..4fd830b64cb 100644 --- a/src/utils/wildcardtree.cpp +++ b/src/utils/wildcardtree.cpp @@ -11,37 +11,37 @@ #include "utils/wildcardtree.hpp" -WildcardTreeNode* WildcardTreeNode::getChild(char ch) { +std::shared_ptr WildcardTreeNode::getChild(char ch) { auto it = children.find(ch); if (it == children.end()) { return nullptr; } - return &it->second; + return it->second; } -const WildcardTreeNode* WildcardTreeNode::getChild(char ch) const { +std::shared_ptr WildcardTreeNode::getChild(char ch) const { auto it = children.find(ch); if (it == children.end()) { return nullptr; } - return &it->second; + return it->second; } -WildcardTreeNode* WildcardTreeNode::addChild(char ch, bool breakp) { - WildcardTreeNode* child = getChild(ch); +std::shared_ptr WildcardTreeNode::addChild(char ch, bool breakp) { + std::shared_ptr child = getChild(ch); if (child) { if (breakp && !child->breakpoint) { child->breakpoint = true; } } else { - auto pair = children.emplace(std::piecewise_construct, std::forward_as_tuple(ch), std::forward_as_tuple(breakp)); - child = &pair.first->second; + auto pair = children.emplace(std::piecewise_construct, std::forward_as_tuple(ch), std::forward_as_tuple(std::make_shared(breakp))); + child = pair.first->second; } return child; } void WildcardTreeNode::insert(const std::string &str) { - WildcardTreeNode* cur = this; + std::shared_ptr cur = static_self_cast(); size_t length = str.length() - 1; for (size_t pos = 0; pos < length; ++pos) { @@ -52,9 +52,9 @@ void WildcardTreeNode::insert(const std::string &str) { } void WildcardTreeNode::remove(const std::string &str) { - WildcardTreeNode* cur = this; + std::shared_ptr cur = static_self_cast(); - std::stack path; + std::stack> path; path.push(cur); size_t len = str.length(); for (size_t pos = 0; pos < len; ++pos) { @@ -85,7 +85,7 @@ void WildcardTreeNode::remove(const std::string &str) { } ReturnValue WildcardTreeNode::findOne(const std::string &query, std::string &result) const { - const WildcardTreeNode* cur = this; + auto cur = static_self_cast(); for (char pos : query) { cur = cur->getChild(pos); if (!cur) { @@ -105,6 +105,6 @@ ReturnValue WildcardTreeNode::findOne(const std::string &query, std::string &res auto it = cur->children.begin(); result += it->first; - cur = &it->second; + cur = it->second; } while (true); } diff --git a/src/utils/wildcardtree.hpp b/src/utils/wildcardtree.hpp index 07728ae9849..9f3d2cf8ece 100644 --- a/src/utils/wildcardtree.hpp +++ b/src/utils/wildcardtree.hpp @@ -11,19 +11,19 @@ #include "declarations.hpp" -class WildcardTreeNode { +class WildcardTreeNode : public SharedObject { public: explicit WildcardTreeNode(bool initBreakpoint) : breakpoint(initBreakpoint) { } - WildcardTreeNode(WildcardTreeNode &&other) = default; + WildcardTreeNode(WildcardTreeNode &&other) noexcept = default; // non-copyable WildcardTreeNode(const WildcardTreeNode &) = delete; WildcardTreeNode &operator=(const WildcardTreeNode &) = delete; - WildcardTreeNode* getChild(char ch); - const WildcardTreeNode* getChild(char ch) const; - WildcardTreeNode* addChild(char ch, bool breakpoint); + std::shared_ptr getChild(char ch); + std::shared_ptr getChild(char ch) const; + std::shared_ptr addChild(char ch, bool breakpoint); void insert(const std::string &str); void remove(const std::string &str); @@ -31,6 +31,6 @@ class WildcardTreeNode { ReturnValue findOne(const std::string &query, std::string &result) const; private: - std::map children; + std::map> children; bool breakpoint; }; diff --git a/vcpkg.json b/vcpkg.json index 82f1058bd94..dda054f3774 100644 --- a/vcpkg.json +++ b/vcpkg.json @@ -9,18 +9,9 @@ "bext-ut", "curl", "eventpp", - "jsoncpp", "luajit", "magic-enum", "mio", - { - "name": "opentelemetry-cpp", - "default-features": true, - "features": [ - "otlp-http", - "prometheus" - ] - }, "parallel-hashmap", "protobuf", "pugixml", diff --git a/vcproj/settings.props b/vcproj/settings.props index 35625d790b9..6f98969614d 100644 --- a/vcproj/settings.props +++ b/vcproj/settings.props @@ -21,7 +21,6 @@ libcurl.lib; fmt.lib; spdlog.lib; - jsoncpp.lib; abseil_dll.lib; argon2.lib; opentelemetry_common.lib; @@ -60,7 +59,6 @@ libcurl-d.lib; fmtd.lib; spdlogd.lib; - jsoncpp.lib; abseil_dll.lib; argon2.lib; opentelemetry_common.lib;