in Programming, Tutorial

Minecraft Modding: Throwable Fireballs

This is the second part of the tutorial on Minecraft modding; in this article we will create throwable fireballs, using data packs and resource packs.

A link to download this mod is available at the end of the page.

In the second part of this tutorial about Minecraft modding, we will see how to create a custom item using data packs and resource packs. More specifically, we will create a throwable fireball. As discussed already in the previous sections, neither data packs not resource packs can really create new items. What they can do instead, is customising an existing item by storing some data in its NBT tags, and render that with a custom texture or model. But at its core, the modded item is and remains one of Minecraft’s existing items.

The Plan

Depending on what weapon or tool you want to create, you should customise one of Minecraft’s existing items. We will see later in this article what are the most commons ones. For now, the plan to create our throwable fireballs is simple:

  • Finding an existing item that closely resembles the interaction we want our fireball to have. In our case, that turns out to be a snowball (yes, a snowball!), since it can be hold in the inventory and thrown to inflict damage.
  • Summoning a fireball (an actual fireball this time) when the custom snowball is thrown.
  • Updating the position of the fireball to follow the trajectory of the existing snowball.

We will organise the code in three main functions (fireball:tick, fireball:throw, fireball:move), plus one (fireball:give) to give players the fireballs in their inventory.

The mod that is available for download at the end of this tutorial also declares fireball:load, although that is only used to display a message to the players.

Data Pack Structure

Our data pack will be called “Fireball”, and will have the following structure:

  • ๐Ÿ“ .minecraft
    • ๐Ÿ“ saves
      • ๐Ÿ“ (WORLD NAME)
        • ๐Ÿ“ datapacks
          • ๐Ÿ“ Fireballs (the name of the mod)
            • ๐Ÿ“„ pack.mcmeta (contains the name and version of the data pack)
            • ๐Ÿ“ data
              • ๐Ÿ“ minecraft
                • ๐Ÿ“ tags
                  • ๐Ÿ“ functions
                    • ๐Ÿ“„ tick.json (used to tell Minecraft to run tick.mcfunction every frame)
              • ๐Ÿ“ fireball (the namespace of the mod, which is used in the code)
                • ๐Ÿ“ functions
                  • ๐Ÿ’พ give.mcfunction (used to give the fireballs to the players)
                  • ๐Ÿ’พ tick.mcfunction (used to run the fireball code each each frame)
                  • ๐Ÿ’พ throw.mcfunction (used to instantiate the fireball)
                  • ๐Ÿ’พ move.mcfunction (used to move the fireball)

The file and folder names in bold are the ones that you are free to change for your own mod. All of the other ones needs to remain as they are.

The file tick.json is used to tell Minecraft that the function called fireball:tick will need to be executed every frame (also known as a tick). This is its actual content:

{
    "values":
    [
        "fireball:tick"
    ]
}

In our case, we will use the function fireball:tick to instantiate the fireballs. Which is why it needs to run every frame.

Minecraft also support a load.json file, which can be used to call a function when the data pack is loaded.

Resource Pack Structure

For our specific asset, this is what we will need:

  • ๐Ÿ“ .minecraft
    • ๐Ÿ“ resourcepacks
      • ๐Ÿ“ Fireballs
        • ๐Ÿ“„ pack.mcmeta
        • ๐Ÿ–ผ๏ธ pack.png
        • ๐Ÿ“ assets
          • ๐Ÿ“ minecraft
            • ๐Ÿ“ models
              • ๐Ÿ“ item
                • ๐Ÿ“„ snowball.json (this pack will change the texture of some snowballs)

Resource packs are often used to completely replace the original textures and model in the game. As we will see later in this article, we will use snowballs as the “base” item for our fireballs. However, we do not want to replace the texture of all snowballs, but only a selected few.

In Minecraft, we can use something called custom model data to associate a 7-digit number to an existing item. A resource pack can be made so that it only replaces the graphics of an item with the right type and custom model data. In our case, we used the (completely arbitrary) number 2538461.

The content of the snowball.json, below, indicates that we want to replace the model of all snowballs which custom model data is equal to 2538461 with fire charges (which looks more like actual fireballs):

{
    "parent": "item/generated",
    "textures":
    {
        "layer0": "item/snowball"
    },
	
    "overrides":
    [
        {
            "predicate": {"custom_model_data":2538461},
            "model"    : "item/fire_charge"
        }
    ]
}

We will need to make sure that the snowballs that we use have the right custom model data, or their graphics will not be changed. You can pick pretty much any 7-digit number you want for this, although the number must not start with a 0.

A good website to get started with more complex examples is NovaSkin, which also allows you to draw your own textures and models.

The Code

While really handy, data packs are subjected to some serious limitations. One above all, is the fact that new items cannot really be created. What is possible, instead, is “repurposing” an existing item which closely resembles what we envisioned. This is possible because entities in Minecraft can hold some arbitrary data. This way, we can tag an existing itemโ€”such as a sword or a crossbowโ€”and detect every time an item with that tag is being used.

However, things are not that easy. Right now, Minecraft data packs lack the ability to properly detect events, such as objects being created, used or even simple collisions. The modding community has nonetheless found some very ingenious ways to get around this, even though some might sound very counterintuitive. For instance…

  • Detecting right click: carrot on a stick
  • Dropping an item: spawn egg / armour stand
  • Launching item with charging: bow
  • Launching item with reload: crossbow
  • Launching item with right click, no charging: snowball

Possibly the most obvious item that we could repurpose to throw fireballs is a bow. A bow could be repurposed as a magic staff, which throws fireballs instead of arrow. However, turning bows and crossbows into guns comes with some additional complexities. This is because while we can tag a a bow to distinguish from the unmodded ones, the arrows that it spawns do not inherit its tags. The problem them becomes detecting when the player shoots an arrow, which is non trivial.

An easier alternative is to use a snowball instead. This is because throwing a snowball does creates a completely new entity, like a bow does. The snowball you are holding is the one that is being thrown, meaning that all of its tags and properties attached while it was in the inventory are preserved when it manifests as a moving entity in the world. Consequently, for this tutorial we will used tagged snowballs to create fireballs.

The YouTube channel Timber Forge has made a very helpful video explaining which item you should start from, depending on what action you want to detect.

Giving snowballs to players

In Minecraft, players usually obtain new items by crafting. While it is possible to create custom crafting recipes, we will start with a much simple approach. We can simply receive a desired item using the /give command. This can be done using a command block inside the game, or typing the command directly in the chat.

MCStacker is a very handy online tool which allows to easily generate commands. We can use the “/give” section to give one snowball, which has a custom NBT tag called fireball with value 1:

# CustomTags "fireball:1b"
give @p minecraft:snowball{display:{Name:'{"text":"Fireball"}'},CustomModelData:2538461,fireball:1b} 1

By all means, this is a normal snowball, which behaves exactly like all of the other ones. The only difference is that we have changed its name in the inventory to “Fireball” and added some extra bits of information to it. We have also added the custom model data necessary to make this snowball appear as a fire charge, as discussed in the previous section about resource packs.

Normally, Minecraft prevents you from seeing the “real” name of an object. However, you can press F3+H on your keyboard to enable the NBT tooltips.

โ“ Can we craft the fireball? โ–ผ

Minecraft is about two things: mining and crafting. Right now, we gave a player the fireballs using a command. It would be nice if they could be crafted like any other item.

This is where things get complicated. Data packs can indeed be used to add custom recipes, but they unfortunately cannot be used to add custom NBT tags to the crafted items. We could add a new recipe for snowballs, but without the possibility of tagging them, they would not be recognised as fireballs by our scripts.

Although some workarounds are possible, they are quite dirty. For instance, the recipe could craft a “Knowledge book”, which unlocks an achievement which gives the player the fireball. The YouTube channel Timber Forge explains how to do this in the following video.

