public static string ReplacePercentColorCodes([NotNull] string message, bool allowNewlines) { if (message == null) { throw new ArgumentNullException("message"); } int startIndex = message.IndexOf('%'); if (startIndex == -1) { return(message); // break out early if there are no percent marks } StringBuilder output = new StringBuilder(message.Length); int lastAppendedIndex = 0; while (startIndex != -1 && startIndex < message.Length - 1) { // see if colorcode was escaped (if odd number of backslashes precede it) bool escaped = false; for (int i = startIndex - 1; i >= 0 && message[i] == '\\'; i--) { escaped = !escaped; } // extract the colorcode char colorCode = message[startIndex + 1]; if (ChatColor.IsColorCode(colorCode) || allowNewlines && (colorCode == 'n' || colorCode == 'N')) { if (escaped) { // it was escaped; remove escaping character startIndex++; output.Append(message, lastAppendedIndex, startIndex - lastAppendedIndex - 2); lastAppendedIndex = startIndex - 1; } else { // it was not escaped; insert substitute character output.Append(message, lastAppendedIndex, startIndex - lastAppendedIndex); output.Append('&'); lastAppendedIndex = startIndex + 1; startIndex += 2; } } else { startIndex++; // unrecognized colorcode, keep going } startIndex = message.IndexOf('%', startIndex); } // append the leftovers output.Append(message, lastAppendedIndex, message.Length - lastAppendedIndex); return(output.ToString()); }
public XElement Serialize() { XElement rankTag = new XElement("Rank"); rankTag.Add(new XAttribute("name", Name)); rankTag.Add(new XAttribute("id", Id)); string colorName = ChatColor.GetName(Color); if (colorName != null) { rankTag.Add(new XAttribute("color", colorName)); } if (Prefix.Length > 0) { rankTag.Add(new XAttribute("prefix", Prefix)); } rankTag.Add(new XAttribute("antiGriefBlocks", AntiGriefBlocks)); rankTag.Add(new XAttribute("antiGriefSeconds", AntiGriefSeconds)); if (DrawLimit > 0) { rankTag.Add(new XAttribute("drawLimit", DrawLimit)); } if (IdleKickTimer > 0) { rankTag.Add(new XAttribute("idleKickAfter", IdleKickTimer)); } if (HasReservedSlot) { rankTag.Add(new XAttribute("reserveSlot", true)); } if (AllowSecurityCircumvention) { rankTag.Add(new XAttribute("allowSecurityCircumvention", true)); } rankTag.Add(new XAttribute("copySlots", CopySlots)); rankTag.Add(new XAttribute("fillLimit", FillLimit)); for (int i = 0; i < PermissionNames.Length; i++) { if (Permissions[i]) { XElement temp = new XElement(PermissionNames[i]); if (PermissionLimits[i] != null) { temp.Add(new XAttribute("max", GetLimit((Permission)i).FullName)); } rankTag.Add(temp); } } return(rankTag); }
public static void Log(LogType type, [NotNull] string message, [NotNull] params object[] args) { if (message == null) { throw new ArgumentNullException("message"); } if (args == null) { throw new ArgumentNullException("args"); } if (!Enabled) { return; } if (args.Length > 0) { message = String.Format(message, args); } // occasionally \r\n newlines slip into the system, e.g. in stack traces message = message.Replace("\r\n", "\n"); message = Chat.ReplaceNewlines(message); message = Chat.ReplaceEmotesWithUnicode(message); message = ChatColor.StripColors(message); string line = DecorateLogMessage(type, message); lock (LogLock) { RaiseLoggedEvent(message, line, type); RecentMessages.Enqueue(line); while (RecentMessages.Count > MaxRecentMessages) { RecentMessages.Dequeue(); } if (LogFileOptions[(int)type]) { try { File.AppendAllText(Path.Combine(Paths.LogPath, CurrentLogFileName), line + Environment.NewLine); } catch (Exception ex) { string errorMessage = "Logger.Log: " + ex; RaiseLoggedEvent(errorMessage, DecorateLogMessage(LogType.Error, errorMessage), LogType.Error); } } } }
public override void Validate(string value) { base.Validate(value); string parsedValue = ChatColor.Parse(value); if (parsedValue == null) { throw new FormatException("Value cannot be parsed as a color."); } else if (parsedValue.Length == 0 && NotBlank) { throw new FormatException("Value may not represent absence of color."); } }
public ColorKeyAttribute(ConfigSection section, [NotNull] string defaultColor, [NotNull] string description) : base(section, typeof(string), ChatColor.White, description) { if (defaultColor == null) { throw new ArgumentNullException("defaultColor"); } string defaultColorName = ChatColor.GetName(defaultColor); if (defaultColorName == null) { throw new ArgumentException("Default color must be a valid color name."); } DefaultValue = defaultColorName; }
/// <summary> Creates a new Rank object from given XML definition. /// XML schema is expected to match the output of Rank.Serialize() </summary> /// <param name="el"> XML element to parse as a rank. </param> /// <exception cref="ArgumentNullException"> el is null </exception> /// <exception cref="RankDefinitionException"> Given XML element could not be parsed as a rank definition. </exception> public Rank([NotNull] XElement el) : this() { if (el == null) { throw new ArgumentNullException("el"); } // Name XAttribute attr = el.Attribute("name"); if (attr == null) { throw new RankDefinitionException(null, "Rank definition with no name was ignored."); } else if (!IsValidRankName(attr.Value.Trim())) { throw new RankDefinitionException(Name, "Invalid name specified for rank \"{0}\". " + "Rank names can only contain letters, digits, and underscores. " + "Rank definition was ignored.", Name); } else { // duplicate Name check is done in RankManager.AddRank() Name = attr.Value.Trim(); } // ID attr = el.Attribute("id"); if (attr == null) { Id = RankManager.GenerateId(); Logger.Log(LogType.Warning, "Rank({0}): No ID specified; issued a new unique ID: {1}", Name, Id); } else if (!IsValidID(attr.Value.Trim())) { Id = RankManager.GenerateId(); Logger.Log(LogType.Warning, "Rank({0}): Invalid ID specified (must be alphanumeric, and exactly 16 characters long); issued a new unique ID: {1}", Name, Id); } else { Id = attr.Value.Trim(); // duplicate ID check is done in RankManager.AddRank() } FullName = Name + "#" + Id; // Color (optional) if ((attr = el.Attribute("color")) != null) { string color = ChatColor.Parse(attr.Value); if (color == null) { Logger.Log(LogType.Warning, "Rank({0}): Could not parse rank color. Assuming default (none).", Name); Color = ChatColor.White; } else { Color = color; } } else { Color = ChatColor.White; } // Prefix (optional) if ((attr = el.Attribute("prefix")) != null) { if (IsValidPrefix(attr.Value)) { Prefix = attr.Value; } else { Logger.Log(LogType.Warning, "Rank({0}): Invalid prefix format. Expecting 1 character.", Name); } } // AntiGrief block limit (assuming unlimited if not given) int value; XAttribute agBlocks = el.Attribute("antiGriefBlocks"); XAttribute agSeconds = el.Attribute("antiGriefSeconds"); if (agBlocks != null && agSeconds != null) { if (Int32.TryParse(agBlocks.Value, out value)) { if (value >= 0 && value < 1000) { AntiGriefBlocks = value; } else { Logger.Log(LogType.Warning, "Rank({0}): Value for antiGriefBlocks is not within valid range (0-1000). Assuming default ({1}).", Name, AntiGriefBlocks); } } else { Logger.Log(LogType.Warning, "Rank({0}): Could not parse the value for antiGriefBlocks. Assuming default ({1}).", Name, AntiGriefBlocks); } if (Int32.TryParse(agSeconds.Value, out value)) { if (value >= 0 && value < 100) { AntiGriefSeconds = value; } else { Logger.Log(LogType.Warning, "Rank({0}): Value for antiGriefSeconds is not within valid range (0-100). Assuming default ({1}).", Name, AntiGriefSeconds); } } else { Logger.Log(LogType.Warning, "Rank({0}): Could not parse the value for antiGriefSeconds. Assuming default ({1}).", Name, AntiGriefSeconds); } } // Draw command limit, in number-of-blocks (assuming unlimited if not given) if ((attr = el.Attribute("drawLimit")) != null) { if (Int32.TryParse(attr.Value, out value)) { if (value >= 0 && value < 100000000) { DrawLimit = value; } else { Logger.Log(LogType.Warning, "Rank({0}): Value for drawLimit is not within valid range (0-100000000). Assuming default ({1}).", Name, DrawLimit); } } else { Logger.Log(LogType.Warning, "Rank({0}): Could not parse the value for drawLimit. Assuming default ({1}).", Name, DrawLimit); } } // Idle kick timer, in minutes. (assuming 'never' if not given) if ((attr = el.Attribute("idleKickAfter")) != null) { if (!Int32.TryParse(attr.Value, out IdleKickTimer)) { Logger.Log(LogType.Warning, "Rank({0}): Could not parse the value for idleKickAfter. Assuming 0 (never).", Name); IdleKickTimer = 0; } } else { IdleKickTimer = 0; } // Reserved slot. (assuming 'no' if not given) if ((attr = el.Attribute("reserveSlot")) != null) { if (!Boolean.TryParse(attr.Value, out HasReservedSlot)) { Logger.Log(LogType.Warning, "Rank({0}): Could not parse value for reserveSlot. Assuming \"false\".", Name); HasReservedSlot = false; } } else { HasReservedSlot = false; } // Security circumvention. (assuming 'no' if not given) if ((attr = el.Attribute("allowSecurityCircumvention")) != null) { if (!Boolean.TryParse(attr.Value, out AllowSecurityCircumvention)) { Logger.Log(LogType.Warning, "Rank({0}): Could not parse the value for allowSecurityCircumvention. Assuming \"false\".", Name); AllowSecurityCircumvention = false; } } else { AllowSecurityCircumvention = false; } // Copy slots (assuming default 2 if not given) if ((attr = el.Attribute("copySlots")) != null) { if (Int32.TryParse(attr.Value, out value)) { if (value > 0 && value < 256) { CopySlots = value; } else { Logger.Log(LogType.Warning, "Rank({0}): Value for copySlots is not within valid range (1-255). Assuming default ({1}).", Name, CopySlots); } } else { Logger.Log(LogType.Warning, "Rank({0}): Could not parse the value for copySlots. Assuming default ({1}).", Name, CopySlots); } } // Fill limit (assuming default 32 if not given) if ((attr = el.Attribute("fillLimit")) != null) { if (Int32.TryParse(attr.Value, out value)) { if (value < 1) { Logger.Log(LogType.Warning, "Rank({0}): Value for fillLimit may not be negative. Assuming default ({1}).", Name, FillLimit); } else if (value > 2048) { FillLimit = 2048; } else { FillLimit = value; } } else { Logger.Log(LogType.Warning, "Rank({0}): Could not parse the value for fillLimit. Assuming default ({1}).", Name, FillLimit); } } // Permissions for (int i = 0; i < PermissionNames.Length; i++) { string permission = PermissionNames[i]; XElement temp; if ((temp = el.Element(permission)) != null) { Permissions[i] = true; if ((attr = temp.Attribute("max")) != null) { permissionLimitStrings[i] = attr.Value; } } } // check consistency of ban permissions if (!Can(Permission.Ban) && (Can(Permission.BanAll) || Can(Permission.BanIP))) { Logger.Log(LogType.Warning, "Rank({0}): Rank is allowed to BanIP and/or BanAll but not allowed to Ban. " + "Assuming that all ban permissions were meant to be off.", Name); Permissions[(int)Permission.BanIP] = false; Permissions[(int)Permission.BanAll] = false; } // check consistency of patrol permissions if (!Can(Permission.Teleport) && Can(Permission.Patrol)) { Logger.Log(LogType.Warning, "Rank({0}): Rank is allowed to Patrol but not allowed to Teleport. " + "Assuming that Patrol permission was meant to be off.", Name); Permissions[(int)Permission.Patrol] = false; } // check consistency of draw permissions if (!Can(Permission.Draw) && Can(Permission.DrawAdvanced)) { Logger.Log(LogType.Warning, "Rank({0}): Rank is allowed to DrawAdvanced but not allowed to Draw. " + "Assuming that DrawAdvanced permission was meant to be off.", Name); Permissions[(int)Permission.DrawAdvanced] = false; } // check consistency of Undo permissions if (!Can(Permission.UndoOthersActions) && Can(Permission.UndoAll)) { Logger.Log(LogType.Warning, "Rank({0}): Rank is allowed to UndoAll but not allowed to UndoOthersActions. " + "Assuming that UndoAll permission was meant to be off.", Name); Permissions[(int)Permission.UndoAll] = false; } }