Resource XSeries - XMaterial, XSound, XPotion, XEnchantment, Titles, ActionBar, etc

Discussion in 'Spigot Plugin Development' started by CryptoMorin, Jun 16, 2019.

?

Do you need XParticle? (Read the first post for more info)

  1. Yes

    74.1%
  2. No

    25.9%
  1. XSeries is a set of utility classes to provide support for different functions to work on 1.8 to the latest version.

    This was originally a resource thread for XMaterial only, but I started working on new utilities.
    If the thread is missing any explanation for resources other than XMaterial, tell me.
    Note that most of the methods have a complete JavaDoc so most of the explanation is there.

    XSound
    Special Methods: playAscendingNote - playSoundRepeatedly - stopMusic - playSoundFromString
    I'm also working on a feature that you can write your own music script. I hope it'll be possible.

    A really special method is playMusic.
    You can make your own song snippets. This method allows you to play notes with a short script without needing to use any redstone or noteblocks! Please share your work if you made any.
    I might replace it with the current snippet in the testMusic method.

    XBlock
    This is used to support block state and data for materials. XMaterial only handles ItemStacks.
    All the methods in this class are special and unique.
    This requires XMaterial to work.


    XEnchantment
    These enchantments use an enum while the Bukkit one uses a class.
    There is also an Essentials version that uses classes ZEnchantment
    this class will not be updated.
    Special Methods: getBook


    XPotion
    These potion effects use an enum while the Bukkit one uses a class.
    Special Methods: buildItemWithEffects - throwPotion - addPotionEffectsFromString - parsePotionEffectFromString - isPotion


    XParticle
    Coming soon...
    This utility will mainly focus on providing easier ways to display particles in different shapes.
    A particle enum will not be added as only two particle name have changed.
    The code for most of these shapes will be collected from different places (since my Math isn't really good) and put into this utility and slightly modified.



    ActionBar & Titles
    So first off all why did I do this when there are already a lot of utilities out there?
    Most of them are missing optimization and some features.
    Note that you need to have ReflectionUtils class for this to work.


    XItemStack
    Serialize YAML ItemStacks without item versions and the ugly class types.
    A neat and cross-version utility to serialize and deserialize items.
    Supports almost all
    the metas.

    SkullUtils
    Get skull with texture from different methods.
    UUIDs, usernames, URLs and Base64.
    This might not work if you're using maven. You'll have to add Spigot JAR directly to your dependencies.

    XEntity

    Spawn entities from YAML. Supports all entities.
    Uses XItemStack, XMaterial and XPotion.
    Supports 1.9+

    XBiome

    Cross-version compatibility for biome names.
    Also has a few methods to change the biome in a selected area.
    Special Methods: setBiome(Chunk) - setBiome(Location start, Location end)


    XMaterial
    This is the continued version of the previous XMaterial resource. Since the previous developer is currently busy, he agreed that I can continue this project from now on.

    You'll be able to support all the materials before/after the 1.13 update which completely removed the item data values. While it was a great idea, some developers still want to support older versions.

    To Those Bending Over Backwards to Support Outdated Versions...
    I just want to make one thing clear in this thread, please. So let me keep it short.
    While I agree with the post above, I just find it fun to do this. And some server owners are still using 1.12
    And yes, even 1.8 is still used, but you're the developer. You're the one who make the changes happen. If they don't like the combat just tell them to use a plugin like OldCombatMechanics.
    If you're worried about the performance, this is wrong. 1.12 fixed a lot of bugs and exploits, and performance improvements.
    The insignificant lag that you're experiencing is because of the new features added. This is completely normal.

    Since I already coded this. Why not post it here?
    While this class supports all the versions, I encourage all the developers to use the Material Suggestion feature only and support 1.13 and above versions.
    So please, do not bring up the discussion about why we shouldn't support outdated versions here.


    Features:
    • ID (Magic Value) and ItemStack data support.
    • Matching materials names with newer and older names.
    • Support for duplicated names.
    • Support for changed material names in 1.13 and 1.14 (not many of them changed)
    • Support for damageable items.
    • Item and Material parser.
    • Comparing XMaterial with an ItemStack.
    • Material name cleanup for all the methods.
    • A small version checker feature.
    • Java 8 techniques for optimization.
    • Suggestion System for completely newly added materials. (Not completed)
    • This is not related to BlockState, BlockData or MaterialData. You cannot do anything that is related to block data with this. Adding support for every single block's data is craziness. There'll be an independent class released in the future called XBlock.
    • Make sure to add "api-version: 1.13" to your plugin.yml

    ProtocolSupport
    Instead of using "1.13" for materials that are newly added in 1.13+ they're now replaced with the version they're added in.
    It can be checked with getVersionIfNew, getSuggestions and suggestOldMaterialIfNew.

    The format for suggested old materials should always be:
    TheLatestMaterialName(DataValueOfTheOldMaterial, AddedVersion/AcceptableOldMaterial, BestOldMaterialSuggestion, "OriginalOldName/Version")

    Read the list below to understand what I mean by those parameters.
    Yes like I said before, this material is "newly" added meaning in 1.13 or above. But OriginalOldName is referring to an old name in one of the
    "new versions" that are older than the latest version if available.


    Suggestion System
    • Example of how it works:
    • LIGHT_GRAY_GLAZED_TERRACOTTA(8, "1.12", "HARD_CLAY", "STAINED_CLAY", "LIGHT_GRAY_TERRACOTTA", "SILVER_GLAZED_TERRACOTTA/1.13"),
    • DataValueOfTheOldMaterial: glazed terracotta already has split IDs but light gray normal terracotta data value is 8, so we'll use it only if in older versions.
    • AddedVersion: This material was added in 1.12
    • AcceptableOldMaterial/BestOldMaterialSuggestion: When checking for materials, the names are checked from the last name to the first name. In here, the first name is HARD_CLAY which is a colorless TERRACOTTA with no data value. Second, we have STAINED_CLAY. That is a colored clay with 8 as the data value.
    • Third is LIGHT_GRAY_TERRACOTTA which has split IDs.
    • The last is SILVER_GLAZED_TERRACOTTA. Notice that there's a version added next to it "/1.13" it means this name is NOT a suggested name. It's just another name for the material but in 1.13. Which means the name was changed in 1.14 to LIGHT_GRAY_GLAZED_TERRACOTTA.
    • FISH_BUCKET(0, "BUCKET", "WATER_BUCKET") Fish bucket is a water bucket with a fish in it. So it's better to have a water bucket instead of an empty bucket.
    • GLAZED_TERRACOTTA(ID, "HARD_CLAY", "STAINED_CLAY", "TERRACOTTA")
    • COLOR_DYE(ID, "ITEM", "INK_SACK") ITEM such as cactus and bone meal.
    • Changed TURTLE_EGG from MONSTER_EGG to EGG
    • STRUCTURE_VOID(0, "1.10", "BARRIER/1.9") Originally developers used barrier blocks for its purpose.
    • If you want to write suggestions make sure to post it here!
    Version Check
    • You might find this unrelated to XMaterial, but it's actually useful in some cases.
    • Added MinecraftVersion enum. These are only the major versions in this case, others are unnecessary.
    • Added isVersionOrHigher, valueOfVersion, getVersion, isSupported and isNewVersion that uses isVersionOrHigher(version) and now it's cached.

    XMaterial v1.0 Resource


    There are some other features added, but I just forgot to add them to this list.
    Happy coding.
    Please report any grammar or format problems.
    Also, feel free to make a pull request if you can improve the code. Even if it's premature optimization.
     
    #1 CryptoMorin, Jun 16, 2019
    Last edited: Jan 17, 2020 at 1:12 PM
    • Useful Useful x 18
    • Like Like x 8
    • Winner Winner x 5
  2. XMaterial Usage & Examples


    Getting Simple Materials
    Code (Java):
    Material material = XMaterial.CRAFTING_TABLE.parseMaterial();
    So how this works in different versions?
    In 1.13 and 1.14, you'll get Material.CRAFTING_TABLE
    But if the plugin was running in 1.12 you'll get Material.WORKBENCH



    Getting Materials With Data Value
    If you want to get a material such as RED_WOOL,
    you can use parseMaterial, but you'll get WOOL 0. We're looking for WOOL 14
    Since data values are not saved in Material objects, you can get it as an ItemStack directly.
    Code (Java):
    ItemStack item = XMaterial.RED_WOOL.parseItem();


    Getting Materials by ID (Magic Value) and Data Value

    It's not recommended to use this. But for nerds that memorized all those IDs, you can use this
    for in-game purposes.
    Code (Java):
    XMaterial pufferfish = XMaterial.matchXMaterial(349, (byte) 3);


    Getting Materials by ItemStack/Materia/Name
    If you want to get RED_WOOL by name you should use:
    Code (Java):
    // By ItemStack
    ItemStack wool = ...;
    XMaterial material = XMaterial.matchXMaterial(wool);

    // By Material
    // You can't use this for materials that have data values but you can use it for other materials.
    Material mat = ...;
    XMaterial material = XMaterial.matchXMaterial(mat);

    // By Name - All have the same result.
    XMaterial material = XMaterial.matchXMaterial("RED_WOOL");
    XMaterial material = XMaterial.matchXMaterial("WOOL:14");
    XMaterial material = XMaterial.matchXMaterial("WOOL", (byte) 14);
    XMaterial material = XMaterial.matchXMaterial("RED_WOOL", (byte) 14);


    Getting Suggestion For Newly Added Blocks
    If a material is added in a new version but you want something similar to it in older versions you can use this.
    For example COD_BUCKET was added in 1.13. If you want something similar to it in 1.12 you can do:
    Code (Java):
    Material material = XMaterial.COD_BUCKET.parseMaterial(true);
    ItemStack item = XMaterial.COD_BUCKET.parseItem(true);
    This will give you COD_BUCKET in 1.13+ and WATER_BUCKET in 1.12-



    XMaterial Paradox (Duplicated Materials)
    Well, you really don't have to do anything about this. Just get the item's material normally using matchXMaterial and parseMaterial. But understanding it is one of the most complex things in this resource.

    Let's take an example. These two are duplicated materials. And I specifically chose these because it exactly shows the two form of duplicated materials.
    Code (Java):
    MELON(0, "MELON_BLOCK")
    MELON_SLICE(0, "MELON")

    CARROT(0, "CARROT_ITEM")
    CARROTS(0, "CARROT")
    What are the two forms?
    The first form is the Singular Form, like MELON.
    Melon slice in 1.13 is called MELON_SLICE while in 1.12 it's called MELON
    Melon block in 1.13 is called MELON while in 1.12 it's called MELON_BLOCK

    The second form, which I like to call it the S Form (Plural Form), like CARROT
    only have a S at the end of the name.
    Such as BRICKS and BEETROOTS.

    So the format from another perspective would be:
    Singular Form:
    NEW(OLD)
    EDIBLE(OLD)

    S Form:
    EDIBLE(OLD)
    NEW(OLD)

    Of course, this is just an example. Not all duplicated materials have the same behavior.
    It might sound confusing, but the conclusion is that:
    There's currently no official method that fixes this. The current method is hardcoded but at least it works.
    Code (Java):
    Material melon = XMaterial.MELON_SLICE.parseMaterial(); // 1
    Material melonBlock = XMaterial.MELON.parseMaterial(); // 2

    Material carrot = XMaterial.CARROT.parseMaterial(); // 3
    Material plantedCarrot = XMaterial.CARROTS.parseMaterial(); // 4
    In 1.13:
    1: MELON_SLICE, 2: MELON
    3: CARROT, 4: CARROTS

    In 1.12:
    1: MELON, 2: MELON_BLOCK
    3: CARROT_ITEM, 4: CARROT



    The Cake Is a Lie?

    There is a really special case with materials, and it's CAKE material. Beds also have similar behavior.
    In 1.12- this material was split into two other materials named CAKE and CAKE_BLOCK
    In 1.13+ CAKE_BLOCK is removed and now uses CAKE as the material for blocks.
    So parseMaterial() on 1.12- cake blocks don't really work well. This cannot be fixed and doesn't even need to be fixed. This is not a bug.
    In order to properly check if a block is a CAKE:
    Code (Java):
    boolean isCake = XMaterial.isNewVersion() ? block.getType() == Material.CAKE : block.getType() == Material.matchMaterial("CAKE_BLOCK");


    Others
    There are other extra methods that can be used. Using them is fairly simple. You can read the

    JavaDocs for info.
     
    #2 CryptoMorin, Jun 16, 2019
    Last edited: Dec 11, 2019
    • Like Like x 11
    • Useful Useful x 2
    • Informative Informative x 1
  3. Cool resource man!, keep it up!

    +1
     
  4. Awesome resource, will definitely use it.
     
  5. Nice resource! A question, at a material like this:
    Code (Java):
    REDSTONE_LAMP(0, "REDSTONE_LAMP_OFF", "REDSTONE_LAMP_ON"),
    How do I need to get the REDSTONE_LAMP_OFF material, and how do i need to get the REDSTONE_LAMP_ON material?

    I want to check if the material of a block is a off redstone lamp or a on redstone lamp. How do I need to do that which the resource?
     
  6. This is a little tricky.
    You'll have to do this yourself, because if I wanted to add BlockData support for all the blocks that'd be crazy.
    Code (Java):
    // 1.13
    Block lamp = ...;
    Lightable lightable = (Lightable) lamp.getBlockData();
    boolean lit = lightable.isLit();

    // 1.12
    boolean lit = lamp.getType() == Material.matchMaterial(XMaterial.REDSTONE_LAMP.getLegacy()[1]); // Like computers 0 off, 1 on
     
    If you have a better idea that'd make this easier directly from XMaterial without having to support Lightable BlockData, make sure to tell me.
     
    • Like Like x 1
  7. XMaterial v2.1 on GtiHub

    v2.1 Changes


    - Added more examples.

    Not really recommended to use these two options. But use it if you're a nerd that memorized all the IDs. Mostly used for in-game purposes.
    - Added matchXMaterial(int id, byte data): Gets an XMaterial based on the material's ID (Magic Value) and ItemStack's data.
    - Added XMaterial#getId(): Safely gets a material's ID without throwing an exception. Returns -1 if the material doesn't have an ID.
    Ignore the 6 and 7 change. It was accidentally.
     
  8. Lovely resource for retrieving Materials across versions. LocaleLib might compliment this nicely for anyone looking to send Material names in chat. It translates them to the client's language for 1.7.2 - 1.14+.
     
  9. Oh, glad you continue this because you took care of our recommendations. Good resource!
     
    • Agree Agree x 1
  10. Ayayay this is dope man I love it!
    I used to do triple checks for people using 1.14. Now, four checks xD Thanks a ton <3 anyways all the best.
     
  11. I'm glad you all liked it. And kinda surprised that there are no bugs reported so far. (After all it passed more than 100 tests)
    I might work on an XBlock soon. An independent class that gets the BlockData of blocks such as "Lit" state for redstones, direction of blocks, half of stairs and etc.

    This, unlike XMaterial, doesn't need that much optimization since the only thing "delaying" the code is checking if the method is called from 1.12- or 1.13+ and the material type (It won't need XMaterial)
    But everything needs to be written from scratch, independent from classes in 1.13 that use BlockData. (Some can be checked with simple objects like "Lit" for redstones, true or false)

    Here's an example how the method for Lightable BlockData would look like:
    Code (Java):
    public static boolean isLit(Block block) {
        if (isNewVersion()) {
            if (!(block.getBlockData() instanceof Lightable)) return false;
            Lightable lightable = (Lightable) block.getBlockData();
            return lightable.isLit();
        }

        String name = block.getType().name();
        if (name.startsWith("REDSTONE_LAMP"))
            return isMaterial(block, "REDSTONE_LAMP_ON");
        if (name.startsWith("REDSTONE") && name.contains("TORCH"))
            return isMaterial(block, "REDSTONE_TORCH_ON");
        // TODO Any solution for furnace?

        return false;
    } // Where isMaterial() is a simple check: block type == parsed material name (not using XMaterial)
    If anyone has any suggestions, let me know.
     
    #11 CryptoMorin, Jun 18, 2019
    Last edited: Jun 19, 2019
    • Agree Agree x 1
    • Useful Useful x 1
  12. Just proposed some improvements on a pull-request over on the repository.
     
    • Winner Winner x 1
  13. Don't hack me please but great resource !
     
  14. Recommended Update
    XMaterial v2.2 on GitHub

    v2.2 Changes:
    • A huge thanks to @WI5E for filling the small gaps left in the code, optimizing this to the fullest.
    • Null and empty checks are now checked properly.
    • Fixed toWord(), returning full caps.
    • Added missing versions for 1.14 materials and added more "suggestion" materials.
     
  15. Is it possible to change a block type to a colored wool?

    I've been using this:
    Code (Text):
    block.setType(XMaterial.BLUE_WOOL.parseMaterial())
    This works fine in 1.13, but going back to 1.8, it returns white.
    You do say it turns white when using parseMaterial(). But what would be the correct way to do this?
    Also, that last sentence in the quote doesn't really make sense.
     
  16. you would need to do either get the data individual from the xMaterial through xMaterial.getData() or get the itemstack which will parse to the correct color through XMaterial::parseItem
     
  17. Using parseItem() doesn't help here, atleast from my understanding. You can't change a block type with an ItemStack.

    Also, you cannot use setData() on Blocks in 1.13, I've also tried using:
    Code (Text):
    setType(XMaterial.matchXMaterial("BLUE_WOOL", (byte) XMaterial.BLUE_WOOL.getData()));
     
    But it throws an NPE. I'm probably using it wrong, but I have no idea how.
     
  18. It's related to BlockState. You can do it like this:


    Code (Java):
    Block block = ...;
    block.setType(XMaterial.BLUE_WOOL.parseMaterial());


    // Recommended Way
    MaterialData state = block.getState().getData();
    if (state instanceof Wool) {
        Wool wool = (Wool) state;
        wool.setColor(DyeColor.BLUE);
    }

    // Lazy way
    block.getState().setRawData((byte) XMaterial.BLUE_WOOL.getData());
    Direct access for this feature will be available in XBlock (It's not released yet)

    Don't worry about that. It simply means it uses new ItemStack(type) in 1.13 instead of new ItemStack(type, data)
     
    #18 CryptoMorin, Jun 21, 2019
    Last edited: Jun 21, 2019
  19. Both of these also make the wool white in 1.8, but they create color in 1.13. I also tried adding
    Code (Text):
    block.getState().update();
    to the "Recommended Way". Still gave me white wool.
     
    #19 DessieYT, Jun 21, 2019
    Last edited: Jun 21, 2019
  20. That's really odd. If that doesn't work I really have no clue.
    Tell me if you found a solution for that.