---
tags: DrakonForge, Minecraft
---
# Datapack Development Overview with DrakonCore
*This article assumes you are at least a novice in datapack development. It will not be explaining the absolute fundamentals of how datapacks work or how to set them up. If you need to brush up on basics, see [**here**](https://minecraft.fandom.com/wiki/Data_Pack) and [**here**](https://minecraft.fandom.com/wiki/Tutorials/Creating_a_data_pack).*
Repository: https://github.com/Drakonkinst/DrakonsDatapacks
DrakonCore is an open-source datapack library that provides utility functions and hooks to make datapack modding easier. Normally, datapacks share much of the same code, such as functions that run every tick, detecting when the player is sneaking, etc. This causes unnecessary overlap when combining two or more packs from unrelated developers. A utility datapack such as DrakonCore provides all datapacks with a common starting point and set of base functions, which eliminates a lot of duplicated code.
One of the major advantages of using DrakonCore is that the repository contains *all* datapacks created by Drakonkinst using this system. Therefore, every datapack previously created is available as a reference for new features (in Visual Studio Code, you can search across the entire directory with `Ctrl+Shift+F`). Make use of this codebase when figuring out how to implement new features!
The [Minecraft Wiki](https://minecraft.fandom.com/wiki/Data_pack) has a more comprehensive documentation of datapacks, but this may be too confusing and spread out to learn how to create datapacks effectively.
## Fundamentals
### What is the Minecraft Commands Language?
### Command Syntax
Syntax | Meaning
--- | ---
`plain text` | **Enter this literally**, exactly as shown.
`<argument>` | A **required argument** that should be replaced with an appropriate value.
`[argument]` | An **optional argument** that may be replaced with an appropriate value, or left empty.
`<entry1\|entry2>` or `(entry1\|entry2)` | A **required choice**. Pick one of the entries shown.
`[entry1\|entry2]` | An **optional choice**. Pick one of the entries shown.
`...` (ellipsis) | Another **sub-command** is required.
#### Permissions
Some commands are **restricted** to certain usages or contexts, such as commands that are op-only. By default, datapacks cannot do **all** commands that operators can--specifically, they cannot run `/reload`, `/datapack`, `/kick`, `/stop`, `/ban`, and others. While it is possible to circumvent this, it is probably not a good idea for your datapack to try to use these commands.
### Common Commands
This is a rough tierlist of commands that are useful in datapack development.
Command | Description | Permission | Impact/Usage
--- | --- | --- | ---
`/execute` | Executes another command from a specific entity or location, with arbitrary conditions. | Datapacks/Operators | Very High
`/scoreboard` | Manages scores and scoreboards. | Datapacks/Operators | Very High
`/tag` | Adds or removes tags from an entity. | Datapacks/Operators | Very High
`/data` | Modifies the data of an entity.| Datapacks/Operators | Very High
`/tp` | Teleports an entity. | Datapacks/Operators | High
`/trigger` | Runs a custom trigger scoreboard, if enabled. | Anyone | High
`/function` | Runs a function. | Datapacks/Operators | High
`/team` | Manages teams. | Datapacks/Operators | High
`/tellraw` | Sends a player a text message. | Datapacks/Operators | High
`/reload` | Refreshes all datapacks. | Operators Only| High
`/schedule` | Schedules a function to be called after a delay. | Datapacks/Operators | High
`/summon` | Summons an entity. | Datapacks/Operators | High
`/advancement` | Grants or revokes advancements. | Datapacks/Operators | High
`/attribute` | Modifies attributes. | Datapacks/Operators | High
`/clear` | Clears a player's inventory. | Datapacks/Operators | High
`/give` | Gives an item to a player. | Datapacks/Operators | High
`/item` | Replaces or modifies an item. | Datapacks/Operators | High
`/kill` | Kills an entity. | Datapacks/Operators | High
`/bossbar` | Displays a boss bar. | Datapacks/Operators | Medium
`/loot` | Simulates the looting of a mob, chest, etc. | Datapacks/Operators | Medium
`/particle` | Creates a particle. | Datapacks/Operators | Medium
`/playsound` | Plays a sound. | Datapacks/Operators | Medium
`/title` | Displays a title message. | Datapacks/Operators | Medium
`/setblock` | Places a block. | Datapacks/Operators | Low
`/effect` | Gives an entity an effect. | Datapacks/Operators | Low
`/time` | Modifies the world time. | Datapacks/Operators | Low
`/weather` | Modifies the weather. | Datapacks/Operators | Low
`/xp` | Modifies a player's xp. | Datapacks/Operators | Low
`/gamemode` | Changes a player's gamemode. | Datapacks/Operators | Low
`/stopsound` | Stops a sound. | Datapacks/Operators | Low
`/spawnpoint` | Sets a player's spawn point. | Datapacks/Operators | Low
`/spreadplayers` | Randomly spreads entities in a certain area. | Datapacks/Operators | Low
`/gamerule` | Modifies a gamerule. | Datapacks/Operators | Low
`/datapack` | Enables or disables datapacks. | Operators Only | Low
`/difficulty` | Changes the difficulty. | Datapacks/Operators | Low
`/fill` | Fills an area with a certain block. | Datapacks/Operators | Low
`/clone` | Clones an area. | Datapacks/Operators | Low
### Selectors
*[Read more](https://minecraft.fandom.com/wiki/Target_selectors)*
Selectors are used to **select** entities for various commands. These can also be replaced with a **player's name** or **entity UUID** in many cases; however since neither of these are usually known at runtime, more general selectors must be used. The five main types are as follows:
- **@s**: The entity running this command.
- **@a**: All players.
- **@p**: The nearest player from the entity running this command.
- **@r**: A random player.
- **@e**: All entities.
These can then be augmented with **arguments** that are written between square brackets `[]`. For example, to select all Creepers, you can write `@e[type=creeper]`. Note that `@a[type=creeper]` would not work here, since `@a` means all players, and no player is of type creeper. Useful selectors include:
- `type=<string>`: Selects only entities of a certain type. Players can be selected with `type=player`, though using `@a` is usually better.
- `tag=<string>`: Selects entity only if they have a certain tag.
- `gamemode=<string>`: Filters by gamemode.
- `distance=<range>`: Selects all entities within a certain radius. This uses a **range**, which can be:
- An exact value, such as `3`
- A min and a max (both inclusive), such as `1..5`
- A min or a max, such as `..5` or `6..`
- Floats (decimal points) are also allowed in this case.
- `limit=<integer>`: Limits the selection to **up to** the given number of selections. For example, `limit=1` will only select one entity, even if multiple entities would match the other conditions. You can use the `sort` argument to control which one is selected first.
- `sort=<string>`: Determines a sort order for how to select entities. The default is `arbitrary`, which is the most efficient but is (somewhat) random. The other options are:
- `nearest`: Sort by increasing distance.
- `furthest`: Sort by decreasing distance.
- `random`: Sort randomly.
- A combination such as `@e[type=creeper,limit=1,sort=nearest]` can be very useful in selecting *only the single closest* creeper.
Some selectors can be **inverted** using the `!` character. to select all entities that do not fulfill the condition. For example, you can use `@e[type=!creeper]` to select all entities that are not creepers, or `@a[gamemode=!spectator]` to select all players that are not in spectator mode.
### Relative Coordinates
The normal syntax for the `/tp` command is `/tp <x> <y> <z>`. Needing to input exact coordinates (such as `/tp 0 60 0`) is not ideal for a datapack that needs to work on every world, so we can instead use **relative coordinates**. By using the tilde `~` character, you can specify a location **relative** to where your command is being executed. For example, `tp ~ ~5 ~` would teleport yourself 5 blocks upwards, while keeping your x and z axis the same.
There are also **angular relative coordinates** which use the carrot `^` character instead and are based on the entity's orientation. For example, `tp ^ ^ ^3` would teleport yourself 3 blocks in the direction you are facing.
### Tags
**Tags** are **strings** that any entity can be tagged with. The `/tag` command can add or remove **tags** from an entity. You can then use selectors such as `@e[tag=a]` to select all entities with the tag "a". You can also invert this selection with `@e[tag=!b]` which selects all entities *without* the tag "b". Notably, if `/tag <selector> remove <tag>` is used on an entity that does not have the tag, there will be no effect. However, this means `tag @a remove ATag` has the same effect as `tag @a[tag=ATag] remove ATag`, though the first option is **more efficient** since it does not have to check for the tag's existence.
### Scoreboards
Scoreboards are **entity to integer** maps that can store an integer value for any entity. You can create a scoreboard with `/scoreboard objectives add <name> <objective>`. Notably, scoreboards can be attached to an **objective**, which is a certain in-game statistic such as **health**, **number of deaths**, **oak logs mined**, **cows killed**, etc. This will mean the scoreboard will automatically update whenever one of these statistics change. However, it will not take into account the statistic *before* the scoreboard was created--if the player kills 10 cows before a scoreboard tracking cow kills is created, they will start at 0. The next time they kill a cow, it will increment to 1.
Scoreboards can also be attached to a **dummy** objective, which means they will only change due to commands. Scoreboards are useful for a variety of operations since they have more range (any number) than tags (only string existence); you can use them to count how many times a player has performed a certain action, how many ticks it has been since they began an action, etc. You can also perform certain **mathematical** operations to add, subtract, multiply, divide, or modulo scoreboards together. Scores can be compared using the `/execute` statement or a selector.
### The `execute` Command
*[Read more](https://minecraft.fandom.com/wiki/Commands/execute)*
Commands have two kinds of sources: The **executor**, which is the entity executing the command, and the **position**, which is the coordinate location where the command is executed. The `/execute` command can be used to change **either** of these independently.
To change the **executor**, use `/execute as <selector> run <command>`. This will change the entity currently running the command (or in other words, which entity the `@s` selector points to). Note you can use this to run commands on **multiple** entities. For example, `/say hi` by itself would just make yourself say "hi". However, `/execute as @e[type=creeper] run say hi` would make **all Creepers** say "hi", and likely flood your chat.
To change the **position**, use `/execute at <selector> run <command>`. This will change the location of the command to **the location of the entity**. You can also use `/execute positioned <x> <y> <z>` to execute a command from exact (or relative) coordinates, though this is used less often. The **position** affects all relative coordinates in the command.
For example, what do you think `/execute as @e[type=creeper] run tp @s ~ ~5 ~` would do? Because the command `/tp @s ~ ~5 ~` is being run **as** all creepers, `@s` means each creeper. Therefore, you might think that this command would make all creepers teleport 5 blocks upwards. However, **this is not the case** because relative coordinates are still based on **you**, since you ran the command. Therefore, this command would actually teleport all creepers 5 blocks above **you** (yikes!).
On the other hand, `/execute at @e[type=creeper] run tp @s ~ ~5 ~` would have a weird effect. `@s` still refers to you, but `~ ~5 ~` now refers to 5 blocks above...every creeper? This will actually teleport you to 5 blocks above every creeper's location **one at a time**, so you will eventually end 5 blocks above an **arbitrary** creeper's head (you could use the `sort` argument to make this more consistent).
We can combine both `as` and `at` to make the command `execute as @e[type=creeper] at @s run tp @s ~ ~5 ~`. Note how by putting `as` first, `@s` already refers to each creeper, thus we do not have to say `@e[type=creeper]` twice. To re-iterate, `execute as @e[type=creeper]` will make **each creeper** run the same command. Therefore, each creeper will run `(execute) at @s run tp @s ~ ~5 ~`. The position of the command will be set to themselves with `at @s`, and then the tp command will make the creeper teleport 5 blocks above itself. In summary, this command will make **each creeper** teleport **5 blocks above itself!**
Finally, `execute` also has an `if` and `unless` option, which can be used as conditional statements similar to **selector arguments**. There are also many other options that can be found on the wiki link above. This is one of the most complex and useful commands for datapack development!
### Functions
Now that you've been introduced to how commands work, **function** files are special files that end in `.mcfunction` that contain **one command** per line. When run with the `/function` command, it will execute all commands in that file **in order**. The syntax of these commands is **exactly the same** as normal commands, except they do not contain a **slash** in front (since it can be assumed that all statements are commands). In addition, they allow for **comments** on their own line--any line starting with a pound `#` character will be ignored by the game, and can be used to write comments.
### Other Datapack Components
Functions exist in datapacks, but they're not the only things that datapacks can store. Other datapack features include:
- Custom **recipes**
- Custom **loot tables**
- Block, Entity, and Item **tags**: Allow you to group together blocks, entities, and items and refer to them with a single tag instead of needing to list each one explicitly. These are very useful for selecting more than one kind of entity in a selector. Not to be confused with **selector tags**, which are managed with the `/tag` command, nor **NBT tags**.
- Custom **advancements** that can be used to trigger functions and act as an "event listener" system.
- Custom **dimensions**, **structures**, and **worldgen** (!) though these aren't as useful for vanilla-style servers.
## Conventions and Patterns
This section will likely be easier to understand once you have actually started creating datapacks.
### Naming conventions
- Datapacks: Id (namespace) differs from name of datapack. Should follow `dc_what_case`
- Scoreboards: `dc_camelCase` unless it's a user-facing trigger scoreboard (for custom commands)
- Tags: `dc_camelCase` (note that tags have a character limit)
- We want to prepend `dc_` as often as possible to avoid conflicting with other datapacks.
### Limit @e and @a
- @e is a very expensive selector, try to use it as little as possible
- If you are using the same selector twice, you should probably use a function instead of separate lines
- DrakonCore features several functions that already run on every entity, you can take advantage of these to avoid the need to sort through them again
### Use `/execute if` instead of selector arguments where possible
- Checking score
- Checking predicates
- Useful for checking NBT and various other properties
- Predicates are one of the most efficient methods of checking
### Avoid tag leakage
- A common pattern is to tag an entity based on a condition, then run commands on the entity.
- Make sure to remove the tag once you're done, so the tag doesn't stay there forever!
- Entities should have **as few tags as possible** on them at once
### Choose update speed wisely
- DrakonCore allows multiple update speeds: every tick (20 times per second), every 5 ticks (4 times per second), every 20 ticks (every second), and every 100 ticks (every 5 seconds).
- This can have a high impact on performance, so try to make it as slow of an update speed as possible without sacrificing responsiveness.
### Only compare partial UUIDs
It may be occasionally useful to check for a matching UUID. According to the [Minecraft wiki](https://minecraft.fandom.com/wiki/Entity#Data_values), this is stored as an array of 4 integers in an entity's NBT. To check for an *exact* match, all 4 components must be stored and compared, which can make UUID checking slow. Instead, we prefer to only store & compare the first UUID component, like the following:
```
execute store result score @s dc_temp_id run data get entity @s UUID[0]
```
Note this is the primary intended use of the `dc_temp_id` scoreboard, and no other scoreboards should be used. By definition (and according to this [Stack Overflow](https://stackoverflow.com/questions/51228450/partial-uuids-a-good-idea) post), this is no longer guaranteed to be *universally unique*. However, even this subset of the UUID is sufficient to differentiate entities on a small scale, especially when comparing player IDs on small servers (which is the target audience of our datapacks). While this makes UUID checking much faster, it's good to know that it doesn't work at scale and really only works best when comparing player UUIDs.
# DrakonCore
## Overview
### Admin Tag
`dc_admin`
Datapacks cannot inherently recognize admins set by plugins or operators, so this tag is used instead
Required to use the config command and see when the datapack has been reloaded
## Scoreboards
| Scoreboard | Type | Purpose |
| --- | --- | --- |
| `dc_value` | dummy | Used to store any arbitrary value. Also useful as the default scoreboard for fake players to store values.
| `dc_temp_id` | dummy | Used to store UUID-related information of an entity.
| `dc_xPos` | dummy | Used to store the x position of an entity.
| `dc_yPos` | dummy | Used to store the y position of an entity.
| `dc_zPos` | dummy | Used to store the z position of an entity.
| `dc_health` | health | Fun scoreboard that displays current health. If set to display below the nametag, it appears nicely as a heart symbol.
| `dc_deathCount` | deathCount | Fun scoreboard that tracks total deaths.
| `dc_playerKills` | playerKillCount | Fun scoreboard that tracks total player kills.
| `help` | trigger | Command that prints out all possible custom commands.
| `mods` | trigger | Command that prints out all currently loaded datapacks.
| `config` | trigger | Admin-only command that displays the config menu where admins can configure datapack settings.
| `dc_login` | minecraft.leave_game | Internally used for the `drakoncore:player_login` hook, do not manipulate.
| `dc_recentDeath` | deathCount | Internally used for the `drakoncore:on_player_death` hook, do not manipulate.
## Hooks
### Summary
| Hook | Function |
| --- | --- |
| `drakoncore:init` | Run when loading the datapack |
| `drakoncore:tick` | Runs 20 times per second globally |
| `drakoncore:tick5` | Runs 4 times per second globally |
| `drakoncore:tick20` | Runs once every second globally |
| `drakoncore:tick100` | Runs once every 5 seconds globally |
| `drakoncore:check_command` | Check for a command |
| `drakoncore:help_list` | Display help submenu |
| `drakoncore:help` | When help command is run |
| `drakoncore:config_list` | Display config submenu |
| `drakoncore:config` | When config command is run |
| `drakoncore:mod_info` | Display mod info |
| `drakoncore:player_tick` | Runs 20 times per second on each player |
| `drakoncore:player_tick5` | Runs 4 times per second on each player |
| `drakoncore:player_tick20` | Runs once per second on each player |
| `drakoncore:player_tick100` | Runs once every 5 seconds on each player |
| `drakoncore:entity_tick` | Runs 20 times per second on each entity |
| `drakoncore:entity_tick5` | Runs 4 times per second on each entity |
| `drakoncore:entity_tick20` | Runs once per second on each entity |
| `drakoncore:entity_tick100` | Runs once every 5 seconds on each entity |
| `drakoncore:player_login` | Run when a player logs in |
| `drakoncore:check_crafting` | Run when checking for a custom crafting |
| `drakoncore:on_player_death` | Run when a player dies |
| `drakoncore:on_mob_spawn/any` | When a mob spawns, does not include other entities or players |
| `drakoncore:on_mob_spawn/zombie` | When a zombie spawns |
### init
# Creating a New Datapack with DrakonCore
# DrakonCore Datapack Conventions
## Item Names and Lore
* All text including name should have `{"italic":false}` unless it is a flavor quote.
## Name
* Color should be based on rarity:
* Common: No color
* Uncommon: Green
* Something that is not easily craftable.
* Rare: Blue
* Epic: Purple
* Rare crafting materials.
* Legendary: Gold
* Unique or hard to obtain items.
### Lore
* Max line length: 30 characters.
* Lore color should generally be based on purpose:
* **Default/Flavor**: `light_purple`
* **Gameplay**: `blue`
* **Flavor Quote**: `light_gray`
* **Status/Group**: `purple`
* "Unique Item"
* "Lore Item"
* There should be a new line in between each "section".