Skip to content

Instantly share code, notes, and snippets.

@Ellivers
Last active December 29, 2024 02:08
Show Gist options
  • Save Ellivers/762822ee452f1beb058f044ec3139d73 to your computer and use it in GitHub Desktop.
Save Ellivers/762822ee452f1beb058f044ec3139d73 to your computer and use it in GitHub Desktop.

Revisions

  1. Ellivers revised this gist May 12, 2024. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion main.md
    Original file line number Diff line number Diff line change
    @@ -84,7 +84,7 @@ Functions in data packs can easily lead to bad performance. Here is a list of so
    "predicate": {
    "equipment": {
    "mainhand": {
    "item": "minecraft:feather"
    "items": "minecraft:feather"
    }
    }
    }
  2. Ellivers revised this gist Jan 11, 2024. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion main.md
    Original file line number Diff line number Diff line change
    @@ -99,7 +99,7 @@ Functions in data packs can easily lead to bad performance. Here is a list of so

    However, predicates will not help if you only use them to check using the `nbt` key.
    This is an example of something that does *not* help performance:
    ```
    ```json
    {
    "condition": "minecraft:entity_properties",
    "entity": "this",
  3. Ellivers revised this gist May 17, 2021. 1 changed file with 11 additions and 9 deletions.
    20 changes: 11 additions & 9 deletions main.md
    Original file line number Diff line number Diff line change
    @@ -2,7 +2,7 @@

    ## Structuring and Consistency

    An organized structure to your data pack's folders and file names always helps you and other people understand your code better and leads to less bugs.
    An organized structure to your data pack's folders and file names always helps you understand your code better and leads to less bugs.
    Place files that have something in common in the same folder, and name them based on what their purpose is.

    Consistency in naming stuff like tags, files, and scores can help keep you sane. Always have a clear structure in place, such as prefixing tag and objective names with your namespace (`namespace.name`) and giving tags different categories (`namespace.entity.name`, `namespace.block.name`).
    @@ -11,7 +11,7 @@ If you are unsure of how a good structure could look, you could take a look at s

    ## Commenting

    Comments are very important and a huge help when working with functions, and any code in general. Ideally, every function should have at least one line of comments in it. A comment is any line that starts with a "#".
    Comments are very important and a huge help when working with functions, as well as any code in general. Ideally, every function should have at least one line of comments in it. A comment is any line that starts with a `#`.

    Here is how I like to structure my comments:

    @@ -31,7 +31,7 @@ command 4

    ## Performance

    Functions in data packs easily lead to bad performance. Here is a list of what you can try to avoid:
    Functions in data packs can easily lead to bad performance. Here is a list of some things to be aware of:

    * **Multiple Entity Selectors**

    @@ -71,7 +71,9 @@ Functions in data packs easily lead to bad performance. Here is a list of what y

    **Predicates**

    Often, NBT checks can be replaced with predicates to improve performance. This is the case for the command above.
    Predicates are JSON files that can be used in combination with commands to check for all kinds of things.

    Often, NBT checks can be replaced with predicates to improve performance. This is the case for the command shown above.

    Here is what a predicate replacing the NBT check above would look like:

    @@ -95,8 +97,8 @@ Functions in data packs easily lead to bad performance. Here is a list of what y
    execute if predicate namespace:path/to/predicate
    ```

    *However,* predicates will not help if you only use them to check using the `nbt` key.
    This is an example of something that does __not__ help performance:
    However, predicates will not help if you only use them to check using the `nbt` key.
    This is an example of something that does *not* help performance:
    ```
    {
    "condition": "minecraft:entity_properties",
    @@ -107,7 +109,7 @@ Functions in data packs easily lead to bad performance. Here is a list of what y
    }
    ```

    Notice how the predicate above only checks for the `nbt` property `OnGround:1b`, and does not use any keys other than `nbt`.
    Notice how the predicate above only checks for the property `OnGround:1b`, and does not use any keys other than `nbt`.
    In this case, it is better to simply check the NBT in the command directly:
    ```mcfunction
    # Check if the executing entity is on the ground
    @@ -118,7 +120,7 @@ Functions in data packs easily lead to bad performance. Here is a list of what y

    Storage is global NBT that can contain anything you want and that can be accessed from anywhere. It is the most performance-friendly option for storing NBT, but is not specific to any entity or block.

    If you either need to modify NBT several times, or check it multiple times and predicates are not applicable, using storage can be a lot more efficient.
    If you need to either modify NBT several times, or check it multiple times while predicates are not applicable, using storage can be a lot more efficient.

    Here is an example:
    ```mcfunction
    @@ -137,7 +139,7 @@ When you need to detect something a player does, like placing a block, first see

    ## Fakeplayers

    "Fakeplayers" are an extremely useful trick to avoid creating big amounts of scoreboard objectives.
    "Fakeplayers" are an extremely useful trick used in order to avoid creating big amounts of scoreboard objectives.
    Simply give a score to a nonexistant player, and you are able to make way more variables using only one objective and no entities.

    Here is an example of what you can do using fakeplayers:
  4. Ellivers revised this gist May 15, 2021. 1 changed file with 6 additions and 4 deletions.
    10 changes: 6 additions & 4 deletions main.md
    Original file line number Diff line number Diff line change
    @@ -116,16 +116,18 @@ Functions in data packs easily lead to bad performance. Here is a list of what y

    **Storage**

    If you either need to write NBT several times, or check it multiple times and predicates are not applicable, using storage can be a lot more efficient.
    Storage is global NBT that can contain anything you want and that can be accessed from anywhere. It is the most performance-friendly option for storing NBT, but is not specific to any entity or block.

    If you either need to modify NBT several times, or check it multiple times and predicates are not applicable, using storage can be a lot more efficient.

    Here is an example:
    ```mcfunction
    # Set the X, Y, and Z coordinates of the executing entity's position
    data modify storage namespace:name Key set from entity @s Pos
    data modify storage namespace:name Key[0] set value 3
    data modify storage namespace:name Key[1] set value 7
    data modify storage namespace:name Key[2] set value 85
    data modify storage namespace:name Key[0] set value 3.0d
    data modify storage namespace:name Key[1] set value 7.0d
    data modify storage namespace:name Key[2] set value 85.0d
    data modify entity @s Pos set from storage namespace:name Key
    ```

  5. Ellivers revised this gist May 15, 2021. 1 changed file with 16 additions and 16 deletions.
    32 changes: 16 additions & 16 deletions main.md
    Original file line number Diff line number Diff line change
    @@ -7,13 +7,13 @@ Place files that have something in common in the same folder, and name them base

    Consistency in naming stuff like tags, files, and scores can help keep you sane. Always have a clear structure in place, such as prefixing tag and objective names with your namespace (`namespace.name`) and giving tags different categories (`namespace.entity.name`, `namespace.block.name`).

    If you're unsure of how a good structure could look, you could take a look at some vanilla assets, such as the lang file or the built-in data pack, as well as get ideas from looking at data packs that other people have made.
    If you are unsure of how a good structure could look, you could take a look at some vanilla assets, such as the lang file or the built-in data pack, as well as get ideas from looking at data packs that other people have made.

    ## Commenting

    Comments are very important and a huge help when working with functions, and any code in general. Ideally, every function should have at least one line of comments in it. A comment is any line that starts with a "#".

    Here's how I like to structure my comments:
    Here is how I like to structure my comments:

    ```mcfunction
    # Called by namespace:path/to/function
    @@ -42,26 +42,26 @@ Functions in data packs easily lead to bad performance. Here is a list of what y

    function1:
    ```mcfunction
    # Executes as all pigs that have the "mytag" tag
    execute as @e[type=minecraft:pig,tag=mytag] run function namespace:function2
    # Executes as all pigs that have the "namespace.mytag" tag
    execute as @e[type=minecraft:pig,tag=namespace.mytag] run function namespace:function2
    ```

    function2:
    ```mcfunction
    # Called by namespace:function1
    # Does things as all pigs that have the "mytag" tag
    # Runs commands as all pigs that have the "namespace.mytag" tag
    say My name is @s
    kill @s
    say ouch
    ```

    **@a** is another selector that selects multiple entities.
    However, it only selects players, and there are usually not nearly as many players as general entities in a world, so it doesn't contribute to lag as much. However, if you have a lot of `@a` selectors you should still be splitting them into `@s`, the same way you do with `@e`.
    It only selects players, and there are usually not nearly as many players as general entities in a world, so it does not contribute to lag as much as `@e`. However, if you have a lot of `@a` selectors you should still be splitting them into `@s`, the same way you do with `@e`.

    * **NBT Checks**

    Checking for NBT data hurts peformance quite a lot, and is something that you should use as little as possible.
    Checking for NBT data hurts performance quite a lot, and is something that you should avoid as much as possible.

    Example of a bad NBT check:
    ```mcfunction
    @@ -73,7 +73,7 @@ Functions in data packs easily lead to bad performance. Here is a list of what y

    Often, NBT checks can be replaced with predicates to improve performance. This is the case for the command above.

    Here's what a predicate replacing the NBT check above would look like:
    Here is what a predicate replacing the NBT check above would look like:

    ```json
    {
    @@ -96,7 +96,7 @@ Functions in data packs easily lead to bad performance. Here is a list of what y
    ```

    *However,* predicates will not help if you only use them to check using the `nbt` key.
    This is an example of something that does __not__ help:
    This is an example of something that does __not__ help performance:
    ```
    {
    "condition": "minecraft:entity_properties",
    @@ -107,7 +107,7 @@ Functions in data packs easily lead to bad performance. Here is a list of what y
    }
    ```

    Notice how the predicate above only checks for the `nbt` property `OnGround:1b`, and doesn't use any other keys than `nbt`.
    Notice how the predicate above only checks for the `nbt` property `OnGround:1b`, and does not use any keys other than `nbt`.
    In this case, it is better to simply check the NBT in the command directly:
    ```mcfunction
    # Check if the executing entity is on the ground
    @@ -116,9 +116,9 @@ Functions in data packs easily lead to bad performance. Here is a list of what y

    **Storage**

    If you either need to write NBT several times, or check it multiple times and predicates aren't applicable, using storage can be a lot more efficient.
    If you either need to write NBT several times, or check it multiple times and predicates are not applicable, using storage can be a lot more efficient.

    Here's an example:
    Here is an example:
    ```mcfunction
    # Set the X, Y, and Z coordinates of the executing entity's position
    @@ -131,14 +131,14 @@ Functions in data packs easily lead to bad performance. Here is a list of what y

    ## Advancements

    When you need to detect something a player does, like placing a block, first see if that is something an advancement can detect, instead of creating a scoreboard objective for it or perhaps running a check every tick for it. Advancements are extremely useful and powerful, as they don't cause any lag (with the exception of the `tick` advancement trigger) and can be used to run a function when something happens.
    When you need to detect something a player does, like placing a block, first see if that is something an advancement can detect, instead of creating a scoreboard objective for it or perhaps running a check for it every tick. Advancements are very useful and powerful, as they do not cause any lag (with the exception of the `tick` advancement trigger) and can be used to run a function when something happens.

    ## Fakeplayers

    "Fakeplayers" are an extremely useful trick to avoid creating big amounts of scoreboard objectives.
    Simply give a score to a nonexistant player and you're able to make way more variables using only one objective and no entities.
    Simply give a score to a nonexistant player, and you are able to make way more variables using only one objective and no entities.

    Here's an example of what you can do using fakeplayers:
    Here is an example of what you can do using fakeplayers:
    ```mcfunction
    # Do some math
    @@ -148,5 +148,5 @@ scoreboard players operation #variable1 objective *= #five objective
    scoreboard players operation #variable2 objective += #variable1 objective
    ```

    Notice how the fakeplayer names are prefixed with `#`. This isn't needed, but it makes sure that the fakeplayer's name can't happen to be the same as a real player's name, since real players can't have `#` in their name.
    Notice how the fakeplayer names are prefixed with `#`. This is not needed, but it makes sure that the fakeplayer's name can't happen to be the same as a real player's name, since real players can't have `#` in their name.
    Fakeplayers are global and not applicable if you need to tie a score to an entity.
  6. Ellivers revised this gist May 15, 2021. 1 changed file with 2 additions and 2 deletions.
    4 changes: 2 additions & 2 deletions main.md
    Original file line number Diff line number Diff line change
    @@ -35,8 +35,8 @@ Functions in data packs easily lead to bad performance. Here is a list of what y

    * **Multiple Entity Selectors**

    **@e** is an essential selector as it is able to select all entities, but it also a huge reason for command lag.
    Therefore, it should be avoided in large quantities as much as possible. If you execute a function as an entity, you can use the `@s` selector for that entity, which is the selector you should be using the most.
    **@e** is an essential selector as it is able to select all entities, but it is also a huge reason for command lag.
    Therefore, it should be avoided in large quantities as much as possible. If you execute a function as an entity, you can then use the `@s` selector to refer to that entity. `@s` is the selector you should be using the most.

    Example of splitting an `@e` selector into multiple `@s`:

  7. Ellivers revised this gist May 15, 2021. 1 changed file with 5 additions and 3 deletions.
    8 changes: 5 additions & 3 deletions main.md
    Original file line number Diff line number Diff line change
    @@ -7,7 +7,7 @@ Place files that have something in common in the same folder, and name them base

    Consistency in naming stuff like tags, files, and scores can help keep you sane. Always have a clear structure in place, such as prefixing tag and objective names with your namespace (`namespace.name`) and giving tags different categories (`namespace.entity.name`, `namespace.block.name`).

    If you're unsure of how a good structure could look, you could take a look at some vanilla assets, such as the lang file or the built-in data pack.
    If you're unsure of how a good structure could look, you could take a look at some vanilla assets, such as the lang file or the built-in data pack, as well as get ideas from looking at data packs that other people have made.

    ## Commenting

    @@ -36,7 +36,7 @@ Functions in data packs easily lead to bad performance. Here is a list of what y
    * **Multiple Entity Selectors**

    **@e** is an essential selector as it is able to select all entities, but it also a huge reason for command lag.
    Therefore, it should be avoided as much as possible. If you execute a function as an entity, you can use the `@s` selector for that entity, which is the selector you should be using the most.
    Therefore, it should be avoided in large quantities as much as possible. If you execute a function as an entity, you can use the `@s` selector for that entity, which is the selector you should be using the most.

    Example of splitting an `@e` selector into multiple `@s`:

    @@ -70,6 +70,7 @@ Functions in data packs easily lead to bad performance. Here is a list of what y
    ```

    **Predicates**

    Often, NBT checks can be replaced with predicates to improve performance. This is the case for the command above.

    Here's what a predicate replacing the NBT check above would look like:
    @@ -114,6 +115,7 @@ Functions in data packs easily lead to bad performance. Here is a list of what y
    ```

    **Storage**

    If you either need to write NBT several times, or check it multiple times and predicates aren't applicable, using storage can be a lot more efficient.

    Here's an example:
    @@ -134,7 +136,7 @@ When you need to detect something a player does, like placing a block, first see
    ## Fakeplayers

    "Fakeplayers" are an extremely useful trick to avoid creating big amounts of scoreboard objectives.
    Simply give a score to a nonexistant player and you're able to create way more variables using only one objective and no entities.
    Simply give a score to a nonexistant player and you're able to make way more variables using only one objective and no entities.

    Here's an example of what you can do using fakeplayers:
    ```mcfunction
  8. Ellivers revised this gist May 15, 2021. 1 changed file with 2 additions and 2 deletions.
    4 changes: 2 additions & 2 deletions main.md
    Original file line number Diff line number Diff line change
    @@ -7,7 +7,7 @@ Place files that have something in common in the same folder, and name them base

    Consistency in naming stuff like tags, files, and scores can help keep you sane. Always have a clear structure in place, such as prefixing tag and objective names with your namespace (`namespace.name`) and giving tags different categories (`namespace.entity.name`, `namespace.block.name`).

    If you're unsure of how a good structure could look, you could take a look at some vanilla assets, such as the lang file or the built-in data pack, as well as get ideas from looking at data packs that other people have made.
    If you're unsure of how a good structure could look, you could take a look at some vanilla assets, such as the lang file or the built-in data pack.

    ## Commenting

    @@ -36,7 +36,7 @@ Functions in data packs easily lead to bad performance. Here is a list of what y
    * **Multiple Entity Selectors**

    **@e** is an essential selector as it is able to select all entities, but it also a huge reason for command lag.
    Therefore, it should be avoided in large quantities as much as possible. If you execute a function as an entity, you can use the `@s` selector for that entity, which is the selector you should be using the most.
    Therefore, it should be avoided as much as possible. If you execute a function as an entity, you can use the `@s` selector for that entity, which is the selector you should be using the most.

    Example of splitting an `@e` selector into multiple `@s`:

  9. Ellivers revised this gist May 15, 2021. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion main.md
    Original file line number Diff line number Diff line change
    @@ -36,7 +36,7 @@ Functions in data packs easily lead to bad performance. Here is a list of what y
    * **Multiple Entity Selectors**

    **@e** is an essential selector as it is able to select all entities, but it also a huge reason for command lag.
    Therefore, it should be avoided as much as possible. If you execute a function as an entity, you can use the `@s` selector for that entity, which is the selector you should be using the most.
    Therefore, it should be avoided in large quantities as much as possible. If you execute a function as an entity, you can use the `@s` selector for that entity, which is the selector you should be using the most.

    Example of splitting an `@e` selector into multiple `@s`:

  10. Ellivers revised this gist May 15, 2021. 1 changed file with 2 additions and 2 deletions.
    4 changes: 2 additions & 2 deletions main.md
    Original file line number Diff line number Diff line change
    @@ -7,7 +7,7 @@ Place files that have something in common in the same folder, and name them base

    Consistency in naming stuff like tags, files, and scores can help keep you sane. Always have a clear structure in place, such as prefixing tag and objective names with your namespace (`namespace.name`) and giving tags different categories (`namespace.entity.name`, `namespace.block.name`).

    If you're unsure of how a good structure could look, you could take a look at some vanilla assets, such as the lang file or the built-in data pack.
    If you're unsure of how a good structure could look, you could take a look at some vanilla assets, such as the lang file or the built-in data pack, as well as get ideas from looking at data packs that other people have made.

    ## Commenting

    @@ -36,7 +36,7 @@ Functions in data packs easily lead to bad performance. Here is a list of what y
    * **Multiple Entity Selectors**

    **@e** is an essential selector as it is able to select all entities, but it also a huge reason for command lag.
    Therefore, it should be avoided in large quantities as much as possible. If you execute a function as an entity, you can use the `@s` selector for that entity, which is the selector you should be using the most.
    Therefore, it should be avoided as much as possible. If you execute a function as an entity, you can use the `@s` selector for that entity, which is the selector you should be using the most.

    Example of splitting an `@e` selector into multiple `@s`:

  11. Ellivers revised this gist May 15, 2021. 1 changed file with 2 additions and 2 deletions.
    4 changes: 2 additions & 2 deletions main.md
    Original file line number Diff line number Diff line change
    @@ -7,7 +7,7 @@ Place files that have something in common in the same folder, and name them base

    Consistency in naming stuff like tags, files, and scores can help keep you sane. Always have a clear structure in place, such as prefixing tag and objective names with your namespace (`namespace.name`) and giving tags different categories (`namespace.entity.name`, `namespace.block.name`).

    If you're unsure of how a good structure could look, you could take a look at some vanilla assets, such as the lang file or the built-in data pack, as well as get ideas from looking at data packs that other people have made.
    If you're unsure of how a good structure could look, you could take a look at some vanilla assets, such as the lang file or the built-in data pack.

    ## Commenting

    @@ -36,7 +36,7 @@ Functions in data packs easily lead to bad performance. Here is a list of what y
    * **Multiple Entity Selectors**

    **@e** is an essential selector as it is able to select all entities, but it also a huge reason for command lag.
    Therefore, it should be avoided as much as possible. If you execute a function as an entity, you can use the `@s` selector for that entity, which is the selector you should be using the most.
    Therefore, it should be avoided in large quantities as much as possible. If you execute a function as an entity, you can use the `@s` selector for that entity, which is the selector you should be using the most.

    Example of splitting an `@e` selector into multiple `@s`:

  12. Ellivers revised this gist May 15, 2021. 1 changed file with 2 additions and 4 deletions.
    6 changes: 2 additions & 4 deletions main.md
    Original file line number Diff line number Diff line change
    @@ -7,7 +7,7 @@ Place files that have something in common in the same folder, and name them base

    Consistency in naming stuff like tags, files, and scores can help keep you sane. Always have a clear structure in place, such as prefixing tag and objective names with your namespace (`namespace.name`) and giving tags different categories (`namespace.entity.name`, `namespace.block.name`).

    If you're unsure of how a good structure could look, you could take a look at some vanilla assets, such as the lang file or the built-in data pack.
    If you're unsure of how a good structure could look, you could take a look at some vanilla assets, such as the lang file or the built-in data pack, as well as get ideas from looking at data packs that other people have made.

    ## Commenting

    @@ -70,7 +70,6 @@ Functions in data packs easily lead to bad performance. Here is a list of what y
    ```

    **Predicates**

    Often, NBT checks can be replaced with predicates to improve performance. This is the case for the command above.

    Here's what a predicate replacing the NBT check above would look like:
    @@ -115,7 +114,6 @@ Functions in data packs easily lead to bad performance. Here is a list of what y
    ```

    **Storage**

    If you either need to write NBT several times, or check it multiple times and predicates aren't applicable, using storage can be a lot more efficient.

    Here's an example:
    @@ -136,7 +134,7 @@ When you need to detect something a player does, like placing a block, first see
    ## Fakeplayers

    "Fakeplayers" are an extremely useful trick to avoid creating big amounts of scoreboard objectives.
    Simply give a score to a nonexistant player and you're able to make way more variables using only one objective and no entities.
    Simply give a score to a nonexistant player and you're able to create way more variables using only one objective and no entities.

    Here's an example of what you can do using fakeplayers:
    ```mcfunction
  13. Ellivers revised this gist May 15, 2021. 1 changed file with 3 additions and 1 deletion.
    4 changes: 3 additions & 1 deletion main.md
    Original file line number Diff line number Diff line change
    @@ -70,6 +70,7 @@ Functions in data packs easily lead to bad performance. Here is a list of what y
    ```

    **Predicates**

    Often, NBT checks can be replaced with predicates to improve performance. This is the case for the command above.

    Here's what a predicate replacing the NBT check above would look like:
    @@ -114,6 +115,7 @@ Functions in data packs easily lead to bad performance. Here is a list of what y
    ```

    **Storage**

    If you either need to write NBT several times, or check it multiple times and predicates aren't applicable, using storage can be a lot more efficient.

    Here's an example:
    @@ -134,7 +136,7 @@ When you need to detect something a player does, like placing a block, first see
    ## Fakeplayers

    "Fakeplayers" are an extremely useful trick to avoid creating big amounts of scoreboard objectives.
    Simply give a score to a nonexistant player and you're able to create way more variables using only one objective and no entities.
    Simply give a score to a nonexistant player and you're able to make way more variables using only one objective and no entities.

    Here's an example of what you can do using fakeplayers:
    ```mcfunction
  14. Ellivers created this gist May 15, 2021.
    150 changes: 150 additions & 0 deletions main.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,150 @@
    # Good Data Pack Practices and Common Tricks

    ## Structuring and Consistency

    An organized structure to your data pack's folders and file names always helps you and other people understand your code better and leads to less bugs.
    Place files that have something in common in the same folder, and name them based on what their purpose is.

    Consistency in naming stuff like tags, files, and scores can help keep you sane. Always have a clear structure in place, such as prefixing tag and objective names with your namespace (`namespace.name`) and giving tags different categories (`namespace.entity.name`, `namespace.block.name`).

    If you're unsure of how a good structure could look, you could take a look at some vanilla assets, such as the lang file or the built-in data pack.

    ## Commenting

    Comments are very important and a huge help when working with functions, and any code in general. Ideally, every function should have at least one line of comments in it. A comment is any line that starts with a "#".

    Here's how I like to structure my comments:

    ```mcfunction
    # Called by namespace:path/to/function
    # Short description of what this function does
    # More describing if needed
    # Description of what these commands do
    command 1
    command 2
    # Description of what these commands do
    command 3
    command 4
    ```

    ## Performance

    Functions in data packs easily lead to bad performance. Here is a list of what you can try to avoid:

    * **Multiple Entity Selectors**

    **@e** is an essential selector as it is able to select all entities, but it also a huge reason for command lag.
    Therefore, it should be avoided as much as possible. If you execute a function as an entity, you can use the `@s` selector for that entity, which is the selector you should be using the most.

    Example of splitting an `@e` selector into multiple `@s`:

    function1:
    ```mcfunction
    # Executes as all pigs that have the "mytag" tag
    execute as @e[type=minecraft:pig,tag=mytag] run function namespace:function2
    ```

    function2:
    ```mcfunction
    # Called by namespace:function1
    # Does things as all pigs that have the "mytag" tag
    say My name is @s
    kill @s
    say ouch
    ```

    **@a** is another selector that selects multiple entities.
    However, it only selects players, and there are usually not nearly as many players as general entities in a world, so it doesn't contribute to lag as much. However, if you have a lot of `@a` selectors you should still be splitting them into `@s`, the same way you do with `@e`.

    * **NBT Checks**

    Checking for NBT data hurts peformance quite a lot, and is something that you should use as little as possible.

    Example of a bad NBT check:
    ```mcfunction
    # Check if the executing player is holding a feather
    execute if entity @s[nbt={SelectedItem:{id:"minecraft:feather"}}]
    ```

    **Predicates**
    Often, NBT checks can be replaced with predicates to improve performance. This is the case for the command above.

    Here's what a predicate replacing the NBT check above would look like:

    ```json
    {
    "condition": "minecraft:entity_properties",
    "entity": "this",
    "predicate": {
    "equipment": {
    "mainhand": {
    "item": "minecraft:feather"
    }
    }
    }
    }
    ```

    It could replace the check in the command like this:
    ```mcfunction
    # Check if the executing player is holding a feather
    execute if predicate namespace:path/to/predicate
    ```

    *However,* predicates will not help if you only use them to check using the `nbt` key.
    This is an example of something that does __not__ help:
    ```
    {
    "condition": "minecraft:entity_properties",
    "entity": "this",
    "predicate": {
    "nbt": "{OnGround:1b}"
    }
    }
    ```

    Notice how the predicate above only checks for the `nbt` property `OnGround:1b`, and doesn't use any other keys than `nbt`.
    In this case, it is better to simply check the NBT in the command directly:
    ```mcfunction
    # Check if the executing entity is on the ground
    execute if entity @s[nbt={OnGround:1b}]
    ```

    **Storage**
    If you either need to write NBT several times, or check it multiple times and predicates aren't applicable, using storage can be a lot more efficient.

    Here's an example:
    ```mcfunction
    # Set the X, Y, and Z coordinates of the executing entity's position
    data modify storage namespace:name Key set from entity @s Pos
    data modify storage namespace:name Key[0] set value 3
    data modify storage namespace:name Key[1] set value 7
    data modify storage namespace:name Key[2] set value 85
    data modify entity @s Pos set from storage namespace:name Key
    ```

    ## Advancements

    When you need to detect something a player does, like placing a block, first see if that is something an advancement can detect, instead of creating a scoreboard objective for it or perhaps running a check every tick for it. Advancements are extremely useful and powerful, as they don't cause any lag (with the exception of the `tick` advancement trigger) and can be used to run a function when something happens.

    ## Fakeplayers

    "Fakeplayers" are an extremely useful trick to avoid creating big amounts of scoreboard objectives.
    Simply give a score to a nonexistant player and you're able to create way more variables using only one objective and no entities.

    Here's an example of what you can do using fakeplayers:
    ```mcfunction
    # Do some math
    scoreboard players set #five objective 5
    scoreboard players operation #variable1 objective *= #five objective
    scoreboard players operation #variable2 objective += #variable1 objective
    ```

    Notice how the fakeplayer names are prefixed with `#`. This isn't needed, but it makes sure that the fakeplayer's name can't happen to be the same as a real player's name, since real players can't have `#` in their name.
    Fakeplayers are global and not applicable if you need to tie a score to an entity.