In this tutorial, we will not use the “knowledge book trick”, and stick with the command. This is a serious limitation, which somewhat breaks the immersiveness of the mod.

If you want to play more with custom recipes, destruc7i0n made an online tool that you can use to generate custom data packs.

Creating a Fireball

As it turns out, Minecraft actually has a fireball entity that we can use. The ghasts in the Nether dimension are known for throwing them at players. Fireball entities are called minecraft:fireball, and the /summon command will instantiate one at the executor position. This makes things much easier for us, because we do not need to actually create any new item.

Since a tagged snowball is available in the player’s inventory, all we need to do is to wait for it to be thrown. Minecraft does not offer any native mechanism to get notified when such an event occurred. For this reason, what we need to do is to run a custom function every frame, to check if a snowballed with an NBT tag fireball:1b has appeared in the game as an entity.

We can now put some code in the “tick.mcfunction” file, searching for all snowballs with the an NBT tag fireball:1b. Once that is found, we can actually summon a fireball where the snowball is. The summoning is conditional to presence of a snowball, and need to happen at the position of the snowball. To do this, we need to use the execute command to change the executor location to the position of the snowball:

# Summon a fireballs at the exact position of each tagged snowball
execute as @e[type=minecraft.snowball, nbt={Item:{tag:{fireball:1b}}}] at @s run summon minecraft:fireball ~ ~ ~
# โŒ This will create a trail of fireballs!

If we run this in a command block set on Repeat, our snowballs will leave a rather spectacular trail of fireballs. Really cool, but not what we are here for.

If you want to customise the fireball, you can use the “/summon” section of MCStacker.

Create a companion fireball for each snowball

What we really want is to create only one fireball per tagged snowball. The easiest way to do this is to create a fireball, and the to add another tag the snowballโ€”let’s call it processed. We can change the previous command so that it only operates on snowballs that do not have the processed tag (possible using the !processed syntax).

In order for all of this to work, we need to execute not one but two commands (summoning the fireball and tagging the snowball). This is not really possible in a single execute ... run command. What we can do, however, is to call a function (fireball:throw, in the example below):

#> tick.mcfunction
# Invoked every frame
execute as @e[type=minecraft:snowball, nbt={Item:{tag:{fireball:1b}}}, tag=!processed] at @s run function fireball:throw

Functions in data packs are just text files with the “mcfunction” extension. This is what throw.mcfunction looks like:

#> throw.mcfunction
# AS AT snowball

# Creates a fireball where the snowball is
# Adds the "player" tag to show it is thrown by the player
summon minecraft:fireball ~ ~ ~ {NoGravity:1b,Fire:0,ExplosionPower:1,Tags:["player"],CustomName:'{"text":"Fireball","color":"red"}'}

# Adds the processed tag
# so that we do not create fire every time
tag @s add processed

Since the function is invoked by an execute command, @s will refer to the snowball being processed. We also add the player tag to the fireball, to distinguish it from the ones that are spawned by ghasts.

โš ๏ธ Difference between NBT tags and Tags list โ–ผ

Something that is somewhat confusion is that here are two separate things that are referred to as tags in Minecraft. One is the NBT tags (previously referred to as data tags, and called CustomTags in MCStacker), which were used when instantiating the fireball. NBT tags are dictionaries where you can associate custom values to keys. In our case, we associated the key fireball to the value 1b. You can test if an entity has a custom NBT tag by doing this:

# Select all entities with the custom NBT tag "KEY" set to "VALUE"
@e[nbt={Item:{tag:{KEY:VALUE}}}]

A completely different thing is the NBT tag called Tags. This is a list of “keywords” that can added and removed using the tag command. You can test if an entity has such a tag like this:

# Select all entities WITH the "KEYWORD" tag (from the "Tags" list)
@e[tag=KEYWORD]

# Select all entities WITHOUT the "KEYWORD" tag (from the "Tags" list)
@e[tag=!KEYWORD]

The give command can set custom NBT tags to objects in the inventory, but not adding custom tags to the Tags list.

โ“ How to get the entity data? โ–ผ

