Skip to content

Added enchantment compatibility for accessories#1569

Closed
Foxyas wants to merge 10 commits intoLtxProgrammer:0.15-featuresfrom
Foxyas:0.15-features
Closed

Added enchantment compatibility for accessories#1569
Foxyas wants to merge 10 commits intoLtxProgrammer:0.15-featuresfrom
Foxyas:0.15-features

Conversation

@Foxyas
Copy link
Contributor

@Foxyas Foxyas commented Dec 31, 2025

added 5 functions;
one to tell if a accessory should be considered by X enchantment. (example: mending, protection, thorns) as well a simpler boolean function that just allow a accessory to be affect by mending,
one to tell if a accessory should do the "doPostHurtEffects",
and one to tell if a accessory should do the "doPostDamageEffects".

the accessory need to specify if it's affected by do Post Damage/Hurt feature, or else it will just do the normal enchantment.
example:
mending -> don't need to be specified if is affected by any "doPost" because it code is on the experience orb which only get a random item with the enchantment from the player that gonna get the experience

just for example i made the exoskeleton be compatible with thorns
idk if you will like such change soo is there just as a example of use

In short term -> Added suggestion from #1540

added 5 functions;
one to tell if a accessory should be considered by X enchantment. (example: mending, protection, thorns) as well a simpler boolean function that just allow a accessory to be affect by mending,
one to tell if a accessory should do the "doPostHurtEffects",
and one to tell if a accessory should do the "doPostDamageEffects".
@Foxyas
Copy link
Contributor Author

Foxyas commented Dec 31, 2025

I HOPE that i didn't break any code style thing..

