Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,6 @@
<versions>
<version>v0.15.0</version>
</versions>
<lastUpdated>20251228235752</lastUpdated>
<lastUpdated>20260101193312</lastUpdated>
</versioning>
</metadata>
Original file line number Diff line number Diff line change
@@ -1 +1 @@
abd9cd51fe52b72dbd56914bc664d2f4
90ec5f615ee399f4c91a06101f43dcef
Original file line number Diff line number Diff line change
@@ -1 +1 @@
8c237978a6c32e163b16ddaa13502a38caef65e9
2a787adaddfdecaa4ee4954d67fe69f45063bb11
Original file line number Diff line number Diff line change
@@ -1 +1 @@
8377337c99473867a8059ee1148761acc4c0dff9c828432b77b82eaaafa17151
db0bc2b03dfc1956eb1e1524c9bb28f6c8a7932920e9f6c030f3eedfd6bd482a
Original file line number Diff line number Diff line change
@@ -1 +1 @@
9fd1e0f602f5f1b58a8e265c3a3f23d5a74be0392923b99937000fe19d869803d58286e353fc844b9b36dd57358b424d2d1c7739befef40a1d253641cca9b747
a468b484c91692ca7378cc0ea9d30fd12750b70b7785e4029716d514b743882a550039e1932bcf61f5c4c0c6fb33f7682c3097a79e0e12a3cd95b9452f8d9f32
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -1 +1 @@
3f08e47aa1942490da96db24870d8673
3def6c33335baf99410958025ad96ab4
Original file line number Diff line number Diff line change
@@ -1 +1 @@
729ce038b0abfa8fc0390434d65d67411a9d2312
28e7e65ab2b8dc69944a7dc97bdb1f7444931b55
Original file line number Diff line number Diff line change
@@ -1 +1 @@
e9ee9ede4b7811b0f5a54d2687d41d3857a5bf2ba0e84dd6c25865cd6b10e29c
ed95cdb61e9a2739881b2da62c38b876d323f89b4892abbf7b8280a3559e8d7d
Original file line number Diff line number Diff line change
@@ -1 +1 @@
66a8220b0b2404339d2b8903b4958e8a872af7e8da0355dc2d9e1730535371927a3d54a9d41d6661672485b574c78fd84049499c37ee0d17d60b6b5202cc3ea4
3a104ff40445e43b7333a7436a6b688f949016691a31a2f4fd5f1c11a9b6d0ff17e86ff86b0454453f594d8e419d31ea61d883b8d72b5846c539d20d8d2c7a19
31 changes: 31 additions & 0 deletions src/main/java/net/ltxprogrammer/changed/item/AccessoryItem.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import net.minecraft.world.damagesource.DamageSource;
import net.minecraft.world.entity.*;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.enchantment.Enchantment;
import net.minecraft.world.level.block.DispenserBlock;
import net.minecraft.world.phys.AABB;

Expand Down Expand Up @@ -92,6 +93,36 @@ default boolean shouldDisableSlot(AccessorySlotContext<?> slotContext, Accessory
return false;
}


/**
* Allow the Accessory to be Considered by an Enchantment
* It Affects directly the Enchantment behavior where it will make the method considerate the item and it equivalentSlot from the slot type
* The main default value is false
* @param accessorySlotContext The Accessory Slot Context (Contains Wearer, ItemStack, etc.)
* @param enchantment The Enchantment to be considered
* @return false if the enchantment should not be considered
*/
default boolean isConsideredByEnchantment(AccessorySlotContext<?> accessorySlotContext, Enchantment enchantment, ExecutionContext executionContext) {
return false;
}

enum ExecutionContext { //TODO: a better name
IDLE,
POST_HURT,
POST_ATTACK
}

/**
* 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 context The Accessory context
* @return false if the enchantment should not be considered
*/
default boolean isAffectedByEnchantments(AccessorySlotContext<?> context) {
return true;
}

default void accessoryEquipped(AccessorySlotContext<?> slotContext) {}
default void accessoryRemoved(AccessorySlotContext<?> slotContext) {}

Expand Down
14 changes: 10 additions & 4 deletions src/main/java/net/ltxprogrammer/changed/item/ExoskeletonItem.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,7 @@
import net.ltxprogrammer.changed.data.AccessorySlots;
import net.ltxprogrammer.changed.entity.robot.AbstractRobot;
import net.ltxprogrammer.changed.entity.robot.ChargerType;
import net.ltxprogrammer.changed.init.ChangedAccessorySlots;
import net.ltxprogrammer.changed.init.ChangedDamageSources;
import net.ltxprogrammer.changed.init.ChangedSounds;
import net.ltxprogrammer.changed.init.ChangedTags;
import net.ltxprogrammer.changed.init.*;
import net.ltxprogrammer.changed.process.ProcessTransfur;
import net.ltxprogrammer.changed.util.Cacheable;
import net.ltxprogrammer.changed.util.EntityUtil;
Expand Down Expand Up @@ -79,9 +76,18 @@ public ExoskeletonItem(Properties builder, Supplier<EntityType<T>> entityType) {

@Override
public boolean canApplyAtEnchantingTable(ItemStack stack, Enchantment enchantment) {
if (enchantment == Enchantments.THORNS) return true;

return enchantment != Enchantments.MENDING && super.canApplyAtEnchantingTable(stack, enchantment);
}

@Override
public boolean isConsideredByEnchantment(AccessorySlotContext<?> accessorySlotContext, Enchantment enchantment, ExecutionContext executionContext) {
if (enchantment == Enchantments.THORNS) return true;

return AccessoryItem.super.isConsideredByEnchantment(accessorySlotContext, enchantment, executionContext);
}

@Override
public boolean allowedInSlot(ItemStack itemStack, LivingEntity wearer, AccessorySlotType slot) {
if (!canUse(itemStack)) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package net.ltxprogrammer.changed.mixin;

import net.ltxprogrammer.changed.data.AccessorySlotContext;
import net.ltxprogrammer.changed.data.AccessorySlots;
import net.ltxprogrammer.changed.item.AccessoryItem;
import net.ltxprogrammer.changed.item.AccessoryItem.ExecutionContext;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EquipmentSlot;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.enchantment.Enchantment;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;

import java.util.HashMap;
import java.util.Map;

@Mixin(Enchantment.class)
public class EnchantmentMixin {

@Inject(method = "getSlotItems", at = @At("RETURN"), cancellable = true)
private void accessoriesEnchantmentDetectionIdle(LivingEntity pEntity, CallbackInfoReturnable<Map<EquipmentSlot, ItemStack>> cir) {
AccessorySlots.getForEntity(pEntity).ifPresent((slots) ->
slots.forEachSlot((slotType, itemStack) -> {
if (itemStack.isEmpty()) return;
if (!(itemStack.getItem() instanceof AccessoryItem accessoryItem)) return;
if (accessoryItem.isConsideredByEnchantment(AccessorySlotContext.of(pEntity, slotType), self(), ExecutionContext.IDLE)) {
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.

cir.setReturnValue(newReturnValue);
}
}
})
);
}

@Inject(method = "doPostAttack", at = @At("HEAD"), cancellable = true)
private void accessoriesEnchantmentDetectionPostAttack(LivingEntity attacker, Entity target, int pLevel, CallbackInfo ci) {
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_ATTACK)) {
ci.cancel(); //Cancel behavior if the accessory item don't support it
}
})
);
}

@Inject(method = "doPostHurt", at = @At("HEAD"), cancellable = true)
private void accessoriesEnchantmentDetectionPostHurt(LivingEntity attacker, Entity target, int pLevel, CallbackInfo ci) {
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
}
})
);
Comment on lines +58 to +66
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()

}

@Unique
private Enchantment self() {
return (Enchantment) (Object) this;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
import net.ltxprogrammer.changed.ability.GrabEntityAbility;
import net.ltxprogrammer.changed.ability.IAbstractChangedEntity;
import net.ltxprogrammer.changed.block.StasisChamber;
import net.ltxprogrammer.changed.data.AccessorySlotContext;
import net.ltxprogrammer.changed.data.AccessorySlots;
import net.ltxprogrammer.changed.entity.ChangedEntity;
import net.ltxprogrammer.changed.entity.LivingEntityDataExtension;
import net.ltxprogrammer.changed.entity.SeatEntity;
Expand All @@ -15,6 +17,7 @@
import net.ltxprogrammer.changed.entity.variant.TransfurVariantInstance;
import net.ltxprogrammer.changed.init.ChangedAbilities;
import net.ltxprogrammer.changed.init.ChangedTags;
import net.ltxprogrammer.changed.item.AccessoryItem;
import net.ltxprogrammer.changed.process.ProcessTransfur;
import net.ltxprogrammer.changed.util.EntityUtil;
import net.ltxprogrammer.changed.world.LatexCoverGetter;
Expand All @@ -32,6 +35,7 @@
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.Pose;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.ClipContext;
import net.minecraft.world.level.Level;
Expand All @@ -51,6 +55,8 @@
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

@Mixin(Entity.class)
Expand Down Expand Up @@ -289,4 +295,31 @@ protected SoundType maybeGetLatexCoverSoundRemapped(BlockState instance, LevelRe
final SoundType coveredSound = coverState.getSoundType(reader, blockPos.above(), entity);
return coveredSound != null ? coveredSound : original.call(instance, reader, blockPos, entity);
}

@Inject(method = "getAllSlots", at = @At("RETURN"), cancellable = true)
private void hookAccessoriesSlots(CallbackInfoReturnable<Iterable<ItemStack>> cir) {
Entity self = (Entity) (Object) this;
if (!(self instanceof LivingEntity livingEntity)) return;
List<ItemStack> defaultStacks = new ArrayList<>();
List<ItemStack> stacks = new ArrayList<>();

AccessorySlots.getForEntity(livingEntity).ifPresent((slots) ->
slots.forEachSlot((slotType, itemStack) -> {
if (itemStack.isEmpty()) return;
if (!(itemStack.getItem() instanceof AccessoryItem accessoryItem)) return;
if (accessoryItem.isAffectedByEnchantments(AccessorySlotContext.of(livingEntity, slotType))) {
stacks.add(itemStack);
}
})
);

if (!stacks.isEmpty()) {
Iterable<ItemStack> returnValue = cir.getReturnValue();
if (returnValue != null) {
returnValue.forEach(defaultStacks::add);
stacks.addAll(defaultStacks);
cir.setReturnValue(stacks);
Comment on lines +319 to +321
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.

}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

public class ChangedGameData {
private final ServerLevel attachedLevel;
private int loggedFacilityTimes = 0;

public final List<ActiveFacilityInstance> facilities = new ObjectArrayList<>(2);

Expand Down Expand Up @@ -116,7 +117,10 @@ public void loadFeatures() {
facility.setHeader(pair.getSecond());
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

Changed.LOGGER.error("Failed to load facility from disk ", e);
loggedFacilityTimes++;
}
}
return null;
}).filter(Objects::nonNull).forEach(facilities::add);
Expand Down
1 change: 1 addition & 0 deletions src/main/resources/changed.mixins.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
"mixins": [
"DataFixTypesMixin",
"EnchantmentHelperMixin",
"EnchantmentMixin",
"InventoryMenuMixin",
"LevelMixin",
"NbtUtilsMixin",
Expand Down