Multiple ChatColors

Discussion in 'Spigot Plugin Development' started by DJJujuVI, May 31, 2016.

  1. Hello! I am trying to put multiple codes in my command.
    Code (Text):
    p.sendMessage(ChatColor.GOLD + ChatColor.BOLD + "Whoops! My Internet Crashed! What were we talking about?");
    It gives me a message that it doesn't work. Any help for this? Thanks!
  2. This doesn't work for the same reason that
    Code (Text):
    String s = new String("here are two numbers in a row " + 1 + 2);
    doesn't work. Java can handle one non-String placed in the middle of a String, and knows to convert it to a String for you. However, if you have two or more non-Strings in a row (including ChatColors, which are not strings!) then you need to convert the first one(s) into Strings for your code to compile.
  3. A chat color cannot be "added" or "concatenated with another chat color. When you do
    Code (Text):
    ChatColor.RED + "message"
    there is an implicit call to toString () in there because the compiler realizes what you are trying to do. With 2 chat colors it is lost. So what you will need to do it
    Code (Text):
    ChatColor.RED.toString () +ChatColor.BOLD + "message"
    • Like Like x 1
  4. Code (Text):
    p.sendMessage(ChatColor.BOLD + "" + ChatColor.BLUE + "Your message here"};
    Although this is inefficient and you should just create a method to handle color codes so you can put color codes in the string itself.

    EDIT: Or what @MrBlobman said above ^^
    • Agree Agree x 2
  5. or make a util with a method named "color" which returns a string and the first arg of it is a string and do something like this:
    Code (Java):
    public final String color(final String string) {
      return ChatColor.translateAlternateColorCodes('&', string);
    and to use this it would be simple
    Code (Java):
    p.sendMessage(color("&9&lThis will be colored!"));
    may be a bit of spoonfeeding but it's 3 lines... plus it's just a util that could help.
  6. Just use String#format(String, Object...) like this:
    Code (Text):
    p.sendMessage(String.format("%s%sYo!", ChatColor.GOLD,  ChatColor.BOLD));
    Every time you have "%s" in the string, it corresponds to an object from the varargs argument
  7. that works too :p
  8. Thanks so much! Im new so I didn't know this :3
  9. Java unary operators follow a "left-most" derivation, just like pretty much anything else in Java. In simple terms, you can think of the `+` operator as a function which takes two arguments and returns one:

    Code (Java):
    public <T> T add(T one, Object two) {
        return one + ((T) two);
    This operation is repeated for each new operator you come across, reading the parameter left-to-right

    If you add a few things together, this is how it breaks down:

    Code (Text):
    String + Int + String + String + Int....
    Type One: String        Type Two: Int         Value: StringInt              New Type (Leftmost): String
    Type One: String        Type Two: String      Value: StringIntString        New Type (Leftmost): String
    But with two ChatColor objects:

    Code (Java):
    ChatColor + ChatColor + String + ChatColor
    Type One: ChatColor    Type Two: ChatColor    Value: ?              New Type (Leftmost): ChatColor
    //breaks down at this point, we don't know how ChatColor + ChatColor works on its own
    When you add two ChatColor objects together first, there's no way of determining what the new value will be.

    Actually that's 100% valid

    Not inefficient, it will be compiled down to the same thing anyhow.
  10. Most of what you said is correct except the last,
    ChatColor.? + "" + ChatColor.? will boil down to CCstringCC so it would be perfectly valid since the + operator in string creation acts as a little string builder (kind of) so it would just build the chat color, then the string, then the chat color so it would come out correct however there is more correct ways of doing it.
  11. It's actually an optimization in the compiler (For oracle's, anyhow) on string concatenation:

    Code (Java):
    Will mean that it is assumed the Object can have #toString instrinsicly called upon it to obtain the new value. Thus it boils the operation down to:

    Code (Text):
    ((String) object) + String
    Code (Text):
    String + String
    It's also why you can add any non-object infinitely before converting to strings:

    Code (Java):
    System.out.println(1 + 2 + "3"); //prints "33"
    The reason this optimization exists is because all Objects have #toString available, but not all objects have a numerical value (disregarding #hashcode, since that's for a totally different purpose). It's a question of when adding those values together is correct or not, and for adding an object to a String it is assumed that #toString can be used.

    I'm not sure what part of my post you stated was "incorrect", I was stating that "Object + ε + Object" isn't inefficient at all, since it will be the same value as "Object.toString() + Object"

    Edit: ε (epsilon) meaning the "empty string", aka:

    Code (Text):
    #11 1Rogue, May 31, 2016
    Last edited: May 31, 2016
  12. You're right, my bad, it is less efficient however what he did will work. The method I put however is very efficient because you will always be able to use it no matter what unless bukkit's api changes which is not likely, even if they change the character code that we utilize which is currently "§"
  13. Well, if you really want to get technical, your method is actually less efficient. It's not an amount of efficiency that matters, but you're moving the evaluation of the colored string to runtime via regex, instead of compile-time (for many, but not most strings). Due to how string concatenation works, ChatColor is an object that is #toString'd at runtime, any string containing:

    Code (Java):
    ChatColor.VALUE + "some string"
    Will be evaluated at runtime, since the only pre-optimized strings are concatenated primitives and string literals. That's based around a JLS section that I'm still trying to find.

    This breaks it down into two categories:

    1) Your solution, which will use a runtime regex-replacement on the string
    2) Concatenation solution, which will simply evaluate the #toString values of the chatcolors and insert them at runtime

    Codewise however I prefer using runtime replacement, it's more readable and contributes to the isolation of data. However some would argue that it's worse for the same reason, readability. Reading something like:

    Code (Java):
    String s = "&e&lThe game will start in &r&c&o%s&r&e seconds!\n";
    //Isn't always obviously readable with a glance, vs say:
    String s = "The game will start in %s seconds!";
    Edit: It's JLS §15.18.1

    Which leads into JLS §15.28:

    #13 1Rogue, May 31, 2016
    Last edited: May 31, 2016
  14. sure that works but where are you translating the &? If you use chatcolor enum then that will work, if you do .replace("&", "§") and they change the code than you're screwed, my way is generally safer for plugin compatibility in the future
  15. I'm not talking about using #replace, that would break more than it would fix. It's simple string concatenation aka:

    Code (Java):
    String s = ChatColor.RED.toString() + ChatColor.BOLD + "Hello World!";
  16. that would work as well.