Uploaded image for project: 'Spigot'
  1. Spigot
  2. SPIGOT-6825

MapFont#getWidth ignores §, but not the color-byte and semicolon following it

XMLWordPrintable

    • This server is running CraftBukkit version 3284-Spigot-3892929-0ebef35 (MC: 1.17.1) (Implementing API version 1.17.1-R0.1-SNAPSHOT)
    • Yes

      When you want to use Color in a Text on a map, you must add the corresponding bytecode (a number from -127 to 128) (see MapPalette) into the string, between a section sign (§) and a semicolon (.

      When displaying the text on a map, the section sign, the byte and the semicolon do not get displayed, but instead change the color of the text following it. You can see the implementation of this in CraftMapCanvas#drawText

      For example "$-49;This is black. §34;And this is white", will result in "This is black. And this is white".

      However when using MapFont#getWidth, only the § is properly ignored, but the byte and semicolon after it aren't.
      You can clearly see this in the code:

      for (int i = 0; i < text.length(); ++i) {
        char ch = text.charAt(i);
        if (ch == ChatColor.COLOR_CHAR) continue; //Here
        result += chars.get(ch).getWidth();
      }

      As you can see, when the char equals $, the width calculation of that char gets skipped. But only that, and not the numbers and semicolon following it. In the example above, the width of "-49;" and "34;" would still get added to the result, althought these chars are not getting displayed on the map.

      Therefore you end up with a wrong width, when using colors in your text.

      Should be fairly easy to fix, for example using:

      public int getWidth(String text) {
          if (!isValid(text)) {
              throw new IllegalArgumentException("text contains invalid characters");
          }
      
          if (text.length() == 0) {
              return 0;
          }
      
          int result = 0;
          int ignored = 0;
          for (int i = 0; i < text.length(); ++i) {
              char ch = text.charAt(i);
              if (ch == ChatColor.COLOR_CHAR) {
                  int j = text.indexOf(';', i);
                  if (j < 0) throw new IllegalArgumentException("Text contains unterminated color string");
                  ignored += j-i+1;
                  i = j;
                  continue;
              }
              result += chars.get(ch).getWidth();
          }
          result += text.length() - ignored - 1; // Account for 1px spacing between characters, but ignore color-setting characters
      
          return result;
      }

            Unassigned Unassigned
            floskater99 Flo
            Votes:
            0 Vote for this issue
            Watchers:
            1 Start watching this issue

              Created:
              Updated:
              Resolved: