-
Notifications
You must be signed in to change notification settings - Fork 94
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add a guide for Custom Enchantments #134
Open
krizh-p
wants to merge
20
commits into
FabricMC:main
Choose a base branch
from
krizh-p:customEnchantments
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 16 commits
Commits
Show all changes
20 commits
Select commit
Hold shift + click to select a range
2b062a2
finished the guide for custom enchantment effects
krizh-p 77ef839
Merge branch 'main' into customEnchantments
krizh-p 5c50c74
addressed markdownlint issues
krizh-p 5ee87ca
Update develop/items/custom-enchantment-effects.md
krizh-p 718d2d8
Update develop/items/custom-enchantment-effects.md
krizh-p ada2148
Update develop/items/custom-enchantment-effects.md
krizh-p 2c63d0d
small fixes
krizh-p 6be0c87
Merge branch 'customEnchantments' of https://github.com/krizh-p/fabri…
krizh-p fc94b8e
fixed everything mentioned in the review
krizh-p afb8c57
changed the entrypoint for the enchantment effects
krizh-p cf940fa
Apply suggestions from code review
krizh-p 069653c
Merge branch 'main' into customEnchantments
krizh-p ac72015
Merge branch 'main' into customEnchantments
krizh-p 4e9dc98
Merge branch 'main' into customEnchantments
krizh-p 390a8d9
Apply suggestions from code review
IMB11 fd47ad1
resolve conflicts -- Merge branch 'main' into customEnchantments
krizh-p 0416f8c
cropped thunder.webm and replaced println() with LOGGER
krizh-p e15d66c
Merge branch 'main' into customEnchantments
IMB11 6bd1c96
grammar/wording fixes
IMB11 1cc3cb2
Merge branch 'customEnchantments' of https://github.com/krizh-p/fabri…
IMB11 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -0,0 +1,60 @@ | ||||||
--- | ||||||
title: Custom Enchantment Effects | ||||||
description: Learn how to create your enchantment effects. | ||||||
authors: | ||||||
- krizh-p | ||||||
--- | ||||||
|
||||||
# Custom Enchantments {#custom-enchantments} | ||||||
|
||||||
Since 1.21, custom enchantments have taken a "data-driven" approach; while this makes adding simple enchantments (like increasing attack damage) easier and more straightforward, it also complicates creating complex enchantments. This was done by breaking down what enchantments do into _effect components_. | ||||||
|
||||||
An effect component contains code for what special things an enchantment should do. By default, Minecraft supports various effects such as item damage, knockback, experience, and more--however, this guide will focus on creating custom enchantment effects that are not supported by default. | ||||||
|
||||||
**[You are heavily suggested to first determine if the default Minecraft effects will work for your use case before continuing](https://minecraft.wiki/w/Enchantment_definition#Effect_components)**. The rest of the guide will assume you understand how "simple" data-driven enchantments are configured. | ||||||
|
||||||
## Custom Enchantment Effects {#custom-enchantment-effects} | ||||||
|
||||||
Start by creating an `enchantment` folder, and within it create a folder `effect`. Within the `effect` folder, we'll create the `LightningEnchantmentEffect` record. | ||||||
|
||||||
Next, we can create a constructor and override the `EnchantmentEntityEffect` interface methods. We'll also create `CODEC` variable to encode and decode our effect; you can read more about [Codecs here](../codecs). | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
|
||||||
The bulk of our code will go into the `apply()` event, which is called when the criteria for your enchantment to work is met. We'll later configure this Effect to be called when an entity is hit, but for now let's write simple code to strike the target with lightning. | ||||||
|
||||||
@[code transcludeWith=#entrypoint](@/reference/latest/src/main/java/com/example/docs/enchantment/effect/LightningEnchantmentEffect.java) | ||||||
|
||||||
Here the `amount` variable indicates a value scaled to the level of the enchantment. We can use this to modify how effective the enchantment is based on level. In the code above, we are using the level of the enchantment to determine how many lightning strikes are spawned. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
|
||||||
## Registering the Enchantment Effect {#registering-the-enchantment-effect} | ||||||
|
||||||
Like every other component of your mod, we'll have to add this EnchantmentEffect to Minecraft's registry. To do so, add a class `ModEnchantmentEffects` (or whatever you want to name it) and a helper method to register the enchantment. Be sure to call the `registerModEnchantmentEffects()` in your main class which contains the `onInitialize()` method. | ||||||
|
||||||
@[code transcludeWith=#entrypoint](@/reference/latest/src/main/java/com/example/docs/enchantment/ModEnchantmentEffects.java) | ||||||
its-miroma marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
|
||||||
## Creating the Enchantment {#creating-the-enchantment} | ||||||
|
||||||
Now we have an enchantment effect! Lastly, we'll create an enchantment to apply our custom effect to. This can be done by creating a JSON file like in datapacks, however, in this guide we'll generate the JSON dynamically using Fabric's data generation tools. To start, create an `EnchantmentGenerator` class. | ||||||
|
||||||
Within this class, we'll first register a new enchantment, and then use the `configure()` method to create our JSON programmatically. | ||||||
|
||||||
@[code transcludeWith=#entrypoint](@/reference/latest/src/main/java/com/example/docs/data/EnchantmentGenerator.java) | ||||||
|
||||||
Before proceeding, you should ensure your project is configured for data generation; if you are unsure, [view the respective wiki page](https://fabricmc.net/wiki/tutorial:datagen_setup). | ||||||
|
||||||
Lastly, we must tell our mod to add our `EnchantmentGenerator` to the list of data generation tasks. To do so, simply add the `EnchantmentGenerator` to this inside of the `onInitializeDataGenerator` class. | ||||||
|
||||||
@[code transcludeWith=#initdatagen](@/reference/latest/src/main/java/com/example/docs/FabricDocsReferenceDataGenerator.java) | ||||||
|
||||||
Now, when you run your mod's data generation task, enchantment JSONs will be generated inside the `generated` folder. An example can be seen below: | ||||||
|
||||||
@[code](@/reference/latest/src/main/generated/data/fabric-docs-reference/enchantment/thundering.json) | ||||||
|
||||||
You should also add translations to your `en_us.json` file to give your enchantment a readable name: | ||||||
|
||||||
```json | ||||||
"enchantment.FabricDocsReference.thundering": "Thundering", | ||||||
``` | ||||||
|
||||||
You should now be able to see our enchantment by running the Client task and opening up Minecraft. | ||||||
|
||||||
<VideoPlayer src="/assets/develop/enchantment-effects/thunder.webm" title="Using the Lightning Effect" /> | ||||||
krizh-p marked this conversation as resolved.
Show resolved
Hide resolved
|
Binary file not shown.
2 changes: 2 additions & 0 deletions
2
reference/latest/src/main/generated/.cache/2f57c34eab409e8d6afbf3588c9395cda8694422
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
// 1.21 2024-07-09T13:17:21.830983 Fabric docs reference/null | ||
b0b8d77fe2f55934f146827951450686de077dac data\fabric-docs-reference\enchantment\thundering.json |
36 changes: 36 additions & 0 deletions
36
reference/latest/src/main/generated/data/fabric-docs-reference/enchantment/thundering.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
{ | ||
"anvil_cost": 5, | ||
"description": { | ||
"translate": "enchantment.fabric-docs-reference.thundering" | ||
}, | ||
"effects": { | ||
"minecraft:post_attack": [ | ||
{ | ||
"affected": "victim", | ||
"effect": { | ||
"type": "fabric-docs-reference:lightning_effect", | ||
"amount": { | ||
"type": "minecraft:linear", | ||
"base": 0.4, | ||
"per_level_above_first": 0.2 | ||
} | ||
}, | ||
"enchanted": "attacker" | ||
} | ||
] | ||
}, | ||
"max_cost": { | ||
"base": 1, | ||
"per_level_above_first": 15 | ||
}, | ||
"max_level": 3, | ||
"min_cost": { | ||
"base": 1, | ||
"per_level_above_first": 10 | ||
}, | ||
"slots": [ | ||
"hand" | ||
], | ||
"supported_items": "#minecraft:enchantable/weapon", | ||
"weight": 10 | ||
} |
1 change: 0 additions & 1 deletion
1
reference/latest/src/main/generated/data/minecraft/tags/damage_type/bypasses_armor.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,4 @@ | ||
{ | ||
"replace": false, | ||
"values": [ | ||
"fabric-docs-reference:tater" | ||
] | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
75 changes: 75 additions & 0 deletions
75
reference/latest/src/main/java/com/example/docs/data/EnchantmentGenerator.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
package com.example.docs.data; | ||
|
||
import java.util.concurrent.CompletableFuture; | ||
|
||
import net.minecraft.component.EnchantmentEffectComponentTypes; | ||
import net.minecraft.component.type.AttributeModifierSlot; | ||
import net.minecraft.enchantment.Enchantment; | ||
import net.minecraft.enchantment.EnchantmentLevelBasedValue; | ||
import net.minecraft.enchantment.effect.EnchantmentEffectTarget; | ||
import net.minecraft.registry.RegistryKey; | ||
import net.minecraft.registry.RegistryKeys; | ||
import net.minecraft.registry.RegistryWrapper; | ||
import net.minecraft.registry.tag.ItemTags; | ||
import net.minecraft.util.Identifier; | ||
|
||
import net.fabricmc.fabric.api.datagen.v1.FabricDataOutput; | ||
import net.fabricmc.fabric.api.datagen.v1.provider.FabricDynamicRegistryProvider; | ||
import net.fabricmc.fabric.api.resource.conditions.v1.ResourceCondition; | ||
|
||
import com.example.docs.FabricDocsReference; | ||
import com.example.docs.enchantment.effect.LightningEnchantmentEffect; | ||
|
||
//#entrypoint | ||
public class EnchantmentGenerator extends FabricDynamicRegistryProvider { | ||
public static final RegistryKey<Enchantment> THUNDERING = EnchantmentGenerator.of("thundering"); | ||
|
||
public EnchantmentGenerator(FabricDataOutput output, CompletableFuture<RegistryWrapper.WrapperLookup> registriesFuture) { | ||
super(output, registriesFuture); | ||
System.out.println("REGISTERING ENCHANTS"); | ||
} | ||
|
||
@Override | ||
protected void configure(RegistryWrapper.WrapperLookup registries, Entries entries) { | ||
// Our new enchantment, "Thundering." | ||
register(entries, THUNDERING, Enchantment.builder( | ||
Enchantment.definition( | ||
registries.getWrapperOrThrow(RegistryKeys.ITEM).getOrThrow(ItemTags.WEAPON_ENCHANTABLE), | ||
// this is the "weight" or probability of our enchantment showing up in the table | ||
10, | ||
// the maximum level of the enchantment | ||
3, | ||
// base cost for level 1 of the enchantment, and min levels required for something higher | ||
Enchantment.leveledCost(1, 10), | ||
// same fields as above but for max cost | ||
Enchantment.leveledCost(1, 15), | ||
// anvil cost | ||
5, | ||
// valid slots | ||
AttributeModifierSlot.HAND | ||
) | ||
) | ||
.addEffect( | ||
krizh-p marked this conversation as resolved.
Show resolved
Hide resolved
|
||
// enchantment occurs POST_ATTACK | ||
EnchantmentEffectComponentTypes.POST_ATTACK, | ||
EnchantmentEffectTarget.ATTACKER, | ||
EnchantmentEffectTarget.VICTIM, | ||
new LightningEnchantmentEffect(EnchantmentLevelBasedValue.linear(0.4f, 0.2f)) // scale the enchantment linearly. | ||
) | ||
); | ||
} | ||
|
||
private void register(Entries entries, RegistryKey<Enchantment> key, Enchantment.Builder builder, ResourceCondition... resourceConditions) { | ||
entries.add(key, builder.build(key.getValue()), resourceConditions); | ||
} | ||
|
||
private static RegistryKey<Enchantment> of(String path) { | ||
Identifier id = Identifier.of(FabricDocsReference.MOD_ID, path); | ||
return RegistryKey.of(RegistryKeys.ENCHANTMENT, id); | ||
} | ||
|
||
@Override | ||
public String getName() { | ||
return "ReferenceDocEnchantmentGenerator"; | ||
} | ||
} |
10 changes: 10 additions & 0 deletions
10
...ce/latest/src/main/java/com/example/docs/enchantment/FabricDocsReferenceEnchantments.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
package com.example.docs.enchantment; | ||
|
||
import net.fabricmc.api.ModInitializer; | ||
|
||
public class FabricDocsReferenceEnchantments implements ModInitializer { | ||
@Override | ||
public void onInitialize() { | ||
ModEnchantmentEffects.registerModEnchantmentEffects(); | ||
} | ||
} |
24 changes: 24 additions & 0 deletions
24
reference/latest/src/main/java/com/example/docs/enchantment/ModEnchantmentEffects.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
package com.example.docs.enchantment; | ||
|
||
import com.mojang.serialization.MapCodec; | ||
|
||
import net.minecraft.enchantment.effect.EnchantmentEntityEffect; | ||
import net.minecraft.registry.Registries; | ||
import net.minecraft.registry.Registry; | ||
import net.minecraft.util.Identifier; | ||
|
||
import com.example.docs.FabricDocsReference; | ||
import com.example.docs.enchantment.effect.LightningEnchantmentEffect; | ||
|
||
//#entrypoint | ||
public class ModEnchantmentEffects { | ||
public static MapCodec<LightningEnchantmentEffect> LIGHTNING_EFFECT = register("lightning_effect", LightningEnchantmentEffect.CODEC); | ||
|
||
private static <T extends EnchantmentEntityEffect> MapCodec<T> register(String id, MapCodec<T> codec) { | ||
return Registry.register(Registries.ENCHANTMENT_ENTITY_EFFECT_TYPE, Identifier.of(FabricDocsReference.MOD_ID, id), codec); | ||
} | ||
|
||
public static void registerModEnchantmentEffects() { | ||
System.out.println("Registering EnchantmentEffects for" + FabricDocsReference.MOD_ID); | ||
krizh-p marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
} |
44 changes: 44 additions & 0 deletions
44
.../latest/src/main/java/com/example/docs/enchantment/effect/LightningEnchantmentEffect.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
package com.example.docs.enchantment.effect; | ||
|
||
import com.mojang.serialization.MapCodec; | ||
import com.mojang.serialization.codecs.RecordCodecBuilder; | ||
|
||
import net.minecraft.enchantment.EnchantmentEffectContext; | ||
import net.minecraft.enchantment.EnchantmentLevelBasedValue; | ||
import net.minecraft.enchantment.effect.EnchantmentEntityEffect; | ||
import net.minecraft.entity.Entity; | ||
import net.minecraft.entity.EntityType; | ||
import net.minecraft.entity.LivingEntity; | ||
import net.minecraft.entity.SpawnReason; | ||
import net.minecraft.entity.player.PlayerEntity; | ||
import net.minecraft.server.world.ServerWorld; | ||
import net.minecraft.util.math.BlockPos; | ||
import net.minecraft.util.math.Vec3d; | ||
|
||
//#entrypoint | ||
public record LightningEnchantmentEffect(EnchantmentLevelBasedValue amount) implements EnchantmentEntityEffect { | ||
public static final MapCodec<LightningEnchantmentEffect> CODEC = RecordCodecBuilder.mapCodec(instance -> | ||
instance.group( | ||
EnchantmentLevelBasedValue.CODEC.fieldOf("amount").forGetter(LightningEnchantmentEffect::amount) | ||
).apply(instance, LightningEnchantmentEffect::new) | ||
); | ||
|
||
@Override | ||
public void apply(ServerWorld world, int level, EnchantmentEffectContext context, Entity target, Vec3d pos) { | ||
krizh-p marked this conversation as resolved.
Show resolved
Hide resolved
|
||
if (target instanceof LivingEntity victim) { | ||
if (context.owner() != null && context.owner() instanceof PlayerEntity player) { | ||
float numStrikes = this.amount.getValue(level); | ||
|
||
for (float i = 0; i < numStrikes; i++) { | ||
BlockPos position = victim.getBlockPos(); | ||
EntityType.LIGHTNING_BOLT.spawn(world, position, SpawnReason.TRIGGERED); | ||
} | ||
} | ||
} | ||
} | ||
|
||
@Override | ||
public MapCodec<? extends EnchantmentEntityEffect> getCodec() { | ||
return CODEC; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.