Resource Center MOTD's and Messages

Discussion in 'Spigot Plugin Development' started by MarcusNerloe, Jan 4, 2019.

  1. Hey guys, i found a lot of threads asking how to center a MOTD, and a lot of answers came up. I followed the answers and made this short method, to center player messages and MOTD's. :D

    The method checks if the characters are bold, and then removes 0.1555555555555556 spaces from the string, because thats the size of a bold character compared to a normal.

    (The lineLength of a MOTD, is 45 characters)

    Code (Java):
        // lineLength = 80 (Chat Length)
        // lineLength = 45 (MOTD Length)
        public String centerText(String text, int lineLength) {
            char[] chars = text.toCharArray(); // Get a list of all characters in text
            boolean isBold = false;
            double length = 0;
            ChatColor pholder = null;
            for (int i = 0; i < chars.length; i++) { // Loop through all characters
                // Check if the character is a ColorCode..
                if (chars[i] == '&' && chars.length != (i + 1) && (pholder = ChatColor.getByChar(chars[i + 1])) != null) {
                    if (pholder != ChatColor.UNDERLINE && pholder != ChatColor.ITALIC
                            && pholder != ChatColor.STRIKETHROUGH && pholder != ChatColor.MAGIC) {
                        isBold = (chars[i + 1] == 'l'); // Setting bold  to true or false, depending on if the ChatColor is Bold.
                        length--; // Removing one from the length, of the string, because we don't wanna count color codes.
                        i += isBold ? 1 : 0;
                    }
                } else {
                    // If the character is not a color code:
                    length++; // Adding a space
                    length += (isBold ? (chars[i] != ' ' ? 0.1555555555555556 : 0) : 0); // Adding 0.156 spaces if the character is bold.
                }
            }

            double spaces = (lineLength - length) / 2; // Getting the spaces to add by (max line length - length) / 2

            // Adding the spaces
            StringBuilder builder = new StringBuilder();
            for (int i = 0; i < spaces; i++) {
                builder.append(' ');
            }
            String copy = builder.toString();
            builder.append(text).append(copy);

            return builder.toString();
        }
    I hope you can use this, and understand my explanations / code! :D
    Happy coding everybody. :p
     
    #1 MarcusNerloe, Jan 4, 2019
    Last edited: Jan 4, 2019
    • Useful Useful x 1
  2. good good nice!
     
  3. Code (Java):
                    if (isBold) {
                        length = length + 1 - 0.1555555555555556;
                    } else {
                        length = length + 1;
                    }
    Thought bold was larger, `+` not `-`
     
  4. Exactly, that is why we are adding 1 normal character and then removing 0.1555555555555556 spaces from the total spaces to be added.
     
  5. But with
    Code (Java):
    double spaces = (lineLength - length) / 2;
    it gives less spaces when the length is higher, so the bold should be adding more length to the current, right? If it adds more than that makes the needed spaces less.
     
  6. So taking from your code I took out a few pieces:
    1 -> the calculation for bold chars vs. normal chars
    2 -> my calculation for bold chars
    3 -> your calculation for the number of spaces to add in

    And in principle, if we have bold characters, that leads to less space. So I've written a little thing to model it, what's printed is the amount of space for each.
    This is the program:
    Code (Java):
    class Main {
      public static void main(String[] args) {
        double lineLength = 100; // this is the motd line length I assume
        // if you have 50 bold chars
        double testBold1 = 50 - (50 * 0.1555555555555556);
        // if we have 50 bold chars
        double testBold = 50 + (50 * 0.1555555555555556);
        // if we have 50 normal chars
        double testNorm = 50;
        System.out.println((lineLength - testBold1) / 2); // you
        System.out.println((lineLength - testBold) / 2); // bold
        System.out.println((lineLength - testNorm) / 2); // norm
      }
    }
    And this is the output:
    Code (Text):
    28.88888888888889
    21.11111111111111
    25.0
    So with yours, with bold characters, we have effectively more spaces, with mine we have effectively less spaces. I'm not sure why you'd have a - there...
    Code (Java):
            for (int i = 0; i < spaces; i++) {
                builder.insert(0, ' ');
                builder.append(' ');
            }
    and ofc this adds in spaces relative to the spaces double

    EDIT: Didn't see your post about editing, but yeah, just as a proof
     
  7. Side note, instead of:
    Code (Java):
                    if (isBold) {
                        length = length + 1 + 0.1555555555555556;
                    } else {
                        length = length + 1;
                    }
    can we instead do
    Code (Java):
    length++
    if (bold) length += .15555556
    or something similar?
    also, this:
    Code (Java):
                if (chars[i] == '&' && (chars.length != (i + 1)) && chars[i + 1] != 'l' && ChatColor.getByChar(chars[(i + 1)]) != null) {
                    length = length - 1;
                    isBold = false;
                } else if (chars[i] == '&' && (chars.length != (i + 1)) && chars[(i + 1)] == 'l') {
                    isBold = true;
                    length = length - 1;
                    i++;
                }
    can be changed into a nested if with less conditions with this being top level:
    Code (Java):
    chars[i] == '&' && chars.length != (i + 1) && ChatColor.getByChar(chars[i + 1]) != null
    then having the bold check inside something like this:
    Code (Java):
    length--
    isBold = chars[i + 1] == 'l'
    this would make it a bit cleaner
    EDIT:
    Something like so:
    Code (Java):
    public String centerText(String text, int lineLength) {
        char[] chars = text.toCharArray();
        boolean isBold = false;
        double length = 0;
        ChatColor pholder = null;
        for (int i = 0; i < chars.length; i++) {
            if (chars[i] == '&' && chars.length != (i + 1) && (pholder = ChatColor.getByChar(chars[i + 1])) != null) {
                // we don't need to change the length...? it's already where we want it if we ignore the colors
                if (pholder != ChatColor.UNDERLINE && pholder != ChatColor.ITALIC // these 4 don't cancel bold
                        && pholder != ChatColor.STRIKETHROUGH && pholder != ChatColor.MAGIC) {
                    isBold = chars[i + 1] == 'l'; // true if the next is a bold modifier
                }
                i++; // we don't care about the next since it's a color init
            } else {
                length += 1;
                if (isBold) length += 0.1555555555555556;
            }
        }

        double spaces = (lineLength - length) / 2;
        StringBuilder builder = new StringBuilder();
        for (int i = 0; i < spaces; i++) {
            builder.append(' ');
        }
        String copy = builder.toString(); // avoid insertions, it's kinda costly I believe
        builder.append(text).append(copy);

        return builder.toString();
    }
    Cost if insertion, which is why we don't want it:
    Code (Java):
        public AbstractStringBuilder insert(int offset, String str) {
            if ((offset < 0) || (offset > length()))
                throw new StringIndexOutOfBoundsException(offset);
            if (str == null)
                str = "null";
            int len = str.length();
            ensureCapacityInternal(count + len);
            System.arraycopy(value, offset, value, offset + len, count - offset);
            str.getChars(value, offset);
            count += len;
            return this;
        }
    (2 array copies instead of 1 I think)
     
    #7 FiXed, Jan 4, 2019
    Last edited: Jan 4, 2019
  8. Okay, so i have actually just tested this with - and + a bit, you were right it seems to be more centered with +. The reason is:
    Example motd: &6&lNice &eServer
    4 bold characters
    7 normal characters (including spaces)

    length = 0;
    length += 7 * 1; (7)
    length += 4*1,1555555555555556; (4,622)

    length is now 11,622

    Then you will have to get the spaces from that, the spaces gets calculated by:
    (lineLength - length) / 2

    So in our example:
    (45 - 11,622) / 2 = 16,689

    And now we have the spaces. If you plus the spaces + the length of the string + spaces, then you will always have the text length.
    16,689 + 11,622 + 16,689 = 45

    (I have also updated the original code, to be more compact. :) )
     
    #8 MarcusNerloe, Jan 4, 2019
    Last edited: Jan 4, 2019
  9. Going to break this down a bit
    bold -> "Nice" not bold -> " Server"
    4 bold and 7 not bold
    length += 11 (the length of raw chars)
    add in the bold offset in this case "0.62222222222"
    which makes the new length 11.62222222222 or 10.3777777778
    Now we have 2 nice lengths to use and compare.
    uh no, again we're missing the bolded chars natural size, which means
    (45 - 11.62222222222) / 2 = 16.6888888889
    and
    (45 - 10.3777777778) / 2 = 17.3111111111

    As we can see, there are fewer spaces due to there being bold, that's the logical response to having bolded chars.
    This is mathematically always true no matter your input due to you dividing and such, don't think this is relevant.

    Anyhow, point is, you missed a couple things in your calculation and the more logically sound solution would have a `+`, could you post some screenshots of the differences so we can see for ourselves? Or I can run some tests on my own server.
     
  10. Sorry, i wrote wrong in the last message, i have now edited it. :)
     
  11. Also, check my post here it has an optimized solution at the bottom for it. It provides checking for when boldening is actually canceled and persisted.
     
  12. Okay, thank you so much, for the updates. :) I have now edited the main thread to the newest code.

    I just have one more little example, if you keep the
    Code (Java):
    length--;
    where you set the bold, then it looks like this:
    https://prnt.sc/m2xfaj

    And if you remove it, the motd looks like this:
    https://prnt.sc/m2xfi2

    So i would definitely keep it. ;)
     
  13. That's only because of the many color assignments, increment i regardless and you won't have to decrement length, that's the one issue you have. Since we know the next will be a color code we'd like to skip it since we couldn't care less about it.
     
    • Agree Agree x 2
  14. I guess this breaks as soon as you use a resourcepack including a custom font. As well players may change the width of their chat window.