Handle stack limits when equipping items to trinket slots

This commit is contained in:
Sollace 2022-09-21 15:08:52 +02:00
parent ac874945cd
commit e02589d07b
6 changed files with 161 additions and 5 deletions

View file

@ -0,0 +1,58 @@
package com.minelittlepony.unicopia.mixin.trinkets;
import org.jetbrains.annotations.Nullable;
import org.spongepowered.asm.mixin.*;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Redirect;
import dev.emi.trinkets.TrinketSlot;
import net.minecraft.item.ItemStack;
import net.minecraft.screen.ScreenHandler;
import net.minecraft.screen.slot.Slot;
import net.minecraft.util.collection.DefaultedList;
// fixed shift-clicking (handles other 10%)
@Mixin(ScreenHandler.class)
abstract class MixinScreenHandler {
@Nullable
private Slot currentSlot;
@Redirect(method = "insertItem",
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/util/collection/DefaultedList;get(I)Ljava/lang/Object;"
)
)
// manual capture of the current slot since @Redirect doesn't support local captures
private Object onGetSlot(DefaultedList<Slot> sender, int index) {
currentSlot = sender.get(index);
return currentSlot;
}
@Redirect(method = "insertItem",
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/screen/slot/Slot;getMaxItemCount()I"
)
)
// redirect slot.getMaxItemCount() to stack aware version
protected int onGetMaxItemCount(Slot sender, ItemStack stack) {
return canApply(sender) ? sender.getMaxItemCount(stack) : sender.getMaxItemCount();
}
@Redirect(method = "insertItem",
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/item/ItemStack;isEmpty()Z",
ordinal = 1
)
)
// redirect "if (!itemStack.isEmpty() && ItemStack.canCombine(stack, itemStack))" -> "if (!canNotInsert(itemStack, slot) && ItemStack.canCombine(stack, itemStack))"
protected boolean canNotInsert(ItemStack sender) {
return sender.isEmpty() || (canApply(currentSlot) && (currentSlot.getStack().getCount() + sender.getCount()) <= currentSlot.getMaxItemCount(sender));
}
private static boolean canApply(Slot slot) {
return slot instanceof TrinketSlot;
}
}

View file

@ -0,0 +1,20 @@
package com.minelittlepony.unicopia.mixin.trinkets;
import org.spongepowered.asm.mixin.*;
import com.minelittlepony.unicopia.trinkets.TrinketsDelegateImpl;
import dev.emi.trinkets.api.*;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.ItemStack;
@Mixin(TrinketItem.class)
abstract class MixinTrinketItem {
// overwrite with a max-count aware version (fixes inserting)
@Overwrite
public static boolean equipItem(PlayerEntity user, ItemStack stack) {
return TrinketsDelegateImpl.INSTANCE.getInventories(user)
.filter(inv -> TrinketsDelegateImpl.tryInsert(inv, stack, user))
.findFirst()
.isPresent();
}
}

View file

@ -0,0 +1,37 @@
package com.minelittlepony.unicopia.mixin.trinkets;
import org.spongepowered.asm.mixin.*;
import com.minelittlepony.unicopia.trinkets.TrinketsDelegateImpl;
import dev.emi.trinkets.*;
import dev.emi.trinkets.api.*;
import net.minecraft.item.ItemStack;
import net.minecraft.screen.slot.Slot;
@Mixin(SurvivalTrinketSlot.class)
abstract class MixinTrinketSurvivalSlot extends Slot implements TrinketSlot {
@Shadow(remap = false)
private @Final int slotOffset;
@Shadow(remap = false)
private @Final TrinketInventory trinketInventory;
MixinTrinketSurvivalSlot() { super(null, 0, 0, 0); }
@Override
public int getMaxItemCount(ItemStack stack) {
return TrinketsDelegateImpl.getMaxCount(stack, new SlotReference(trinketInventory, slotOffset), super.getMaxItemCount(stack));
}
}
@Mixin(CreativeTrinketSlot.class)
abstract class MixinTrinketCreativeSlot extends Slot implements TrinketSlot {
@Shadow(remap = false)
private @Final SurvivalTrinketSlot original;
MixinTrinketCreativeSlot() { super(null, 0, 0, 0); }
@Override
public int getMaxItemCount(ItemStack stack) {
return original.getMaxItemCount(stack);
}
}

View file

@ -9,14 +9,15 @@ import com.minelittlepony.unicopia.util.InventoryUtil;
import dev.emi.trinkets.TrinketSlot;
import dev.emi.trinkets.api.*;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.sound.SoundEvent;
import net.minecraft.util.Identifier;
import net.minecraft.world.event.GameEvent;
class TrinketsDelegateImpl implements TrinketsDelegate {
static final TrinketsDelegateImpl INSTANCE = new TrinketsDelegateImpl();
public class TrinketsDelegateImpl implements TrinketsDelegate {
public static final TrinketsDelegateImpl INSTANCE = new TrinketsDelegateImpl();
// who tf designed this api?
@Override
@ -71,7 +72,7 @@ class TrinketsDelegateImpl implements TrinketsDelegate {
);
}
private Stream<TrinketInventory> getInventories(LivingEntity entity) {
public Stream<TrinketInventory> getInventories(LivingEntity entity) {
return TrinketsApi.getTrinketComponent(entity)
.stream()
.map(component -> component.getInventory())
@ -82,4 +83,40 @@ class TrinketsDelegateImpl implements TrinketsDelegate {
private static Identifier getSlotId(SlotType slotType) {
return new Identifier(slotType.getGroup(), slotType.getName());
}
public static int getMaxCount(ItemStack stack, SlotReference ref, int normal) {
Trinket trinket = TrinketsApi.getTrinket(stack.getItem());
if (trinket instanceof UnicopiaTrinket ut) {
return Math.min(
normal,
Math.min(
stack.getMaxCount(),
ut.getMaxCount(stack, ref)
));
}
return normal;
}
public static boolean tryInsert(TrinketInventory inv, ItemStack stack, PlayerEntity user) {
int i = InventoryUtil.getOpenSlot(inv);
if (i == -1) {
return false;
}
SlotReference ref = new SlotReference(inv, i);
if (!TrinketSlot.canInsert(stack, ref, user)) {
return false;
}
Trinket trinket = TrinketsApi.getTrinket(stack.getItem());
SoundEvent soundEvent = stack.getEquipSound();
inv.setStack(i, stack.split(trinket instanceof UnicopiaTrinket ut ? ut.getMaxCount(stack, ref) : stack.getMaxCount()));
if (!stack.isEmpty() && soundEvent != null) {
user.emitGameEvent(GameEvent.EQUIP);
user.playSound(soundEvent, 1, 1);
}
return true;
}
}

View file

@ -35,7 +35,7 @@ public class UnicopiaTrinket implements Trinket {
}
// @Override
public int getMaxCount(ItemStack stack, SlotReference slot, LivingEntity entity) {
public int getMaxCount(ItemStack stack, SlotReference slot) {
// https://github.com/emilyploszaj/trinkets/issues/215
return 1;
}

View file

@ -32,7 +32,11 @@
"MixinShulkerEntity",
"MixinTargetPredicate",
"MixinWorld",
"MixinWorldChunk"
"MixinWorldChunk",
"trinkets.MixinTrinketSurvivalSlot",
"trinkets.MixinTrinketCreativeSlot",
"trinkets.MixinTrinketItem",
"trinkets.MixinScreenHandler"
],
"client": [
"client.MixinAnimalModel",