More work on commands, still needs some work but most should be working now.
This commit is contained in:
+322
-349
@@ -15,6 +15,10 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using Framework.Constants;
|
||||
using Game.DataStorage;
|
||||
using Game.Entities;
|
||||
using Game.Spells;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
@@ -24,375 +28,344 @@ namespace Game.Chat
|
||||
{
|
||||
class CommandArgs
|
||||
{
|
||||
static Dictionary<Type, Func<CommandArguments, ParseStringResult>> Parsers = new()
|
||||
public static ChatCommandResult ConsumeFromOffset(dynamic[] tuple, int offset, ParameterInfo[] parameterInfos, CommandHandler handler, string args)
|
||||
{
|
||||
{ typeof(sbyte), args => args.NextSByte() },
|
||||
{ typeof(short), args => args.NextInt16() },
|
||||
{ typeof(int), args => args.NextInt32() },
|
||||
{ typeof(long), args => args.NextInt64() },
|
||||
{ typeof(byte), args => args.NextByte() },
|
||||
{ typeof(ushort), args => args.NextUInt16() },
|
||||
{ typeof(uint), args => args.NextUInt32() },
|
||||
{ typeof(ulong), args => args.NextUInt64() },
|
||||
{ typeof(float), args => args.NextSingle() },
|
||||
{ typeof(string), args => args.NextString() },
|
||||
{ typeof(bool), args => args.NextBoolean() },
|
||||
{ typeof(PlayerIdentifier), args => PlayerIdentifier.ParseFromString(args) },
|
||||
{ typeof(AccountIdentifier), args => AccountIdentifier.ParseFromString(args) },
|
||||
{ typeof(Tail), args => Tail.ParseFromString(args) },
|
||||
};
|
||||
|
||||
public static bool Parse(out dynamic[] parsedArgs, CommandHandler handler, ParameterInfo[] parameterInfos, string tailCmd)
|
||||
{
|
||||
parsedArgs = new dynamic[parameterInfos.Length];
|
||||
parsedArgs[0] = handler;
|
||||
|
||||
CommandArguments args = new CommandArguments(tailCmd);
|
||||
|
||||
for (var i = 1; i < parameterInfos.Length; i++)
|
||||
{
|
||||
if (!ParseArgument(out dynamic value, parameterInfos[i], args))
|
||||
return false;
|
||||
|
||||
parsedArgs[i] = value;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool ParseArgument(out dynamic value, ParameterInfo parameterInfo, CommandArguments args)
|
||||
{
|
||||
var parameterType = parameterInfo.ParameterType;
|
||||
|
||||
if (Hyperlink.TryParse(out value, parameterType, args))
|
||||
return true;
|
||||
|
||||
bool isOptional = false;
|
||||
|
||||
var optionalArgAttribute = parameterInfo.GetCustomAttribute<OptionalArgAttribute>(true);
|
||||
if (optionalArgAttribute != null)
|
||||
isOptional = true;
|
||||
|
||||
if (parameterType.IsGenericType && parameterType.GetGenericTypeDefinition() == typeof(Nullable<>))
|
||||
{
|
||||
parameterType = Nullable.GetUnderlyingType(parameterType);
|
||||
isOptional = true;
|
||||
}
|
||||
|
||||
if (parameterType.IsEnum)
|
||||
parameterType = parameterType.GetEnumUnderlyingType();
|
||||
|
||||
var pos = args.GetCurrentPosition();
|
||||
|
||||
var result = Parsers[parameterType](args);
|
||||
if (result != ParseResult.Ok)
|
||||
{
|
||||
if (!isOptional)
|
||||
return false;
|
||||
if (offset < tuple.Length)
|
||||
return TryConsumeTo(tuple, offset, parameterInfos, handler, args);
|
||||
else if (!args.IsEmpty()) /* the entire string must be consumed */
|
||||
return default;
|
||||
else
|
||||
args.SetCurrentPosition(pos);
|
||||
return new ChatCommandResult(args);
|
||||
}
|
||||
|
||||
value = result.GetValue();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public enum ParseResult
|
||||
static ChatCommandResult TryConsumeTo(dynamic[] tuple, int offset, ParameterInfo[] parameterInfos, CommandHandler handler, string args)
|
||||
{
|
||||
Ok,
|
||||
Error,
|
||||
EndOfString
|
||||
var optionalArgAttribute = parameterInfos[offset].GetCustomAttribute<OptionalArgAttribute>(true);
|
||||
if (optionalArgAttribute != null || parameterInfos[offset].ParameterType.IsGenericType && parameterInfos[offset].ParameterType.GetGenericTypeDefinition() == typeof(Nullable<>))
|
||||
{
|
||||
// try with the argument
|
||||
Type myArg = Nullable.GetUnderlyingType(parameterInfos[offset].ParameterType) ?? parameterInfos[offset].ParameterType;
|
||||
|
||||
ChatCommandResult result1 = TryConsume(out tuple[offset], myArg, handler, args);
|
||||
if (result1.IsSuccessful())
|
||||
if ((result1 = ConsumeFromOffset(tuple, offset + 1, parameterInfos, handler, result1)).IsSuccessful())
|
||||
return result1;
|
||||
|
||||
// try again omitting the argument
|
||||
tuple[offset] = default;
|
||||
ChatCommandResult result2 = ConsumeFromOffset(tuple, offset + 1, parameterInfos, handler, args);
|
||||
if (result2.IsSuccessful())
|
||||
return result2;
|
||||
if (result1.HasErrorMessage() && result2.HasErrorMessage())
|
||||
{
|
||||
return ChatCommandResult.FromErrorMessage($"{handler.GetCypherString(CypherStrings.CmdparserEither)} \"{result2.GetErrorMessage()}\"\n{handler.GetCypherString(CypherStrings.CmdparserOr)} \"{result1.GetErrorMessage()}\"");
|
||||
}
|
||||
else if (result1.HasErrorMessage())
|
||||
return result1;
|
||||
else
|
||||
return result2;
|
||||
}
|
||||
else
|
||||
{
|
||||
ChatCommandResult next;
|
||||
|
||||
var variantArgAttribute = parameterInfos[offset].GetCustomAttribute<VariantArgAttribute>(true);
|
||||
if (variantArgAttribute != null)
|
||||
next = TryConsumeVariant(out tuple[offset], variantArgAttribute.Types, handler, args);
|
||||
else
|
||||
next = TryConsume(out tuple[offset], parameterInfos[offset].ParameterType, handler, args);
|
||||
|
||||
if (next.IsSuccessful())
|
||||
return ConsumeFromOffset(tuple, offset + 1, parameterInfos, handler, next);
|
||||
else
|
||||
return next;
|
||||
}
|
||||
}
|
||||
|
||||
public struct ParseStringResult
|
||||
public static ChatCommandResult TryConsume(out dynamic val, Type type, CommandHandler handler, string args)
|
||||
{
|
||||
ParseResult result;
|
||||
val = default;
|
||||
|
||||
var hyperlinkResult = Hyperlink.TryParse(out val, type, handler, args);
|
||||
if (hyperlinkResult.IsSuccessful())
|
||||
return hyperlinkResult;
|
||||
|
||||
if (type.IsEnum)
|
||||
type = type.GetEnumUnderlyingType();
|
||||
|
||||
var (token, tail) = Tokenize(args);
|
||||
switch (Type.GetTypeCode(type))
|
||||
{
|
||||
case TypeCode.SByte:
|
||||
{
|
||||
if (token.IsEmpty())
|
||||
return default;
|
||||
|
||||
if (sbyte.TryParse(token, out sbyte tempValue))
|
||||
val = tempValue;
|
||||
else
|
||||
return ChatCommandResult.FromErrorMessage(handler.GetParsedString(CypherStrings.CmdparserStringValueInvalid, token, Type.GetTypeCode(type)));
|
||||
|
||||
return new ChatCommandResult(tail);
|
||||
}
|
||||
case TypeCode.Int16:
|
||||
{
|
||||
if (token.IsEmpty())
|
||||
return default;
|
||||
|
||||
if (short.TryParse(token, out short tempValue))
|
||||
val = tempValue;
|
||||
else
|
||||
return ChatCommandResult.FromErrorMessage(handler.GetParsedString(CypherStrings.CmdparserStringValueInvalid, token, Type.GetTypeCode(type)));
|
||||
|
||||
return new ChatCommandResult(tail);
|
||||
}
|
||||
case TypeCode.Int32:
|
||||
{
|
||||
if (token.IsEmpty())
|
||||
return default;
|
||||
|
||||
if (int.TryParse(token, out int tempValue))
|
||||
val = tempValue;
|
||||
else
|
||||
return ChatCommandResult.FromErrorMessage(handler.GetParsedString(CypherStrings.CmdparserStringValueInvalid, token, Type.GetTypeCode(type)));
|
||||
|
||||
return new ChatCommandResult(tail);
|
||||
}
|
||||
case TypeCode.Int64:
|
||||
{
|
||||
if (token.IsEmpty())
|
||||
return default;
|
||||
|
||||
if (long.TryParse(token, out long tempValue))
|
||||
val = tempValue;
|
||||
else
|
||||
return ChatCommandResult.FromErrorMessage(handler.GetParsedString(CypherStrings.CmdparserStringValueInvalid, token, Type.GetTypeCode(type)));
|
||||
|
||||
return new ChatCommandResult(tail);
|
||||
}
|
||||
case TypeCode.Byte:
|
||||
{
|
||||
if (token.IsEmpty())
|
||||
return default;
|
||||
|
||||
if (byte.TryParse(token, out byte tempValue))
|
||||
val = tempValue;
|
||||
else
|
||||
return ChatCommandResult.FromErrorMessage(handler.GetParsedString(CypherStrings.CmdparserStringValueInvalid, token, Type.GetTypeCode(type)));
|
||||
|
||||
return new ChatCommandResult(tail);
|
||||
}
|
||||
case TypeCode.UInt16:
|
||||
{
|
||||
if (token.IsEmpty())
|
||||
return default;
|
||||
|
||||
if (ushort.TryParse(token, out ushort tempValue))
|
||||
val = tempValue;
|
||||
else
|
||||
return ChatCommandResult.FromErrorMessage(handler.GetParsedString(CypherStrings.CmdparserStringValueInvalid, token, Type.GetTypeCode(type)));
|
||||
|
||||
return new ChatCommandResult(tail);
|
||||
}
|
||||
case TypeCode.UInt32:
|
||||
{
|
||||
if (token.IsEmpty())
|
||||
return default;
|
||||
|
||||
if (uint.TryParse(token, out uint tempValue))
|
||||
val = tempValue;
|
||||
else
|
||||
return ChatCommandResult.FromErrorMessage(handler.GetParsedString(CypherStrings.CmdparserStringValueInvalid, token, Type.GetTypeCode(type)));
|
||||
|
||||
return new ChatCommandResult(tail);
|
||||
}
|
||||
case TypeCode.UInt64:
|
||||
{
|
||||
if (token.IsEmpty())
|
||||
return default;
|
||||
|
||||
if (ulong.TryParse(token, out ulong tempValue))
|
||||
val = tempValue;
|
||||
else
|
||||
return ChatCommandResult.FromErrorMessage(handler.GetParsedString(CypherStrings.CmdparserStringValueInvalid, token, Type.GetTypeCode(type)));
|
||||
|
||||
return new ChatCommandResult(tail);
|
||||
}
|
||||
case TypeCode.Single:
|
||||
{
|
||||
if (token.IsEmpty())
|
||||
return default;
|
||||
|
||||
if (float.TryParse(token, out float tempValue))
|
||||
val = tempValue;
|
||||
else
|
||||
return ChatCommandResult.FromErrorMessage(handler.GetParsedString(CypherStrings.CmdparserStringValueInvalid, token, Type.GetTypeCode(type)));
|
||||
|
||||
if (!float.IsFinite(val))
|
||||
return ChatCommandResult.FromErrorMessage(handler.GetParsedString(CypherStrings.CmdparserStringValueInvalid, token, Type.GetTypeCode(type)));
|
||||
|
||||
return new ChatCommandResult(tail);
|
||||
}
|
||||
case TypeCode.String:
|
||||
{
|
||||
if (token.IsEmpty())
|
||||
return default;
|
||||
|
||||
val = token;
|
||||
return new ChatCommandResult(tail);
|
||||
}
|
||||
case TypeCode.Object:
|
||||
{
|
||||
switch (type.Name)
|
||||
{
|
||||
case nameof(Tail):
|
||||
val = new Tail();
|
||||
return val.TryConsume(handler, args);
|
||||
case nameof(PlayerIdentifier):
|
||||
val = new PlayerIdentifier();
|
||||
return val.TryConsume(handler, args);
|
||||
case nameof(AccountIdentifier):
|
||||
val = new AccountIdentifier();
|
||||
return val.TryConsume(handler, args);
|
||||
case nameof(AchievementRecord):
|
||||
{
|
||||
ChatCommandResult result = TryConsume(out dynamic tempVal, typeof(uint), handler, args);
|
||||
if (!result.IsSuccessful() || (val = CliDB.AchievementStorage.LookupByKey((uint)tempVal)) != null)
|
||||
return result;
|
||||
return ChatCommandResult.FromErrorMessage(handler.GetParsedString(CypherStrings.CmdparserAchievementNoExist, tempVal));
|
||||
}
|
||||
case nameof(CurrencyTypesRecord):
|
||||
{
|
||||
ChatCommandResult result = TryConsume(out dynamic tempVal, typeof(uint), handler, args);
|
||||
if (!result.IsSuccessful() || (val = CliDB.CurrencyTypesStorage.LookupByKey((uint)tempVal)) != null)
|
||||
return result;
|
||||
return ChatCommandResult.FromErrorMessage(handler.GetParsedString(CypherStrings.CmdparserCurrencyNoExist, tempVal));
|
||||
}
|
||||
case nameof(GameTele):
|
||||
{
|
||||
ChatCommandResult result = TryConsume(out dynamic tempVal, typeof(uint), handler, args);
|
||||
if (!result.IsSuccessful())
|
||||
result = TryConsume(out tempVal, typeof(string), handler, args);
|
||||
|
||||
if (!result.IsSuccessful() || (val = Global.ObjectMgr.GetGameTele(tempVal)) != null)
|
||||
return result;
|
||||
if (tempVal is uint)
|
||||
return ChatCommandResult.FromErrorMessage(handler.GetParsedString(CypherStrings.CmdparserGameTeleIdNoExist, tempVal));
|
||||
else
|
||||
return ChatCommandResult.FromErrorMessage(handler.GetParsedString(CypherStrings.CmdparserGameTeleNoExist, tempVal));
|
||||
}
|
||||
case nameof(ItemTemplate):
|
||||
{
|
||||
ChatCommandResult result = TryConsume(out dynamic tempVal, typeof(uint), handler, args);
|
||||
if (!result.IsSuccessful() || (val = Global.ObjectMgr.GetItemTemplate(tempVal)))
|
||||
return result;
|
||||
|
||||
return ChatCommandResult.FromErrorMessage(handler.GetParsedString(CypherStrings.CmdparserItemNoExist, tempVal));
|
||||
}
|
||||
case nameof(SpellInfo):
|
||||
{
|
||||
ChatCommandResult result = TryConsume(out dynamic tempVal, typeof(uint), handler, args);
|
||||
if (!result.IsSuccessful() || (val = Global.SpellMgr.GetSpellInfo(tempVal, Difficulty.None)) != null)
|
||||
return result;
|
||||
|
||||
return ChatCommandResult.FromErrorMessage(handler.GetParsedString(CypherStrings.CmdparserSpellNoExist, tempVal));
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return default;
|
||||
}
|
||||
|
||||
public static ChatCommandResult TryConsumeVariant(out dynamic val, Type[] types, CommandHandler handler, string args)
|
||||
{
|
||||
ChatCommandResult result = TryAtIndex(out val, types, 0, handler, args);
|
||||
if (result.HasErrorMessage() && (result.GetErrorMessage().IndexOf('\n') != -1))
|
||||
return ChatCommandResult.FromErrorMessage($"{handler.GetCypherString(CypherStrings.CmdparserEither)} {result.GetErrorMessage()}");
|
||||
return result;
|
||||
}
|
||||
|
||||
static ChatCommandResult TryAtIndex(out dynamic val, Type[] types, int index, CommandHandler handler, string args)
|
||||
{
|
||||
val = default;
|
||||
|
||||
if (index < types.Length)
|
||||
{
|
||||
ChatCommandResult thisResult = TryConsume(out val, types[index], handler, args);
|
||||
if (thisResult.IsSuccessful())
|
||||
return thisResult;
|
||||
else
|
||||
{
|
||||
ChatCommandResult nestedResult = TryAtIndex(out val, types, index+1, handler, args);
|
||||
if (nestedResult.IsSuccessful() || !thisResult.HasErrorMessage())
|
||||
return nestedResult;
|
||||
if (!nestedResult.HasErrorMessage())
|
||||
return thisResult;
|
||||
if (nestedResult.GetErrorMessage().StartsWith("\""))
|
||||
return ChatCommandResult.FromErrorMessage($"\"{thisResult.GetErrorMessage()}\"\n{handler.GetCypherString(CypherStrings.CmdparserOr)} {nestedResult.GetErrorMessage()}");
|
||||
else
|
||||
return ChatCommandResult.FromErrorMessage($"\"{thisResult.GetErrorMessage()}\"\n{handler.GetCypherString(CypherStrings.CmdparserOr)} \"{nestedResult.GetErrorMessage()}\"");
|
||||
}
|
||||
}
|
||||
else
|
||||
return default;
|
||||
}
|
||||
|
||||
public static (string token, string tail) Tokenize(string args)
|
||||
{
|
||||
(string token, string tail) result = new ("", "");
|
||||
int delimPos = args.IndexOf(' ');
|
||||
if (delimPos != -1)
|
||||
{
|
||||
result.token = args.Substring(0, delimPos);
|
||||
int tailPos = args.FindFirstNotOf(" ", delimPos);
|
||||
if (tailPos != -1)
|
||||
result.tail = args.Substring(tailPos);
|
||||
}
|
||||
else
|
||||
result.token = args;
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
public struct ChatCommandResult
|
||||
{
|
||||
bool result;
|
||||
dynamic value;
|
||||
string errorMessage;
|
||||
|
||||
public ParseStringResult(ParseResult _result, dynamic _value = default)
|
||||
public ChatCommandResult(string _value = "")
|
||||
{
|
||||
result = _result;
|
||||
result = true;
|
||||
value = _value;
|
||||
errorMessage = null;
|
||||
}
|
||||
|
||||
public dynamic GetValue() { return value; }
|
||||
public bool IsSuccessful() { return result; }
|
||||
|
||||
public static implicit operator ParseResult(ParseStringResult stringResult)
|
||||
public bool HasErrorMessage() { return !errorMessage.IsEmpty(); }
|
||||
|
||||
public string GetErrorMessage() { return errorMessage; }
|
||||
|
||||
public void SetErrorMessage(string _value)
|
||||
{
|
||||
return stringResult.result;
|
||||
result = false;
|
||||
errorMessage = _value;
|
||||
}
|
||||
|
||||
public static implicit operator string(ParseStringResult stringResult)
|
||||
public static ChatCommandResult FromErrorMessage(string str)
|
||||
{
|
||||
var result = new ChatCommandResult();
|
||||
result.SetErrorMessage(str);
|
||||
return result;
|
||||
}
|
||||
|
||||
public static implicit operator string(ChatCommandResult stringResult)
|
||||
{
|
||||
return stringResult.value;
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class CommandArguments
|
||||
{
|
||||
static ParseStringResult ErrorResult = new(ParseResult.Error);
|
||||
static ParseStringResult EndOfStringResult = new(ParseResult.EndOfString);
|
||||
|
||||
public CommandArguments(string args)
|
||||
{
|
||||
if (!args.IsEmpty())
|
||||
activestring = args.TrimStart(' ');
|
||||
activeposition = -1;
|
||||
}
|
||||
|
||||
public CommandArguments(CommandArguments args)
|
||||
{
|
||||
activestring = args.activestring;
|
||||
activeposition = args.activeposition;
|
||||
Current = args.Current;
|
||||
}
|
||||
|
||||
public bool Empty()
|
||||
{
|
||||
return activestring.IsEmpty();
|
||||
}
|
||||
|
||||
public void MoveToNextChar(char c)
|
||||
{
|
||||
for (var i = activeposition; i < activestring.Length; ++i)
|
||||
if (activestring[i] == c)
|
||||
break;
|
||||
}
|
||||
|
||||
public ParseStringResult NextString(string delimiters = " ")
|
||||
{
|
||||
if (!MoveNext(delimiters))
|
||||
return new ParseStringResult(ParseResult.EndOfString, "");
|
||||
|
||||
if (Current.Any(c => char.IsLetter(c)))
|
||||
return new ParseStringResult(ParseResult.Ok, Current);
|
||||
|
||||
return new ParseStringResult(ParseResult.Error, "");
|
||||
}
|
||||
|
||||
public ParseStringResult NextBoolean(string delimiters = " ")
|
||||
{
|
||||
if (!MoveNext(delimiters))
|
||||
return EndOfStringResult;
|
||||
|
||||
bool value;
|
||||
if (bool.TryParse(Current, out value))
|
||||
return new ParseStringResult(ParseResult.Ok, value);
|
||||
|
||||
if ((Current == "1") || Current.Equals("y", StringComparison.OrdinalIgnoreCase) || Current.Equals("on", StringComparison.OrdinalIgnoreCase) || Current.Equals("yes", StringComparison.OrdinalIgnoreCase) || Current.Equals("true", StringComparison.OrdinalIgnoreCase))
|
||||
return new ParseStringResult(ParseResult.Ok, true);
|
||||
if ((Current == "0") || Current.Equals("n", StringComparison.OrdinalIgnoreCase) || Current.Equals("off", StringComparison.OrdinalIgnoreCase) || Current.Equals("no", StringComparison.OrdinalIgnoreCase) || Current.Equals("false", StringComparison.OrdinalIgnoreCase))
|
||||
return new ParseStringResult(ParseResult.Ok, false);
|
||||
|
||||
return ErrorResult;
|
||||
}
|
||||
|
||||
public ParseStringResult NextChar(string delimiters = " ")
|
||||
{
|
||||
if (!MoveNext(delimiters))
|
||||
return EndOfStringResult;
|
||||
|
||||
if (char.TryParse(Current, out char value))
|
||||
return new ParseStringResult(ParseResult.Ok, value);
|
||||
|
||||
return ErrorResult;
|
||||
}
|
||||
|
||||
public ParseStringResult NextByte(string delimiters = " ")
|
||||
{
|
||||
if (!MoveNext(delimiters))
|
||||
return EndOfStringResult;
|
||||
|
||||
if (byte.TryParse(Current, out byte value))
|
||||
return new ParseStringResult(ParseResult.Ok, value);
|
||||
|
||||
return ErrorResult;
|
||||
}
|
||||
|
||||
public ParseStringResult NextSByte(string delimiters = " ")
|
||||
{
|
||||
if (!MoveNext(delimiters))
|
||||
return EndOfStringResult;
|
||||
|
||||
if (sbyte.TryParse(Current, out sbyte value))
|
||||
return new ParseStringResult(ParseResult.Ok, value);
|
||||
|
||||
return ErrorResult;
|
||||
}
|
||||
|
||||
public ParseStringResult NextUInt16(string delimiters = " ")
|
||||
{
|
||||
if (!MoveNext(delimiters))
|
||||
return EndOfStringResult;
|
||||
|
||||
if (ushort.TryParse(Current, out ushort value))
|
||||
return new ParseStringResult(ParseResult.Ok, value);
|
||||
|
||||
return ErrorResult;
|
||||
}
|
||||
|
||||
public ParseStringResult NextInt16(string delimiters = " ")
|
||||
{
|
||||
if (!MoveNext(delimiters))
|
||||
return EndOfStringResult;
|
||||
|
||||
if (short.TryParse(Current, out short value))
|
||||
return new ParseStringResult(ParseResult.Ok, value);
|
||||
|
||||
return ErrorResult;
|
||||
}
|
||||
|
||||
public ParseStringResult NextUInt32(string delimiters = " ")
|
||||
{
|
||||
if (!MoveNext(delimiters))
|
||||
return EndOfStringResult;
|
||||
|
||||
if (uint.TryParse(Current, out uint value))
|
||||
return new ParseStringResult(ParseResult.Ok, value);
|
||||
|
||||
return ErrorResult;
|
||||
}
|
||||
|
||||
public ParseStringResult NextInt32(string delimiters = " ")
|
||||
{
|
||||
if (!MoveNext(delimiters))
|
||||
return EndOfStringResult;
|
||||
|
||||
if (int.TryParse(Current, out int value))
|
||||
return new ParseStringResult(ParseResult.Ok, value);
|
||||
|
||||
return ErrorResult;
|
||||
}
|
||||
|
||||
public ParseStringResult NextUInt64(string delimiters = " ")
|
||||
{
|
||||
if (!MoveNext(delimiters))
|
||||
return EndOfStringResult;
|
||||
|
||||
if (ulong.TryParse(Current, out ulong value))
|
||||
return new ParseStringResult(ParseResult.Ok, value);
|
||||
|
||||
return ErrorResult;
|
||||
}
|
||||
|
||||
public ParseStringResult NextInt64(string delimiters = " ")
|
||||
{
|
||||
if (!MoveNext(delimiters))
|
||||
return EndOfStringResult;
|
||||
|
||||
if (long.TryParse(Current, out long value))
|
||||
return new ParseStringResult(ParseResult.Ok, value);
|
||||
|
||||
return ErrorResult;
|
||||
}
|
||||
|
||||
public ParseStringResult NextSingle(string delimiters = " ")
|
||||
{
|
||||
if (!MoveNext(delimiters))
|
||||
return EndOfStringResult;
|
||||
|
||||
if (float.TryParse(Current, out float value))
|
||||
return new ParseStringResult(ParseResult.Ok, value);
|
||||
|
||||
return ErrorResult;
|
||||
}
|
||||
|
||||
public ParseStringResult NextDouble(string delimiters = " ")
|
||||
{
|
||||
if (!MoveNext(delimiters))
|
||||
return EndOfStringResult;
|
||||
|
||||
if (double.TryParse(Current, out double value))
|
||||
return new ParseStringResult(ParseResult.Ok, value);
|
||||
|
||||
return ErrorResult;
|
||||
}
|
||||
|
||||
public ParseStringResult NextDecimal(string delimiters = " ")
|
||||
{
|
||||
if (!MoveNext(delimiters))
|
||||
return EndOfStringResult;
|
||||
|
||||
if (decimal.TryParse(Current, out decimal value))
|
||||
return new ParseStringResult(ParseResult.Ok, value);
|
||||
|
||||
return ErrorResult;
|
||||
}
|
||||
|
||||
public void AlignToNextChar()
|
||||
{
|
||||
while (activeposition < activestring.Length && activestring[activeposition] != ' ')
|
||||
activeposition++;
|
||||
}
|
||||
|
||||
public char this[int index]
|
||||
{
|
||||
get { return activestring[index]; }
|
||||
}
|
||||
|
||||
public string GetString()
|
||||
{
|
||||
return activestring;
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
activeposition = -1;
|
||||
Current = null;
|
||||
}
|
||||
|
||||
public bool IsAtEnd()
|
||||
{
|
||||
return activestring.IsEmpty() || activeposition == activestring.Length;
|
||||
}
|
||||
|
||||
public int GetCurrentPosition()
|
||||
{
|
||||
return activeposition;
|
||||
}
|
||||
|
||||
public void SetCurrentPosition(int currentPosition)
|
||||
{
|
||||
activeposition = currentPosition;
|
||||
}
|
||||
|
||||
bool MoveNext(string delimiters)
|
||||
{
|
||||
//the stringtotokenize was never set:
|
||||
if (activestring == null)
|
||||
return false;
|
||||
|
||||
//all tokens have already been extracted:
|
||||
if (activeposition == activestring.Length)
|
||||
return false;
|
||||
|
||||
//bypass delimiters:
|
||||
activeposition++;
|
||||
while (activeposition < activestring.Length && delimiters.IndexOf(activestring[activeposition]) > -1)
|
||||
{
|
||||
activeposition++;
|
||||
}
|
||||
|
||||
//only delimiters were left, so return null:
|
||||
if (activeposition == activestring.Length)
|
||||
return false;
|
||||
|
||||
//get starting position of string to return:
|
||||
int startingposition = activeposition;
|
||||
|
||||
//read until next delimiter:
|
||||
do
|
||||
{
|
||||
activeposition++;
|
||||
} while (activeposition < activestring.Length && delimiters.IndexOf(activestring[activeposition]) == -1);
|
||||
|
||||
Current = activestring.Substring(startingposition, activeposition - startingposition);
|
||||
return true;
|
||||
}
|
||||
|
||||
private string activestring;
|
||||
private int activeposition;
|
||||
private string Current;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -79,4 +79,15 @@ namespace Game.Chat
|
||||
|
||||
[AttributeUsage(AttributeTargets.Parameter)]
|
||||
public class OptionalArgAttribute : Attribute { }
|
||||
|
||||
[AttributeUsage(AttributeTargets.Parameter)]
|
||||
public class VariantArgAttribute : Attribute
|
||||
{
|
||||
public Type[] Types { get; set; }
|
||||
|
||||
public VariantArgAttribute(params Type[] types)
|
||||
{
|
||||
Types = types;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -417,9 +417,9 @@ namespace Game.Chat
|
||||
return searcher.GetTarget();
|
||||
}
|
||||
|
||||
public string PlayerLink(string name, bool console = false)
|
||||
public string PlayerLink(string name)
|
||||
{
|
||||
return console ? name : "|cffffffff|Hplayer:" + name + "|h[" + name + "]|h|r";
|
||||
return _session != null ? "|cffffffff|Hplayer:" + name + "|h[" + name + "]|h|r" : name;
|
||||
}
|
||||
public virtual string GetNameLink()
|
||||
{
|
||||
@@ -622,8 +622,9 @@ namespace Game.Chat
|
||||
}
|
||||
|
||||
public bool HasSentErrorMessage() { return _sentErrorMessage; }
|
||||
public void SetSentErrorMessage(bool val) { _sentErrorMessage = val; }
|
||||
|
||||
internal bool _sentErrorMessage;
|
||||
bool _sentErrorMessage;
|
||||
WorldSession _session;
|
||||
}
|
||||
|
||||
@@ -739,8 +740,7 @@ namespace Game.Chat
|
||||
|
||||
public override void SendSysMessage(string str, bool escapeCharacters)
|
||||
{
|
||||
_sentErrorMessage = true;
|
||||
|
||||
SetSentErrorMessage(true);
|
||||
Log.outInfo(LogFilter.Server, str);
|
||||
}
|
||||
|
||||
@@ -798,8 +798,7 @@ namespace Game.Chat
|
||||
|
||||
public override void SendSysMessage(string str, bool escapeCharacters)
|
||||
{
|
||||
_sentErrorMessage = true;
|
||||
|
||||
SetSentErrorMessage(true);
|
||||
_reportToRA(str);
|
||||
}
|
||||
|
||||
|
||||
@@ -223,7 +223,7 @@ namespace Game.Chat
|
||||
|
||||
if (cmd != null)
|
||||
{ /* if we matched a command at some point, invoke it */
|
||||
handler._sentErrorMessage = false;
|
||||
handler.SetSentErrorMessage(false);
|
||||
if (cmd.IsInvokerVisible(handler) && cmd.Invoke(handler, oldTail))
|
||||
{ /* invocation succeeded, log this */
|
||||
if (!handler.IsConsole())
|
||||
@@ -413,13 +413,23 @@ namespace Game.Chat
|
||||
return (bool)_methodInfo.Invoke(null, new object[] { handler, new StringArguments(args) });
|
||||
else
|
||||
{
|
||||
if (CommandArgs.Parse(out dynamic[] parseArgs, handler, parameters, args))
|
||||
var parseArgs = new dynamic[parameters.Length];
|
||||
parseArgs[0] = handler;
|
||||
var result = CommandArgs.ConsumeFromOffset(parseArgs, 1, parameters, handler, args);
|
||||
if (result.IsSuccessful())
|
||||
return (bool)_methodInfo.Invoke(null, parseArgs);
|
||||
|
||||
else
|
||||
{
|
||||
if (result.HasErrorMessage())
|
||||
{
|
||||
handler.SendSysMessage(result.GetErrorMessage());
|
||||
handler.SetSentErrorMessage(true);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public struct CommandPermissions
|
||||
{
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using Framework.Constants;
|
||||
using Game.Entities;
|
||||
using System;
|
||||
|
||||
@@ -26,11 +27,7 @@ namespace Game.Chat
|
||||
ObjectGuid _guid;
|
||||
Player _player;
|
||||
|
||||
public PlayerIdentifier(string name, ObjectGuid guid)
|
||||
{
|
||||
_name = name;
|
||||
_guid = guid;
|
||||
}
|
||||
public PlayerIdentifier() { }
|
||||
|
||||
public PlayerIdentifier(Player player)
|
||||
{
|
||||
@@ -75,40 +72,37 @@ namespace Game.Chat
|
||||
return FromSelf(handler);
|
||||
}
|
||||
|
||||
public static ParseStringResult ParseFromString(CommandArguments args)
|
||||
public ChatCommandResult TryConsume(CommandHandler handler, string args)
|
||||
{
|
||||
var result = args.NextString();
|
||||
if (result != ParseResult.Ok)
|
||||
return new ParseStringResult(ParseResult.Error);
|
||||
ChatCommandResult next = CommandArgs.TryConsume(out dynamic tempVal, typeof(ulong), handler, args);
|
||||
if (!next.IsSuccessful())
|
||||
next = CommandArgs.TryConsume(out tempVal, typeof(string), handler, args);
|
||||
if (!next.IsSuccessful())
|
||||
return next;
|
||||
|
||||
string arg = result.GetValue();
|
||||
|
||||
ulong guid = 0;
|
||||
string name;
|
||||
if (!Hyperlink.TryParse(out name, arg) || !ulong.TryParse(arg, out guid))
|
||||
name = arg;
|
||||
|
||||
if (!name.IsEmpty())
|
||||
if (tempVal is ulong)
|
||||
{
|
||||
ObjectManager.NormalizePlayerName(ref name);
|
||||
var player = Global.ObjAccessor.FindPlayerByName(name);
|
||||
if (player != null)
|
||||
return new ParseStringResult(ParseResult.Ok, new PlayerIdentifier(player));
|
||||
_guid = ObjectGuid.Create(HighGuid.Player, tempVal);
|
||||
if ((_player = Global.ObjAccessor.FindPlayerByLowGUID(_guid.GetCounter())))
|
||||
_name = _player.GetName();
|
||||
else
|
||||
if (!Global.CharacterCacheStorage.GetCharacterNameByGuid(_guid, out _name))
|
||||
return ChatCommandResult.FromErrorMessage(handler.GetParsedString(CypherStrings.CmdparserCharGuidNoExist, _guid.ToString()));
|
||||
return next;
|
||||
}
|
||||
else
|
||||
{
|
||||
var objectGuid = Global.CharacterCacheStorage.GetCharacterGuidByName(name);
|
||||
if (objectGuid.IsEmpty())
|
||||
return new ParseStringResult(ParseResult.Ok, new PlayerIdentifier(name, objectGuid));
|
||||
}
|
||||
}
|
||||
else if (guid != 0)
|
||||
{
|
||||
var player = Global.ObjAccessor.FindPlayerByLowGUID(guid);
|
||||
if (player != null)
|
||||
return new ParseStringResult(ParseResult.Ok, new PlayerIdentifier(player));
|
||||
}
|
||||
_name = tempVal;
|
||||
|
||||
return new ParseStringResult(ParseResult.Error);
|
||||
if (!ObjectManager.NormalizePlayerName(ref _name))
|
||||
return ChatCommandResult.FromErrorMessage(handler.GetParsedString(CypherStrings.CmdparserCharNameInvalid, _name));
|
||||
|
||||
if ((_player = Global.ObjAccessor.FindPlayerByName(_name)))
|
||||
_guid = _player.GetGUID();
|
||||
else if ((_guid = Global.CharacterCacheStorage.GetCharacterGuidByName(_name)).IsEmpty())
|
||||
return ChatCommandResult.FromErrorMessage(handler.GetParsedString(CypherStrings.CmdparserCharNameNoExist, _name));
|
||||
return next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -118,6 +112,7 @@ namespace Game.Chat
|
||||
string _name;
|
||||
WorldSession _session;
|
||||
|
||||
public AccountIdentifier() { }
|
||||
public AccountIdentifier(WorldSession session)
|
||||
{
|
||||
_id = session.GetAccountId();
|
||||
@@ -130,26 +125,29 @@ namespace Game.Chat
|
||||
public bool IsConnected() { return _session != null; }
|
||||
public WorldSession GetConnectedSession() { return _session; }
|
||||
|
||||
public static ParseStringResult ParseFromString(CommandArguments args)
|
||||
public ChatCommandResult TryConsume(CommandHandler handler, string args)
|
||||
{
|
||||
var result = args.NextString();
|
||||
if (result != ParseResult.Ok)
|
||||
return new ParseStringResult(ParseResult.Error);
|
||||
ChatCommandResult next = CommandArgs.TryConsume(out dynamic text, typeof(string), handler, args);
|
||||
if (!next.IsSuccessful())
|
||||
return next;
|
||||
|
||||
// try parsing as account name
|
||||
var session = Global.WorldMgr.FindSession(Global.AccountMgr.GetId(result.GetValue()));
|
||||
if (session != null) // account with name exists, we are done
|
||||
return new ParseStringResult(ParseResult.Ok, new AccountIdentifier(session));
|
||||
// first try parsing as account name
|
||||
_name = text;
|
||||
_id = Global.AccountMgr.GetId(_name);
|
||||
_session = Global.WorldMgr.FindSession(_id);
|
||||
if (_id != 0) // account with name exists, we are done
|
||||
return next;
|
||||
|
||||
// try parsing as account id
|
||||
if (!uint.TryParse(result.GetValue(), out uint id))
|
||||
return new ParseStringResult(ParseResult.Error);
|
||||
// try parsing as account id instead
|
||||
if (uint.TryParse(text, out uint id))
|
||||
return ChatCommandResult.FromErrorMessage(handler.GetParsedString(CypherStrings.CmdparserAccountNameNoExist, _name));
|
||||
_id = id;
|
||||
_session = Global.WorldMgr.FindSession(_id);
|
||||
|
||||
session = Global.WorldMgr.FindSession(id);
|
||||
if (session != null)
|
||||
return new ParseStringResult(ParseResult.Ok, new AccountIdentifier(session));
|
||||
|
||||
return new ParseStringResult(ParseResult.Error);
|
||||
if (Global.AccountMgr.GetName(_id, out _name))
|
||||
return next;
|
||||
else
|
||||
return ChatCommandResult.FromErrorMessage(handler.GetParsedString(CypherStrings.CmdparserAccountIdNoExist, _id));
|
||||
}
|
||||
|
||||
public static AccountIdentifier FromTarget(CommandHandler handler)
|
||||
@@ -174,11 +172,6 @@ namespace Game.Chat
|
||||
{
|
||||
string str;
|
||||
|
||||
public Tail(CommandArguments args)
|
||||
{
|
||||
str = args.NextString("").GetValue();
|
||||
}
|
||||
|
||||
public bool IsEmpty() { return str.IsEmpty(); }
|
||||
|
||||
public static implicit operator string(Tail tail)
|
||||
@@ -186,9 +179,10 @@ namespace Game.Chat
|
||||
return tail.str;
|
||||
}
|
||||
|
||||
public static ParseStringResult ParseFromString(CommandArguments args)
|
||||
public ChatCommandResult TryConsume(CommandHandler handler, string args)
|
||||
{
|
||||
return new ParseStringResult(ParseResult.Ok, new Tail(args));
|
||||
str = args;
|
||||
return new ChatCommandResult(str);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -95,7 +95,7 @@ namespace Game.Chat
|
||||
return false;
|
||||
}
|
||||
|
||||
AccountOpResult result = Global.AccountMgr.CreateAccount(accountName, password, email);
|
||||
AccountOpResult result = Global.AccountMgr.CreateAccount(accountName, password, email ?? "");
|
||||
switch (result)
|
||||
{
|
||||
case AccountOpResult.Ok:
|
||||
@@ -105,7 +105,7 @@ namespace Game.Chat
|
||||
Log.outInfo(LogFilter.Player, "Account: {0} (IP: {1}) Character:[{2}] (GUID: {3}) created Account {4} (Email: '{5}')",
|
||||
handler.GetSession().GetAccountId(), handler.GetSession().GetRemoteAddress(),
|
||||
handler.GetSession().GetPlayer().GetName(), handler.GetSession().GetPlayer().GetGUID().ToString(),
|
||||
accountName, email);
|
||||
accountName, email ?? "");
|
||||
}
|
||||
break;
|
||||
case AccountOpResult.NameTooLong:
|
||||
|
||||
@@ -27,12 +27,8 @@ namespace Game.Chat.Commands
|
||||
class AchievementCommand
|
||||
{
|
||||
[Command("add", CypherStrings.CommandAchievementAddHelp, RBACPermissions.CommandAchievementAdd)]
|
||||
static bool HandleAchievementAddCommand(CommandHandler handler, uint achievemntId)
|
||||
static bool HandleAchievementAddCommand(CommandHandler handler, AchievementRecord achievementEntry)
|
||||
{
|
||||
AchievementRecord achievementEntry = CliDB.AchievementStorage.LookupByKey(achievemntId);
|
||||
if (achievementEntry == null)
|
||||
return false;
|
||||
|
||||
Player target = handler.GetSelectedPlayer();
|
||||
if (!target)
|
||||
{
|
||||
|
||||
@@ -453,7 +453,7 @@ namespace Game.Chat
|
||||
}
|
||||
|
||||
[Command("instancespawn", RBACPermissions.CommandDebug)]
|
||||
static bool HandleDebugInstanceSpawns(CommandHandler handler, string optArg)
|
||||
static bool HandleDebugInstanceSpawns(CommandHandler handler, [VariantArg(typeof(uint), typeof(string))] object optArg)
|
||||
{
|
||||
Player player = handler.GetPlayer();
|
||||
if (player == null)
|
||||
@@ -461,10 +461,10 @@ namespace Game.Chat
|
||||
|
||||
bool explain = false;
|
||||
uint groupID = 0;
|
||||
if (optArg.Equals("explain", StringComparison.OrdinalIgnoreCase))
|
||||
if (optArg is string && (optArg as string).Equals("explain", StringComparison.OrdinalIgnoreCase))
|
||||
explain = true;
|
||||
else
|
||||
groupID = uint.Parse(optArg);
|
||||
groupID = (uint)optArg;
|
||||
|
||||
if (groupID != 0 && Global.ObjectMgr.GetSpawnGroupData(groupID) == null)
|
||||
{
|
||||
@@ -786,6 +786,36 @@ namespace Game.Chat
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("pvp warmode", RBACPermissions.CommandDebug, true)]
|
||||
static bool HandleDebugWarModeBalanceCommand(CommandHandler handler, string command, int? rewardValue)
|
||||
{
|
||||
// USAGE: .debug pvp fb <alliance|horde|neutral|off> [pct]
|
||||
// neutral Sets faction balance off.
|
||||
// alliance Set faction balance to alliance.
|
||||
// horde Set faction balance to horde.
|
||||
// off Reset the faction balance and use the calculated value of it
|
||||
switch (command)
|
||||
{
|
||||
case "alliance":
|
||||
Global.WorldMgr.SetForcedWarModeFactionBalanceState(TeamId.Alliance, rewardValue.GetValueOrDefault(0));
|
||||
break;
|
||||
case "horde":
|
||||
Global.WorldMgr.SetForcedWarModeFactionBalanceState(TeamId.Horde, rewardValue.GetValueOrDefault(0));
|
||||
break;
|
||||
case "neutral":
|
||||
Global.WorldMgr.SetForcedWarModeFactionBalanceState(TeamId.Neutral);
|
||||
break;
|
||||
case "off":
|
||||
Global.WorldMgr.DisableForcedWarModeFactionBalanceState();
|
||||
break;
|
||||
default:
|
||||
handler.SendSysMessage(CypherStrings.BadValue);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("questreset", RBACPermissions.CommandDebug)]
|
||||
static bool HandleDebugQuestResetCommand(CommandHandler handler, string arg)
|
||||
{
|
||||
|
||||
@@ -115,7 +115,7 @@ namespace Game.Chat
|
||||
}
|
||||
|
||||
[Command("info", RBACPermissions.CommandGobjectInfo)]
|
||||
static bool HandleGameObjectInfoCommand(CommandHandler handler, string isGuid, uint data)
|
||||
static bool HandleGameObjectInfoCommand(CommandHandler handler, [OptionalArg] string isGuid, ulong data)
|
||||
{
|
||||
GameObject thisGO = null;
|
||||
GameObjectData spawnData = null;
|
||||
@@ -137,7 +137,7 @@ namespace Game.Chat
|
||||
}
|
||||
else
|
||||
{
|
||||
entry = data;
|
||||
entry = (uint)data;
|
||||
}
|
||||
|
||||
GameObjectTemplate gameObjectInfo = Global.ObjectMgr.GetGameObjectTemplate(entry);
|
||||
|
||||
@@ -442,7 +442,7 @@ namespace Game.Chat.Commands
|
||||
}
|
||||
|
||||
[Command("respawns", RBACPermissions.CommandListRespawns)]
|
||||
static bool HandleListRespawnsCommand(CommandHandler handler, uint range)
|
||||
static bool HandleListRespawnsCommand(CommandHandler handler, uint? range)
|
||||
{
|
||||
Player player = handler.GetSession().GetPlayer();
|
||||
Map map = player.GetMap();
|
||||
@@ -454,8 +454,8 @@ namespace Game.Chat.Commands
|
||||
string zoneName = GetZoneName(zoneId, locale);
|
||||
for (SpawnObjectType type = 0; type < SpawnObjectType.NumSpawnTypes; type++)
|
||||
{
|
||||
if (range != 0)
|
||||
handler.SendSysMessage(CypherStrings.ListRespawnsRange, type, range);
|
||||
if (range.HasValue)
|
||||
handler.SendSysMessage(CypherStrings.ListRespawnsRange, type, range.Value);
|
||||
else
|
||||
handler.SendSysMessage(CypherStrings.ListRespawnsZone, type, zoneName, zoneId);
|
||||
|
||||
@@ -473,9 +473,9 @@ namespace Game.Chat.Commands
|
||||
if (edata != null)
|
||||
{
|
||||
respawnZoneId = map.GetZoneId(PhasingHandler.EmptyPhaseShift, edata.SpawnPoint);
|
||||
if (range != 0)
|
||||
if (range.HasValue)
|
||||
{
|
||||
if (!player.IsInDist(edata.SpawnPoint, range))
|
||||
if (!player.IsInDist(edata.SpawnPoint, range.Value))
|
||||
continue;
|
||||
}
|
||||
else
|
||||
@@ -615,9 +615,9 @@ namespace Game.Chat.Commands
|
||||
aura.GetCasterGUID().ToString());
|
||||
}
|
||||
|
||||
for (ushort i = 0; i < (int)AuraType.Total; ++i)
|
||||
for (AuraType auraType = 0; auraType < AuraType.Total; ++auraType)
|
||||
{
|
||||
var auraList = unit.GetAuraEffectsByType((AuraType)i);
|
||||
var auraList = unit.GetAuraEffectsByType(auraType);
|
||||
if (auraList.Empty())
|
||||
continue;
|
||||
|
||||
@@ -631,7 +631,7 @@ namespace Game.Chat.Commands
|
||||
if (!sizeLogged)
|
||||
{
|
||||
sizeLogged = true;
|
||||
handler.SendSysMessage(CypherStrings.CommandTargetListauratype, auraList.Count, i);
|
||||
handler.SendSysMessage(CypherStrings.CommandTargetListauratype, auraList.Count, auraType);
|
||||
}
|
||||
|
||||
handler.SendSysMessage(CypherStrings.CommandTargetAurasimple, effect.GetId(), effect.GetEffIndex(), effect.GetAmount());
|
||||
|
||||
@@ -31,9 +31,8 @@ namespace Game.Chat
|
||||
class TeleCommands
|
||||
{
|
||||
[Command("", RBACPermissions.CommandTele)]
|
||||
static bool HandleTeleCommand(CommandHandler handler, string name)
|
||||
static bool HandleTeleCommand(CommandHandler handler, GameTele tele)
|
||||
{
|
||||
var tele = Global.ObjectMgr.GetGameTele(name);
|
||||
if (tele == null)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.CommandTeleNotfound);
|
||||
@@ -71,7 +70,7 @@ namespace Game.Chat
|
||||
if (player == null)
|
||||
return false;
|
||||
|
||||
if (Global.ObjectMgr.GetGameTele(name) != null)
|
||||
if (Global.ObjectMgr.GetGameTeleExactName(name) != null)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.CommandTpAlreadyexist);
|
||||
return false;
|
||||
@@ -100,9 +99,8 @@ namespace Game.Chat
|
||||
}
|
||||
|
||||
[Command("del", RBACPermissions.CommandTeleDel, true)]
|
||||
static bool HandleTeleDelCommand(CommandHandler handler, string name)
|
||||
static bool HandleTeleDelCommand(CommandHandler handler, GameTele tele)
|
||||
{
|
||||
var tele = Global.ObjectMgr.GetGameTele(name);
|
||||
if (tele == null)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.CommandTeleNotfound);
|
||||
@@ -115,9 +113,8 @@ namespace Game.Chat
|
||||
}
|
||||
|
||||
[Command("group", RBACPermissions.CommandTeleGroup)]
|
||||
static bool HandleTeleGroupCommand(CommandHandler handler, string name)
|
||||
static bool HandleTeleGroupCommand(CommandHandler handler, GameTele tele)
|
||||
{
|
||||
var tele = Global.ObjectMgr.GetGameTele(name);
|
||||
if (tele == null)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.CommandTeleNotfound);
|
||||
@@ -240,7 +237,7 @@ namespace Game.Chat
|
||||
class TeleNameCommands
|
||||
{
|
||||
[Command("", RBACPermissions.CommandTeleName, true)]
|
||||
static bool HandleTeleNameCommand(CommandHandler handler, PlayerIdentifier player, string where)
|
||||
static bool HandleTeleNameCommand(CommandHandler handler, [OptionalArg] PlayerIdentifier player, [VariantArg(typeof(GameTele), typeof(string))] object where)
|
||||
{
|
||||
if (player == null)
|
||||
player = PlayerIdentifier.FromTargetOrSelf(handler);
|
||||
@@ -249,7 +246,7 @@ namespace Game.Chat
|
||||
|
||||
Player target = player.GetConnectedPlayer();
|
||||
|
||||
if (where.Equals("home", StringComparison.OrdinalIgnoreCase)) // References target's homebind
|
||||
if (where is string && where.Equals("$home")) // References target's homebind
|
||||
{
|
||||
if (target)
|
||||
target.TeleportTo(target.GetHomebind());
|
||||
@@ -272,10 +269,7 @@ namespace Game.Chat
|
||||
}
|
||||
|
||||
// id, or string, or [name] Shift-click form |color|Htele:id|h[name]|h|r
|
||||
GameTele tele = Global.ObjectMgr.GetGameTele(where);
|
||||
if (tele == null)
|
||||
return false;
|
||||
|
||||
GameTele tele = where as GameTele;
|
||||
return DoNameTeleport(handler, player, tele.mapId, new Position(tele.posX, tele.posY, tele.posZ, tele.orientation), tele.name);
|
||||
}
|
||||
|
||||
|
||||
@@ -15,33 +15,23 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using Framework.Constants;
|
||||
using System;
|
||||
|
||||
namespace Game.Chat
|
||||
{
|
||||
class Hyperlink
|
||||
{
|
||||
public static bool TryParse(out string value, string arg)
|
||||
public static ChatCommandResult TryParse(out dynamic value, Type type, CommandHandler handler, string arg)
|
||||
{
|
||||
value = null;
|
||||
value = default;
|
||||
|
||||
HyperlinkInfo info = ParseHyperlink(arg);
|
||||
// invalid hyperlinks cannot be consumed
|
||||
if (info == null)
|
||||
return false;
|
||||
return default;
|
||||
|
||||
value = info.Data;
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool TryParse(out dynamic value, Type type, CommandArguments args)
|
||||
{
|
||||
value = default;
|
||||
|
||||
HyperlinkInfo info = ParseHyperlink(args.GetString());
|
||||
// invalid hyperlinks cannot be consumed
|
||||
if (info == null)
|
||||
return false;
|
||||
ChatCommandResult errorResult = ChatCommandResult.FromErrorMessage(handler.GetCypherString(CypherStrings.CmdparserLinkdataInvalid));
|
||||
|
||||
// store value
|
||||
switch (Type.GetTypeCode(type))
|
||||
@@ -49,42 +39,34 @@ namespace Game.Chat
|
||||
case TypeCode.UInt32:
|
||||
{
|
||||
if (!uint.TryParse(info.Data, out uint tempValue))
|
||||
return false;
|
||||
return errorResult;
|
||||
|
||||
value = tempValue;
|
||||
return true;
|
||||
break;
|
||||
}
|
||||
case TypeCode.UInt64:
|
||||
{
|
||||
if (!ulong.TryParse(info.Data, out ulong tempValue))
|
||||
return false;
|
||||
return errorResult;
|
||||
|
||||
value = tempValue;
|
||||
return true;
|
||||
break;
|
||||
}
|
||||
case TypeCode.String:
|
||||
{
|
||||
value = info.Data;
|
||||
return true;
|
||||
break;
|
||||
}
|
||||
case TypeCode.Object:
|
||||
{
|
||||
switch (type.Name)
|
||||
{
|
||||
case nameof(PlayerIdentifier):
|
||||
value = PlayerIdentifier.ParseFromString(args);
|
||||
break;
|
||||
case nameof(AccountIdentifier):
|
||||
value = AccountIdentifier.ParseFromString(args);
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return errorResult;
|
||||
}
|
||||
|
||||
return false;
|
||||
// finally, skip any potential delimiters
|
||||
var (token, next) = CommandArgs.Tokenize(info.Tail);
|
||||
if (token.IsEmpty()) /* empty token = first character is delimiter, skip past it */
|
||||
return new ChatCommandResult(next);
|
||||
else
|
||||
return new ChatCommandResult(info.Tail);
|
||||
}
|
||||
|
||||
public static bool CheckAllLinks(string str)
|
||||
@@ -123,7 +105,7 @@ namespace Game.Chat
|
||||
return false;
|
||||
|
||||
// tag is fine, find the next one
|
||||
pos = str.Length - info.next.Length;
|
||||
pos = str.Length - info.Tail.Length;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -204,16 +186,16 @@ namespace Game.Chat
|
||||
|
||||
class HyperlinkInfo
|
||||
{
|
||||
public HyperlinkInfo(string n = null, uint c = 0, string tag = null, string data = null, string text = null)
|
||||
public HyperlinkInfo(string t = null, uint c = 0, string tag = null, string data = null, string text = null)
|
||||
{
|
||||
next = n;
|
||||
Tail = t;
|
||||
color = new(c);
|
||||
Tag = tag;
|
||||
Data = data;
|
||||
Text = text;
|
||||
}
|
||||
|
||||
public string next;
|
||||
public string Tail;
|
||||
public HyperlinkColor color;
|
||||
public string Tag;
|
||||
public string Data;
|
||||
|
||||
@@ -5766,7 +5766,30 @@ namespace Game
|
||||
}
|
||||
public GameTele GetGameTele(string name)
|
||||
{
|
||||
return gameTeleStorage.Values.FirstOrDefault(p => p.nameLow == name.ToLower());
|
||||
name = name.ToLower();
|
||||
|
||||
// Alternative first GameTele what contains wnameLow as substring in case no GameTele location found
|
||||
GameTele alt = null;
|
||||
foreach (var (_, tele) in gameTeleStorage)
|
||||
{
|
||||
if (tele.nameLow == name)
|
||||
return tele;
|
||||
else if (alt == null && tele.nameLow.Contains(name))
|
||||
alt = tele;
|
||||
}
|
||||
|
||||
return alt;
|
||||
}
|
||||
public GameTele GetGameTeleExactName(string name)
|
||||
{
|
||||
name = name.ToLower();
|
||||
foreach (var (_, tele) in gameTeleStorage)
|
||||
{
|
||||
if (tele.nameLow == name)
|
||||
return tele;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
public bool AddGameTele(GameTele tele)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user