diff --git a/SpongeAPI b/SpongeAPI index 34622032e7b..01f256bd223 160000 --- a/SpongeAPI +++ b/SpongeAPI @@ -1 +1 @@ -Subproject commit 34622032e7bda623d9eff36cd00e7d1503cb2af6 +Subproject commit 01f256bd22344a1224fd76c3738477eb36a7b094 diff --git a/generator/src/main/java/org/spongepowered/vanilla/generator/world/entities/EntityRegistries.java b/generator/src/main/java/org/spongepowered/vanilla/generator/world/entities/EntityRegistries.java index d99ca8c48f9..186a115dd67 100644 --- a/generator/src/main/java/org/spongepowered/vanilla/generator/world/entities/EntityRegistries.java +++ b/generator/src/main/java/org/spongepowered/vanilla/generator/world/entities/EntityRegistries.java @@ -28,6 +28,7 @@ import net.minecraft.resources.ResourceLocation; import net.minecraft.world.entity.Display; import net.minecraft.world.entity.EquipmentSlot; +import net.minecraft.world.entity.EquipmentSlotGroup; import net.minecraft.world.entity.MobCategory; import net.minecraft.world.entity.animal.Fox; import net.minecraft.world.entity.animal.MushroomCow; @@ -159,6 +160,13 @@ public static List enumEntries(final Context context) { "getSerializedName", "sponge" ), + new EnumEntriesValidator<>( + "item.inventory.equipment", + "EquipmentConditions", + EquipmentSlotGroup.class, + "getSerializedName", + "sponge" + ), new EnumEntriesValidator<>( "item.inventory.equipment", "EquipmentGroups", diff --git a/src/main/java/org/spongepowered/common/data/provider/item/stack/ItemStackData.java b/src/main/java/org/spongepowered/common/data/provider/item/stack/ItemStackData.java index eb411c5c0b7..4f1a9ba32c5 100644 --- a/src/main/java/org/spongepowered/common/data/provider/item/stack/ItemStackData.java +++ b/src/main/java/org/spongepowered/common/data/provider/item/stack/ItemStackData.java @@ -43,6 +43,7 @@ import net.minecraft.world.item.component.CustomModelData; import net.minecraft.world.item.component.DamageResistant; import net.minecraft.world.item.component.DeathProtection; +import net.minecraft.world.item.component.ItemAttributeModifiers; import net.minecraft.world.item.component.ItemContainerContents; import net.minecraft.world.item.component.ItemLore; import net.minecraft.world.item.component.Unbreakable; @@ -56,6 +57,7 @@ import org.spongepowered.api.data.Keys; import org.spongepowered.api.data.type.ItemAction; import org.spongepowered.api.data.value.Value; +import org.spongepowered.api.entity.attribute.ItemAttribute; import org.spongepowered.api.item.ItemRarity; import org.spongepowered.api.item.ItemType; import org.spongepowered.api.item.inventory.Inventory; @@ -82,7 +84,6 @@ private ItemStackData() { // @formatter:off public static void register(final DataProviderRegistrator registrator) { // TODO DataComponents.SUSPICIOUS_STEW_EFFECTS - // TODO maybe DataComponents.ATTRIBUTE_MODIFIERS as keys? // TODO DataComponents.BUNDLE_CONTENTS also check for Shulker Boxes? - removing the component prevents using the bundle // TODO DataComponents.CONTAINER_LOOT for containers with loottable data, also for blockentity? // TODO DataComponents.BLOCK_ENTITY_DATA maybe expose as raw DataContainer? (id MUST have block entity type) @@ -367,6 +368,16 @@ public static void register(final DataProviderRegistrator registrator) { return builder.build(); }) .deleteAndGet(ItemStackData::deleteAndTransactUseCooldown) + .create(Keys.ITEM_ATTRIBUTES) + .get(stack -> { + final var attributes = stack.getOrDefault(DataComponents.ATTRIBUTE_MODIFIERS, ItemAttributeModifiers.EMPTY).modifiers(); + return attributes.isEmpty() ? null : (List) (Object) List.copyOf(attributes); + }) + .set((stack, v) -> { + final var attributes = (List) (Object) List.copyOf(v); + stack.update(DataComponents.ATTRIBUTE_MODIFIERS, ItemAttributeModifiers.EMPTY, p -> new ItemAttributeModifiers(attributes, p.showInTooltip())); + }) + .resetOnDelete(List.of()) ; } // @formatter:on diff --git a/src/main/java/org/spongepowered/common/entity/attribute/SpongeItemAttributeFactory.java b/src/main/java/org/spongepowered/common/entity/attribute/SpongeItemAttributeFactory.java new file mode 100644 index 00000000000..cafaadd17c5 --- /dev/null +++ b/src/main/java/org/spongepowered/common/entity/attribute/SpongeItemAttributeFactory.java @@ -0,0 +1,52 @@ +/* + * This file is part of Sponge, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.common.entity.attribute; + +import net.minecraft.core.registries.Registries; +import net.minecraft.world.entity.EquipmentSlotGroup; +import net.minecraft.world.entity.ai.attributes.Attribute; +import net.minecraft.world.item.component.ItemAttributeModifiers; +import org.spongepowered.api.entity.attribute.AttributeModifier; +import org.spongepowered.api.entity.attribute.ItemAttribute; +import org.spongepowered.api.entity.attribute.type.AttributeType; +import org.spongepowered.api.item.inventory.equipment.EquipmentCondition; +import org.spongepowered.common.SpongeCommon; + +import java.util.Objects; + +public final class SpongeItemAttributeFactory implements ItemAttribute.Factory { + + @Override + public ItemAttribute of(final AttributeType type, final AttributeModifier modifier, final EquipmentCondition condition) { + Objects.requireNonNull(type, "type"); + Objects.requireNonNull(modifier, "modifier"); + Objects.requireNonNull(condition, "condition"); + return (ItemAttribute) (Object) new ItemAttributeModifiers.Entry( + SpongeCommon.vanillaRegistry(Registries.ATTRIBUTE).wrapAsHolder((Attribute) type), + (net.minecraft.world.entity.ai.attributes.AttributeModifier) (Object) modifier, + (EquipmentSlotGroup) (Object) condition + ); + } +} diff --git a/src/main/java/org/spongepowered/common/registry/SpongeFactoryProvider.java b/src/main/java/org/spongepowered/common/registry/SpongeFactoryProvider.java index b39affb0bce..87dc9b84657 100644 --- a/src/main/java/org/spongepowered/common/registry/SpongeFactoryProvider.java +++ b/src/main/java/org/spongepowered/common/registry/SpongeFactoryProvider.java @@ -46,6 +46,7 @@ import org.spongepowered.api.data.value.Value; import org.spongepowered.api.effect.ForwardingViewer; import org.spongepowered.api.effect.VanishState; +import org.spongepowered.api.entity.attribute.ItemAttribute; import org.spongepowered.api.event.EventListenerRegistration; import org.spongepowered.api.event.cause.entity.damage.DamageStepType; import org.spongepowered.api.event.cause.entity.damage.source.DamageSource; @@ -123,6 +124,7 @@ import org.spongepowered.common.data.manipulator.MutableDataManipulatorFactory; import org.spongepowered.common.data.value.SpongeValueFactory; import org.spongepowered.common.effect.SpongeCustomForwardingViewer; +import org.spongepowered.common.entity.attribute.SpongeItemAttributeFactory; import org.spongepowered.common.entity.effect.SpongeVanishState; import org.spongepowered.common.event.SpongeEventListenerRegistration; import org.spongepowered.common.event.cause.entity.damage.SpongeDamageStepType; @@ -287,6 +289,7 @@ public void registerDefaultFactories() { .registerFactory(NaturalSpawner.Factory.class, new SpongeNaturalSpawnerFactory()) .registerFactory(ScoreFormat.Factory.class, new SpongeScoreFormatFactory()) .registerFactory(ToolRule.Factory.class, new SpongeToolRuleFactory()) + .registerFactory(ItemAttribute.Factory.class, new SpongeItemAttributeFactory()) .registerFactory(ItemAction.Factory.class, new SpongeItemActionFactory()) .registerFactory(PortalLogic.Factory.class, new SpongePortalLogicFactory()) .registerFactory(RecipeInput.Factory.class, new SpongeRecipeInputFactory()) diff --git a/src/main/java/org/spongepowered/common/registry/loader/VanillaRegistryLoader.java b/src/main/java/org/spongepowered/common/registry/loader/VanillaRegistryLoader.java index 4727ac90857..31479222e40 100644 --- a/src/main/java/org/spongepowered/common/registry/loader/VanillaRegistryLoader.java +++ b/src/main/java/org/spongepowered/common/registry/loader/VanillaRegistryLoader.java @@ -36,6 +36,7 @@ import net.minecraft.world.damagesource.DamageScaling; import net.minecraft.world.entity.Display; import net.minecraft.world.entity.EquipmentSlot; +import net.minecraft.world.entity.EquipmentSlotGroup; import net.minecraft.world.entity.HumanoidArm; import net.minecraft.world.entity.MobCategory; import net.minecraft.world.entity.ai.attributes.AttributeModifier; @@ -183,6 +184,7 @@ private void loadEnumRegistries() { this.automaticName(RegistryTypes.DYE_COLOR, DyeColor.values()); this.automaticName(RegistryTypes.DOOR_HINGE, DoorHingeSide.values()); this.automaticName(RegistryTypes.DRIPSTONE_SEGMENT, DripstoneThickness.values()); + this.automaticName(RegistryTypes.EQUIPMENT_CONDITION, EquipmentSlotGroup.values()); this.automaticName(RegistryTypes.EQUIPMENT_GROUP, EquipmentSlot.Type.values()); this.automaticName(RegistryTypes.EQUIPMENT_TYPE, EquipmentSlot.values()); this.automaticName(RegistryTypes.FOX_TYPE, Fox.Variant.values()); diff --git a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/item/component/ItemAttributeModifiers_EntryMixin_API.java b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/item/component/ItemAttributeModifiers_EntryMixin_API.java new file mode 100644 index 00000000000..14ad842499e --- /dev/null +++ b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/item/component/ItemAttributeModifiers_EntryMixin_API.java @@ -0,0 +1,64 @@ +/* + * This file is part of Sponge, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.common.mixin.api.minecraft.world.item.component; + +import net.minecraft.core.Holder; +import net.minecraft.world.entity.EquipmentSlotGroup; +import net.minecraft.world.entity.ai.attributes.Attribute; +import net.minecraft.world.item.component.ItemAttributeModifiers; +import org.spongepowered.api.entity.attribute.AttributeModifier; +import org.spongepowered.api.entity.attribute.ItemAttribute; +import org.spongepowered.api.entity.attribute.type.AttributeType; +import org.spongepowered.api.item.inventory.equipment.EquipmentCondition; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Implements; +import org.spongepowered.asm.mixin.Interface; +import org.spongepowered.asm.mixin.Intrinsic; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; + +@Mixin(ItemAttributeModifiers.Entry.class) +@Implements(@Interface(iface = ItemAttribute.class, prefix = "attribute$")) +public abstract class ItemAttributeModifiers_EntryMixin_API implements ItemAttribute { + + @Shadow @Final private Holder attribute; + @Shadow @Final private net.minecraft.world.entity.ai.attributes.AttributeModifier modifier; + @Shadow @Final private EquipmentSlotGroup slot; + + @Override + public AttributeType type() { + return (AttributeType) this.attribute.value(); + } + + @Intrinsic + public AttributeModifier attribute$modifier() { + return (AttributeModifier) (Object) this.modifier; + } + + @Override + public EquipmentCondition condition() { + return (EquipmentCondition) (Object) this.slot; + } +} diff --git a/src/mixins/java/org/spongepowered/common/mixin/inventory/api/world/entity/EquipmentSlotGroupMixin_Inventory_API.java b/src/mixins/java/org/spongepowered/common/mixin/inventory/api/world/entity/EquipmentSlotGroupMixin_Inventory_API.java new file mode 100644 index 00000000000..4f15254dc48 --- /dev/null +++ b/src/mixins/java/org/spongepowered/common/mixin/inventory/api/world/entity/EquipmentSlotGroupMixin_Inventory_API.java @@ -0,0 +1,64 @@ +/* + * This file is part of Sponge, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.common.mixin.inventory.api.world.entity; + +import net.kyori.adventure.text.Component; +import net.minecraft.world.entity.EquipmentSlot; +import net.minecraft.world.entity.EquipmentSlotGroup; +import org.spongepowered.api.item.inventory.equipment.EquipmentCondition; +import org.spongepowered.api.item.inventory.equipment.EquipmentType; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import java.util.Objects; + +@Mixin(EquipmentSlotGroup.class) +public abstract class EquipmentSlotGroupMixin_Inventory_API implements EquipmentCondition { + + @Shadow public abstract boolean shadow$test(EquipmentSlot slot); + + @Shadow @Final private String key; + + private Component api$component; + + @Inject(method = "(Ljava/lang/String;IILjava/lang/String;Ljava/util/function/Predicate;)V", at = @At("RETURN")) + private void api$setComponent(final CallbackInfo ci) { + this.api$component = Component.translatable("item.modifiers." + this.key); + } + + @Override + public Component asComponent() { + return this.api$component; + } + + @Override + public boolean test(final EquipmentType type) { + return this.shadow$test((EquipmentSlot) (Object) Objects.requireNonNull(type, "type")); + } +} diff --git a/src/mixins/java/org/spongepowered/common/mixin/inventory/api/world/entity/EquipmentSlotMixin_Inventory_API.java b/src/mixins/java/org/spongepowered/common/mixin/inventory/api/world/entity/EquipmentSlotMixin_Inventory_API.java index f9ad70efbd4..1e5310f9c6c 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/inventory/api/world/entity/EquipmentSlotMixin_Inventory_API.java +++ b/src/mixins/java/org/spongepowered/common/mixin/inventory/api/world/entity/EquipmentSlotMixin_Inventory_API.java @@ -25,6 +25,8 @@ package org.spongepowered.common.mixin.inventory.api.world.entity; import net.minecraft.world.entity.EquipmentSlot; +import net.minecraft.world.entity.EquipmentSlotGroup; +import org.spongepowered.api.item.inventory.equipment.EquipmentCondition; import org.spongepowered.api.item.inventory.equipment.EquipmentGroup; import org.spongepowered.api.item.inventory.equipment.EquipmentType; import org.spongepowered.asm.mixin.Final; @@ -40,4 +42,9 @@ public abstract class EquipmentSlotMixin_Inventory_API implements EquipmentType public EquipmentGroup group() { return (EquipmentGroup) (Object) this.type; } + + @Override + public EquipmentCondition condition() { + return (EquipmentCondition) (Object) EquipmentSlotGroup.bySlot((EquipmentSlot) (Object) this); + } } diff --git a/src/mixins/resources/mixins.sponge.api.json b/src/mixins/resources/mixins.sponge.api.json index 835e8e57719..035f216ac18 100644 --- a/src/mixins/resources/mixins.sponge.api.json +++ b/src/mixins/resources/mixins.sponge.api.json @@ -332,6 +332,7 @@ "minecraft.world.item.ToolMaterialMixin_API", "minecraft.world.item.alchemy.PotionMixin_API", "minecraft.world.item.component.FireworkExplosionMixin_API", + "minecraft.world.item.component.ItemAttributeModifiers_EntryMixin_API", "minecraft.world.item.component.Tool_RuleMixin_API", "minecraft.world.item.consume_effects.ApplyStatusEffectsConsumeEffectMixin_API", "minecraft.world.item.consume_effects.ClearAllStatusEffectsConsumeEffectMixin_API", diff --git a/src/mixins/resources/mixins.sponge.inventory.json b/src/mixins/resources/mixins.sponge.inventory.json index 0b4ba5ddbb6..6ea796e028c 100644 --- a/src/mixins/resources/mixins.sponge.inventory.json +++ b/src/mixins/resources/mixins.sponge.inventory.json @@ -18,6 +18,7 @@ "api.world.CompoundContainerMixin_Carrier_Inventory_API", "api.world.ContainerMixin_Inventory_API", "api.world.entity.EquipmentSlot_TypeMixin_Inventory_API", + "api.world.entity.EquipmentSlotGroupMixin_Inventory_API", "api.world.entity.EquipmentSlotMixin_Inventory_API", "api.world.entity.animal.horse.AbstractHorseMixin_Carrier_Inventory_API", "api.world.entity.monster.PillagerMixin_Carrier_Inventory_API", diff --git a/testplugins/src/main/java/org/spongepowered/test/data/AttributeDataTest.java b/testplugins/src/main/java/org/spongepowered/test/data/AttributeDataTest.java new file mode 100644 index 00000000000..ce27e065d2c --- /dev/null +++ b/testplugins/src/main/java/org/spongepowered/test/data/AttributeDataTest.java @@ -0,0 +1,124 @@ +/* + * This file is part of Sponge, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.test.data; + +import com.google.inject.Inject; +import net.kyori.adventure.text.Component; +import org.spongepowered.api.ResourceKey; +import org.spongepowered.api.command.Command; +import org.spongepowered.api.command.CommandResult; +import org.spongepowered.api.command.parameter.CommandContext; +import org.spongepowered.api.data.Keys; +import org.spongepowered.api.data.value.Value; +import org.spongepowered.api.entity.attribute.AttributeModifier; +import org.spongepowered.api.entity.attribute.AttributeOperations; +import org.spongepowered.api.entity.attribute.ItemAttribute; +import org.spongepowered.api.entity.attribute.type.AttributeTypes; +import org.spongepowered.api.entity.living.player.server.ServerPlayer; +import org.spongepowered.api.event.Listener; +import org.spongepowered.api.event.lifecycle.RegisterCommandEvent; +import org.spongepowered.api.item.ItemTypes; +import org.spongepowered.api.item.inventory.ItemStack; +import org.spongepowered.api.item.inventory.equipment.EquipmentConditions; +import org.spongepowered.plugin.PluginContainer; +import org.spongepowered.plugin.builtin.jvm.Plugin; +import org.spongepowered.test.LoadableModule; + +@Plugin("attributedata") +public class AttributeDataTest implements LoadableModule { + + private final PluginContainer plugin; + + @Inject + public AttributeDataTest(final PluginContainer plugin) { + this.plugin = plugin; + } + + @Override + public void enable(final CommandContext ctx) { + } + + @Listener + public void onRegisterCommand(final RegisterCommandEvent event) { + final Command.Builder builder = Command.builder(); + builder.addChild(Command.builder().executor(this::items).build(), "items"); + event.register(this.plugin, builder.build(), "attributedata"); + } + + private CommandResult items(final CommandContext commandContext) { + final ServerPlayer player = commandContext.cause().first(ServerPlayer.class).orElse(null); + if (player == null) { + return CommandResult.error(Component.text("Must be run ingame by a player")); + } + + final ItemStack stack1 = ItemStack.of(ItemTypes.DIAMOND_BOOTS); + stack1.offer(Keys.CUSTOM_NAME, Component.text("Speed when on feet, jump boost when in hand")); + stack1.offerSingle(Keys.ITEM_ATTRIBUTES, ItemAttribute.of( + AttributeTypes.MOVEMENT_SPEED, + AttributeModifier.of(ResourceKey.of(this.plugin, "boots_speed"), AttributeOperations.ADDITION, 1), + EquipmentConditions.FEET + )); + stack1.offerSingle(Keys.ITEM_ATTRIBUTES, ItemAttribute.of( + AttributeTypes.JUMP_STRENGTH, + AttributeModifier.of(ResourceKey.of(this.plugin, "boots_jump"), AttributeOperations.ADDITION, 1), + EquipmentConditions.HAND + )); + + final ItemStack stack2 = ItemStack.of(ItemTypes.NETHERITE_SWORD); + stack2.offer(Keys.CUSTOM_NAME, Component.text("Sword without damage")); + stack2.getValue(Keys.ITEM_ATTRIBUTES) + .map(Value::asMutable) + .map(v -> v.transform(list -> list.stream() + .filter(attribute -> attribute.type() != AttributeTypes.ATTACK_DAMAGE.get()) + .toList())) + .ifPresent(stack2::offer); + + // In vanilla only one modifier with the same + // key is applied within each attribute type. + // This is to ensure that vanilla accepts + // modifiers with the same key on the item. + final ItemStack stack3 = ItemStack.of(ItemTypes.SUGAR); + final ResourceKey sameKey = ResourceKey.of(this.plugin, "same_key"); + stack3.offer(Keys.CUSTOM_NAME, Component.text("Scale and one (out of 2) health boost")); + stack3.offerSingle(Keys.ITEM_ATTRIBUTES, ItemAttribute.of( + AttributeTypes.MAX_HEALTH, + AttributeModifier.of(sameKey, AttributeOperations.ADDITION, 10), + EquipmentConditions.MAINHAND + )); + stack3.offerSingle(Keys.ITEM_ATTRIBUTES, ItemAttribute.of( + AttributeTypes.MAX_HEALTH, + AttributeModifier.of(sameKey, AttributeOperations.ADDITION, 20), + EquipmentConditions.MAINHAND + )).ifNotSuccessful(RuntimeException::new); + stack3.offerSingle(Keys.ITEM_ATTRIBUTES, ItemAttribute.of( + AttributeTypes.SCALE, + AttributeModifier.of(sameKey, AttributeOperations.MULTIPLY_TOTAL, 1), + EquipmentConditions.MAINHAND + )); + + player.inventory().offer(stack1, stack2, stack3); + return CommandResult.success(); + } +} diff --git a/testplugins/src/main/resource-templates/META-INF/sponge_plugins.json b/testplugins/src/main/resource-templates/META-INF/sponge_plugins.json index b0d8f7fcf9d..ea4cbd7e716 100644 --- a/testplugins/src/main/resource-templates/META-INF/sponge_plugins.json +++ b/testplugins/src/main/resource-templates/META-INF/sponge_plugins.json @@ -372,6 +372,12 @@ } ] }, + { + "id": "attributedata", + "name": "Attribute Data", + "entrypoint": "org.spongepowered.test.data.AttributeDataTest", + "description": "Attribute Data" + }, { "id": "decoratedpotdata", "name": "Decorated Pot Data",