Resource XSeries - XMaterial, XParticle, XSound, XPotion, 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)

Poll closed Oct 28, 2020.
  1. Yes

  2. No

  1. XSeries is a set of utility classes that provides different functions that are fully optimized to make plugin development easier.
    Most of the projects here aim to provide cross-version compatibility as well.
    Note that most of the methods have a complete JavaDoc so most of the explanation is there.

    For the latest version check the XSeries GitHub page.
    Please read the maven part in the GitHub page as well. It's important.

    Performance & Memory Usage
    There is absolutely no performance difference between parsing the enum from these utilities and getting them directly from the Bukkit enum other than XMaterial utility which still has a really powerful cache system.
    Fun fact that the match method for strings, is even faster than Bukkit's in most cases. This is not just great for cross-version support, but for config options as well.
    While the cross-version utilities do consume a little memory, it's just insignificant. Other classes that are not made for cross-version compatibility aim to provide the best performance and options.
    The only downfall for using it is it's just going to increase your JAR file size by a few kbs.

    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.
    All the methods in this class are special and unique.
    You'll need ParticleDisplay for this to work.
    • Many static and animated shapes.
    • Display images as particles.
    • Text to particles.
    • Complex shapes like tesseracts and double pendulums.
    • XParticle will not add support for 1.8, reflection will be really heavy and the server will lag.

    Special Methods: playAscendingNote - playSoundRepeatedly - stopMusic - playSoundFromString

    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.

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

    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

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

    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.

    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.

    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.

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

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

    Supports changed material names for 1.8 up to the latest version.
    Since this class is widely used, version related functions are in this class.
    supports(int) - getVersion(), getMajorVersion(String)
    • ID (Magic Value) and ItemStack data support.
    • Matching materials names with newer and older names.
    • A list for the config to check with CONTAINS and REGEX prefix support.
    • 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.
    • XMaterial is not related to BlockState, BlockData or MaterialData. You cannot do anything that is related to blocks with this. Adding support for every single block's data is craziness. Use XBlock instead.
    • XMaterial v1 Resource

    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, some server owners are still using 1.12
    And yes, even 1.8 is still used, but you're the developer. If they don't like the combat system they can 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.
    While most of these utilities support 1.8 version, I encourage all the developers to drop support for anything below 1.12
    If people want to support lower versions, nothing is going to stop them. If this utility wasn't a thing, someone else would've create it with low performance. I made it instead so you can enjoy the high performance. Trust me, I've seen some really horrible codes related to this cross-version compatibility thing. While the utility is mostly used for cross-version compatibility, it also has some other useful methods.
    So please, do not bring up the discussion about why we shouldn't support outdated versions here.

    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 a little optimization, but make sure to read the contributing guidelines section first
    #1 CryptoMorin, Jun 16, 2019
    Last edited: Sep 30, 2020
    • Useful x 33
    • Like x 14
    • Winner x 10
    • Informative x 1
    • Creative x 1
  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):

    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:

    S Form:

    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:

    In 1.12:

    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");

    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 x 16
    • Winner x 5
    • Useful x 5
    • Agree x 1
    • Informative x 1
  3. Cool resource man!, keep it up!

    • Agree Agree x 1
  4. Awesome resource, will definitely use it.
  5. Nice resource! A question, at a material like this:
    Code (Java):
    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
    • Useful Useful 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.
    • Useful Useful x 1
  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
    • Useful Useful x 2
    • Agree Agree 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.
    • Useful Useful x 1
  15. Is it possible to change a block type to a colored wool?

    I've been using this:
    Code (Text):
    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. FrostedSnowman

    Resource Staff

    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 = ...;

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

    // 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):
    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.