Skip to content

Commit affbbf9

Browse files
committed
Add item component granting to enchantments.
1 parent f350edb commit affbbf9

18 files changed

Lines changed: 360 additions & 14 deletions

src/main/generated/assets/combat-plus-core/lang/en_us.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@
2424
"tag.enchantment.combat-plus.aspect": "Aspect Enchantments",
2525
"tag.enchantment.combat-plus.offhand": "Offhand Enchantments",
2626
"tag.enchantment.combat-plus.weapon_utility": "Weapon Utility Enchantments",
27-
"tag.item.combat-plus.breaks_shields": "Breaks Shields",
2827
"tag.item.combat-plus.dual_weapon": "Dual Weapons",
2928
"tag.item.combat-plus.enchantable.aspect": "Aspect Enchantable",
3029
"tag.item.combat-plus.enchantable.aspect_primary": "Primary Aspect Enchantable",

src/main/generated/data/combat-plus/tags/item/breaks_shields.json

Lines changed: 0 additions & 12 deletions
This file was deleted.
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
{
2+
"anvil_cost": 2,
3+
"description": {
4+
"translate": "enchantment.minecraft.loyalty"
5+
},
6+
"effects": {
7+
"combat-plus:data_component": [
8+
{
9+
"effect": {
10+
"type": "combat-plus:use_group_component",
11+
"group": "combat-plus:loyalty_trident"
12+
}
13+
}
14+
],
15+
"minecraft:trident_return_acceleration": [
16+
{
17+
"effect": {
18+
"type": "minecraft:add",
19+
"value": {
20+
"type": "minecraft:linear",
21+
"base": 1.0,
22+
"per_level_above_first": 1.0
23+
}
24+
}
25+
}
26+
]
27+
},
28+
"max_cost": {
29+
"base": 50,
30+
"per_level_above_first": 0
31+
},
32+
"max_level": 3,
33+
"min_cost": {
34+
"base": 12,
35+
"per_level_above_first": 7
36+
},
37+
"slots": [
38+
"mainhand"
39+
],
40+
"supported_items": "#minecraft:enchantable/trident",
41+
"weight": 5
42+
}

src/main/java/com/provismet/CombatPlusCore/CPCMain.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package com.provismet.CombatPlusCore;
22

