|
1 | 1 | package xyz.nucleoid.stimuli.mixin.projectile;
|
2 | 2 |
|
| 3 | +import com.llamalad7.mixinextras.injector.v2.WrapWithCondition; |
| 4 | +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; |
| 5 | +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; |
3 | 6 | import com.llamalad7.mixinextras.sugar.Local;
|
| 7 | +import com.llamalad7.mixinextras.sugar.Share; |
| 8 | +import com.llamalad7.mixinextras.sugar.ref.LocalBooleanRef; |
| 9 | +import net.minecraft.entity.EquipmentSlot; |
4 | 10 | import net.minecraft.entity.LivingEntity;
|
5 | 11 | import net.minecraft.entity.projectile.PersistentProjectileEntity;
|
6 | 12 | import net.minecraft.entity.projectile.ProjectileEntity;
|
|
10 | 16 | import net.minecraft.item.RangedWeaponItem;
|
11 | 17 | import net.minecraft.server.network.ServerPlayerEntity;
|
12 | 18 | import net.minecraft.server.world.ServerWorld;
|
13 |
| -import net.minecraft.util.Hand; |
14 | 19 | import net.minecraft.world.World;
|
15 |
| -import org.jetbrains.annotations.Nullable; |
16 | 20 | import org.spongepowered.asm.mixin.Mixin;
|
17 | 21 | import org.spongepowered.asm.mixin.Shadow;
|
18 |
| -import org.spongepowered.asm.mixin.Unique; |
19 | 22 | import org.spongepowered.asm.mixin.injection.At;
|
20 |
| -import org.spongepowered.asm.mixin.injection.Inject; |
21 |
| -import org.spongepowered.asm.mixin.injection.ModifyArg; |
22 |
| -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; |
23 | 23 | import xyz.nucleoid.stimuli.Stimuli;
|
24 | 24 | import xyz.nucleoid.stimuli.duck.PassBowUseTicks;
|
25 | 25 | import xyz.nucleoid.stimuli.event.EventResult;
|
26 | 26 | import xyz.nucleoid.stimuli.event.projectile.ArrowFireEvent;
|
27 | 27 |
|
28 |
| -import java.util.List; |
| 28 | +import java.util.function.Consumer; |
29 | 29 |
|
30 | 30 | @Mixin(RangedWeaponItem.class)
|
31 | 31 | public abstract class RangedWeaponItemMixin implements PassBowUseTicks {
|
32 |
| - @Unique private ThreadLocal<ProjectileEntity> projectile = new ThreadLocal<>(); |
33 | 32 |
|
34 | 33 | @Shadow
|
35 | 34 | protected abstract ProjectileEntity createArrowEntity(World world, LivingEntity shooter, ItemStack weaponStack, ItemStack projectileStack, boolean critical);
|
36 | 35 |
|
37 |
| - @Inject( |
| 36 | + @WrapOperation( |
38 | 37 | method = "shootAll",
|
39 |
| - at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/projectile/ProjectileEntity;spawn(Lnet/minecraft/entity/projectile/ProjectileEntity;Lnet/minecraft/server/world/ServerWorld;Lnet/minecraft/item/ItemStack;Ljava/util/function/Consumer;)Lnet/minecraft/entity/projectile/ProjectileEntity;"), |
40 |
| - cancellable = true |
| 38 | + at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/projectile/ProjectileEntity;spawn(Lnet/minecraft/entity/projectile/ProjectileEntity;Lnet/minecraft/server/world/ServerWorld;Lnet/minecraft/item/ItemStack;Ljava/util/function/Consumer;)Lnet/minecraft/entity/projectile/ProjectileEntity;") |
41 | 39 | )
|
42 |
| - private void onFireArrow( |
43 |
| - ServerWorld world, |
44 |
| - LivingEntity shooter, |
45 |
| - Hand hand, |
46 |
| - ItemStack tool, |
47 |
| - List<ItemStack> projectiles, |
48 |
| - float speed, |
49 |
| - float divergence, |
50 |
| - boolean critical, |
51 |
| - @Nullable LivingEntity target, |
52 |
| - CallbackInfo ci, |
53 |
| - @Local(ordinal = 1) ItemStack projectileStack |
| 40 | + private ProjectileEntity onFireArrow( |
| 41 | + ProjectileEntity projectile, ServerWorld world, ItemStack projectileStack, Consumer<ProjectileEntity> beforeSpawn, Operation<ProjectileEntity> original, |
| 42 | + @Local(argsOnly = true, ordinal = 0) LivingEntity shooter, @Local(argsOnly = true) ItemStack tool, @Share("damage") LocalBooleanRef damage |
54 | 43 | ) {
|
55 | 44 | if (!(shooter instanceof ServerPlayerEntity player)) {
|
56 |
| - return; |
| 45 | + return null; |
57 | 46 | }
|
58 | 47 |
|
59 |
| - ProjectileEntity projectile = this.createArrowEntity(world, shooter, tool, projectileStack, critical); |
60 |
| - this.projectile.set(projectile); |
61 |
| - |
62 | 48 | Item projectileItem = projectileStack.getItem();
|
63 | 49 | if (!(projectileItem instanceof ArrowItem item) || !(projectile instanceof PersistentProjectileEntity persistentProjectile)) {
|
64 |
| - return; |
| 50 | + damage.set(true); |
| 51 | + return original.call(projectile, world, projectileStack, beforeSpawn); |
65 | 52 | }
|
66 | 53 |
|
67 | 54 | try (var invokers = Stimuli.select().forEntity(player)) {
|
68 | 55 | var result = invokers.get(ArrowFireEvent.EVENT)
|
69 | 56 | .onFireArrow(player, tool, item, this.stimuli$getLastRemainingUseTicks(), persistentProjectile);
|
70 | 57 |
|
71 | 58 | if (result == EventResult.DENY) {
|
72 |
| - ci.cancel(); |
| 59 | + damage.set(false); |
| 60 | + return projectile; |
73 | 61 | }
|
74 | 62 | }
|
| 63 | + damage.set(true); |
| 64 | + return original.call(projectile, world, projectileStack, beforeSpawn); |
75 | 65 | }
|
76 | 66 |
|
77 |
| - @ModifyArg( |
78 |
| - method = "shootAll", |
79 |
| - at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/projectile/ProjectileEntity;spawn(Lnet/minecraft/entity/projectile/ProjectileEntity;Lnet/minecraft/server/world/ServerWorld;Lnet/minecraft/item/ItemStack;Ljava/util/function/Consumer;)Lnet/minecraft/entity/projectile/ProjectileEntity;") |
80 |
| - ) |
81 |
| - private ProjectileEntity useStoredProjectile(ProjectileEntity original) { |
82 |
| - ProjectileEntity stored = this.projectile.get(); |
83 |
| - this.projectile.set(null); |
84 |
| - return stored != null ? stored : original; |
| 67 | + @WrapWithCondition(method = "shootAll", at = @At(value = "INVOKE", target = "Lnet/minecraft/item/ItemStack;damage(ILnet/minecraft/entity/LivingEntity;Lnet/minecraft/entity/EquipmentSlot;)V")) |
| 68 | + private boolean cancelDamageIfNoProjectile(ItemStack instance, int amount, LivingEntity entity, EquipmentSlot slot, @Share("damage") LocalBooleanRef damage) { |
| 69 | + return damage.get(); |
85 | 70 | }
|
86 | 71 | }
|
0 commit comments