diff --git a/Source/Game/Chat/CommandArgs.cs b/Source/Game/Chat/CommandArgs.cs index 6ad7cc97c..942ac5d99 100644 --- a/Source/Game/Chat/CommandArgs.cs +++ b/Source/Game/Chat/CommandArgs.cs @@ -17,7 +17,7 @@ using Framework.Constants; using Framework.IO; -using Game.DataStorage; +using Game.Entities; using Game.Spells; using System; using System.Collections.Generic; @@ -41,7 +41,7 @@ namespace Game.Chat int oldPos = args.GetCurrentPosition(); //Is this a hyperlink? - if (Hyperlink.TryConsume(out dynamic value, parameterTypes[index], args) || ParseArgument(out value, parameterTypes[index], args)) + if (ParseArgument(out dynamic value, parameterTypes[index], args)) index++; if (args.IsAtEnd() && index < parameterTypes.Length) @@ -58,14 +58,17 @@ namespace Game.Chat return arguments.ToArray(); } - public static bool ParseArgument(out dynamic value, Type type, StringArguments args) + static bool ParseArgument(out dynamic value, Type type, StringArguments args) { value = default; + if (Hyperlink.TryParse(out value, type, args)) + return true; + if (args.IsAtEnd()) return false; - if (Hyperlink.TryConsume(out value, type, args)) + if (Hyperlink.TryParse(out value, type, args)) return value; if (type.IsEnum) @@ -115,12 +118,6 @@ namespace Game.Chat switch (type.Name) { - case nameof(AchievementRecord): - value = CliDB.AchievementStorage.LookupByKey(args.NextUInt32()); - break; - case nameof(CurrencyTypesRecord): - value = CliDB.CurrencyTypesStorage.LookupByKey(args.NextUInt32()); - break; case nameof(GameTele): value = Global.ObjectMgr.GetGameTele(args.NextString()); break; @@ -138,4 +135,89 @@ namespace Game.Chat return true; } } + + class PlayerIdentifier + { + string _name; + ObjectGuid _guid; + Player _player; + + public PlayerIdentifier(string name, ObjectGuid guid) + { + _name = name; + _guid = guid; + } + + public PlayerIdentifier(Player player) + { + _name = player.GetName(); + _guid = player.GetGUID(); + _player = player; + } + + public string GetName() { return _name; } + public ObjectGuid GetGUID() { return _guid; } + public Player GetPlayer() { return _player; } + + public static PlayerIdentifier FromTarget(CommandHandler handler) + { + Player player = handler.GetPlayer(); + if (player != null) + { + Player target = player.GetSelectedPlayer(); + if (target != null) + return new PlayerIdentifier(target); + } + + return null; + } + + public static PlayerIdentifier FromSelf(CommandHandler handler) + { + Player player = handler.GetPlayer(); + if (player != null) + return new PlayerIdentifier(player); + + return null; + } + + public static PlayerIdentifier FromTargetOrSelf(CommandHandler handler) + { + PlayerIdentifier fromTarget = FromTarget(handler); + if (fromTarget != null) + return fromTarget; + else + return FromSelf(handler); + } + + public static PlayerIdentifier ParseFromString(string arg) + { + ulong guid = 0; + string name; + if (!Hyperlink.TryParse(out name, arg) || !ulong.TryParse(arg, out guid)) + name = arg; + + if (!name.IsEmpty()) + { + ObjectManager.NormalizePlayerName(ref name); + var player = Global.ObjAccessor.FindPlayerByName(name); + if (player != null) + return new PlayerIdentifier(player); + else + { + var objectGuid = Global.CharacterCacheStorage.GetCharacterGuidByName(name); + if (objectGuid.IsEmpty()) + return new PlayerIdentifier(name, objectGuid); + } + } + else if (guid != 0) + { + var player = Global.ObjAccessor.FindPlayerByLowGUID(guid); + if (player != null) + return new PlayerIdentifier(player); + } + + return null; + } + } } diff --git a/Source/Game/Chat/Commands/AchievementCommands.cs b/Source/Game/Chat/Commands/AchievementCommands.cs index fc75564fe..1ee1f7b7d 100644 --- a/Source/Game/Chat/Commands/AchievementCommands.cs +++ b/Source/Game/Chat/Commands/AchievementCommands.cs @@ -27,8 +27,12 @@ namespace Game.Chat.Commands class AchievementCommand { [Command("add", RBACPermissions.CommandAchievementAdd)] - static bool Add(CommandHandler handler, AchievementRecord achievementEntry) + static bool HandleAchievementAddCommand(CommandHandler handler, uint achievemntId) { + AchievementRecord achievementEntry = CliDB.AchievementStorage.LookupByKey(achievemntId); + if (achievementEntry == null) + return false; + Player target = handler.GetSelectedPlayer(); if (!target) { diff --git a/Source/Game/Chat/Commands/DebugCommands.cs b/Source/Game/Chat/Commands/DebugCommands.cs index dcff088b5..3c84304a4 100644 --- a/Source/Game/Chat/Commands/DebugCommands.cs +++ b/Source/Game/Chat/Commands/DebugCommands.cs @@ -470,7 +470,7 @@ namespace Game.Chat bool explain = false; uint groupID = 0; - if (explainOrGroupId.Equals("explain")) + if (explainOrGroupId.Equals("explain", StringComparison.OrdinalIgnoreCase)) explain = true; else groupID = uint.Parse(explainOrGroupId); diff --git a/Source/Game/Chat/Commands/GameObjectCommands.cs b/Source/Game/Chat/Commands/GameObjectCommands.cs index c4e15505a..63bfdb900 100644 --- a/Source/Game/Chat/Commands/GameObjectCommands.cs +++ b/Source/Game/Chat/Commands/GameObjectCommands.cs @@ -94,7 +94,7 @@ namespace Game.Chat // Decode arguments foreach (var variant in opts) { - if (variant.Equals("removerespawntime")) + if (variant.Equals("removerespawntime", StringComparison.OrdinalIgnoreCase)) deleteRespawnTimes = true; else uint.TryParse(variant, out groupId); @@ -122,7 +122,7 @@ namespace Game.Chat uint entry; ulong spawnId = 0; - if (!isGuid.IsEmpty() && isGuid.Equals("guid")) + if (!isGuid.IsEmpty() && isGuid.Equals("guid", StringComparison.OrdinalIgnoreCase)) { spawnId = data; spawnData = Global.ObjectMgr.GetGameObjectData(spawnId); diff --git a/Source/Game/Chat/Commands/MMapsCommands.cs b/Source/Game/Chat/Commands/MMapsCommands.cs index 9afb94f0b..d69546a63 100644 --- a/Source/Game/Chat/Commands/MMapsCommands.cs +++ b/Source/Game/Chat/Commands/MMapsCommands.cs @@ -51,11 +51,11 @@ namespace Game.Chat string para = args.NextString(); bool useStraightPath = false; - if (para.Equals("true")) + if (para.Equals("true", StringComparison.OrdinalIgnoreCase)) useStraightPath = true; bool useRaycast = false; - if (para.Equals("line") || para.Equals("ray") || para.Equals("raycast")) + if (para.Equals("line", StringComparison.OrdinalIgnoreCase) || para.Equals("ray", StringComparison.OrdinalIgnoreCase) || para.Equals("raycast", StringComparison.OrdinalIgnoreCase)) useRaycast = true; // unit locations diff --git a/Source/Game/Chat/Commands/MessageCommands.cs b/Source/Game/Chat/Commands/MessageCommands.cs index 94636b83c..327d3794f 100644 --- a/Source/Game/Chat/Commands/MessageCommands.cs +++ b/Source/Game/Chat/Commands/MessageCommands.cs @@ -143,7 +143,7 @@ namespace Game.Chat uint channelId = 0; foreach (var channelEntry in CliDB.ChatChannelsStorage.Values) { - if (channelEntry.Name[handler.GetSessionDbcLocale()].Equals(channelName)) + if (channelEntry.Name[handler.GetSessionDbcLocale()].Equals(channelName, StringComparison.OrdinalIgnoreCase)) { channelId = channelEntry.Id; break; @@ -153,7 +153,7 @@ namespace Game.Chat AreaTableRecord zoneEntry = null; foreach (var entry in CliDB.AreaTableStorage.Values) { - if (entry.AreaName[handler.GetSessionDbcLocale()].Equals(channelName)) + if (entry.AreaName[handler.GetSessionDbcLocale()].Equals(channelName, StringComparison.OrdinalIgnoreCase)) { zoneEntry = entry; break; diff --git a/Source/Game/Chat/Commands/MiscCommands.cs b/Source/Game/Chat/Commands/MiscCommands.cs index a5c7639cc..2a9366eaa 100644 --- a/Source/Game/Chat/Commands/MiscCommands.cs +++ b/Source/Game/Chat/Commands/MiscCommands.cs @@ -1076,9 +1076,9 @@ namespace Game.Chat Team team; if (teamArg.IsEmpty()) team = 0; - else if (teamArg.Equals("horde")) + else if (teamArg.Equals("horde", StringComparison.OrdinalIgnoreCase)) team = Team.Horde; - else if (teamArg.Equals("alliance")) + else if (teamArg.Equals("alliance", StringComparison.OrdinalIgnoreCase)) team = Team.Alliance; else return false; @@ -1364,9 +1364,9 @@ namespace Game.Chat Team team; if (teamArg.IsEmpty()) team = 0; - else if (teamArg.Equals("horde")) + else if (teamArg.Equals("horde", StringComparison.OrdinalIgnoreCase)) team = Team.Horde; - else if (teamArg.Equals("alliance")) + else if (teamArg.Equals("alliance", StringComparison.OrdinalIgnoreCase)) team = Team.Alliance; else return false; diff --git a/Source/Game/Chat/Commands/ModifyCommands.cs b/Source/Game/Chat/Commands/ModifyCommands.cs index 292a286c3..8868fefa4 100644 --- a/Source/Game/Chat/Commands/ModifyCommands.cs +++ b/Source/Game/Chat/Commands/ModifyCommands.cs @@ -420,7 +420,7 @@ namespace Game.Chat if (string.IsNullOrEmpty(rank)) continue; - if (rank.Equals(rankStr)) + if (rank.Equals(rankStr, StringComparison.OrdinalIgnoreCase)) break; if (i == ReputationMgr.ReputationRankThresholds.Length - 1) diff --git a/Source/Game/Chat/Commands/NPCCommands.cs b/Source/Game/Chat/Commands/NPCCommands.cs index 2c0c78762..5cdd512bb 100644 --- a/Source/Game/Chat/Commands/NPCCommands.cs +++ b/Source/Game/Chat/Commands/NPCCommands.cs @@ -76,7 +76,7 @@ namespace Game.Chat return false; } - if (force.Equals("force")) + if (force.Equals("force", StringComparison.OrdinalIgnoreCase)) creatureTarget.ClearUnitState(UnitState.Evade); creatureTarget.GetAI().EnterEvadeMode(why.GetValueOrDefault(EvadeReason.Other)); @@ -334,7 +334,7 @@ namespace Game.Chat handler.SendSysMessage(CypherStrings.CommandNpcShowLootHeader, creatureTarget.GetName(), creatureTarget.GetEntry()); handler.SendSysMessage(CypherStrings.CommandNpcShowLootMoney, loot.gold / MoneyConstants.Gold, (loot.gold % MoneyConstants.Gold) / MoneyConstants.Silver, loot.gold % MoneyConstants.Silver); - if (all.Equals("all")) // nonzero from strcmp <. not equal + if (all.Equals("all", StringComparison.OrdinalIgnoreCase)) // nonzero from strcmp <. not equal { handler.SendSysMessage(CypherStrings.CommandNpcShowLootLabel, "Standard items", loot.items.Count); foreach (LootItem item in loot.items) @@ -745,9 +745,9 @@ namespace Game.Chat bool loot = false; if (!lootStr.IsEmpty()) { - if (lootStr.Equals("loot")) + if (lootStr.Equals("loot", StringComparison.OrdinalIgnoreCase)) loot = true; - else if (lootStr.Equals("noloot")) + else if (lootStr.Equals("noloot", StringComparison.OrdinalIgnoreCase)) loot = false; else return false; diff --git a/Source/Game/Chat/Commands/ServerCommands.cs b/Source/Game/Chat/Commands/ServerCommands.cs index 4d5eb3245..ab3e4505b 100644 --- a/Source/Game/Chat/Commands/ServerCommands.cs +++ b/Source/Game/Chat/Commands/ServerCommands.cs @@ -364,13 +364,13 @@ namespace Game.Chat static bool SetClosed(CommandHandler handler, StringArguments args) { string arg1 = args.NextString(); - if (arg1.Equals("on")) + if (arg1.Equals("on", StringComparison.OrdinalIgnoreCase)) { handler.SendSysMessage(CypherStrings.WorldClosed); Global.WorldMgr.SetClosed(true); return true; } - else if (arg1.Equals("off")) + else if (arg1.Equals("off", StringComparison.OrdinalIgnoreCase)) { handler.SendSysMessage(CypherStrings.WorldOpened); Global.WorldMgr.SetClosed(false); diff --git a/Source/Game/Chat/Commands/TeleCommands.cs b/Source/Game/Chat/Commands/TeleCommands.cs index 40bb0c1b8..411408878 100644 --- a/Source/Game/Chat/Commands/TeleCommands.cs +++ b/Source/Game/Chat/Commands/TeleCommands.cs @@ -191,7 +191,7 @@ namespace Game.Chat if (!handler.ExtractPlayerTarget(new StringArguments(nameStr), out Player target, out ObjectGuid targetGuid, out string targetName)) return false; - if (teleStr.Equals("$home")) // References target's homebind + if (teleStr.Equals("home", StringComparison.OrdinalIgnoreCase)) // References target's homebind { if (target) target.TeleportTo(target.GetHomebind()); diff --git a/Source/Game/Chat/Hyperlink.cs b/Source/Game/Chat/Hyperlink.cs index 760d8e0d9..45f5f102b 100644 --- a/Source/Game/Chat/Hyperlink.cs +++ b/Source/Game/Chat/Hyperlink.cs @@ -26,7 +26,20 @@ namespace Game.Chat { class Hyperlink { - public static bool TryConsume(out dynamic value, Type type, StringArguments args) + public static bool TryParse(out string value, string arg) + { + value = null; + + HyperlinkInfo info = ParseHyperlink(arg); + // invalid hyperlinks cannot be consumed + if (info == null) + return false; + + value = info.Data; + return true; + } + + public static bool TryParse(out dynamic value, Type type, StringArguments args) { value = default; @@ -60,27 +73,18 @@ namespace Game.Chat return true; } case TypeCode.Object: - return TryConsumeObject(out value, type, info); + return TryParseToObject(out value, type, info); } return false; } - public static bool TryConsumeObject(out dynamic value, Type type, HyperlinkInfo info) + public static bool TryParseToObject(out dynamic value, Type type, HyperlinkInfo info) { value = default; switch (type.Name) { - case nameof(AchievementRecord): - { - HyperlinkDataTokenizer t = new(info.Data); - if (!t.TryConsumeTo(out uint achievementId)) - return false; - - value = CliDB.AchievementStorage.LookupByKey(achievementId); - return true; - } case nameof(CurrencyTypesRecord): { HyperlinkDataTokenizer t = new(info.Data);