diff options
author | Treeston <treeston.mmoc@gmail.com> | 2018-09-09 12:41:00 +0200 |
---|---|---|
committer | Shauren <shauren.trinity@gmail.com> | 2021-10-25 15:06:41 +0200 |
commit | f91faa161cf8f12cf066edf36e88b12f73c1f054 (patch) | |
tree | 1f05b5f8434f0eaf0d4a8e516e07c9e098bd09e7 | |
parent | c323758631fe5e414e7e2bb002b5ba89aa449834 (diff) |
Core/ChatCommands: Implement achievement link parsing
(cherry picked from commit a4c666dc3d75d0c77fdeb52a6d2cd21100ba4588)
6 files changed, 112 insertions, 18 deletions
diff --git a/src/server/game/Chat/ChatCommands/ChatCommandArgs.cpp b/src/server/game/Chat/ChatCommands/ChatCommandArgs.cpp index 16a750e1314..b00b48fe0a0 100644 --- a/src/server/game/Chat/ChatCommands/ChatCommandArgs.cpp +++ b/src/server/game/Chat/ChatCommands/ChatCommandArgs.cpp @@ -18,10 +18,25 @@ #include "ChatCommandArgs.h" #include "ChatCommand.h" #include "ChatCommandHyperlinks.h" +#include "DB2Stores.h" #include "ObjectMgr.h" using namespace Trinity::ChatCommands; +struct AchievementVisitor +{ + using value_type = AchievementEntry const*; + value_type operator()(Hyperlink<achievement> achData) const { return achData->achievement; } + value_type operator()(uint32 achId) const { return sAchievementStore.LookupEntry(achId); } +}; +char const* Trinity::ChatCommands::ArgInfo<AchievementEntry const*>::TryConsume(AchievementEntry const*& data, char const* args) +{ + Variant <Hyperlink<achievement>, uint32> val; + if ((args = CommandArgsConsumerSingle<decltype(val)>::TryConsumeTo(val, args))) + data = boost::apply_visitor(AchievementVisitor(), val); + return args; +} + struct GameTeleVisitor { using value_type = GameTele const*; diff --git a/src/server/game/Chat/ChatCommands/ChatCommandArgs.h b/src/server/game/Chat/ChatCommands/ChatCommandArgs.h index 811981e1244..bbdb2565f25 100644 --- a/src/server/game/Chat/ChatCommands/ChatCommandArgs.h +++ b/src/server/game/Chat/ChatCommands/ChatCommandArgs.h @@ -108,6 +108,13 @@ struct ArgInfo<T, std::enable_if_t<advstd::is_base_of_v<ContainerTag, T>>> } }; +// AchievementEntry* from numeric id or link +template <> +struct TC_GAME_API ArgInfo<AchievementEntry const*> +{ + static char const* TryConsume(AchievementEntry const*&, char const*); +}; + // GameTele* from string name or link template <> struct TC_GAME_API ArgInfo<GameTele const*> diff --git a/src/server/game/Chat/ChatCommands/ChatCommandHelpers.h b/src/server/game/Chat/ChatCommands/ChatCommandHelpers.h index f099d7eac57..42c0a195041 100644 --- a/src/server/game/Chat/ChatCommands/ChatCommandHelpers.h +++ b/src/server/game/Chat/ChatCommands/ChatCommandHelpers.h @@ -24,7 +24,7 @@ namespace Trinity { namespace ChatCommands { -static const char COMMAND_DELIMITER = ' '; +static constexpr char COMMAND_DELIMITER = ' '; /***************** HELPERS *************************\ |* These really aren't for outside use... *| diff --git a/src/server/game/Chat/ChatCommands/ChatCommandHyperlinks.cpp b/src/server/game/Chat/ChatCommands/ChatCommandHyperlinks.cpp new file mode 100644 index 00000000000..53035813769 --- /dev/null +++ b/src/server/game/Chat/ChatCommands/ChatCommandHyperlinks.cpp @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2008-2018 TrinityCore <https://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "ChatCommandHyperlinks.h" +#include "DB2Stores.h" + +static constexpr char HYPERLINK_DELIMITER = ':'; + +class AchievementLinkTokenizer +{ + public: + AchievementLinkTokenizer(char const* pos, size_t len) : _pos(pos), _len(len), _empty(false) {} + + template <typename T> + bool TryConsumeTo(T& val) + { + if (_empty) + return false; + + char const* firstPos = _pos; + size_t thisLen = 0; + // find next delimiter + for (; _len && *_pos != HYPERLINK_DELIMITER; --_len, ++_pos, ++thisLen); + if (_len) + --_len, ++_pos; // skip the delimiter + else + _empty = true; + + return Trinity::ChatCommands::base_tag::StoreTo(val, firstPos, thisLen); + } + + bool IsEmpty() { return _empty; } + + private: + char const* _pos; + size_t _len; + bool _empty; +}; + +bool Trinity::ChatCommands::achievement::StoreTo(AchievementLinkData& val, char const* pos, size_t len) +{ + AchievementLinkTokenizer t(pos, len); + uint32 achievementId; + if (!t.TryConsumeTo(achievementId)) + return false; + val.achievement = sAchievementStore.LookupEntry(achievementId); + return val.achievement && t.TryConsumeTo(val.characterId) && t.TryConsumeTo(val.isFinished) && + t.TryConsumeTo(val.month) && t.TryConsumeTo(val.day) && t.TryConsumeTo(val.year) && t.TryConsumeTo(val.criteria[0]) && + t.TryConsumeTo(val.criteria[1]) && t.TryConsumeTo(val.criteria[2]) && t.TryConsumeTo(val.criteria[3]) && t.IsEmpty(); +} diff --git a/src/server/game/Chat/ChatCommands/ChatCommandHyperlinks.h b/src/server/game/Chat/ChatCommands/ChatCommandHyperlinks.h index f3fcf74ecf4..bb4d8727f16 100644 --- a/src/server/game/Chat/ChatCommands/ChatCommandHyperlinks.h +++ b/src/server/game/Chat/ChatCommands/ChatCommandHyperlinks.h @@ -22,6 +22,8 @@ #include "ChatCommandTags.h" #include "ObjectGuid.h" +struct AchievementEntry; + namespace Trinity { namespace ChatCommands { @@ -34,6 +36,8 @@ struct Hyperlink : public ContainerTag public: operator value_type() const { return val; } + value_type const& operator*() const { return val; } + value_type const* operator->() const { return &val; } char const* TryConsume(char const* pos) { @@ -117,7 +121,7 @@ struct base_tag } }; -#define make_base_tag(ltag, type) struct ltag : public base_tag { typedef type value_type; static constexpr char const* tag() { return #ltag; } } +#define make_base_tag(ltag, type) struct ltag : public base_tag { using value_type = type; static constexpr char const* tag() { return #ltag; } } make_base_tag(areatrigger, uint32); make_base_tag(creature, ObjectGuid::LowType); make_base_tag(creature_entry, uint32); @@ -126,6 +130,24 @@ make_base_tag(taxinode, uint32); make_base_tag(tele, uint32); #undef make_base_tag +struct AchievementLinkData +{ + AchievementEntry const* achievement; + std::string characterId; // TODO: full ObjectGuid (implement parsing guid strings) + bool isFinished; + uint16 year; + uint8 month; + uint8 day; + uint32 criteria[4]; +}; + +struct TC_GAME_API achievement +{ + using value_type = AchievementLinkData; + static constexpr char const* tag() { return "achievement"; } + static bool StoreTo(AchievementLinkData& val, char const* pos, size_t len); +}; + }} #endif diff --git a/src/server/scripts/Commands/cs_achievement.cpp b/src/server/scripts/Commands/cs_achievement.cpp index 7d019f5258b..ba2c764e4ee 100644 --- a/src/server/scripts/Commands/cs_achievement.cpp +++ b/src/server/scripts/Commands/cs_achievement.cpp @@ -48,20 +48,8 @@ public: return commandTable; } - static bool HandleAchievementAddCommand(ChatHandler* handler, char const* args) + static bool HandleAchievementAddCommand(ChatHandler* handler, AchievementEntry const* achievementEntry) { - if (!*args) - return false; - - uint32 achievementId = atoi((char*)args); - if (!achievementId) - { - if (char* id = handler->extractKeyFromLink((char*)args, "Hachievement")) - achievementId = atoul(id); - if (!achievementId) - return false; - } - Player* target = handler->getSelectedPlayer(); if (!target) { @@ -69,9 +57,7 @@ public: handler->SetSentErrorMessage(true); return false; } - - if (AchievementEntry const* achievementEntry = sAchievementStore.LookupEntry(achievementId)) - target->CompletedAchievement(achievementEntry); + target->CompletedAchievement(achievementEntry); return true; } |