Since entities in Minecraft can hold arbitrary data, things can get pretty complex. Luckily, the data get entity command can be used to retrieve and print to the console the data hold by an object.

 data get entity @e[type=minecraft:snowball, limit=1]

It is important to limit the number of entries to 1 in the target selector, because the command will only work if exactly one entity is found.

Invoking the command when a snowball is in the air will output something like this:

{
    Motion: [0.32417156880477205d, -0.86282526378978d, -0.7039967172972504d],
    Owner: [I; 305053590, 96157799, -1483452418, -1630112461],
    Invulnerable: 0b,
    LeftOwner: 1b,
    Air: 300s,
    OnGround: 0b,
    PortalCooldown: 0,
    Rotation: [155.2752f, -42.428066f],
    FallDistance: 0.0f,
    Item:
    {
        id: "minecraft:snowball",
        Count: 1b,
        tag:
        {
            fireball: 1b,
            display:
            {
                Name: '{"text":"Fireball","color":"red"}'
            }
        }
    },
    Pos: [187.94527571361726d, 72.54139077541004d, 159.17886174477383d],
    Fire: -1s,
    UUID: [I; 1291038096, -1680192976, -1835876018, -1892172398],
    Tags: ["processed"]
 }

Playing the fireball sound

One smallโ€”yet effectiveโ€”addition to the throw.mcfunction script would be sound. We can play a sound using the playsound command. Since the fireball model comes from the ghasts, it makes sense to also use the same sound, which is called entity.ghast.shoot:

playsound entity.ghast.shoot player @p

The keyword player inside the command indicates what type of sound this is.

Move the fireball to the position of the snowball

The really important bit is to make sure that the fireball will always follow the trajectory of the snowball. One way to do that, is to invoke a function (let’s call it fireball:move) every frame, on every special snowball with a companion fireball instantiated (that is, a snowball with the processed tag).

#> tick.mcfunction
# Invoked every tick

# If the snowball h as been processed,
# then we have already created a fireball on top of it
# All we need to do is to find that fireball, and update its position
execute as @e[type=minecraft:snowball, nbt={Item:{tag:{fireball:1b}}}, tag=processed] at @s run function fireball:move

The most obvious way to move the fireball would be to teleport it to the position of its closest snowball. For instance, by doing the following:

#> move.mcfunction
# AS AT snowball

# Teleport the fireball to the snowball
tp @e[type=minecraft:fireball,tag=player,sort=nearest,limit=1] @s
# โŒ Does not work! It only moves at integer positions!

Unfortunately, it appears that this solution does not work as intended. If we try, the fireball will only move at integer positions, basically “lagging” behind the snowball.

So, the alternative is to copy the position and velocity of the snowball into the fireball. We can do this using the data modify entity command on the Pos and Motion properties, which every entity has.

#> move.mcfunction
# AS AT snowball

# Copies the position from the snowball (@s) to its closest fireball
data modify entity @e[type=minecraft:fireball,tag=player,sort=nearest,limit=1] Pos set from entity @s Pos 
data modify entity @e[type=minecraft:fireball,tag=player,sort=nearest,limit=1] Motion set from entity @s Motion

This finally allows us to create a real, throwable fireball!

Destroying orphaned fireballs

There is one last thing that we need to take care of. The fireball and the snowball are overlapping, but they technically are different entities. This means that, although unlikely, there is a change that one might die while the other survives.

Unfortunately, there is no way to check if or when an entity gets destroyed. The best we can do it is to destroy all fireballs that do not have a sufficiently close snowball. This can be done using the sub-command unless entity of the execute command. It works as a “complement” to the if entity sub-command, allowing to run a function only when there are no entities of a certain types around. In this case, the target selector is looking for at least one snowball within 1 block away form the fireball. If none is found (= unless entity) then the fireball is destroyed:

#> tick.mcfunction

