From dce5f03e74d57ee9306af01caf93c502efd655a4 Mon Sep 17 00:00:00 2001 From: Chris Miles Date: Wed, 14 Dec 2022 22:26:05 -0600 Subject: [PATCH] [Commands] Nested Command Aliases (#2636) --- common/strings.cpp | 10 ++ common/strings.h | 1 + zone/command.cpp | 14 +-- zone/gm_commands/feature.cpp | 20 +++- zone/gm_commands/reload.cpp | 182 ++++++++++++++++++++--------------- 5 files changed, 137 insertions(+), 90 deletions(-) diff --git a/common/strings.cpp b/common/strings.cpp index dc31cf848..2b31a3881 100644 --- a/common/strings.cpp +++ b/common/strings.cpp @@ -200,6 +200,16 @@ bool Strings::IsNumber(const std::string &s) } } +bool Strings::IsFloat(const std::string &s) +{ + try { + auto r = stof(s); + return true; + } + catch (std::exception &) { + return false; + } +} std::string Strings::Join(const std::vector &ar, const std::string &delim) { diff --git a/common/strings.h b/common/strings.h index 9f4121542..90decba75 100644 --- a/common/strings.h +++ b/common/strings.h @@ -86,6 +86,7 @@ public: static bool Contains(std::vector container, std::string element); static bool Contains(const std::string& subject, const std::string& search); static bool IsNumber(const std::string &s); + static bool IsFloat(const std::string &s); static const std::string ToLower(std::string s); static const std::string ToUpper(std::string s); static const std::string UcFirst(std::string s); diff --git a/zone/command.cpp b/zone/command.cpp index 0894f21d6..9ab5db87a 100644 --- a/zone/command.cpp +++ b/zone/command.cpp @@ -143,6 +143,7 @@ int command_init(void) command_add("faction", "[Find (criteria | all ) | Review (criteria | all) | Reset (id)] - Resets Player's Faction", AccountStatus::QuestTroupe, command_faction) || command_add("factionassociation", "[factionid] [amount] - triggers a faction hits via association", AccountStatus::GMLeadAdmin, command_faction_association) || command_add("feature", "Change your or your target's feature's temporarily", AccountStatus::QuestTroupe, command_feature) || + command_add("size", "Change your targets size (alias of #feature size)", AccountStatus::QuestTroupe, command_feature) || command_add("findaa", "[Search Criteria] - Search for an AA", AccountStatus::Guide, command_findaa) || command_add("findaliases", "[Search Criteria]- Searches for available command aliases, by alias or command", AccountStatus::Player, command_findaliases) || command_add("findclass", "[Search Criteria] - Search for a class", AccountStatus::Guide, command_findclass) || @@ -261,6 +262,8 @@ int command_init(void) command_add("randomfeatures", "Temporarily randomizes the Facial Features of your target", AccountStatus::QuestTroupe, command_randomfeatures) || command_add("refreshgroup", "Refreshes Group for you or your player target.", AccountStatus::Player, command_refreshgroup) || command_add("reload", "Reloads different types of server data globally, use no argument for help menu.", AccountStatus::GMMgmt, command_reload) || + command_add("rq", "Reloads quests (alias of #reload quests).", AccountStatus::GMMgmt, command_reload) || + command_add("rl", "Reloads logs (alias of #reload logs).", AccountStatus::GMMgmt, command_reload) || command_add("removeitem", "[Item ID] [Amount] - Removes the specified Item ID by Amount from you or your player target's inventory (Amount defaults to 1 if not used)", AccountStatus::GMAdmin, command_removeitem) || command_add("repop", "[Force] - Repop the zone with optional force repop", AccountStatus::GMAdmin, command_repop) || command_add("resetaa", "Resets a Player's AA in their profile and refunds spent AA's to unspent, may disconnect player.", AccountStatus::GMMgmt, command_resetaa) || @@ -517,15 +520,6 @@ int command_add(std::string command_name, std::string description, uint8 admin, return -1; } - for (const auto& c : commandlist) { - if (c.second->function != function) { - continue; - } - - LogError("command_add() - Command [{}] equates to an alias of [{}] - check command.cpp", command_name, c.first); - return -1; - } - auto c = new CommandRecord; c->admin = admin; c->description = description; @@ -617,7 +611,7 @@ void command_help(Client *c, const Seperator *sep) for (const auto& cur : commandlist) { if (!search_criteria.empty()) { - if (cur.first.find(search_criteria) == std::string::npos) { + if (!Strings::Contains(cur.first, search_criteria) && !Strings::Contains(cur.second->description, search_criteria)) { continue; } } diff --git a/zone/gm_commands/feature.cpp b/zone/gm_commands/feature.cpp index 3a9f2dfe0..55b6648d9 100644 --- a/zone/gm_commands/feature.cpp +++ b/zone/gm_commands/feature.cpp @@ -2,8 +2,13 @@ void command_feature(Client *c, const Seperator *sep) { + // nested command aliasing + std::string command = sep->arg[0] ? sep->arg[0] : ""; + bool is_size_alias = sep->arg[0] && Strings::Contains(command, "#size"); + bool is_nested_alias = (is_size_alias); + int arguments = sep->argnum; - if (arguments < 2 || !sep->IsNumber(2)) { + if ((arguments < 2 || !sep->IsNumber(2)) && !is_nested_alias) { auto feature_save_link = Saylink::Silent("#npcedit featuresave"); c->Message(Chat::White, "Usage: #feature beard [Beard] - Change your or your target's Beard"); @@ -43,7 +48,7 @@ void command_feature(Client *c, const Seperator *sep) bool is_helm = !strcasecmp(sep->arg[1], "helm"); bool is_heritage = !strcasecmp(sep->arg[1], "heritage"); bool is_race = !strcasecmp(sep->arg[1], "race"); - bool is_size = !strcasecmp(sep->arg[1], "size"); + bool is_size = !strcasecmp(sep->arg[1], "size") || is_size_alias; bool is_tattoo = !strcasecmp(sep->arg[1], "tattoo"); bool is_texture = !strcasecmp(sep->arg[1], "texture"); @@ -165,7 +170,16 @@ void command_feature(Client *c, const Seperator *sep) feature_changed = "Race"; value_changed = race; } else if (is_size) { - size = std::stof(sep->arg[2]); + // handle aliased input + if (is_size_alias) { + c->Message(Chat::White, "Usage: #feature size [Size] - Change your or your target's Size temporarily (Valid values are 0 to 255, decimal increments are allowed.)"); + if (sep->arg[1] && Strings::IsFloat(sep->arg[1])) { + size = std::stof(sep->arg[1]); + } + } + else { + size = std::stof(sep->arg[2]); + } if (size < 0 || size > 255) { c->Message(Chat::White, "Usage: #feature size [Size] - Change your or your target's Size temporarily (Valid values are 0 to 255, decimal increments are allowed.)"); diff --git a/zone/gm_commands/reload.cpp b/zone/gm_commands/reload.cpp index eeb5c20d8..2f4e9511e 100644 --- a/zone/gm_commands/reload.cpp +++ b/zone/gm_commands/reload.cpp @@ -2,37 +2,40 @@ void command_reload(Client *c, const Seperator *sep) { - int arguments = sep->argnum; - if (!arguments) { + std::string command = sep->arg[0] ? sep->arg[0] : ""; + int arguments = sep->argnum; + if (!arguments && Strings::Contains(command, "#reload")) { c->SendReloadCommandMessages(); return; } - bool is_aa = !strcasecmp(sep->arg[1], "aa"); + bool is_rq_alias = sep->arg[0] && Strings::Contains(command, "#rq"); + bool is_logs_reload_alias = sep->arg[0] && Strings::Contains(command, "#rl"); + bool is_aa = !strcasecmp(sep->arg[1], "aa"); bool is_alternate_currencies = !strcasecmp(sep->arg[1], "alternate_currencies"); - bool is_blocked_spells = !strcasecmp(sep->arg[1], "blocked_spells"); - bool is_commands = !strcasecmp(sep->arg[1], "commands"); - bool is_content_flags = !strcasecmp(sep->arg[1], "content_flags"); - bool is_doors = !strcasecmp(sep->arg[1], "doors"); - bool is_dztemplates = !strcasecmp(sep->arg[1], "dztemplates"); - bool is_ground_spawns = !strcasecmp(sep->arg[1], "ground_spawns"); - bool is_level_mods = !strcasecmp(sep->arg[1], "level_mods"); - bool is_logs = !strcasecmp(sep->arg[1], "logs"); - bool is_merchants = !strcasecmp(sep->arg[1], "merchants"); - bool is_npc_emotes = !strcasecmp(sep->arg[1], "npc_emotes"); - bool is_objects = !strcasecmp(sep->arg[1], "objects"); - bool is_perl_export = !strcasecmp(sep->arg[1], "perl_export"); - bool is_quest = !strcasecmp(sep->arg[1], "quest"); - bool is_rules = !strcasecmp(sep->arg[1], "rules"); - bool is_static = !strcasecmp(sep->arg[1], "static"); - bool is_tasks = !strcasecmp(sep->arg[1], "tasks"); - bool is_titles = !strcasecmp(sep->arg[1], "titles"); - bool is_traps = !strcasecmp(sep->arg[1], "traps"); - bool is_variables = !strcasecmp(sep->arg[1], "variables"); - bool is_veteran_rewards = !strcasecmp(sep->arg[1], "veteran_rewards"); - bool is_world = !strcasecmp(sep->arg[1], "world"); - bool is_zone = !strcasecmp(sep->arg[1], "zone"); - bool is_zone_points = !strcasecmp(sep->arg[1], "zone_points"); + bool is_blocked_spells = !strcasecmp(sep->arg[1], "blocked_spells"); + bool is_commands = !strcasecmp(sep->arg[1], "commands"); + bool is_content_flags = !strcasecmp(sep->arg[1], "content_flags"); + bool is_doors = !strcasecmp(sep->arg[1], "doors"); + bool is_dztemplates = !strcasecmp(sep->arg[1], "dztemplates"); + bool is_ground_spawns = !strcasecmp(sep->arg[1], "ground_spawns"); + bool is_level_mods = !strcasecmp(sep->arg[1], "level_mods"); + bool is_logs = !strcasecmp(sep->arg[1], "logs") || is_logs_reload_alias; + bool is_merchants = !strcasecmp(sep->arg[1], "merchants"); + bool is_npc_emotes = !strcasecmp(sep->arg[1], "npc_emotes"); + bool is_objects = !strcasecmp(sep->arg[1], "objects"); + bool is_perl_export = !strcasecmp(sep->arg[1], "perl_export"); + bool is_quest = !strcasecmp(sep->arg[1], "quest") || (is_rq_alias); + bool is_rules = !strcasecmp(sep->arg[1], "rules"); + bool is_static = !strcasecmp(sep->arg[1], "static"); + bool is_tasks = !strcasecmp(sep->arg[1], "tasks"); + bool is_titles = !strcasecmp(sep->arg[1], "titles"); + bool is_traps = !strcasecmp(sep->arg[1], "traps"); + bool is_variables = !strcasecmp(sep->arg[1], "variables"); + bool is_veteran_rewards = !strcasecmp(sep->arg[1], "veteran_rewards"); + bool is_world = !strcasecmp(sep->arg[1], "world"); + bool is_zone = !strcasecmp(sep->arg[1], "zone"); + bool is_zone_points = !strcasecmp(sep->arg[1], "zone_points"); if ( !is_aa && @@ -60,38 +63,46 @@ void command_reload(Client *c, const Seperator *sep) !is_world && !is_zone && !is_zone_points - ) { + ) { c->SendReloadCommandMessages(); return; } - ServerPacket* pack = nullptr; + ServerPacket *pack = nullptr; if (is_aa) { c->Message(Chat::White, "Attempting to reload Alternate Advancement Data globally."); pack = new ServerPacket(ServerOP_ReloadAAData, 0); - } else if (is_alternate_currencies) { + } + else if (is_alternate_currencies) { c->Message(Chat::White, "Attempting to reload Alternate Currencies globally."); pack = new ServerPacket(ServerOP_ReloadAlternateCurrencies, 0); - } else if (is_blocked_spells) { + } + else if (is_blocked_spells) { c->Message(Chat::White, "Attempting to reload Blocked Spells globally."); pack = new ServerPacket(ServerOP_ReloadBlockedSpells, 0); - } else if (is_commands) { + } + else if (is_commands) { c->Message(Chat::White, "Attempting to reload Commands globally."); pack = new ServerPacket(ServerOP_ReloadCommands, 0); - } else if (is_content_flags) { + } + else if (is_content_flags) { c->Message(Chat::White, "Attempting to reload Content Flags globally."); pack = new ServerPacket(ServerOP_ReloadContentFlags, 0); - } else if (is_doors) { + } + else if (is_doors) { c->Message(Chat::White, "Attempting to reload Doors globally."); pack = new ServerPacket(ServerOP_ReloadDoors, 0); - } else if (is_dztemplates) { + } + else if (is_dztemplates) { c->Message(Chat::White, "Attempting to reload Dynamic Zone Templates globally."); pack = new ServerPacket(ServerOP_ReloadDzTemplates, 0); - } else if (is_ground_spawns) { + } + else if (is_ground_spawns) { c->Message(Chat::White, "Attempting to reload Ground Spawns globally."); pack = new ServerPacket(ServerOP_ReloadGroundSpawns, 0); - } else if (is_level_mods) { + } + else if (is_level_mods) { if (!RuleB(Zone, LevelBasedEXPMods)) { c->Message(Chat::White, "Level Based Experience Modifiers are disabled."); return; @@ -99,22 +110,28 @@ void command_reload(Client *c, const Seperator *sep) c->Message(Chat::White, "Attempting to reload Level Based Experience Modifiers globally."); pack = new ServerPacket(ServerOP_ReloadLevelEXPMods, 0); - } else if (is_logs) { + } + else if (is_logs) { c->Message(Chat::White, "Attempting to reload Log Settings globally."); pack = new ServerPacket(ServerOP_ReloadLogs, 0); - } else if (is_merchants) { + } + else if (is_merchants) { c->Message(Chat::White, "Attempting to reload Merchants globally."); pack = new ServerPacket(ServerOP_ReloadMerchants, 0); - } else if (is_npc_emotes) { + } + else if (is_npc_emotes) { c->Message(Chat::White, "Attempting to reload NPC Emotes globally."); pack = new ServerPacket(ServerOP_ReloadNPCEmotes, 0); - } else if (is_objects) { + } + else if (is_objects) { c->Message(Chat::White, "Attempting to reload Objects globally."); pack = new ServerPacket(ServerOP_ReloadObjects, 0); - } else if (is_perl_export) { + } + else if (is_perl_export) { c->Message(Chat::White, "Attempting to reload Perl Event Export Settings globally."); pack = new ServerPacket(ServerOP_ReloadPerlExportSettings, 0); - } else if (is_quest) { + } + else if (is_quest) { bool stop_timers = false; if (sep->IsNumber(2)) { @@ -134,28 +151,34 @@ void command_reload(Client *c, const Seperator *sep) entity_list.ClearAreas(); parse->ReloadQuests(stop_timers); - } else if (is_rules) { + } + else if (is_rules) { c->Message(Chat::White, "Attempting to reload Rules globally."); pack = new ServerPacket(ServerOP_ReloadRules, 0); - } else if (is_static) { + } + else if (is_static) { c->Message(Chat::White, "Attempting to reload Static Zone Data globally."); pack = new ServerPacket(ServerOP_ReloadStaticZoneData, 0); - } else if (is_tasks) { + } + else if (is_tasks) { uint32 task_id = 0; if (!sep->IsNumber(2)) { c->Message(Chat::White, "Attempting to reload Tasks globally."); pack = new ServerPacket(ServerOP_ReloadTasks, sizeof(ReloadTasks_Struct)); - } else { + } + else { task_id = std::stoul(sep->arg[2]); } - auto rts = (ReloadTasks_Struct*) pack->pBuffer; + auto rts = (ReloadTasks_Struct *) pack->pBuffer; rts->reload_type = RELOADTASKS; - rts->task_id = task_id; - } else if (is_titles) { + rts->task_id = task_id; + } + else if (is_titles) { c->Message(Chat::White, "Attempting to reload Titles globally."); pack = new ServerPacket(ServerOP_ReloadTitles, 0); - } else if (is_traps) { + } + else if (is_traps) { if (arguments < 2 || !sep->IsNumber(2)) { entity_list.UpdateAllTraps(true, true); c->Message( @@ -184,13 +207,16 @@ void command_reload(Client *c, const Seperator *sep) c->Message(Chat::White, "Attempting to reload Traps globally."); pack = new ServerPacket(ServerOP_ReloadTraps, 0); - } else if (is_variables) { + } + else if (is_variables) { c->Message(Chat::White, "Attempting to reload Variables globally."); pack = new ServerPacket(ServerOP_ReloadVariables, 0); - } else if (is_veteran_rewards) { + } + else if (is_veteran_rewards) { c->Message(Chat::White, "Attempting to reload Veteran Rewards globally."); pack = new ServerPacket(ServerOP_ReloadVeteranRewards, 0); - } else if (is_world) { + } + else if (is_world) { uint8 global_repop = ReloadWorld::NoRepop; if (sep->IsNumber(2)) { @@ -207,20 +233,21 @@ void command_reload(Client *c, const Seperator *sep) "Attempting to reload Quests {}worldwide.", ( global_repop ? - ( - global_repop == ReloadWorld::Repop ? - "and repop NPCs " : - "and forcefully repop NPCs " - ) : - "" + ( + global_repop == ReloadWorld::Repop ? + "and repop NPCs " : + "and forcefully repop NPCs " + ) : + "" ) ).c_str() ); pack = new ServerPacket(ServerOP_ReloadWorld, sizeof(ReloadWorld_Struct)); - auto RW = (ReloadWorld_Struct *) pack->pBuffer; + auto RW = (ReloadWorld_Struct *) pack->pBuffer; RW->global_repop = global_repop; - } else if (is_zone) { + } + else if (is_zone) { zone_store.LoadZones(content_db); if (arguments < 2) { @@ -230,8 +257,8 @@ void command_reload(Client *c, const Seperator *sep) "Zone Header Load {} | Zone: {}", ( zone->LoadZoneCFG(zone->GetShortName(), zone->GetInstanceVersion()) ? - "Succeeded" : - "Failed" + "Succeeded" : + "Failed" ), zone->GetZoneDescription() ).c_str() @@ -241,8 +268,8 @@ void command_reload(Client *c, const Seperator *sep) auto zone_id = ( sep->IsNumber(2) ? - std::stoul(sep->arg[2]) : - ZoneID(sep->arg[2]) + std::stoul(sep->arg[2]) : + ZoneID(sep->arg[2]) ); if (!zone_id) { c->Message( @@ -256,11 +283,11 @@ void command_reload(Client *c, const Seperator *sep) } auto zone_short_name = ZoneName(zone_id); - auto zone_long_name = ZoneLongName(zone_id); - auto version = ( + auto zone_long_name = ZoneLongName(zone_id); + auto version = ( sep->IsNumber(3) ? - std::stoul(sep->arg[3]) : - 0 + std::stoul(sep->arg[3]) : + 0 ); auto outapp = new EQApplicationPacket(OP_NewZone, sizeof(NewZone_Struct)); @@ -274,22 +301,23 @@ void command_reload(Client *c, const Seperator *sep) "Zone Header Load {} | Zone: {} ({}){}", ( zone->LoadZoneCFG(zone_short_name, version) ? - "Succeeded" : - "Failed" + "Succeeded" : + "Failed" ), zone_long_name, zone_short_name, ( version ? - fmt::format( - " Version: {}", - version - ) : - "" + fmt::format( + " Version: {}", + version + ) : + "" ) ).c_str() ); - } else if (is_zone_points) { + } + else if (is_zone_points) { c->Message(Chat::White, "Attempting to reloading Zone Points globally."); pack = new ServerPacket(ServerOP_ReloadZonePoints, 0); }