33
import com.provismet.CombatPlusCore.debug.registries.CPCDebugItems;
4+
import com.provismet.CombatPlusCore.registries.CPCDataComponentEffects;
5+
import com.provismet.CombatPlusCore.registries.CPCDataComponentTypes;
46
import com.provismet.CombatPlusCore.registries.CPCEnchantmentComponentTypes;
57
import com.provismet.CombatPlusCore.registries.CPCLootFunctionTypes;
68
import com.provismet.CombatPlusCore.registries.DoubleEntityEffects;
@@ -51,6 +53,8 @@ public void onInitialize () {
5153
LambdaRegistry.register();
5254
CPCGameRules.init();
5355
SingleEntityEffects.register();
56+
CPCDataComponentEffects.register();
57+
CPCDataComponentTypes.init();
5458

5559
LilyResourceConditions.register();
5660

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package com.provismet.CombatPlusCore.enchantment.effect;
2+
3+
import com.mojang.serialization.Codec;
4+
import com.mojang.serialization.MapCodec;
5+
import com.provismet.CombatPlusCore.utility.CPCRegistries;
6+
import net.minecraft.component.ComponentType;
7+
import net.minecraft.item.ItemStack;
8+
9+
import java.util.function.Function;
10+
11+
public interface CPCDataComponentEntityEffect<T> {
12+
Codec<CPCDataComponentEntityEffect<?>> CODEC = CPCRegistries.ENCHANTMENT_DATA_COMPONENT_EFFECT_TYPE.getCodec().dispatch(CPCDataComponentEntityEffect::getCodec, Function.identity());
13+
14+
default void apply (ItemStack stack, int level) {
15+
if (stack.get(this.getComponentType()) == null) {
16+
stack.set(this.getComponentType(), this.getComponent(level));
17+
}
18+
}
19+
20+
default void remove (ItemStack stack, int level) {
21+
// Would this item normally have this component? If so then assume the enchantment never applied a new version.
22+
if (stack.getItem().getDefaultStack().get(this.getComponentType()) == null) {
23+
stack.remove(this.getComponentType());
24+
}
25+
}
26+
27+
T getComponent (int level);
28+
ComponentType<T> getComponentType ();
29+
MapCodec<? extends CPCDataComponentEntityEffect<?>> getCodec ();
30+
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
package com.provismet.CombatPlusCore.enchantment.effect.component;
2+
3+
import com.mojang.serialization.MapCodec;
4+
import com.mojang.serialization.codecs.RecordCodecBuilder;
5+
import com.provismet.CombatPlusCore.enchantment.effect.CPCDataComponentEntityEffect;
6+
import net.minecraft.component.ComponentType;
7+
import net.minecraft.component.DataComponentTypes;
8+
import net.minecraft.component.type.BlocksAttacksComponent;
9+
import net.minecraft.enchantment.EnchantmentLevelBasedValue;
10+
import net.minecraft.entity.damage.DamageType;
11+
import net.minecraft.registry.RegistryKeys;
12+
import net.minecraft.registry.entry.RegistryEntry;
13+
import net.minecraft.registry.tag.TagKey;
14+
import net.minecraft.sound.SoundEvent;
15+
16+
import java.util.List;
17+
import java.util.Optional;
18+
19+
public record BlocksAttacksComponentEntityEffect (
20+
EnchantmentLevelBasedValue blockDelaySeconds,
21+
EnchantmentLevelBasedValue disableCooldownScale,
22+
List<BlocksAttacksComponent.DamageReduction> damageReductions,
23+
BlocksAttacksComponent.ItemDamage itemDamage,
24+
Optional<TagKey<DamageType>> bypassedBy,
25+
Optional<RegistryEntry<SoundEvent>> blockSound,
26+
Optional<RegistryEntry<SoundEvent>> disableSound)
27+
implements CPCDataComponentEntityEffect<BlocksAttacksComponent>
28+
{
29+
public static final MapCodec<BlocksAttacksComponentEntityEffect> CODEC = RecordCodecBuilder.mapCodec(
30+
instance -> instance.group(
31+
EnchantmentLevelBasedValue.CODEC.optionalFieldOf("block_delay_seconds", EnchantmentLevelBasedValue.constant(0)).forGetter(BlocksAttacksComponentEntityEffect::blockDelaySeconds),
32+
EnchantmentLevelBasedValue.CODEC.optionalFieldOf("disable_cooldown_scale", EnchantmentLevelBasedValue.constant(1)).forGetter(BlocksAttacksComponentEntityEffect::disableCooldownScale),
33+
BlocksAttacksComponent.DamageReduction.CODEC.listOf().optionalFieldOf("damage_reductions", List.of(new BlocksAttacksComponent.DamageReduction(90f, Optional.empty(), 0f, 1f))).forGetter(BlocksAttacksComponentEntityEffect::damageReductions),
34+
BlocksAttacksComponent.ItemDamage.CODEC.optionalFieldOf("item_damage", BlocksAttacksComponent.ItemDamage.DEFAULT).forGetter(BlocksAttacksComponentEntityEffect::itemDamage),
35+
TagKey.codec(RegistryKeys.DAMAGE_TYPE).optionalFieldOf("bypassed_by").forGetter(BlocksAttacksComponentEntityEffect::bypassedBy),
36+
SoundEvent.ENTRY_CODEC.optionalFieldOf("block_sound").forGetter(BlocksAttacksComponentEntityEffect::blockSound),
37+
SoundEvent.ENTRY_CODEC.optionalFieldOf("disabled_sound").forGetter(BlocksAttacksComponentEntityEffect::disableSound)
38+
).apply(instance, BlocksAttacksComponentEntityEffect::new)
39+
);
40+
41+
@Override
42+
public MapCodec<BlocksAttacksComponentEntityEffect> getCodec () {
43+
return CODEC;
44+
}
45+
46+
@Override
47+
public BlocksAttacksComponent getComponent (int level) {
48+
return new BlocksAttacksComponent(
49+
this.blockDelaySeconds.getValue(level),
50+
this.disableCooldownScale.getValue(level),
51+
this.damageReductions,
52+
this.itemDamage,
53+
this.bypassedBy,
54+
this.blockSound,
55+
this.disableSound
56+
);
57+
}
58+
59+
@Override
60+
public ComponentType<BlocksAttacksComponent> getComponentType () {
61+
return DataComponentTypes.BLOCKS_ATTACKS;
62+
}
63+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package com.provismet.CombatPlusCore.enchantment.effect.component;
2+
3+
import com.mojang.serialization.MapCodec;
4+
import com.mojang.serialization.codecs.RecordCodecBuilder;
5+
import com.provismet.CombatPlusCore.enchantment.effect.CPCDataComponentEntityEffect;
6+
import com.provismet.CombatPlusCore.registries.CPCDataComponentTypes;
7+
import net.minecraft.component.ComponentType;
8+
import net.minecraft.util.Identifier;
9+
10+
public record CooldownGroupComponentEntityEffect (Identifier group) implements CPCDataComponentEntityEffect<Identifier> {
11+
public static final MapCodec<CooldownGroupComponentEntityEffect> CODEC = RecordCodecBuilder.mapCodec(
12+
instance -> instance.group(
13+
Identifier.CODEC.fieldOf("group").forGetter(CooldownGroupComponentEntityEffect::group)
14+
).apply(instance, CooldownGroupComponentEntityEffect::new)
15+
);
16+
17+
@Override
18+
public Identifier getComponent (int level) {
19+
return this.group;
20+
}
21+
22+
@Override
23+
public ComponentType<Identifier> getComponentType () {
24+
return CPCDataComponentTypes.COOLDOWN_GROUP;
25+
}
26+
27+
@Override
28+
public MapCodec<CooldownGroupComponentEntityEffect> getCodec () {
29+
return CODEC;
30+
}
31+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package com.provismet.CombatPlusCore.enchantment.effect.component;
2+
3+
import com.mojang.serialization.MapCodec;
4+
import com.mojang.serialization.codecs.RecordCodecBuilder;
5+
import com.provismet.CombatPlusCore.enchantment.effect.CPCDataComponentEntityEffect;
6+
import net.minecraft.component.ComponentType;
7+
import net.minecraft.component.DataComponentTypes;
8+
import net.minecraft.component.type.UseCooldownComponent;
9+
import net.minecraft.enchantment.EnchantmentLevelBasedValue;
10+
import net.minecraft.util.Identifier;
11+
12+
import java.util.Optional;
13+
14+
public record UseCooldownComponentEntityEffect (EnchantmentLevelBasedValue seconds, Optional<Identifier> cooldownGroup) implements CPCDataComponentEntityEffect<UseCooldownComponent> {
15+
public static final MapCodec<UseCooldownComponentEntityEffect> CODEC = RecordCodecBuilder.mapCodec(
16+
instance -> instance.group(
17+
EnchantmentLevelBasedValue.CODEC.fieldOf("seconds").forGetter(UseCooldownComponentEntityEffect::seconds),
18+
Identifier.CODEC.optionalFieldOf("cooldown_group").forGetter(UseCooldownComponentEntityEffect::cooldownGroup)
19+
).apply(instance, UseCooldownComponentEntityEffect::new)
20+
);
21+
22+
@Override
23+
public UseCooldownComponent getComponent (int level) {
24+
return new UseCooldownComponent(Math.max(this.seconds.getValue(level), 0.0001f), this.cooldownGroup);
25+
}
26+
27+
@Override
28+
public ComponentType<UseCooldownComponent> getComponentType () {
29+
return DataComponentTypes.USE_COOLDOWN;
30+
}
31+
32+
@Override
33+
public MapCodec<UseCooldownComponentEntityEffect> getCodec () {
34+
return CODEC;
35+
}
36+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package com.provismet.CombatPlusCore.enchantment.effect.singleEntity;
2+
3+
import com.mojang.serialization.MapCodec;
4+
import com.mojang.serialization.codecs.RecordCodecBuilder;
5+
import com.provismet.CombatPlusCore.registries.CPCEnchantmentComponentTypes;
6+
import com.provismet.CombatPlusCore.utility.CPCEnchantmentHelper;
7+
import net.minecraft.enchantment.EnchantmentEffectContext;
8+
import net.minecraft.enchantment.EnchantmentLevelBasedValue;
9+
import net.minecraft.enchantment.effect.EnchantmentEntityEffect;
10+
import net.minecraft.entity.Entity;
11+
import net.minecraft.entity.player.PlayerEntity;
12+
import net.minecraft.server.world.ServerWorld;
13+
import net.minecraft.util.math.Vec3d;
14+
15+
public record SetCooldownEnchantmentEffect (EnchantmentLevelBasedValue ticks) implements EnchantmentEntityEffect {
16+
public static final MapCodec<SetCooldownEnchantmentEffect> CODEC = RecordCodecBuilder.mapCodec(instance ->
17+
instance.group(
18+
EnchantmentLevelBasedValue.CODEC.fieldOf("ticks").forGetter(SetCooldownEnchantmentEffect::ticks)
19+
).apply(instance, SetCooldownEnchantmentEffect::new)
20+
);
21+
22+
@Override
23+
public void apply (ServerWorld world, int level, EnchantmentEffectContext context, Entity user, Vec3d pos) {
24+
if (!(user instanceof PlayerEntity player)) return;
25+
26+
int cooldown = (int)CPCEnchantmentHelper.modifyValue(CPCEnchantmentComponentTypes.MODIFY_COOLDOWN, world, context.stack(), user, this.ticks.getValue(level));
27+
player.getItemCooldownManager().set(context.stack(), cooldown);
28+
}
29+
30+
@Override
31+
public MapCodec<? extends EnchantmentEntityEffect> getCodec () {
32+
return CODEC;
33+
}
34+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
package com.provismet.CombatPlusCore.mixin;
2+
3+
import com.provismet.CombatPlusCore.enchantment.effect.CPCDataComponentEntityEffect;
4+
import com.provismet.CombatPlusCore.registries.CPCEnchantmentComponentTypes;
5+
import com.provismet.CombatPlusCore.utility.CPCEnchantmentHelper;
6+
import net.minecraft.component.ComponentType;
7+
import net.minecraft.component.DataComponentTypes;
8+
import net.minecraft.component.type.ItemEnchantmentsComponent;
9+
import net.minecraft.enchantment.effect.EnchantmentEffectEntry;
10+
import net.minecraft.item.ItemStack;
11+
import org.jetbrains.annotations.Nullable;
12+
import org.spongepowered.asm.mixin.Mixin;
13+
import org.spongepowered.asm.mixin.Shadow;
14+
import org.spongepowered.asm.mixin.injection.At;
15+
import org.spongepowered.asm.mixin.injection.Inject;
16+
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
17+
18+
import java.util.List;
19+
20+
@Mixin(ItemStack.class)
21+
public abstract class ItemStackMixin {
22+
@Shadow public abstract ItemEnchantmentsComponent getEnchantments ();
23+
24+
@Inject(method = "set", at = @At("HEAD"))
25+
private <T> void applyItemComponentsFromEnchantments (ComponentType<T> type, @Nullable T value, CallbackInfoReturnable<T> cir) {
26+
if (type != DataComponentTypes.ENCHANTMENTS) return;
27+
if (!(value instanceof ItemEnchantmentsComponent newComponent)) return;
28+
29+
ItemStack thisItem = (ItemStack)(Object)this;
30+
31+
// Remove the old components.
32+
CPCEnchantmentHelper.forEachEnchantment((enchantment, level) -> {
33+
List<EnchantmentEffectEntry<CPCDataComponentEntityEffect<?>>> componentEffects = enchantment.value().getEffect(CPCEnchantmentComponentTypes.DATA_COMPONENT);
34+
for (EnchantmentEffectEntry<CPCDataComponentEntityEffect<?>> effect : componentEffects) {
35+
effect.effect().remove(thisItem, level);
36+
}
37+
}, thisItem);
38+
39+
// Add the new components.
40+
newComponent.getEnchantmentEntries().forEach(entry -> {
41+
List<EnchantmentEffectEntry<CPCDataComponentEntityEffect<?>>> componentEffects = entry.getKey().value().getEffect(CPCEnchantmentComponentTypes.DATA_COMPONENT);
42+
for (EnchantmentEffectEntry<CPCDataComponentEntityEffect<?>> effect : componentEffects) {
43+
effect.effect().apply(thisItem, entry.getIntValue());
44+
}
45+
});
46+
}
47+
}

0 commit comments

Comments
 (0)