#> Destroy orphaned fireballs
# Destroys all fireballs if their closest snowball has been destroyed.
# 
# For every fireball (@s),
# 	IF there are zero snowballs nearby (= UNLESS there is at least one snowball in a radius of 1block)
#	THEN delete that fireball (@s)
execute as @e[type=minecraft:fireball,tag=player] at @s unless entity @e[type=minecraft:snowball, nbt={Item:{tag:{fireball:1b}}}, distance=..1, limit=1] run kill @s

In the command above, we used limit=1 because we only need to find one snowball, not to run this code for all snowballs.

If you are familiar with C# and LINQ, that command is loosely equivalent to the following snippet:

// Destroys all fireballs which do not have a snowball nearby
// execute as @e[type=minecraft:fireball,tag=player] at @s unless entity @e[type=minecraft:snowball, nbt={Item:{tag:{fireball:1b}}}, distance=..1, limit=1] run kill @s

// execute as @e[type=minecraft:fireball,tag=player] at @s ...
foreach (Entity fireball in EntityList
    .HasType("minecraft:fireball")
    .HasTag("player"))
{
    SetExecutor(fireball); // as @e
    SetLocation(fireball); // as @s

    // ... @e[type=minecraft:snowball, nbt={Item:{tag:{fireball:1b}}}, distance=..1, limit=1]
    bool anySnowballNearby= EntityList
        .HasType("minecraft:snowball")
        .HasTag("fireball")
        .DistanceBetween(0f, 1f)
        .Any();

    // unless entity ... run kill @s
    if (! anySnowballNearby)
        Kill(fireball);
}

We can test that this works simply by killing all snowballs /kill @e[type=minecraft.snowball] and see that the fireballs are destroyed as well.

If needed, we could also add another condition to destroy all special snowballs which do not have a special fireball nearby.

๐Ÿ“š Numerical ranges โ–ผ

Minecraft supports three types of numerical ranges, all taking one of the following formats:

  • ..1: less or equal to 1;
  • 1..: greater or equalt to 1;
  • 5..10: between 5 and 10 (included).

What’s Next…

Let’s recap what we have done to create a throwable fireball.

  • We use the /give command to give to the player a custom snowball, with two important changes:
    • A custom NBT tag fireball:1b to mark it as an actual fireball
    • A custom model data connected to a resource pack, to render the custom snowball as a fire charge
  • We run the fireball:tick function every frame, to do the following:
    • For every snowball with the custom NBT tag fireball:1b which has not been processed yet, a “companion” fireball is summoned; the snowball also received the tag processed
    • For every snowball with the custom NBT tag fireball:1b which has been processed, we find the closest fireball and place it at the same position
    • Every summoned fireball which is not close enough to a snowball, gets destroyed

This concludes the tutorial on how to create throwable fireballs in Minecraft using data packs and resource packs.

Other resources

This was possibly the easiest way to make throwable fireballs in Minecraft. If you are interested, there are many other resource online which have taken somewhat different approaches.

Download Minecraft Mod

Become a Patron!

The data packs and resource packs used in this tutorial series to create throwable fireballs and laser guns are available for downloads on Patreon.

๐Ÿ’– Support this blog

This website exists thanks to the contribution of patrons on Patreon. If you think these posts have either helped or inspired you, please consider supporting this blog.

Patreon Patreon_button
Twitter_logo

YouTube_logo
๐Ÿ“ง Stay updated

You will be notified when a new tutorial is released!

๐Ÿ“ Licensing

You are free to use, adapt and build upon this tutorial for your own projects (even commercially) as long as you credit me.

You are not allowed to redistribute the content of this tutorial on other platforms, especially the parts that are only available on Patreon.

If the knowledge you have gained had a significant impact on your project, a mention in the credit would be very appreciated. โค๏ธ๐Ÿง”๐Ÿป

Write a Comment

Comment

Webmentions

  • Minecraft Modding: Laser Gun - Alan Zucconi

    […] Part 2: Minecraft Modding: Throwable Fireballs […]

  • An Introduction to Minecraft Modding - Alan Zucconi

    […] Part 2: Minecraft Modding: Throwable Fireballs […]