From 5d0d1c9e0947dee376461a51caa828c430521ca7 Mon Sep 17 00:00:00 2001 From: Karin Date: Wed, 12 Jun 2024 10:17:48 -0300 Subject: [PATCH 1/4] fix: prevent guests to rotate dummy (#2684) --- src/game/game.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/game/game.cpp b/src/game/game.cpp index 899a89549d9..fed3a3910a1 100644 --- a/src/game/game.cpp +++ b/src/game/game.cpp @@ -126,6 +126,10 @@ namespace InternalGame { if (isGuest && !isItemInGuestInventory && !item->isLadder() && !item->canBeUsedByGuests()) { return false; } + + if (isGuest && item->isDummy()) { + return false; + } } return true; From 201aa8cb940bab3c2db6779a0dee3be3ae218198 Mon Sep 17 00:00:00 2001 From: Beats Date: Wed, 12 Jun 2024 10:43:03 -0300 Subject: [PATCH 2/4] feat: shared_ptr: familiar, groups and reload: familiars, outfits (#2556) --- CMakePresets.json | 1 + data/scripts/talkactions/god/reload.lua | 3 + src/creatures/appearance/mounts/mounts.cpp | 2 +- src/creatures/appearance/outfit/outfit.cpp | 37 +++-- src/creatures/appearance/outfit/outfit.hpp | 14 +- src/creatures/players/grouping/familiars.cpp | 7 +- src/creatures/players/grouping/familiars.hpp | 5 +- src/creatures/players/grouping/groups.cpp | 4 +- src/creatures/players/grouping/groups.hpp | 4 +- src/creatures/players/player.cpp | 6 +- src/creatures/players/player.hpp | 11 +- src/game/functions/game_reload.cpp | 154 ++++++++++-------- src/game/functions/game_reload.hpp | 50 +++--- src/game/game.cpp | 4 +- src/game/game.hpp | 2 + src/io/functions/iologindata_load_player.cpp | 4 +- .../creatures/player/group_functions.cpp | 16 +- src/server/network/protocol/protocolgame.cpp | 2 +- 18 files changed, 184 insertions(+), 142 deletions(-) diff --git a/CMakePresets.json b/CMakePresets.json index 92ef2d33c6a..49f631e1921 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -54,6 +54,7 @@ "DEBUG_LOG": "ON", "ASAN_ENABLED": "OFF", "BUILD_STATIC_LIBRARY": "OFF", + "SPEED_UP_BUILD_UNITY": "OFF", "VCPKG_TARGET_TRIPLET": "x64-windows" } }, diff --git a/data/scripts/talkactions/god/reload.lua b/data/scripts/talkactions/god/reload.lua index 20b9431dbba..d0c0cdd45a8 100644 --- a/data/scripts/talkactions/god/reload.lua +++ b/data/scripts/talkactions/god/reload.lua @@ -7,6 +7,7 @@ local reloadTypes = { ["configuration"] = RELOAD_TYPE_CONFIG, ["core"] = RELOAD_TYPE_CORE, ["events"] = RELOAD_TYPE_EVENTS, + ["familiar"] = RELOAD_TYPE_FAMILIARS, ["global"] = RELOAD_TYPE_CORE, ["group"] = RELOAD_TYPE_GROUPS, ["groups"] = RELOAD_TYPE_GROUPS, @@ -20,6 +21,8 @@ local reloadTypes = { ["monsters"] = RELOAD_TYPE_MONSTERS, ["mount"] = RELOAD_TYPE_MOUNTS, ["mounts"] = RELOAD_TYPE_MOUNTS, + ["outfit"] = RELOAD_TYPE_OUTFITS, + ["outfits"] = RELOAD_TYPE_OUTFITS, ["npc"] = RELOAD_TYPE_NPCS, ["npcs"] = RELOAD_TYPE_NPCS, ["raid"] = RELOAD_TYPE_RAIDS, diff --git a/src/creatures/appearance/mounts/mounts.cpp b/src/creatures/appearance/mounts/mounts.cpp index 7051d04ddb8..7014d0b026b 100644 --- a/src/creatures/appearance/mounts/mounts.cpp +++ b/src/creatures/appearance/mounts/mounts.cpp @@ -29,7 +29,7 @@ bool Mounts::loadFromXml() { } for (auto mountNode : doc.child("mounts").children()) { - uint16_t lookType = pugi::cast(mountNode.attribute("clientid").value()); + auto lookType = pugi::cast(mountNode.attribute("clientid").value()); if (g_configManager().getBoolean(WARN_UNSAFE_SCRIPTS, __FUNCTION__) && lookType != 0 && !g_game().isLookTypeRegistered(lookType)) { g_logger().warn("{} - An unregistered creature mount with id '{}' was blocked to prevent client crash.", __FUNCTION__, lookType); continue; diff --git a/src/creatures/appearance/outfit/outfit.cpp b/src/creatures/appearance/outfit/outfit.cpp index 9e96c60e756..97120659333 100644 --- a/src/creatures/appearance/outfit/outfit.cpp +++ b/src/creatures/appearance/outfit/outfit.cpp @@ -14,6 +14,10 @@ #include "utils/tools.hpp" #include "game/game.hpp" +Outfits &Outfits::getInstance() { + return inject(); +} + bool Outfits::reload() { for (auto &outfitsVector : outfits) { outfitsVector.clear(); @@ -41,7 +45,7 @@ bool Outfits::loadFromXml() { continue; } - uint16_t type = pugi::cast(attr.value()); + auto type = pugi::cast(attr.value()); if (type > PLAYERSEX_LAST) { g_logger().warn("[Outfits::loadFromXml] - Invalid outfit type {}", type); continue; @@ -53,7 +57,7 @@ bool Outfits::loadFromXml() { continue; } - if (uint16_t lookType = pugi::cast(lookTypeAttribute.value()); + if (auto lookType = pugi::cast(lookTypeAttribute.value()); g_configManager().getBoolean(WARN_UNSAFE_SCRIPTS, __FUNCTION__) && lookType != 0 && !g_game().isLookTypeRegistered(lookType)) { g_logger().warn("[Outfits::loadFromXml] An unregistered creature looktype type with id '{}' was ignored to prevent client crash.", lookType); @@ -74,7 +78,22 @@ bool Outfits::loadFromXml() { return true; } -std::shared_ptr Outfits::getOutfitByLookType(PlayerSex_t sex, uint16_t lookType) const { +std::shared_ptr Outfits::getOutfitByLookType(const std::shared_ptr &player, uint16_t lookType, bool isOppositeOutfit) const { + if (!player) { + g_logger().error("[{}] - Player not found", __FUNCTION__); + return nullptr; + } + + auto sex = player->getSex(); + if (sex != PLAYERSEX_FEMALE && sex != PLAYERSEX_MALE) { + g_logger().error("[{}] - Sex invalid or player: {}", __FUNCTION__, player->getName()); + return nullptr; + } + + if (isOppositeOutfit) { + sex = (sex == PLAYERSEX_MALE) ? PLAYERSEX_FEMALE : PLAYERSEX_MALE; + } + auto it = std::ranges::find_if(outfits[sex], [&lookType](const auto &outfit) { return outfit->lookType == lookType; }); @@ -84,15 +103,3 @@ std::shared_ptr Outfits::getOutfitByLookType(PlayerSex_t sex, uint16_t l } return nullptr; } - -/** - * Get the oposite sex equivalent outfit - * @param sex current sex - * @param lookType current looktype - * @return const pointer to the outfit or nullptr if it could not be found. - */ - -std::shared_ptr Outfits::getOpositeSexOutfitByLookType(PlayerSex_t sex, uint16_t lookType) const { - PlayerSex_t searchSex = (sex == PLAYERSEX_MALE) ? PLAYERSEX_FEMALE : PLAYERSEX_MALE; - return getOutfitByLookType(searchSex, lookType); -} diff --git a/src/creatures/appearance/outfit/outfit.hpp b/src/creatures/appearance/outfit/outfit.hpp index 30b84d1aca2..0d89a2c932d 100644 --- a/src/creatures/appearance/outfit/outfit.hpp +++ b/src/creatures/appearance/outfit/outfit.hpp @@ -12,8 +12,10 @@ #include "declarations.hpp" #include "lib/di/container.hpp" +class Player; + struct OutfitEntry { - constexpr OutfitEntry(uint16_t initLookType, uint8_t initAddons) : + constexpr explicit OutfitEntry(uint16_t initLookType, uint8_t initAddons) : lookType(initLookType), addons(initAddons) { } uint16_t lookType; @@ -42,16 +44,12 @@ struct ProtocolOutfit { class Outfits { public: - static Outfits &getInstance() { - return inject(); - } - - std::shared_ptr getOpositeSexOutfitByLookType(PlayerSex_t sex, uint16_t lookType) const; + static Outfits &getInstance(); - bool loadFromXml(); bool reload(); + bool loadFromXml(); - [[nodiscard]] std::shared_ptr getOutfitByLookType(PlayerSex_t sex, uint16_t lookType) const; + [[nodiscard]] std::shared_ptr getOutfitByLookType(const std::shared_ptr &player, uint16_t lookType, bool isOppositeOutfit = false) const; [[nodiscard]] const std::vector> &getOutfits(PlayerSex_t sex) const { return outfits[sex]; } diff --git a/src/creatures/players/grouping/familiars.cpp b/src/creatures/players/grouping/familiars.cpp index a922013f19b..6e923b823dc 100644 --- a/src/creatures/players/grouping/familiars.cpp +++ b/src/creatures/players/grouping/familiars.cpp @@ -10,10 +10,15 @@ #include "pch.hpp" #include "creatures/players/grouping/familiars.hpp" +#include "lib/di/container.hpp" #include "config/configmanager.hpp" #include "utils/pugicast.hpp" #include "utils/tools.hpp" +Familiars &Familiars::getInstance() { + return inject(); +} + bool Familiars::reload() { for (auto &familiarsVector : familiars) { familiarsVector.clear(); @@ -42,7 +47,7 @@ bool Familiars::loadFromXml() { continue; } - uint16_t vocation = pugi::cast(attr.value()); + auto vocation = pugi::cast(attr.value()); if (vocation > VOCATION_LAST) { g_logger().warn("[Familiars::loadFromXml] - Invalid familiar vocation {}", vocation); continue; diff --git a/src/creatures/players/grouping/familiars.hpp b/src/creatures/players/grouping/familiars.hpp index 8f553af9fbe..9eda7d95ba2 100644 --- a/src/creatures/players/grouping/familiars.hpp +++ b/src/creatures/players/grouping/familiars.hpp @@ -9,6 +9,7 @@ #pragma once +#include "declarations.hpp" #include "lib/di/container.hpp" struct FamiliarEntry { @@ -32,9 +33,7 @@ struct Familiar { class Familiars { public: - static Familiars &getInstance() { - return inject(); - } + static Familiars &getInstance(); bool loadFromXml(); bool reload(); diff --git a/src/creatures/players/grouping/groups.cpp b/src/creatures/players/grouping/groups.cpp index 27ae68d9fd4..937fa848f3f 100644 --- a/src/creatures/players/grouping/groups.cpp +++ b/src/creatures/players/grouping/groups.cpp @@ -43,7 +43,7 @@ PlayerFlags_t Groups::getFlagFromNumber(uint8_t value) { return magic_enum::enum_value(value); } -bool Groups::reload() const { +bool Groups::reload() { // Clear groups g_game().groups.getGroups().clear(); return g_game().groups.load(); @@ -99,7 +99,7 @@ bool Groups::load() { return true; } -std::shared_ptr Groups::getGroup(uint16_t id) { +std::shared_ptr Groups::getGroup(uint16_t id) const { if (auto it = std::find_if(groups_vector.begin(), groups_vector.end(), [id](auto group_it) { return group_it->id == id; }); diff --git a/src/creatures/players/grouping/groups.hpp b/src/creatures/players/grouping/groups.hpp index d76914e2632..af319e95772 100644 --- a/src/creatures/players/grouping/groups.hpp +++ b/src/creatures/players/grouping/groups.hpp @@ -24,9 +24,9 @@ class Groups { public: static uint8_t getFlagNumber(PlayerFlags_t playerFlags); static PlayerFlags_t getFlagFromNumber(uint8_t value); - bool reload() const; + static bool reload(); bool load(); - std::shared_ptr getGroup(uint16_t id); + [[nodiscard]] std::shared_ptr getGroup(uint16_t id) const; std::vector> &getGroups() { return groups_vector; } diff --git a/src/creatures/players/player.cpp b/src/creatures/players/player.cpp index 4109eb77472..2b10c0f77ee 100644 --- a/src/creatures/players/player.cpp +++ b/src/creatures/players/player.cpp @@ -4914,7 +4914,7 @@ bool Player::canWear(uint16_t lookType, uint8_t addons) const { return true; } - const auto &outfit = Outfits::getInstance().getOutfitByLookType(sex, lookType); + const auto &outfit = Outfits::getInstance().getOutfitByLookType(getPlayer(), lookType); if (!outfit) { return false; } @@ -5001,7 +5001,7 @@ bool Player::removeOutfitAddon(uint16_t lookType, uint8_t addons) { return false; } -bool Player::getOutfitAddons(const std::shared_ptr outfit, uint8_t &addons) const { +bool Player::getOutfitAddons(const std::shared_ptr &outfit, uint8_t &addons) const { if (group->access) { addons = 3; return true; @@ -5826,7 +5826,7 @@ bool Player::toggleMount(bool mount) { return false; } - const auto &playerOutfit = Outfits::getInstance().getOutfitByLookType(getSex(), defaultOutfit.lookType); + const auto &playerOutfit = Outfits::getInstance().getOutfitByLookType(getPlayer(), defaultOutfit.lookType); if (!playerOutfit) { return false; } diff --git a/src/creatures/players/player.hpp b/src/creatures/players/player.hpp index c0761704db4..19e3af5ca9c 100644 --- a/src/creatures/players/player.hpp +++ b/src/creatures/players/player.hpp @@ -476,7 +476,12 @@ class Player final : public Creature, public Cylinder, public Bankable { return blessings[index - 1] != 0; } uint8_t getBlessingCount(uint8_t index) const { - return blessings[index - 1]; + if (index > 0 && index <= blessings.size()) { + return blessings[index - 1]; + } else { + g_logger().error("[{}] - index outside range 0-10.", __FUNCTION__); + return 0; + } } std::string getBlessingsName() const; @@ -1031,7 +1036,7 @@ class Player final : public Creature, public Cylinder, public Bankable { void addOutfit(uint16_t lookType, uint8_t addons); bool removeOutfit(uint16_t lookType); bool removeOutfitAddon(uint16_t lookType, uint8_t addons); - bool getOutfitAddons(const std::shared_ptr outfit, uint8_t &addons) const; + bool getOutfitAddons(const std::shared_ptr &outfit, uint8_t &addons) const; bool canFamiliar(uint16_t lookType) const; void addFamiliar(uint16_t lookType); @@ -2853,7 +2858,7 @@ class Player final : public Creature, public Cylinder, public Bankable { uint16_t lastStatsTrainingTime = 0; uint16_t staminaMinutes = 2520; - std::vector blessings = { 0, 0, 0, 0, 0, 0, 0, 0 }; + std::vector blessings = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; uint16_t maxWriteLen = 0; uint16_t baseXpGain = 100; uint16_t voucherXpBoost = 0; diff --git a/src/game/functions/game_reload.cpp b/src/game/functions/game_reload.cpp index 0fc74bcee71..d9d9eb1f449 100644 --- a/src/game/functions/game_reload.cpp +++ b/src/game/functions/game_reload.cpp @@ -22,7 +22,7 @@ GameReload::GameReload() = default; GameReload::~GameReload() = default; -bool GameReload::init(Reload_t reloadTypes) const { +bool GameReload::init(Reload_t reloadTypes) { switch (reloadTypes) { case Reload_t::RELOAD_TYPE_ALL: return reloadAll(); @@ -32,34 +32,38 @@ bool GameReload::init(Reload_t reloadTypes) const { return reloadConfig(); case Reload_t::RELOAD_TYPE_EVENTS: return reloadEvents(); - case Reload_t::RELOAD_TYPE_CORE: - return reloadCore(); + case Reload_t::RELOAD_TYPE_MODULES: + return reloadModules(); + case Reload_t::RELOAD_TYPE_OUTFITS: + return reloadOutfits(); + case Reload_t::RELOAD_TYPE_MOUNTS: + return reloadMounts(); + case Reload_t::RELOAD_TYPE_FAMILIARS: + return reloadFamiliars(); case Reload_t::RELOAD_TYPE_IMBUEMENTS: return reloadImbuements(); + case Reload_t::RELOAD_TYPE_VOCATIONS: + return reloadVocations(); + case Reload_t::RELOAD_TYPE_CORE: + return reloadCore(); + case Reload_t::RELOAD_TYPE_GROUPS: + return reloadGroups(); + case Reload_t::RELOAD_TYPE_SCRIPTS: + return reloadScripts(); case Reload_t::RELOAD_TYPE_ITEMS: return reloadItems(); - case Reload_t::RELOAD_TYPE_MODULES: - return reloadModules(); case Reload_t::RELOAD_TYPE_MONSTERS: return reloadMonsters(); - case Reload_t::RELOAD_TYPE_MOUNTS: - return reloadMounts(); case Reload_t::RELOAD_TYPE_NPCS: return reloadNpcs(); case Reload_t::RELOAD_TYPE_RAIDS: return reloadRaids(); - case Reload_t::RELOAD_TYPE_SCRIPTS: - return reloadScripts(); - case Reload_t::RELOAD_TYPE_GROUPS: - return reloadGroups(); - case Reload_t::RELOAD_TYPE_VOCATIONS: - return reloadVocations(); default: return false; } } -uint8_t GameReload::getReloadNumber(Reload_t reloadTypes) const { +uint8_t GameReload::getReloadNumber(Reload_t reloadTypes) { return magic_enum::enum_integer(reloadTypes); } @@ -78,7 +82,7 @@ void logReloadStatus(const std::string &name, bool result) { * If it is necessary to call elsewhere, seriously think about creating a function that calls this * Changing this to public may cause some unexpected behavior or bug */ -bool GameReload::reloadAll() const { +bool GameReload::reloadAll() { std::vector reloadResults; reloadResults.reserve(magic_enum::enum_count()); @@ -93,25 +97,62 @@ bool GameReload::reloadAll() const { return std::ranges::any_of(reloadResults, [](bool result) { return result; }); } -bool GameReload::reloadChat() const { +bool GameReload::reloadChat() { const bool result = g_chat().load(); logReloadStatus("Chat", result); return result; } -bool GameReload::reloadConfig() const { +bool GameReload::reloadConfig() { const bool result = g_configManager().reload(); logReloadStatus("Config", result); return result; } -bool GameReload::reloadEvents() const { +bool GameReload::reloadEvents() { const bool result = g_events().loadFromXml(); logReloadStatus("Events", result); return result; } -bool GameReload::reloadCore() const { +bool GameReload::reloadModules() { + const bool result = g_modules().reload(); + logReloadStatus("Modules", result); + return result; +} + +bool GameReload::reloadOutfits() { + const bool result = g_game().outfits.reload(); + logReloadStatus("Outfits", result); + return result; +} + +bool GameReload::reloadMounts() { + const bool result = g_game().mounts.reload(); + logReloadStatus("Mounts", result); + return result; +} + +bool GameReload::reloadFamiliars() { + const bool result = g_game().familiars.reload(); + logReloadStatus("Familiars", result); + return result; +} + +bool GameReload::reloadImbuements() { + const bool result = g_imbuements().reload(); + logReloadStatus("Imbuements", result); + return result; +} + +bool GameReload::reloadVocations() { + const bool result = g_vocations().reload(); + reloadScripts(); + logReloadStatus("Vocations", result); + return result; +} + +bool GameReload::reloadCore() { const auto &coreFolder = g_configManager().getString(CORE_DIRECTORY, __FUNCTION__); const bool coreLoaded = g_luaEnvironment().loadFile(coreFolder + "/core.lua", "core.lua") == 0; @@ -126,25 +167,38 @@ bool GameReload::reloadCore() const { return false; } -bool GameReload::reloadImbuements() const { - const bool result = g_imbuements().reload(); - logReloadStatus("Imbuements", result); +bool GameReload::reloadGroups() { + const bool result = g_game().groups.reload(); + logReloadStatus("Groups", result); return result; } -bool GameReload::reloadItems() const { - const bool result = Item::items.reload(); - logReloadStatus("Items", result); - return result; +bool GameReload::reloadScripts() { + g_scripts().clearAllScripts(); + Zone::clearZones(); + + const auto &datapackFolder = g_configManager().getString(DATA_DIRECTORY, __FUNCTION__); + const auto &coreFolder = g_configManager().getString(CORE_DIRECTORY, __FUNCTION__); + + g_scripts().loadScripts(coreFolder + "/scripts/lib", true, false); + g_scripts().loadScripts(datapackFolder + "/scripts", false, true); + g_scripts().loadScripts(coreFolder + "/scripts", false, true); + + // It should come last, after everything else has been cleaned up. + reloadMonsters(); + reloadNpcs(); + reloadItems(); + logReloadStatus("Scripts", true); + return true; } -bool GameReload::reloadModules() const { - const bool result = g_modules().reload(); - logReloadStatus("Modules", result); +bool GameReload::reloadItems() { + const bool result = Item::items.reload(); + logReloadStatus("Items", result); return result; } -bool GameReload::reloadMonsters() const { +bool GameReload::reloadMonsters() { g_monsters().clear(); const auto &datapackFolder = g_configManager().getString(DATA_DIRECTORY, __FUNCTION__); const auto &coreFolder = g_configManager().getString(CORE_DIRECTORY, __FUNCTION__); @@ -161,50 +215,14 @@ bool GameReload::reloadMonsters() const { } } -bool GameReload::reloadMounts() const { - const bool result = g_game().mounts.reload(); - logReloadStatus("Mounts", result); - return result; -} - -bool GameReload::reloadNpcs() const { +bool GameReload::reloadNpcs() { const bool result = g_npcs().reload(); logReloadStatus("NPCs", result); return result; } -bool GameReload::reloadRaids() const { +bool GameReload::reloadRaids() { const bool result = g_game().raids.reload() && g_game().raids.startup(); logReloadStatus("Raids", result); return result; } - -bool GameReload::reloadScripts() const { - g_scripts().clearAllScripts(); - Zone::clearZones(); - - const auto &datapackFolder = g_configManager().getString(DATA_DIRECTORY, __FUNCTION__); - const auto &coreFolder = g_configManager().getString(CORE_DIRECTORY, __FUNCTION__); - - g_scripts().loadScripts(coreFolder + "/scripts/lib", true, false); - g_scripts().loadScripts(datapackFolder + "/scripts", false, true); - g_scripts().loadScripts(coreFolder + "/scripts", false, true); - - // It should come last, after everything else has been cleaned up. - reloadMonsters(); - reloadNpcs(); - logReloadStatus("Scripts", true); - return true; -} - -bool GameReload::reloadGroups() const { - const bool result = g_game().groups.reload(); - logReloadStatus("Groups", result); - return result; -} - -bool GameReload::reloadVocations() const { - const bool result = g_vocations().reload(); - logReloadStatus("Vocations", result); - return result; -} diff --git a/src/game/functions/game_reload.hpp b/src/game/functions/game_reload.hpp index 45ff35c01a2..0f59046a9d4 100644 --- a/src/game/functions/game_reload.hpp +++ b/src/game/functions/game_reload.hpp @@ -19,17 +19,19 @@ enum class Reload_t : uint8_t { RELOAD_TYPE_CHAT, RELOAD_TYPE_CONFIG, RELOAD_TYPE_EVENTS, - RELOAD_TYPE_CORE, + RELOAD_TYPE_MODULES, + RELOAD_TYPE_OUTFITS, + RELOAD_TYPE_MOUNTS, + RELOAD_TYPE_FAMILIARS, RELOAD_TYPE_IMBUEMENTS, + RELOAD_TYPE_VOCATIONS, + RELOAD_TYPE_CORE, + RELOAD_TYPE_GROUPS, + RELOAD_TYPE_SCRIPTS, RELOAD_TYPE_ITEMS, - RELOAD_TYPE_MODULES, RELOAD_TYPE_MONSTERS, - RELOAD_TYPE_MOUNTS, RELOAD_TYPE_NPCS, RELOAD_TYPE_RAIDS, - RELOAD_TYPE_SCRIPTS, - RELOAD_TYPE_GROUPS, - RELOAD_TYPE_VOCATIONS, // Every is last RELOAD_TYPE_LAST @@ -48,25 +50,27 @@ class GameReload : public Game { return inject(); } - bool init(Reload_t reloadType) const; - uint8_t getReloadNumber(Reload_t reloadTypes) const; + static bool init(Reload_t reloadType); + static uint8_t getReloadNumber(Reload_t reloadTypes); private: - bool reloadAll() const; - bool reloadChat() const; - bool reloadConfig() const; - bool reloadEvents() const; - bool reloadCore() const; - bool reloadImbuements() const; - bool reloadItems() const; - bool reloadModules() const; - bool reloadMonsters() const; - bool reloadMounts() const; - bool reloadNpcs() const; - bool reloadRaids() const; - bool reloadScripts() const; - bool reloadGroups() const; - bool reloadVocations() const; + static bool reloadAll(); + static bool reloadChat(); + static bool reloadConfig(); + static bool reloadEvents(); + static bool reloadModules(); + static bool reloadOutfits(); + static bool reloadMounts(); + static bool reloadFamiliars(); + static bool reloadImbuements(); + static bool reloadVocations(); + static bool reloadCore(); + static bool reloadGroups(); + static bool reloadScripts(); + static bool reloadItems(); + static bool reloadMonsters(); + static bool reloadNpcs(); + static bool reloadRaids(); }; constexpr auto g_gameReload = GameReload::getInstance; diff --git a/src/game/game.cpp b/src/game/game.cpp index fed3a3910a1..57daddded2e 100644 --- a/src/game/game.cpp +++ b/src/game/game.cpp @@ -4261,7 +4261,7 @@ void Game::playerSetShowOffSocket(uint32_t playerId, Outfit_t &outfit, const Pos name << item->getName() << " displaying the "; bool outfited = false; if (outfit.lookType != 0) { - const auto &outfitInfo = Outfits::getInstance().getOutfitByLookType(player->getSex(), outfit.lookType); + const auto &outfitInfo = Outfits::getInstance().getOutfitByLookType(player, outfit.lookType); if (!outfitInfo) { return; } @@ -5927,7 +5927,7 @@ void Game::playerChangeOutfit(uint32_t playerId, Outfit_t outfit, uint8_t isMoun outfit.lookMount = randomMount->clientId; } - const auto playerOutfit = Outfits::getInstance().getOutfitByLookType(player->getSex(), outfit.lookType); + const auto playerOutfit = Outfits::getInstance().getOutfitByLookType(player, outfit.lookType); if (!playerOutfit) { outfit.lookMount = 0; } diff --git a/src/game/game.hpp b/src/game/game.hpp index 3a199254259..b4be8facd09 100644 --- a/src/game/game.hpp +++ b/src/game/game.hpp @@ -582,8 +582,10 @@ class Game { bool hasDistanceEffect(uint16_t effectId); Groups groups; + Familiars familiars; Map map; Mounts mounts; + Outfits outfits; Raids raids; std::unique_ptr m_appearancesPtr; diff --git a/src/io/functions/iologindata_load_player.cpp b/src/io/functions/iologindata_load_player.cpp index 6273f8fefbb..8f7cf461fdf 100644 --- a/src/io/functions/iologindata_load_player.cpp +++ b/src/io/functions/iologindata_load_player.cpp @@ -66,7 +66,7 @@ bool IOLoginDataLoad::preLoadPlayer(std::shared_ptr player, const std::s } player->setGUID(result->getNumber("id")); - std::shared_ptr group = g_game().groups.getGroup(result->getNumber("group_id")); + const auto &group = g_game().groups.getGroup(result->getNumber("group_id")); if (!group) { g_logger().error("Player {} has group id {} which doesn't exist", player->name, result->getNumber("group_id")); return false; @@ -118,7 +118,7 @@ bool IOLoginDataLoad::loadPlayerFirst(std::shared_ptr player, DBResult_p player->setAccount(result->getNumber("account_id")); } - std::shared_ptr group = g_game().groups.getGroup(result->getNumber("group_id")); + const auto &group = g_game().groups.getGroup(result->getNumber("group_id")); if (!group) { g_logger().error("Player {} has group id {} which doesn't exist", player->name, result->getNumber("group_id")); return false; diff --git a/src/lua/functions/creatures/player/group_functions.cpp b/src/lua/functions/creatures/player/group_functions.cpp index 5acc16d72a9..f547eec1590 100644 --- a/src/lua/functions/creatures/player/group_functions.cpp +++ b/src/lua/functions/creatures/player/group_functions.cpp @@ -17,7 +17,7 @@ int GroupFunctions::luaGroupCreate(lua_State* L) { // Group(id) uint32_t id = getNumber(L, 2); - std::shared_ptr group = g_game().groups.getGroup(id); + const auto &group = g_game().groups.getGroup(id); if (group) { pushUserdata(L, group); setMetatable(L, -1, "Group"); @@ -29,7 +29,7 @@ int GroupFunctions::luaGroupCreate(lua_State* L) { int GroupFunctions::luaGroupGetId(lua_State* L) { // group:getId() - std::shared_ptr group = getUserdataShared(L, 1); + const auto &group = getUserdataShared(L, 1); if (group) { lua_pushnumber(L, group->id); } else { @@ -40,7 +40,7 @@ int GroupFunctions::luaGroupGetId(lua_State* L) { int GroupFunctions::luaGroupGetName(lua_State* L) { // group:getName() - std::shared_ptr group = getUserdataShared(L, 1); + const auto &group = getUserdataShared(L, 1); if (group) { pushString(L, group->name); } else { @@ -51,7 +51,7 @@ int GroupFunctions::luaGroupGetName(lua_State* L) { int GroupFunctions::luaGroupGetFlags(lua_State* L) { // group:getFlags() - std::shared_ptr group = getUserdataShared(L, 1); + const auto &group = getUserdataShared(L, 1); if (group) { std::bitset flags; for (uint8_t i = 0; i < magic_enum::enum_integer(PlayerFlags_t::FlagLast); ++i) { @@ -68,7 +68,7 @@ int GroupFunctions::luaGroupGetFlags(lua_State* L) { int GroupFunctions::luaGroupGetAccess(lua_State* L) { // group:getAccess() - std::shared_ptr group = getUserdataShared(L, 1); + const auto &group = getUserdataShared(L, 1); if (group) { pushBoolean(L, group->access); } else { @@ -79,7 +79,7 @@ int GroupFunctions::luaGroupGetAccess(lua_State* L) { int GroupFunctions::luaGroupGetMaxDepotItems(lua_State* L) { // group:getMaxDepotItems() - std::shared_ptr group = getUserdataShared(L, 1); + const auto &group = getUserdataShared(L, 1); if (group) { lua_pushnumber(L, group->maxDepotItems); } else { @@ -90,7 +90,7 @@ int GroupFunctions::luaGroupGetMaxDepotItems(lua_State* L) { int GroupFunctions::luaGroupGetMaxVipEntries(lua_State* L) { // group:getMaxVipEntries() - std::shared_ptr group = getUserdataShared(L, 1); + const auto &group = getUserdataShared(L, 1); if (group) { lua_pushnumber(L, group->maxVipEntries); } else { @@ -101,7 +101,7 @@ int GroupFunctions::luaGroupGetMaxVipEntries(lua_State* L) { int GroupFunctions::luaGroupHasFlag(lua_State* L) { // group:hasFlag(flag) - std::shared_ptr group = getUserdataShared(L, 1); + const auto &group = getUserdataShared(L, 1); if (group) { auto flag = static_cast(getNumber(L, 2)); pushBoolean(L, group->flags[Groups::getFlagNumber(flag)]); diff --git a/src/server/network/protocol/protocolgame.cpp b/src/server/network/protocol/protocolgame.cpp index 751da531273..98bacfc5e12 100644 --- a/src/server/network/protocol/protocolgame.cpp +++ b/src/server/network/protocol/protocolgame.cpp @@ -4055,7 +4055,7 @@ void ProtocolGame::sendCyclopediaCharacterInspection() { // Outfit description playerDescriptionSize++; msg.addString("Outfit", "ProtocolGame::sendCyclopediaCharacterInspection - Outfit"); - if (const auto outfit = Outfits::getInstance().getOutfitByLookType(player->getSex(), player->getDefaultOutfit().lookType)) { + if (const auto outfit = Outfits::getInstance().getOutfitByLookType(player, player->getDefaultOutfit().lookType)) { msg.addString(outfit->name, "ProtocolGame::sendCyclopediaCharacterInspection - outfit->name"); } else { msg.addString("unknown", "ProtocolGame::sendCyclopediaCharacterInspection - unknown"); From e20e7eb68b24eafdbc13b1c3c72928ee8caf3ee1 Mon Sep 17 00:00:00 2001 From: Luan Luciano Date: Wed, 12 Jun 2024 10:43:24 -0300 Subject: [PATCH 3/4] feat: monster rename functionality (#2621) --- ...{create_monster.lua => manage_monster.lua} | 32 +++++++++++++++++- src/creatures/monsters/monster.cpp | 33 ++++++++++++++++++- src/creatures/monsters/monster.hpp | 20 ++++++----- src/creatures/players/player.hpp | 9 +++-- .../creatures/monster/monster_functions.cpp | 20 ++++++++++- .../creatures/monster/monster_functions.hpp | 2 ++ src/server/network/protocol/protocolgame.cpp | 33 ++++++++++++++----- src/server/network/protocol/protocolgame.hpp | 1 + 8 files changed, 128 insertions(+), 22 deletions(-) rename data/scripts/talkactions/god/{create_monster.lua => manage_monster.lua} (83%) diff --git a/data/scripts/talkactions/god/create_monster.lua b/data/scripts/talkactions/god/manage_monster.lua similarity index 83% rename from data/scripts/talkactions/god/create_monster.lua rename to data/scripts/talkactions/god/manage_monster.lua index ce5869a2eee..da110d59265 100644 --- a/data/scripts/talkactions/god/create_monster.lua +++ b/data/scripts/talkactions/god/manage_monster.lua @@ -56,7 +56,7 @@ local createMonster = TalkAction("/m") -- @param param: String containing the command parameters. -- Format: "/m monstername, monstercount, [fiendish/influenced level], spawnRadius, [forceCreate]" -- Example: "/m rat, 10, fiendish, 5, true" --- @param: the last param is by default "false", if add "," or any value i'ts set to true +-- @param: the last param is by default "false", if add "," or any value it's set to true -- @return true if the command is executed successfully, false otherwise. function createMonster.onSay(player, words, param) -- create log @@ -127,3 +127,33 @@ end createMonster:separator(" ") createMonster:groupType("god") createMonster:register() + +----------------- Rename monster name ----------------- +local setMonsterName = TalkAction("/setmonstername") + +-- @function setMonsterName.onSay +-- @desc TalkAction to rename nearby monsters within a radius of 4 sqm. +-- Format: "/setmonstername newName" +function setMonsterName.onSay(player, words, param) + if param == "" then + player:sendCancelMessage("Command param required.") + return true + end + + local split = param:split(",") + local monsterNewName = split[1] + + local spectators, spectator = Game.getSpectators(player:getPosition(), false, false, 4, 4, 4, 4) + for i = 1, #spectators do + spectator = spectators[i] + if spectator:isMonster() then + spectator:setName(monsterNewName) + end + end + + return true +end + +setMonsterName:separator(" ") +setMonsterName:groupType("god") +setMonsterName:register() diff --git a/src/creatures/monsters/monster.cpp b/src/creatures/monsters/monster.cpp index fccc19b05e5..5e0a7d16bb4 100644 --- a/src/creatures/monsters/monster.cpp +++ b/src/creatures/monsters/monster.cpp @@ -33,7 +33,7 @@ std::shared_ptr Monster::createMonster(const std::string &name) { Monster::Monster(const std::shared_ptr mType) : Creature(), - strDescription(asLowerCaseString(mType->nameDescription)), + nameDescription(asLowerCaseString(mType->nameDescription)), mType(mType) { defaultOutfit = mType->info.outfit; currentOutfit = mType->info.outfit; @@ -64,6 +64,37 @@ void Monster::removeList() { g_game().removeMonster(static_self_cast()); } +const std::string &Monster::getName() const { + if (name.empty()) { + return mType->name; + } + return name; +} + +void Monster::setName(const std::string &name) { + if (getName() == name) { + return; + } + + this->name = name; + + // NOTE: Due to how client caches known creatures, + // it is not feasible to send creature update to everyone that has ever met it + auto spectators = Spectators().find(position, true); + for (const auto &spectator : spectators) { + if (const auto &tmpPlayer = spectator->getPlayer()) { + tmpPlayer->sendUpdateTileCreature(static_self_cast()); + } + } +} + +const std::string &Monster::getNameDescription() const { + if (nameDescription.empty()) { + return mType->nameDescription; + } + return nameDescription; +} + bool Monster::canWalkOnFieldType(CombatType_t combatType) const { switch (combatType) { case COMBAT_ENERGYDAMAGE: diff --git a/src/creatures/monsters/monster.hpp b/src/creatures/monsters/monster.hpp index bf9a39e4133..6c45fa3eaca 100644 --- a/src/creatures/monsters/monster.hpp +++ b/src/creatures/monsters/monster.hpp @@ -41,21 +41,22 @@ class Monster final : public Creature { } } - void removeList() override; void addList() override; + void removeList() override; + + const std::string &getName() const override; + void setName(const std::string &name); - const std::string &getName() const override { - return mType->name; - } // Real monster name, set on monster creation "createMonsterType(typeName)" const std::string &getTypeName() const override { return mType->typeName; } - const std::string &getNameDescription() const override { - return mType->nameDescription; - } + const std::string &getNameDescription() const override; + void setNameDescription(const std::string &nameDescription) { + this->nameDescription = nameDescription; + }; std::string getDescription(int32_t) override { - return strDescription + '.'; + return nameDescription + '.'; } CreatureType_t getType() const override { @@ -363,7 +364,8 @@ class Monster final : public Creature { uint16_t forgeStack = 0; ForgeClassifications_t monsterForgeClassification = ForgeClassifications_t::FORGE_NORMAL_MONSTER; - std::string strDescription; + std::string name; + std::string nameDescription; std::shared_ptr mType; SpawnMonster* spawnMonster = nullptr; diff --git a/src/creatures/players/player.hpp b/src/creatures/players/player.hpp index 19e3af5ca9c..947acedca54 100644 --- a/src/creatures/players/player.hpp +++ b/src/creatures/players/player.hpp @@ -153,8 +153,8 @@ class Player final : public Creature, public Cylinder, public Bankable { const std::string &getName() const override { return name; } - void setName(std::string newName) { - this->name = std::move(newName); + void setName(const std::string &name) { + this->name = name; } const std::string &getTypeName() const override { return name; @@ -1075,6 +1075,11 @@ class Player final : public Creature, public Cylinder, public Bankable { client->sendRemoveTileThing(pos, stackpos); } } + void sendUpdateTileCreature(const std::shared_ptr creature) { + if (client) { + client->sendUpdateTileCreature(creature->getPosition(), creature->getTile()->getClientIndexOfCreature(static_self_cast(), creature), creature); + } + } void sendUpdateTile(std::shared_ptr updateTile, const Position &pos) { if (client) { client->sendUpdateTile(updateTile, pos); diff --git a/src/lua/functions/creatures/monster/monster_functions.cpp b/src/lua/functions/creatures/monster/monster_functions.cpp index 1591053c391..273f6af5c99 100644 --- a/src/lua/functions/creatures/monster/monster_functions.cpp +++ b/src/lua/functions/creatures/monster/monster_functions.cpp @@ -77,7 +77,7 @@ int MonsterFunctions::luaMonsterSetType(lua_State* L) { } // Assign new MonsterType monster->mType = mType; - monster->strDescription = asLowerCaseString(mType->nameDescription); + monster->nameDescription = asLowerCaseString(mType->nameDescription); monster->defaultOutfit = mType->info.outfit; monster->currentOutfit = mType->info.outfit; monster->skull = mType->info.skull; @@ -529,6 +529,24 @@ int MonsterFunctions::luaMonsterGetName(lua_State* L) { return 1; } +int MonsterFunctions::luaMonsterSetName(lua_State* L) { + // monster:setName(name[, nameDescription]) + auto monster = getUserdataShared(L, 1); + if (!monster) { + reportErrorFunc(getErrorDesc(LUA_ERROR_MONSTER_NOT_FOUND)); + pushBoolean(L, false); + return 0; + } + + monster->setName(getString(L, 2)); + if (lua_gettop(L) >= 3) { + monster->setNameDescription(getString(L, 3)); + } + + pushBoolean(L, true); + return 1; +} + int MonsterFunctions::luaMonsterHazard(lua_State* L) { // get: monster:hazard() ; set: monster:hazard(hazard) std::shared_ptr monster = getUserdataShared(L, 1); diff --git a/src/lua/functions/creatures/monster/monster_functions.hpp b/src/lua/functions/creatures/monster/monster_functions.hpp index bf2785ae430..dd1c3827344 100644 --- a/src/lua/functions/creatures/monster/monster_functions.hpp +++ b/src/lua/functions/creatures/monster/monster_functions.hpp @@ -56,6 +56,7 @@ class MonsterFunctions final : LuaScriptInterface { registerMethod(L, "Monster", "isForgeable", MonsterFunctions::luaMonsterIsForgeable); registerMethod(L, "Monster", "getName", MonsterFunctions::luaMonsterGetName); + registerMethod(L, "Monster", "setName", MonsterFunctions::luaMonsterSetName); registerMethod(L, "Monster", "hazard", MonsterFunctions::luaMonsterHazard); registerMethod(L, "Monster", "hazardCrit", MonsterFunctions::luaMonsterHazardCrit); @@ -116,6 +117,7 @@ class MonsterFunctions final : LuaScriptInterface { static int luaMonsterIsForgeable(lua_State* L); static int luaMonsterGetName(lua_State* L); + static int luaMonsterSetName(lua_State* L); static int luaMonsterHazard(lua_State* L); static int luaMonsterHazardCrit(lua_State* L); diff --git a/src/server/network/protocol/protocolgame.cpp b/src/server/network/protocol/protocolgame.cpp index 98bacfc5e12..8cf0660a262 100644 --- a/src/server/network/protocol/protocolgame.cpp +++ b/src/server/network/protocol/protocolgame.cpp @@ -5947,7 +5947,7 @@ void ProtocolGame::sendCreatureTurn(std::shared_ptr creature, uint32_t NetworkMessage msg; msg.addByte(0x6B); msg.addPosition(creature->getPosition()); - msg.addByte(stackPos); + msg.addByte(static_cast(stackPos)); msg.add(0x63); msg.add(creature->getID()); msg.addByte(creature->getDirection()); @@ -6385,7 +6385,7 @@ void ProtocolGame::sendAddTileItem(const Position &pos, uint32_t stackpos, std:: NetworkMessage msg; msg.addByte(0x6A); msg.addPosition(pos); - msg.addByte(stackpos); + msg.addByte(static_cast(stackpos)); AddItem(msg, item); writeToOutputBuffer(msg); } @@ -6398,7 +6398,7 @@ void ProtocolGame::sendUpdateTileItem(const Position &pos, uint32_t stackpos, st NetworkMessage msg; msg.addByte(0x6B); msg.addPosition(pos); - msg.addByte(stackpos); + msg.addByte(static_cast(stackpos)); AddItem(msg, item); writeToOutputBuffer(msg); } @@ -6413,6 +6413,23 @@ void ProtocolGame::sendRemoveTileThing(const Position &pos, uint32_t stackpos) { writeToOutputBuffer(msg); } +void ProtocolGame::sendUpdateTileCreature(const Position &pos, uint32_t stackpos, const std::shared_ptr creature) { + if (!canSee(pos)) { + return; + } + + NetworkMessage msg; + msg.addByte(0x6B); + msg.addPosition(pos); + msg.addByte(static_cast(stackpos)); + + bool known; + uint32_t removedKnown; + checkCreatureAsKnown(creature->getID(), known, removedKnown); + AddCreature(msg, creature, false, removedKnown); + writeToOutputBuffer(msg); +} + void ProtocolGame::sendUpdateTile(std::shared_ptr tile, const Position &pos) { if (!canSee(pos)) { return; @@ -6484,7 +6501,7 @@ void ProtocolGame::sendAddCreature(std::shared_ptr creature, const Pos NetworkMessage msg; msg.addByte(0x6A); msg.addPosition(pos); - msg.addByte(stackpos); + msg.addByte(static_cast(stackpos)); bool known; uint32_t removedKnown; @@ -6641,7 +6658,7 @@ void ProtocolGame::sendMoveCreature(std::shared_ptr creature, const Po } else { msg.addByte(0x6D); msg.addPosition(oldPos); - msg.addByte(oldStackPos); + msg.addByte(static_cast(oldStackPos)); msg.addPosition(newPos); } @@ -6676,7 +6693,7 @@ void ProtocolGame::sendMoveCreature(std::shared_ptr creature, const Po NetworkMessage msg; msg.addByte(0x6D); msg.addPosition(oldPos); - msg.addByte(oldStackPos); + msg.addByte(static_cast(oldStackPos)); msg.addPosition(newPos); writeToOutputBuffer(msg); } @@ -7836,7 +7853,7 @@ void ProtocolGame::RemoveTileThing(NetworkMessage &msg, const Position &pos, uin msg.addByte(0x6C); msg.addPosition(pos); - msg.addByte(stackpos); + msg.addByte(static_cast(stackpos)); } void ProtocolGame::sendKillTrackerUpdate(std::shared_ptr corpse, const std::string &name, const Outfit_t creatureOutfit) { @@ -8279,7 +8296,7 @@ void ProtocolGame::reloadCreature(std::shared_ptr creature) { if (knownCreatureSet.contains(creature->getID())) { msg.addByte(0x6B); msg.addPosition(creature->getPosition()); - msg.addByte(stackpos); + msg.addByte(static_cast(stackpos)); AddCreature(msg, creature, false, 0); } else { sendAddCreature(creature, creature->getPosition(), stackpos, false); diff --git a/src/server/network/protocol/protocolgame.hpp b/src/server/network/protocol/protocolgame.hpp index 0386093cfc4..100ca199b77 100644 --- a/src/server/network/protocol/protocolgame.hpp +++ b/src/server/network/protocol/protocolgame.hpp @@ -393,6 +393,7 @@ class ProtocolGame final : public Protocol { void sendAddTileItem(const Position &pos, uint32_t stackpos, std::shared_ptr item); void sendUpdateTileItem(const Position &pos, uint32_t stackpos, std::shared_ptr item); void sendRemoveTileThing(const Position &pos, uint32_t stackpos); + void sendUpdateTileCreature(const Position &pos, uint32_t stackpos, const std::shared_ptr creature); void sendUpdateTile(std::shared_ptr tile, const Position &pos); void sendAddCreature(std::shared_ptr creature, const Position &pos, int32_t stackpos, bool isLogin); From 7c3393a1015ff4d8c1f43c5988b33f489302e20f Mon Sep 17 00:00:00 2001 From: Renato Machado Date: Wed, 12 Jun 2024 10:48:41 -0300 Subject: [PATCH 4/4] fix: crash on shutdown (#2676) --- src/lib/thread/thread_pool.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/lib/thread/thread_pool.cpp b/src/lib/thread/thread_pool.cpp index 702f0c05504..b2f51ef8f9d 100644 --- a/src/lib/thread/thread_pool.cpp +++ b/src/lib/thread/thread_pool.cpp @@ -26,7 +26,7 @@ #endif ThreadPool::ThreadPool(Logger &logger) : - logger(logger), BS::thread_pool(std::max(getNumberOfCores(), DEFAULT_NUMBER_OF_THREADS)) { + BS::thread_pool(std::max(getNumberOfCores(), DEFAULT_NUMBER_OF_THREADS)), logger(logger) { start(); } @@ -35,6 +35,7 @@ void ThreadPool::start() { } void ThreadPool::shutdown() { - stopped = true; logger.info("Shutting down thread pool..."); + stopped = true; + wait(); }