made it use the @WrapOperation instead of @reDIrect
added quick band-aid fix for spamming logs
LtxProgrammer#1570
it don't fix the issue. just ignore more than 20 logs
return facility;
} catch (Exception e) {
Changed.LOGGER.error("Failed to load facility from disk ", e);
if (loggedFacilityTimes < 20) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Band aid fix, i will remove it

Copy link
Owner

@LtxProgrammer LtxProgrammer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See review comments. Also I'd like to be the one to setup the mixins.

Comment on lines +97 to +107
/**
* Allows the Accessory be affected by mending enchantment
* This is a split method from the AccessoryItem$isConsideredByEnchantment for better class organization
* The main default value is false
* @param slotType The Accessory Slot Type
* @param itemStack The Accessory ItemStack
* @return false if not affected by mending
*/
default boolean isAffectedByMending(AccessorySlotType slotType, ItemStack itemStack) {
return false;
}
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think splitting this function out is necessary. With the exception of the Thunder Science vest, no accessories in Changed are planned to be affected by mending.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

alright. i only split such method because it looks cleaner :p

Comment on lines +109 to +125
/**
* Allow the Accessory to be Considered by an Enchantment
* It Affects directly the Enchantment$getSlotItems where it will make the method considerate the item and it equivalentSlot from the slot type
* The main default value is false
* @param enchantment The Enchantment to be considered
* @param itemStack The Accessory ItemStack
* @param slotType The Accessory Slot Type
* @param pEntity The User
* @return false if the enchantment should not be considered
*/
default boolean isConsideredByEnchantment(Enchantment enchantment, ItemStack itemStack, AccessorySlotType slotType, LivingEntity pEntity) {
if (enchantment == Enchantments.MENDING) {
return this.isAffectedByMending(slotType, itemStack);
}

return false;
}
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I worry about the possibility of modded enchantments relying on the accessory being present in the equivalentSlot field. I suppose if it is up to the accessory item to specify which enchantments it will support in getRandomItemWith(), then this is fine.

Comment on lines +127 to +164
/**
* It Affects directly the Entity$getAllSlots where it will make the method considerate the item and it equivalentSlot from the slot type
* This make the item be affected by Post Damage/Hurt Effects use with it caution
* The main default value is false
* @param itemStack The Accessory ItemStack
* @param slotType The Accessory Slot Type
* @param livingEntity The User
* @return false if the enchantment should not be considered
*/
default boolean isConsideredBySlots(ItemStack itemStack, AccessorySlotType slotType, LivingEntity livingEntity) {
return false;
}

/**
* It Affects directly the EnchantmentHelper$doPostDamageEffects where it will make the method considerate the item and it equivalentSlot from the slot type
* It is here just for precision, example ("claw gloves" which would be affected by sharpness but not thorns)
* The main default value is false
* @param itemStack The Accessory ItemStack
* @param slotType The Accessory Slot Type
* @param livingEntity The User
* @return false if the enchantment should not be considered
*/
default boolean isConsideredIntoPostDamageEffects(ItemStack itemStack, AccessorySlotType slotType, LivingEntity livingEntity) {
return false;
}

/**
* It Affects directly the EnchantmentHelper$doPostHurtEffects where it will make the method considerate the item and it equivalentSlot from the slot type
* It is here just for precision, example ("Chain Vest" which would be affected by protection but not from bane of arthropods)
* The main default value is false
* @param itemStack The Accessory ItemStack
* @param slotType The Accessory Slot Type
* @param livingEntity The User
* @return false if the enchantment should not be considered
*/
default boolean isConsideredIntoPostHurtEffects(ItemStack itemStack, AccessorySlotType slotType, LivingEntity livingEntity) {
return false;
}
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think these three functions are redundant. It would be up to the item to specify which enchantments it supports using isConsideredByEnchantment(). Both examples you provide can be handled in that way.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

okay so should accessories just be always considered into "getAllSlots"?

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would implement this another, simpler way. Depends on the removal of the doPostHurt and doPostDamage specifiers in AccessoryItem.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would implement this another, simpler way. Depends on the removal of the doPostHurt and doPostDamage specifiers in AccessoryItem.

we could make accessories always be considered into get all slots.
it would make them more similar to how normal items are considerated too

@Foxyas
Copy link
Contributor Author

Foxyas commented Jan 1, 2026

how about a mixin into Enchantment$doPostAttack and Enchantment$doPostHurt to considerate the accessory slots too?

@Foxyas
Copy link
Contributor Author

Foxyas commented Jan 1, 2026

btw both methods only work if the Entity$getAllSlots return the accessories slots items too

@Foxyas
Copy link
Contributor Author

Foxyas commented Jan 1, 2026

@LtxProgrammer how about this?

Copy link
Owner

@LtxProgrammer LtxProgrammer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See comments

Comment on lines +58 to +66
AccessorySlots.getForEntity(attacker).ifPresent((slots) ->
slots.forEachSlot((slotType, itemStack) -> {
if (itemStack.isEmpty()) return;
if (!(itemStack.getItem() instanceof AccessoryItem accessoryItem)) return;
if (!accessoryItem.isConsideredByEnchantment(AccessorySlotContext.of(attacker, slotType), self(), ExecutionContext.POST_HURT)) {
ci.cancel(); //Cancel behavior if the accessory item don't support it
}
})
);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This mixin will not work as intended:

  1. Injecting at the HEAD of Enchantment.doPostHurt() will not apply to enchantments that override it (e.g. ThornsEnchantment.doPostHurt()).
  2. The entire doPostHurt() effect is canceled if the player is wearing an accessory that denies that enchantment, despite wearing another item that has it. (e.g. Thorns on a chestplate fails to work when wearing benign shorts). This is because doPostHurt() is called per enchantment per item. This mixin code will check every accessory slot without knowing which item doPostHurt() has been called for.

This comment can also be applied to accessoriesEnchantmentDetectionPostAttack()

Map<EquipmentSlot, ItemStack> returnValue = cir.getReturnValue();
Map<EquipmentSlot, ItemStack> newReturnValue = new HashMap<>();
if (returnValue != null) {
newReturnValue.put(slotType.getEquivalentSlot(), itemStack);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function will override the enchantment effects of any armor item present in the accessory's equivalent slot, should that accessory item return true for consideration.

Comment on lines +319 to +321
returnValue.forEach(defaultStacks::add);
stacks.addAll(defaultStacks);
cir.setReturnValue(stacks);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This return condition will cause entities that have null default slots but present accessories to ignore said accessories. It is also very inefficient to use two lists like this. defaultStacks is completely redundant, as List::add can be called on stacks. Furthermore, the result of iterating each accessory slot will be completely ignored on a check that can be done earlier in the function.

@LtxProgrammer
Copy link
Owner

I have implemented these changes locally. I will close this PR and push the changes.

LtxProgrammer added a commit that referenced this pull request Jan 2, 2026
Signed-off-by: LtxPgm <ltxprogrammer@outlook.com>
@Foxyas
Copy link
Contributor Author

Foxyas commented Jan 2, 2026

i just got into my pc now, and alright

@Foxyas
Copy link
Contributor Author

Foxyas commented Jan 2, 2026

well, now that i think about it. i'm evolving in dev skills abit too fast kk.
i was breaking my head to do a simple animation work and now that is basic to me.
anyway i never heard of @Local() anotation before is that anything very advanced from mixin? or just a new thing from mixin extras?

@LtxProgrammer
Copy link
Owner

anyway i never heard of @Local() anotation before is that anything very advanced from mixin? or just a new thing from mixin extras?

It's from mixin extras. It lets you capture variables present in the context of your mixin function.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants