Skip to content

Commit

Permalink
fix: Auto switch elytra (#6)
Browse files Browse the repository at this point in the history
* fix: auto switch elytra dont check if player isOnGround()

* fix: auto switch elytra switch back to default chestplate

* fix: improve InventoryUtils.swapElytraWithChestPlate

* fix: improve InventoryUtils.swapElytraWithChestPlate

* Reformatting

* Reformatting

---------

Co-authored-by: Sakura Ryoko <[email protected]>
  • Loading branch information
zly2006 and sakura-ryoko authored Jun 23, 2024
1 parent 700b8c8 commit 60d518f
Show file tree
Hide file tree
Showing 3 changed files with 91 additions and 27 deletions.
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ author = masa
mod_file_name = tweakeroo-fabric

# Current mod version
mod_version = 0.20.999-sakura.7
mod_version = 0.20.999-sakura.7-pr6

# Required malilib version
malilib_version = 0.19.999-sakura.3
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,17 +33,12 @@ public abstract class MixinClientPlayerEntity extends AbstractClientPlayerEntity
{
@Shadow public Input input;
@Shadow protected int ticksLeftToDoubleTapSprint;

@Shadow public float prevNauseaIntensity;
@Shadow public float nauseaIntensity;
@Unique
private final DummyMovementInput dummyMovementInput = new DummyMovementInput(null);
@Unique
private Input realInput;
@Unique
private float realNauseaIntensity;
@Unique
private ItemStack autoSwitchElytraChestplate = ItemStack.EMPTY;
@Unique private final DummyMovementInput dummyMovementInput = new DummyMovementInput(null);
@Unique private Input realInput;
@Unique private float realNauseaIntensity;
@Unique private ItemStack autoSwitchElytraChestplate = ItemStack.EMPTY;

private MixinClientPlayerEntity(ClientWorld world, GameProfile profile)
{
Expand Down Expand Up @@ -133,14 +128,17 @@ private void onFallFlyingCheckChestSlot(CallbackInfo ci)
if (FeatureToggle.TWEAK_AUTO_SWITCH_ELYTRA.getBooleanValue())
{
// Sakura's version calculating fall distance...
/*
if ((!this.getEquippedStack(EquipmentSlot.CHEST).isOf(Items.ELYTRA) && this.fallDistance > 20.0f)
//if ((!this.getEquippedStack(EquipmentSlot.CHEST).isOf(Items.ELYTRA) && this.fallDistance > 20.0f)

// Auto switch if it is not elytra after falling, or is totally broken.
// This also shouldn't activate on the Ground if the Chest Equipment is EMPTY,
// or not an Elytra to be swapped back.
//
// !isOnGround(): Minecraft also check elytra even if the player is on the ground, skip it.
if (!this.isOnGround()
&& (!this.getEquippedStack(EquipmentSlot.CHEST).isOf(Items.ELYTRA))
|| (this.getEquippedStack(EquipmentSlot.CHEST).getDamage() > this.getEquippedStack(EquipmentSlot.CHEST).getMaxDamage() - 10)
&& (!this.getEquippedStack(EquipmentSlot.CHEST).isEmpty() || this.autoSwitchElytraChestplate.isOf(Items.ELYTRA)))
*/
// auto switch if it is not elytra or is totally broken.
if (getEquippedStack(EquipmentSlot.CHEST).isOf(Items.ELYTRA) == false ||
getEquippedStack(EquipmentSlot.CHEST).getDamage() > getEquippedStack(EquipmentSlot.CHEST).getMaxDamage() - 10)
{
this.autoSwitchElytraChestplate = this.getEquippedStack(EquipmentSlot.CHEST).copy();
InventoryUtils.swapElytraWithChestPlate(this);
Expand All @@ -154,21 +152,30 @@ private void onFallFlyingCheckChestSlot(CallbackInfo ci)
}

@Inject(method = "tickMovement", at = @At("RETURN"))
private void onMovementEnd(CallbackInfo ci) {
private void onMovementEnd(CallbackInfo ci)
{
if (FeatureToggle.TWEAK_AUTO_SWITCH_ELYTRA.getBooleanValue())
{
if (!this.autoSwitchElytraChestplate.isEmpty() && !this.isFallFlying() && this.getEquippedStack(EquipmentSlot.CHEST).isOf(Items.ELYTRA))
if (!this.isFallFlying() && this.getEquippedStack(EquipmentSlot.CHEST).isOf(Items.ELYTRA))
{
if (this.playerScreenHandler.getCursorStack().isEmpty())
if (!this.autoSwitchElytraChestplate.isEmpty())
{
int targetSlot = InventoryUtils.findSlotWithItem(this.playerScreenHandler, this.autoSwitchElytraChestplate, true, false);

if (targetSlot >= 0)
if (this.playerScreenHandler.getCursorStack().isEmpty())
{
InventoryUtils.swapItemToEquipmentSlot(this, EquipmentSlot.CHEST, targetSlot);
this.autoSwitchElytraChestplate = ItemStack.EMPTY;
int targetSlot = InventoryUtils.findSlotWithItem(this.playerScreenHandler, this.autoSwitchElytraChestplate, true, false);

if (targetSlot >= 0)
{
InventoryUtils.swapItemToEquipmentSlot(this, EquipmentSlot.CHEST, targetSlot);
this.autoSwitchElytraChestplate = ItemStack.EMPTY;
}
}
}
else
{
// if cached previous item is empty, try to swap back to the default chest plate.
InventoryUtils.swapElytraWithChestPlate(this);
}
}
}
}
Expand Down
63 changes: 60 additions & 3 deletions src/main/java/fi/dy/masa/tweakeroo/util/InventoryUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.io.ObjectInputFilter;
import java.util.*;
import java.util.function.Predicate;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import net.minecraft.block.BlockState;
import net.minecraft.client.MinecraftClient;
import net.minecraft.component.DataComponentTypes;
import net.minecraft.component.type.AttributeModifierSlot;
import net.minecraft.component.type.AttributeModifiersComponent;
import net.minecraft.component.type.ItemEnchantmentsComponent;
import net.minecraft.enchantment.Enchantment;
Expand Down Expand Up @@ -862,9 +862,38 @@ public static void swapElytraWithChestPlate(@Nullable PlayerEntity player)

Predicate<ItemStack> stackFilterChestPlate = (s) -> s.getItem() instanceof ArmorItem && ((ArmorItem) s.getItem()).getSlotType() == EquipmentSlot.CHEST;
Predicate<ItemStack> stackFilterElytra = (s) -> s.getItem() instanceof ElytraItem && ElytraItem.isUsable(s);
Predicate<ItemStack> stackFilter = (currentStack.isEmpty() || stackFilterChestPlate.test(currentStack)) ? stackFilterElytra : stackFilterChestPlate;
boolean switchingToElytra = (currentStack.isEmpty() || stackFilterChestPlate.test(currentStack));
Predicate<ItemStack> stackFilter = switchingToElytra ? stackFilterElytra : stackFilterChestPlate;
Predicate<ItemStack> finalFilter = (s) -> s.isEmpty() == false && stackFilter.test(s) && s.getDamage() < s.getMaxDamage() - 10;
int targetSlot = findSuitableSlot(container, finalFilter);

int targetSlot = findSlotWithBestItemMatch(container, (testedStack, previousBestMatch) -> {
if (!finalFilter.test(testedStack)) return false;
if (!finalFilter.test(previousBestMatch)) return true;
if (switchingToElytra)
{
if (getEnchantmentLevel(testedStack, Enchantments.UNBREAKING) < getEnchantmentLevel(previousBestMatch, Enchantments.UNBREAKING))
{
return false;
}
if (testedStack.getDamage() > previousBestMatch.getDamage())
{
return false;
}
}
else
{
if (getArmorAndArmorToughnessValue(previousBestMatch, 1, AttributeModifierSlot.CHEST) > getArmorAndArmorToughnessValue(testedStack, 1, AttributeModifierSlot.CHEST))
{
return false;
}
if (getEnchantmentLevel(previousBestMatch, Enchantments.PROTECTION) > getEnchantmentLevel(testedStack, Enchantments.PROTECTION))
{
return false;
}
}

return true;
}, UniformIntProvider.create(9, container.slots.size() - 1));

if (targetSlot >= 0)
{
Expand All @@ -873,6 +902,34 @@ public static void swapElytraWithChestPlate(@Nullable PlayerEntity player)
}
}

private static double getArmorAndArmorToughnessValue(ItemStack stack, double base, AttributeModifierSlot slot)
{
final double[] total = {base};

stack.applyAttributeModifier(slot, (entry, modifier) -> {
if (entry.getKey().orElseThrow() == EntityAttributes.GENERIC_ARMOR
|| entry.getKey().orElseThrow() == EntityAttributes.GENERIC_ARMOR_TOUGHNESS)
{
switch (modifier.operation())
{
case ADD_VALUE:
total[0] += modifier.value();
break;
case ADD_MULTIPLIED_BASE:
total[0] += modifier.value() * base;
break;
case ADD_MULTIPLIED_TOTAL:
total[0] += modifier.value() * total[0];
break;
default:
throw new MatchException(null, null);
}
}
});

return total[0];
}

/**
*
* Finds a slot with an identical item than <b>stackReference</b>, ignoring the durability
Expand Down

0 comments on commit 60d518f

Please sign in to comment.