Printing special characters [♠, ♣, ♥, ♦] in chat...

Discussion in 'Plugin Development' started by Father Of Time, Apr 24, 2012.

Thread Status:
Not open for further replies.
  1. Offline

    Father Of Time

    dev.bukkit.org profile:
    CFUSERNAME
    My Plugins (CFCOUNT)
    Minecraft account:
    MCUSERNAME
    This is a pretty simple question; does anyone know a method to display these special character in Minecraft in-game chat?

    ♠ - spade
    ♣ - club
    ♥ - heart
    ♦ - diamond

    I think it's fairly obvious what I am trying to do with them, but if not I am trying to make a card deck plug-in that can be expanded to include additional card games (starting with blackjack).

    Any ideas? Thanks in advance for your expertise!

    p.s. it will only run on a Windows based server, I know this may affect the responses.
  2. Offline

    TopGear93

    dev.bukkit.org profile:
    CFUSERNAME
    My Plugins (CFCOUNT)
    Minecraft account:
    MCUSERNAME

    This post has been edited 1 time. It was last edited by TopGear93 Apr 24, 2012.
  3. Offline

    Father Of Time

    dev.bukkit.org profile:
    CFUSERNAME
    My Plugins (CFCOUNT)
    Minecraft account:
    MCUSERNAME
    I could be mistaken, but I believe that would work only if we were creating the client from the ground up and included that into the minecraft client library. If the plug-in server side imported the font library I can only imagine that it wouldn't appear in game because the client doesn't share that same library.

    I am curious what character set Minecraft utilizes, I'm assuming the ASCII standard?

    [IMG]

    because I've seen all of these characters in game, yet it doesn't include the card special characters so it makes sense. Even if I try to force the character for experimental reasons it simply doesn't print anything:

    Code:
        player.sendMessage("♣");
    
    So can anyone confirm whether or not the client will be able to print these characters if the plug-in itself imports a new character library?

    This post has been edited 1 time. It was last edited by Father Of Time Apr 24, 2012.
  4. Offline

    Father Of Time

    dev.bukkit.org profile:
    CFUSERNAME
    My Plugins (CFCOUNT)
    Minecraft account:
    MCUSERNAME
    Hmm, I just found this that is interesting:

    http://www.allbusiness.com/glossaries/unicode/4943833-1.html


    So it appears that bukkit doesn't use ASCII, but rather Unicode; however, it appears as if it's ASCII because the first 127 characters are identical in ASCII and unicode, and you can only utilize the additional character set by installing additional fonts...

    However, I still haven't figured out if this can be done server side?
  5. Offline

    Father Of Time

    dev.bukkit.org profile:
    CFUSERNAME
    My Plugins (CFCOUNT)
    Minecraft account:
    MCUSERNAME
  6. Offline

    Njol

    dev.bukkit.org profile:
    CFUSERNAME
    My Plugins (CFCOUNT)
    Minecraft account:
    MCUSERNAME
    Minecraft uses it's own font, and if a character is missing you can't use it since MC has no idea how it should look like.
    ThatOtherGuyLax and kroltan like this.
  7. Offline

    Father Of Time

    dev.bukkit.org profile:
    CFUSERNAME
    My Plugins (CFCOUNT)
    Minecraft account:
    MCUSERNAME
  8. Offline

    Father Of Time

    dev.bukkit.org profile:
    CFUSERNAME
    My Plugins (CFCOUNT)
    Minecraft account:
    MCUSERNAME
    I was assuming this was the case, but I figured I would run it paste the community to see if anyone knew of a method.

    Thanks for the input Njol.
  9. Offline

    Father Of Time

    dev.bukkit.org profile:
    CFUSERNAME
    My Plugins (CFCOUNT)
    Minecraft account:
    MCUSERNAME
    Hmm, okay... So I found this file inside the de-obfuscated client in the same folder the GUI image is stored.

    font.txt (UTF-8)
    Now at first I thought this meant I was F'ed, but looking closer I see that this isn't actually UTF8 because UTF8 ends at the "END" character:

    So I think this is UTF-16. If this is the case does that mean that the characters following that are "placeholders" for what ever font pack is being used, or are those the literal characters available to the client.

    If that is what available it seem's like an odd collection of characters to have available... What are all of those A characters about?
  10. Offline

    Father Of Time

    dev.bukkit.org profile:
    CFUSERNAME
    My Plugins (CFCOUNT)
    Minecraft account:
    MCUSERNAME
    Hmm, okay I found a very interesting conversation here regarding a plug-in that utilizes special character sets:

    http://www.minecraftforum.net/topic...ated-for-125/page__view__findpost__p__8150444

    As the author of the plugin states:

    [IMG]

    The author claims, the symbols in the Minecraft font correspond to CP 437

    http://en.wikipedia.org/wiki/Code_page_437

    So maybe there is some merit to this... But I won't be able to tell until I get home and do a little investigating...

    edit:
    useful for later when I get home and do some experimenting:
    http://stackoverflow.com/questions/4747358/java-unicode-confusion

    This post has been edited 1 time. It was last edited by Father Of Time Apr 24, 2012.
  11. Offline

    Njol

    dev.bukkit.org profile:
    CFUSERNAME
    My Plugins (CFCOUNT)
    Minecraft account:
    MCUSERNAME
    These usually appear if you use the wrong encoding to view a text file. You're likely viewing in ASCII mode while the file is UTF-8.
  12. Offline

    Father Of Time

    dev.bukkit.org profile:
    CFUSERNAME
    My Plugins (CFCOUNT)
    Minecraft account:
    MCUSERNAME
    Yea, I just confirmed that this method doesn't work for the ingame chat... Well S***! :D

    Code:
     char spade = '\u0003';
    String spadestring = Character.toString( spade );
    player.sendMessage( "Character value is: " + spadestring );
    System.out.println("Character value is: " + spadestring );
    The above prints the following in the console:

    But the following in game chat:

    It appears the Minecraft client font set doesn't contain the spade character... If anyone comes up with additional ideas of how to accomplish this I would love to hear them, otherwise I will consider this a dead end...

    Thanks to those who contributed.
  13. Offline

    md_5

    dev.bukkit.org profile:
    CFUSERNAME
    My Plugins (CFCOUNT)
    Minecraft account:
    MCUSERNAME
    Cannot be done as Minecraft has no idea how to render those characters, as was mentioned previously.
    Only way it can be done is with changes to the client.
  14. Offline

    Father Of Time

    dev.bukkit.org profile:
    CFUSERNAME
    My Plugins (CFCOUNT)
    Minecraft account:
    MCUSERNAME
    I figured as much, but the post from above was slightly misleading and gave me false hope that it may be doable:

    http://www.minecraftforum.net/topic...ated-for-125/page__view__findpost__p__8150444

    This post was very convincing that Minecraft uses Code_page_437, but upon further inspection of the client I realized that this was not the case...

    Oh well, it wasn't anything important, just looking for some money sinkholes for my economy and gambling is always a good one. :D
  15. Offline

    Njol

    dev.bukkit.org profile:
    CFUSERNAME
    My Plugins (CFCOUNT)
    Minecraft account:
    MCUSERNAME
    Well it actially seems like Minecraft used CP 437 until 1.0:
    [IMG]

    But since 1.0 MC has unicode support (I guess this from the hundreds of glyph_XY.png files in the mc.jar/font folder). glyph_26.png contains the characters you need, so you should actually be able to use those characters. Just remember to save your sources files as UTF-8 if you use the characters directly, or alternatively use \u2660 (♠) etc.
  16. Offline

    Father Of Time

    dev.bukkit.org profile:
    CFUSERNAME
    My Plugins (CFCOUNT)
    Minecraft account:
    MCUSERNAME
    *makes the record scratch noise* wait, what!

    So do I have this right, after 1.0 minecraft ditched CP 437 and moved to Unicode, but the client filters out any special character that is not a pre-defined acceptable character? However, one of the glyph (assuming those insignias from enchanting? ) is the character that I wish to use?

    So I am confused about your suggestion:

    I believe I am missing a step, because I tried as you suggested and it did not print the character in game, but it did print it in the console. I tried making a loop that simply looped through every char and printed them to see which chars were available using:

    Code:
    for( int i = 0; i < 250; i++ )
    {
        char c = (char) (i + '0');
        String cstring = Character.toString( c );
        player.sendMessage( cstring );
    }
    But this only displays 250 characters at a time, so I never went up past 1000.

    Rarely do I ask this, but would you be willing to provide me with a code snippet of your suggested method, because at the moment I don't fully understand how to use the glyph.png image as an ingame font.

    Thank you in advance for your assistance @Njol, and even more reviving what was once a dead concept.

    This post has been edited 4 times. It was last edited by Father Of Time Apr 25, 2012.
  17. Offline

    Njol

    dev.bukkit.org profile:
    CFUSERNAME
    My Plugins (CFCOUNT)
    Minecraft account:
    MCUSERNAME
    The glyph_XY.pngs look like Minecraft's font ressource, e.g. if the black spade ♠ (\u2660) is to be displayed it should display the 0x60th char from glyph_26.png.
    But apparently this doesn't happen. I've tried printing all four chars ♠♣♥♦ which displayed nothing. I also sent some random unicode chars: "¿ÐÑØ×Ựὲ慂똿ハ﹏" of which only "¿ÑØ×" was displayed, which are all in CP 437...

    edit: I tried printing all characters from 0 to 255, and it looks like at least in the beginning it's unicode: !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ

    edit2: I tried the same thing with chars between U+2600 and U+2700, but nothing was displayed.
    From the chars between U+0100 and U+0200 only 'ƒ' (U+0192) was displayed.

    This post has been edited 3 times. It was last edited by Njol Apr 25, 2012.
  18. Offline

    Father Of Time

    dev.bukkit.org profile:
    CFUSERNAME
    My Plugins (CFCOUNT)
    Minecraft account:
    MCUSERNAME
    I experienced that same problem. From what my research suggest this is due to a bug fix released by Jeb after 1.2.4 to stop players from sending Unicode characters in chat to displaythat spamming character set (known as "magic" in the color enum these days), among other issues.

    Although I am only going off other peoples suggestions and not personal research, it appears that the only characters that can appear in chat are the characters listed in TEMP/GUI/font.txt if the deobfuscated client.

    However, if you managed to get some of the characters from above to print in game, such as:

    then this must not be the case, as the font.txt in the GUI directory does not contain those characters.

    Also, I should note that I found usable characters far outside the 0-255 range, some up in the 1000's...

    I can only imagine that if the character is in the distribution files then there must be a way to utilize them... Well... not really, not if the rendering classes are designed to intentionally block them...

    Arg, this is so overly complicated for wanting to print 4 characters. :D

    This post has been edited 3 times. It was last edited by Father Of Time Apr 25, 2012.
  19. Offline

    Father Of Time

    dev.bukkit.org profile:
    CFUSERNAME
    My Plugins (CFCOUNT)
    Minecraft account:
    MCUSERNAME
    I just realized something, not only do those characters appear in glyph_26.png but they also appear in default.png... What is that file used for? It's clear it's not a 1 to 1 ratio ( char 1 = char in the first slot) because none of those characters appear when cycling through the character list, so it leads me to believe that this default.png is not used for in game chat.

    Can anyone confirm what this file is actually used for( the default.png inside minecraft.jar in the font folder )?
  20. Offline

    Njol

    dev.bukkit.org profile:
    CFUSERNAME
    My Plugins (CFCOUNT)
    Minecraft account:
    MCUSERNAME
    That's the old font file (CP 437):
  21. Offline

    desht

    dev.bukkit.org profile:
    CFUSERNAME
    My Plugins (CFCOUNT)
    Minecraft account:
    MCUSERNAME
    My understanding (confirming @Father Of Time 's observation) is that only those characters that appear in font.txt (in craftbukkit.jar) will actually be displayed to the client. See https://github.com/Bukkit/mc-dev/blob/master/net/minecraft/server/SharedConstants.java and https://github.com/Bukkit/CraftBukk.../java/org/bukkit/craftbukkit/TextWrapper.java

    I've had some experience with this recently while getting Cyrillic text to display in my ChessCraft plugin - an unmodified craftbukkit.jar can't do it. See https://bukkit.atlassian.net/browse/BUKKIT-507

    So in theory, adding any Unicode (UTF-8) character to font.txt should allow its display in the client (assuming there's an image for it in one of the client's glyph files), but I haven't tested that... the downside of course is that anyone who runs your plugin would need to modify their font.txt, so it's not a very pretty solution.

    I'd thought of using reflection to modify org.bukkit.craftbukkit.TextWrapper.allowedChars, but that's unlikely to work since it's a static final field, i.e. a compile-time constant. It might be possible to inject a new net.minecraft.server.SharedConstants.a() method (that's what actually reads "font.txt"), or at least mock up its return value, but that would likely require a third party library like PowerMock. I don't think reflection alone can be used to replace a static method like that.

    So it seems to me that the Bukkit API could have a method to allow new characters to be added to the set of permitted characters. Which, while we're on the subject, really should be a Set, not a String - right now craftbukkit calls allowedCharacters.indexOf() - a linear search - for every single character that's sent to the client. Talk about inefficient. Same for net.minecraft.server.a(Packet3Chat packet).
  22. Offline

    Father Of Time

    dev.bukkit.org profile:
    CFUSERNAME
    My Plugins (CFCOUNT)
    Minecraft account:
    MCUSERNAME
    Thank you for your response desht, as usual it's a wealth of information. You have brought some great options to my attention, thank you for that. I was wondering some time ago if it would be as easy as adding the desired characters to the font.txt file, but assuming that it was "to easy to be possible" I didn't even bother look into it... Funny that it turns out that the server scans that file and that it is indeed that easy (in theory at least).

    My projects are all designed for a single community and are not publicly available, so editing the font.txt file isn't a major deal for my purposes, however it would be nice to make it more "universal" if possible. I will play around with injecting the required data into the allowedCharacters string (which I agree with you, shouldn't be a string) and go from there.

    I couldn't agree with you more... Although I feel this restrictive filter is a good thing, it should have the ability to register additional characters so that instances like this don't arise. It's one thing to block all unwanted incoming chars from clients, but if the server owners wishes to allow them their should be a method to register the characters with your plug-in to override the filter.

    The current filter just seems like using a sledgehammer to kill ants... Sure it will kill them, but was it necessary?
  23. Offline

    Njol

    dev.bukkit.org profile:
    CFUSERNAME
    My Plugins (CFCOUNT)
    Minecraft account:
    MCUSERNAME
  24. Offline

    Father Of Time

    dev.bukkit.org profile:
    CFUSERNAME
    My Plugins (CFCOUNT)
    Minecraft account:
    MCUSERNAME
  25. Offline

    desht

    dev.bukkit.org profile:
    CFUSERNAME
    My Plugins (CFCOUNT)
    Minecraft account:
    MCUSERNAME
    Yeah, but see also http://stackoverflow.com/questions/...-private-static-final-field-didnt-do-anything - so reflection isn't guaranteed to work. However, this particular String is initialised from a method - net.minecraft.server.SharedConstants.a(), which reads the string contents from file at runtime - so the compiler shouldn't get the chance to inline it away. In other words, it might work :)
  26. Offline

    Father Of Time

    dev.bukkit.org profile:
    CFUSERNAME
    My Plugins (CFCOUNT)
    Minecraft account:
    MCUSERNAME
    *Does the ancy dance* I wanna test it NoooooooW!

    *sigh* I can log into my remote desktop and code it, but due to the antiquated java installation at my work station I am unable to remotely launch the Minecraft client, aka I can't test it!

    *stares at the clock and tries to speed it up with telepathy* :eek:
  27. Offline

    Father Of Time

    dev.bukkit.org profile:
    CFUSERNAME
    My Plugins (CFCOUNT)
    Minecraft account:
    MCUSERNAME
    Good afternoon all,

    Well I am extremely excited to announce that I was successful! it turns out that the solution was a combination of everyones advice, and for that I am extremely greatful.

    It turned out that as deskt suggested, that the final static aspecs of the field raised issues at first, throwing an illegal access error; but I simply had to remove the static and final aspects of the field and then obtain the content, alter it, and reset it again and it worked perfectly! Here is the end result:

    [IMG]

    It would definately be nice if I could make them a little bigger, but I am absolutely satisfied with the results.

    So without further adue, the code that made this possible:

    Code:
     public void ModifyAllowedCharacters() throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException
     {
      Field field = SharedConstants.class.getDeclaredField("allowedCharacters");
      field.setAccessible(true);
      Field modifiersField = Field.class.getDeclaredField( "modifiers" );
      modifiersField.setAccessible( true );
      modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
      String oldallowedchars = (String)field.get(null);
      String suits = "\u2665\u2666\u2663\u2660";
      StringBuilder sb = new StringBuilder();
      sb.append( oldallowedchars );
      sb.append( suits );
      field.set( null, sb.toString() );
     }
    
    Thank you all for your contributions to this experiment, without your efforts I would not have been able to accomplish this. I hope someone else finds this as useful as I do, happy coding!

    This post has been edited 1 time. It was last edited by Father Of Time Apr 29, 2012.
  28. Offline

    d33k40

    dev.bukkit.org profile:
    CFUSERNAME
    My Plugins (CFCOUNT)
    Minecraft account:
    MCUSERNAME
    Thanks for the code Father Of Time :) so helpfull!
  29. Offline

    Tauryuu

    dev.bukkit.org profile:
    CFUSERNAME
    My Plugins (CFCOUNT)
    Minecraft account:
    MCUSERNAME
    Would you be kind enough to make a full Resource tutorial in how to do this? I'm still quite confused about how it works.

    Thanks :)
  30. Offline

    ewbragg

    dev.bukkit.org profile:
    CFUSERNAME
    My Plugins (CFCOUNT)
    Minecraft account:
    MCUSERNAME
    It works! I just copied the above method to my class and made sure I called it when I initialized.

    You do have to import some of the classes referenced:

    Code:
    import java.lang.reflect.Field;
    import java.lang.reflect.Modifier;
    import net.minecraft.server.SharedConstants;
    



Thread Status:
Not open for further replies.

Share This Page