-
Notifications
You must be signed in to change notification settings - Fork 0
2. Introduction to Spells & Spell Trees
This page will go into detail on how data driven spells and spel ltrees work. A good way to understand all of this is to read the introduction followed by the examples. There is also a small "Getting Started" guide at the bottom.
Spell trees are what the name suggests. They are made of nodes that represent entries of spells in the tree. Every spell tree starts with a root node and nodes may have any amount of children nodes attached to them. Once you unlock a node you get access to this node's child nodes and may unlock them as well. It is important to understand that spells can be in multiple spell trees and also multiple times in the same spell tree with different configurations.
Every node in a spell tree has requirements to be able to unlocked together with the cost in xp levels and you having to have the parent unlocked already, of course. These requirements allow you to restrict the unlocking further so the player has to achieve more than just grinding xp. There are two different kinds of requirements, however:
- Hidden requirements must be fulfilled in order to be able to see the spell node in the spell tree at all. If the hidden requirements of the root node are not met then the entire spell tree will not show up for the player.
- Learn requirements must be fulfilled in order to be able to learn the spell once you already see it.
The basic spell trees of this mod barely use hidden requirements as transparency and ease of use was a goal. But this should not stop anyone from finding nice uses for this feature.
Another important aspect is synchronization. Clients do not need to have the same spell tree file contents as the server counter part. Instead, they get synchronized on demand (when the client opens the spell progression menu in the enchantment table). This not only allows servers to change spell trees on demand without clients needing any adjust ments, but also allows servers to hide features of spell trees until they are discovered by the player (eg. by using hidden requirements). So you can give the clients empty spell tree files and then only fill the contents of these files on the server to hide the spell progression to players up to the point they discovered it themselves.
Finally, please understand that you can modify spell trees (which is very easy to do) without having to enter the world of data generated spells which is far more advanced and complex. You can combine any collection of spells and then make your own spell trees out of them without ever directly touching the files of these spells.
This section is about spells. Again, you do not need to work through this if you only intend on editing spell trees.
Important node already: You have the power to make spells however you like. But this also means that you have the power to lag out the server, destroy the world or even in very rare circumstances crash the game (everything is coded in a way that should always avoid crashes but there may have been slight oversights that can result in a crash in very specific circumstances; please report an issue in case this happens).
First we talk about the when and the what (eg. when a spell does something and what it does). Every spell is made up of spell actions that are sequentially executed. These can be anything, eg. the first action picks the entity the spell owner is currently looking at and the second action applies damage to it. Every spell action has an activation defined. Basically, depending on which activation is active spell actions are either executed or ignored. The initial activation that starts the whole execution is also called an event. Events can be eg. active when a spell is activated by its owner, on_equip when a spell is equipped into a spell slot, or on_unequip when a spell is unequipped, respectively, to name a few. Every spell has a list of events it hooks into and events that are not listed in there are ignored. A lot of actions allow you to interact with your own activations like when certain conditions are met or when a timer has run out activation x is activated.
If certain requirements of a spell action are not met then the spell action simply does nothing. Examples are requiring only exactly 1 target inside a target group, requiring specific elements to be set (in JSON) and so on. This is mentioned in the documentation for each spell action type.
Next up we talk about the who and how. Spell actions typically interact with target groups either by basically finding/defining them or by doing something with/to them. These target groups contain targets as the name suggests. There are different kind of target types that are explained below and certain actions find/define/require certain target types, eg. the damage action requires targets of type living_entity (eg. players, cows, zombies, the dragon, but not paintings, armor stands, or projectiles). Some spell actions also require single targets which simply means that there may only be a single target within the target group.
These are all the existing target types:
-
position: Anything in a world that has a position, eg. block positions or entities. -
entity: Entities, eg. Armor Stands, Arrow Projectiles, Thrown Potions, Chickens, Spiders. -
living_entity: Entities with health, eg. Players, Spiders, the Dragon, Sheep. -
player: Players. -
static: Anything in a world that has a static position, eg. block positions. -
item: Items that are usually part of some inventory.
The inheritance chain is as follows (see the first point for explanation):
-
static>position(every target of typestaticis also automatically of typepositionbut not the other way around). -
player>living_entity>entity>position.
Spell actions require you to supply values to configure them. These value types have names that are listed here:
-
int: integers, eg.0,7,-87. -
double: floating point numbers, eg.0.0,1.7,-43.467,2. -
vec3: 3-dimensional vector made of 3doubleelements representing any position or motion in a world. -
boolean: Logical values, eg. eithertrueorfalse. -
tag: NBT compound tags (see Minecraft wiki). -
string: A sequence of characters, eg.'hello','ABCdef123_','Let us also do some Spaces!!'.
The last important concept to talk about are variables. These allow you numerous different things that include defining a variable and its value (of course), using them for spell actions instead of writing direct values, or getting certain values from targets (eg. player health, item count, entity uuid) that are deposited in variables. Almost every value of a spell action allows you to substitute it with a variable. You can also use them to make tiered spells - by defining variables for the entire spell you can set them dependent on their position in a spell tree.
If a spell action has an element that has the prefix d/ you can always subtitute it with a variable. You do that by supplying a string instead of format <<variable_name>>. This prefix also allows you to do in-line math expressions (eg. << a + b >>) which is explained on another page in this wiki.
JSON keys can look overwhelming but they are not hard to grasp and are instead meant to help you without having to constantly look at documentation. Prefixes are delimited by / and the name of the key is always behind the last one.
The prefixes (eg. s1, s2, s3, n1, n2, t1, t2, etc.) are primarily there to order the elements and to help with keeping a proper oversight. They have no meaning except that s is used for Spells, n is used for Spell Nodes, and t is used for Spell Trees.
-
a/: The activation to interact with (eg. enable or disable).- The activation that a spell ations requires to be fired will always just be named
activation
- The activation that a spell ations requires to be fired will always just be named
-
ad/: The delayed activation to interact with.- These types of activations happen after a certain amount of time and restart the entire list of actions from the top (eg. targets and variables are reset)
-
t/: A target group containing a single target to interact with. -
ts/: A target group containing any amount of targets to interact with. -
td/: A target group to add a new target to. You may leave this empty to not add it to any target group. -
d/: Allows you to substitute a value with a variable (see the section about variables) or with an in-line math expression. -
[variable-type]/: Tells you what type is expected. -
var/: The variable to deposit a value in. You may leave this empty to not assign this value to any variable.
This action replenishes mana for all living entities in a given target group by a set amount.
Explanation:
-
d/double/mana_amount: The amount of mana replenished.-
d/: You may substitute this value with a variable. -
double/: Adoublevalue is expected. -
mana_amountThe name of the key (i.e. something that describes it further).
-
-
ts/targets: The target group to replenish mana for.-
ts/: The target group may be of any size. -
targets: The name of the key (i.e. something that describes it further).
-
Delayed spells can be attached to entities. This essentially only means to run a spell with a custom activation for an entity after a set amount of time. This can be used in a lot of ways, one of them being to do something repeatedly by whenever a delayed spell runs after its time ran out you attach another copy to the same entity.
Next, built-in values are explained. These are defined for certain events and circumstances but you can always modify or interact with them however you like (if you edit eg. a variable that came built-in the change will only apply for this context so the next time the spell is fired the variable comes with it's proper value again). Not all of them are listed here as some are only interacting with certain spell actions.
Here are some examples of events (built-in activations):
-
activeactivation: When the spell in a spell slot of a player is fired by pressing the key bind. -
on_equipactivation: When a spell is equipped into a spell slot of a player (eg. when equipping a spell in the spell progression menu). -
on_unequipactivation: When a spell in a spell slot of a player is unequipped or overridden by another spell.
These always come with the following target groups and variables (other events might not come with these):
-
ownertarget group (playertype): The player that has/had this spell equipped. -
spell_slotvariable (inttype): The integer representing the slot the spell was equipped in starting at0.
The following variable always exists no matter the activation:
-
mana_costvariable (doubletype): Contains the set mana cost of a spell.
Note: The mod comes with a bunch of spells that can also serve as examples. You can view them in this repository by going back to the "code" tab and then into: main/src/main/resources/data/spells_and_shields/spells_and_shields/spells.
Let us make a spell that damages the target we are looking at. We are omitting everything except for the spell actions and we also do not include any spell action parameters that are not important for this example right now (this means that this example is not usable just like that and requires minor additions to work like the proper key prefixes):
...
{
"type": "spells_and_shields:look_at_target",
"activation": "active",
"miss_activation": "",
"block_hit_activation": "",
"entity_hit_activation": "looked_at_entity",
"range": 50.0,
"source": "owner"
},
{
"type": "spells_and_shields:simple_mana_check",
"activation": "looked_at_entity",
"target": "owner"
},
{
"type": "spells_and_shields:sourced_damage",
"activation": "looked_at_entity",
"damage": 2.0,
"source": "owner",
"targets": "entity_hit"
},
...These spell actions do the following:
- The first action is activated by
active(firing the spell using a key bind). We try to find an entity the source (the owner of the spell) is looking at. If such an entity exists we enable thelooked_at_entityactivation with the entity automatically being put into theentity_hittarget group. If no such entity was found (theownerdoes not look at an entity but rather at a block or air) then this is not enabled. - Next, if we found such an entity we perform a simple mana check. If the target (
owner) has enough mana then this mana is burned otherwise thelooked_at_entityactivation is automatically disabled. - Finally, if the
looked_at_entityactivation is still active (there was enough mana) we damage the targets (we damageentity_hitwhich is the entity theownerlooked at) withownerbeing the source of the damage.
To summarize:
- We look for the entity the owner is looking at
- If this entity exists we perform the mana check
- If the mana check succeeds we damage the entity
Notes:
- The amount of mana checked and burned is set in the base of the spell and not as part of the action. There are other actions to do this with a custom amount.
- If the entity is not of type
living_entitythen this damage action would simply do nothing. - If we were to do the mana check first then we might burn the mana but then not find an entity to perform the damage on
How to get started making a data pack.
Follow these steps (or alternatively check out the wiki https://minecraft.fandom.com/wiki/Tutorials/Creating_a_data_pack):
- Pick a namespace (only lowercase, numbers and underscore) for your data pack. Eg. the default data pack has namespace
spells_and_shields. - Make a new zip folder. You may name it however you like. The zip folder must have the following structure:
- `<namespace>.zip` ZIP Folder.
| - `pack.mcmeta` file (more about that below).
| - `data` folder
| - `<namespace>` folder
| - `spells_and_shields` folder
| - `spells` folder
| - `spell_trees` folder
- The
pack.mcmetafile must have the following contents:
{
"pack": {
"pack_format": 10,
"description": "spells_and_shields resources"
}
}The pack format may change. See here: https://minecraft.fandom.com/wiki/Tutorials/Creating_a_data_pack#%22pack_format%22
All kinds of tips and recommendations starting with a general section followed by spell trees and spells specific sections.
General tips for data pack making.
Always ask for help. Do not hesitate! Use the official Discord server for this mod: https://discord.gg/3zXwr2atcY
By adding your own resource pack with your own assets in addition to your data pack you can use custom textures for spells and spell trees and also add custom sounds and language translation files. You may put these in your own namespace folder again but make sure you reference them correctly in your data pack (<namespace>:... instead of spells_and_shields: for references). This will not be explained here but there is a wiki page explaining it: https://minecraft.fandom.com/wiki/Tutorials/Creating_a_resource_pack
These tips specifically apply for making of spell trees.
Spell nodes can override the mana cost and the parameters of a spell. If eg. the damage of a spell is set via parameter you can add a spell into a spell tree multiple times with different mana costs and damage for each. This allows you to basically do tiered spells.
These tips specifically apply for making of spells.
This is a big one. If you are making your own spells make sure you enable debugging in the common config (set debugSpells = true). This will constantly (between every spell action) print out all information about the current spell context to the console (also viewable in logs) whenever you fire a spell. This will also make it a lot easier to understand the entire system if you are getting started. If you are on a dedicated server the information is only printed to the server.
However, printing to console lags a lot. So make sure you disable it again and never have this option enabled if players are actually playing with this mod.
If a player has infinitely repeating delayed spell effects on them or a particle emitter that is running for a very long time and this is the result of a mistake do the following:
- Fix the spell that caused this
- Kill the player
Killing the player will always make them get rid of any delayed spells and particle emitters on them.
{ "type": "spells_and_shields:replenish_mana", "activation": String, "d/double/mana_amount": Double, "ts/targets": String },