static char LastColor(char[] line, int length) { for (int i = length - 2; i >= 0; i--) { if (line[i] != '&') { continue; } char col = Colors.Lookup(line[i + 1]); if (col != '\0') { return(col); } } return('f'); }
// Trims trailing color codes and whitespace static int TrimTrailingInvisible(char[] chars, int len) { while (len >= 2) { char c = chars[len - 1]; if (c == ' ') { len--; continue; } if (chars[len - 2] != '&') { break; } if (Colors.Lookup(c) == '\0') { break; } len -= 2; // remove color code } return(len); }
/// <summary> Removes redundant colour codes and fixes some colour codes to behave correctly for older clients </summary> /// <param name="fullAmpersands"> if false, ampersands not followed by valid colour code are removed </param> /// <param name="customCols"> if false, converts custom colour codes into fallback colour code </param> public static string CleanupColors(string value, bool fullAmpersands, bool customCols) { if (value.IndexOf('&') == -1) { return(value); } StringBuilder sb = new StringBuilder(value.Length); int lastIdx = -1; char lastCol = 'f', col; bool combinable = false; for (int i = 0; i < value.Length; i++) { char c = value[i]; // Definitely not a colour code if (c != '&') { if (c != ' ') { combinable = false; } sb.Append(c); continue; } // Maybe still not a colour code if (i == value.Length - 1 || (col = Colors.Lookup(value[i + 1])) == '\0') { if (!fullAmpersands) { // Client doesn't support standalone &, skip over it i++; } else { // Treat the & like a normal character combinable = false; sb.Append(c); } continue; } if (!customCols) { col = Colors.Get(col).Fallback; } // Don't append duplicate colour codes if (lastCol != col) { // Remove first colour code in "&a&b or "&a &b" if (combinable) { sb.Remove(lastIdx, 2); } sb.Append('&').Append(col); lastIdx = sb.Length - 2; lastCol = col; combinable = true; } i++; // skip over color code } // Trim trailing color codes while (sb.Length >= 2) { if (sb[sb.Length - 2] != '&') { break; } if (Colors.Lookup(sb[sb.Length - 1]) == '\0') { break; } // got a color code at the end, remove sb.Remove(sb.Length - 2, 2); } return(sb.ToString()); }
static bool StartsWithColor(string message, int offset) { return(message[offset] == '&' && (offset + 1) < message.Length && Colors.Lookup(message[offset + 1]) != '\0'); }
/// <summary> Removes redundant colour codes and fixes some colour codes to behave correctly for older clients </summary> /// <param name="fullAmpersands"> if false, ampersands not followed by valid colour code are removed </param> /// <param name="customCols"> if false, converts custom colour codes into fallback colour code </param> public static string CleanupColors(string value, bool fullAmpersands, bool customCols) { if (value.IndexOf('&') == -1) { return(value); } char[] chars = new char[value.Length]; int lastIdx = -1, len = 0; char lastColor = 'f', col; bool combinable = false; for (int i = 0; i < value.Length; i++) { char c = value[i]; // Definitely not a colour code if (c != '&') { if (c != ' ') { combinable = false; } chars[len++] = c; continue; } // Maybe still not a colour code if (i == value.Length - 1 || (col = Colors.Lookup(value[i + 1])) == '\0') { // Treat the & like a normal character // For clients not supporting standalone '&', show '%' instead combinable = false; chars[len++] = fullAmpersands ? '&' : '%'; continue; } if (!customCols) { col = Colors.Get(col).Fallback; } // Don't append duplicate colour codes if (lastColor != col) { // If no gap or only whitepsace since prior color code, // then just replace the prior color code with this one if (combinable) { // e.g. "&a&bTest" -> "&bTest" // e.g. "&a &bTest" -> "&b Test" // (it's particularly useful to replace prior color codes // since original classic trims leading whitespace) chars[lastIdx + 1] = col; } else { // can't simplify, so just append this color code lastIdx = len; chars[len++] = '&'; chars[len++] = col; } lastColor = col; combinable = true; } i++; // skip over color code } len = TrimTrailingInvisible(chars, len); return(new string(chars, 0, len)); }