World Border (Fabric)

World Border (Fabric)

261k Downloads

Requiem Softlock Bug/Collective Compatibility Issue.

dalekfan opened this issue · 2 comments

commented

Information

Minecraft version: 1.18.2
Modloader: Fabric
Fabric loader version:
Environment: Singleplayer / Multiplayer

Mod name: Requiem
Mod version: 2.0.0-beta.8.jar

Description

So, it seems your collective library mod seems to be making it impossible for players to self-cure while possessing a undead mob. I don't know how familiar you are with this mod, but basically when you die, instead of respawning, you become a ghost and can possess undead stuff. The goal usually is to eventually cure yourself so you aren't weighed down by undead weaknesses, but alas, your mod seems to be interfering with that somehow. Normally you'd just need to apply a weakness potion to yourself and eat a golden apple, but for some reason it's not registering as a cure attempt. Under normal circumstances, the weakness effect should be replaced by strength, and no additional side effects happen until the strength runs out, in which you are then cured.

Crash report

Sorry, no crash, just a softlock of sorts.

commented

The incompatibility stems from ItemStackMixin#finishUsingItem. It applies before any other mixin and it always calls setReturnValue, which cancels normal execution of the method, preventing other events from firing. I believe this same issue also prevents Origins' powers from working correctly.

A more compatible alternative to the current injection would be something like this:

private static final ThreadLocal<ItemStack> COLLECTIVE$PROCESSED_STACK = new ThreadLocal<>();

@Inject(method = "finishUsingItem(Lnet/minecraft/world/level/Level;Lnet/minecraft/world/entity/LivingEntity;)Lnet/minecraft/world/item/ItemStack;", at = @At(value = "HEAD"), cancellable = true)
public void finishUsingItem(Level level, LivingEntity livingEntity, CallbackInfoReturnable<ItemStack> cir) {
	if (livingEntity instanceof Player) {
		ItemStack itemStack = (ItemStack) (Object) this;
		COLLECTIVE$PROCESSED_STACK.set(itemStack.copy());
	}
}

@Inject(method = "finishUsingItem(Lnet/minecraft/world/level/Level;Lnet/minecraft/world/entity/LivingEntity;)Lnet/minecraft/world/item/ItemStack;", at = @At(value = "HEAD"), cancellable = true)
public void finishUsingItem(Level level, LivingEntity livingEntity, CallbackInfoReturnable<ItemStack> cir) {
	if (livingEntity instanceof Player) {
		ItemStack copyStack = COLLECTIVE$PROCESSED_STACK.get();
		ItemStack newStack = cir.getReturnValue();
			InteractionHand hand = livingEntity.getUsedItemHand();
		boolean changed = CollectiveItemEvents.ON_ITEM_USE_FINISHED.invoker().onItemUsedFinished((Player) livingEntity, copyStack, newStack, hand);

		if (changed) cir.setReturnValue(newStack);
	}
}
commented

Thanks @Pyrofab for the code suggestion! In the end I went with this code, but it's heavily based on your example:

private static final ThreadLocal<ItemStack> COLLECTIVE$PROCESSED_STACK = new ThreadLocal<>();

@Inject(method = "finishUsingItem(Lnet/minecraft/world/level/Level;Lnet/minecraft/world/entity/LivingEntity;)Lnet/minecraft/world/item/ItemStack;", at = @At(value = "HEAD"))
public void finishUsingItemA(Level level, LivingEntity livingEntity, CallbackInfoReturnable<ItemStack> cir) {
	if (livingEntity instanceof Player) {
		ItemStack itemStack = (ItemStack) (Object) this;
		COLLECTIVE$PROCESSED_STACK.set(itemStack.copy());
	}
}

@Inject(method = "finishUsingItem(Lnet/minecraft/world/level/Level;Lnet/minecraft/world/entity/LivingEntity;)Lnet/minecraft/world/item/ItemStack;", at = @At(value = "RETURN"), cancellable = true)
public void finishUsingItemB(Level level, LivingEntity livingEntity, CallbackInfoReturnable<ItemStack> cir) {
	if (livingEntity instanceof Player) {
		InteractionHand hand = livingEntity.getUsedItemHand();

		ItemStack copyStack = COLLECTIVE$PROCESSED_STACK.get();
		ItemStack newStack = cir.getReturnValue();
		ItemStack changedStack = CollectiveItemEvents.ON_ITEM_USE_FINISHED.invoker().onItemUsedFinished((Player) livingEntity, copyStack, newStack, hand);

		if (changedStack != null) {
			cir.setReturnValue(changedStack);
		}
	}
}

This should fix the incompatibility problem in version 4.63 of Collective. Apologies it took so long. Thank you @dalekfan for opening the issue!

https://www.curseforge.com/minecraft/mc-mods/collective-fabric/files