|
24 | 24 | */ |
25 | 25 | package org.spongepowered.common.mixin.core.world.entity.projectile; |
26 | 26 |
|
27 | | -import net.minecraft.advancements.CriteriaTriggers; |
28 | | -import net.minecraft.server.level.ServerLevel; |
29 | | -import net.minecraft.server.level.ServerPlayer; |
30 | | -import net.minecraft.stats.Stats; |
31 | | -import net.minecraft.tags.ItemTags; |
32 | | -import net.minecraft.world.entity.ExperienceOrb; |
33 | | -import net.minecraft.world.entity.item.ItemEntity; |
34 | | -import net.minecraft.world.entity.player.Player; |
| 27 | +import com.llamalad7.mixinextras.injector.wrapmethod.WrapMethod; |
| 28 | +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; |
| 29 | +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; |
| 30 | +import com.llamalad7.mixinextras.sugar.Cancellable; |
| 31 | +import it.unimi.dsi.fastutil.objects.ObjectArrayList; |
| 32 | +import net.minecraft.world.entity.Entity; |
35 | 33 | import net.minecraft.world.entity.projectile.FishingHook; |
36 | 34 | import net.minecraft.world.item.ItemStack; |
37 | | -import net.minecraft.world.level.storage.loot.BuiltInLootTables; |
38 | 35 | import net.minecraft.world.level.storage.loot.LootParams; |
39 | 36 | import net.minecraft.world.level.storage.loot.LootTable; |
40 | | -import net.minecraft.world.level.storage.loot.parameters.LootContextParamSets; |
41 | | -import net.minecraft.world.level.storage.loot.parameters.LootContextParams; |
42 | | -import org.checkerframework.checker.nullness.qual.NonNull; |
43 | 37 | import org.checkerframework.checker.nullness.qual.Nullable; |
| 38 | +import org.jetbrains.annotations.NotNull; |
44 | 39 | import org.spongepowered.api.data.Transaction; |
45 | | -import org.spongepowered.api.entity.Entity; |
46 | 40 | import org.spongepowered.api.entity.projectile.FishingBobber; |
| 41 | +import org.spongepowered.api.event.CauseStackManager; |
47 | 42 | import org.spongepowered.api.event.SpongeEventFactory; |
48 | 43 | import org.spongepowered.api.item.inventory.ItemStackSnapshot; |
49 | | -import org.spongepowered.asm.mixin.Final; |
50 | 44 | import org.spongepowered.asm.mixin.Mixin; |
51 | | -import org.spongepowered.asm.mixin.Overwrite; |
52 | 45 | import org.spongepowered.asm.mixin.Shadow; |
53 | 46 | import org.spongepowered.asm.mixin.injection.At; |
54 | 47 | import org.spongepowered.asm.mixin.injection.Inject; |
55 | 48 | import org.spongepowered.asm.mixin.injection.Slice; |
56 | 49 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; |
| 50 | +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; |
57 | 51 | import org.spongepowered.common.SpongeCommon; |
58 | 52 | import org.spongepowered.common.event.tracking.PhaseTracker; |
59 | 53 | import org.spongepowered.common.item.util.ItemStackUtil; |
60 | 54 |
|
61 | | -import java.util.ArrayList; |
62 | | -import java.util.Collections; |
63 | 55 | import java.util.List; |
64 | | -import java.util.stream.Collectors; |
65 | 56 |
|
66 | 57 | @Mixin(FishingHook.class) |
67 | 58 | public abstract class FishingHookMixin extends ProjectileMixin { |
68 | 59 |
|
69 | 60 | // @formatter:off |
70 | | - @Shadow private net.minecraft.world.entity.@Nullable Entity hookedIn; |
71 | | - @Shadow private int nibble; |
72 | | - @Shadow @Final private int luck; |
73 | | - |
74 | | - @Shadow @Nullable public abstract Player shadow$getPlayerOwner(); |
75 | | - @Shadow protected abstract void shadow$pullEntity(net.minecraft.world.entity.Entity var1); |
| 61 | + @Shadow @Nullable private Entity hookedIn; |
76 | 62 | // @formatter:on |
77 | 63 |
|
78 | 64 | @Inject(method = "setHookedEntity", at = @At("HEAD"), cancellable = true) |
79 | | - private void onSetHookedEntity(final net.minecraft.world.entity.@Nullable Entity hookedIn, final CallbackInfo ci) { |
80 | | - if (hookedIn != null && SpongeCommon |
81 | | - .post(SpongeEventFactory.createFishingEventHookEntity(PhaseTracker.getInstance().currentCause(), (Entity) hookedIn, (FishingBobber) this))) { |
| 65 | + private void impl$onSetHookedEntity(final @Nullable Entity hookedIn, final CallbackInfo ci) { |
| 66 | + if (hookedIn != null && SpongeCommon.post(SpongeEventFactory.createFishingEventHookEntity(PhaseTracker.getInstance().currentCause(), (org.spongepowered.api.entity.Entity) hookedIn, (FishingBobber) this))) { |
82 | 67 | this.hookedIn = null; |
83 | 68 | ci.cancel(); |
84 | 69 | } |
85 | 70 | } |
86 | 71 |
|
87 | | - /** |
88 | | - * @author Aaron1011 - February 6th, 2015 |
89 | | - * @author Minecrell - December 24th, 2016 (Updated to Minecraft 1.11.2) |
90 | | - * @author Minecrell - June 14th, 2017 (Rewritten to handle cases where no items are dropped) |
91 | | - * @reason This needs to handle for both cases where a fish and/or an entity is being caught. |
92 | | - */ |
93 | | - @Overwrite |
94 | | - public int retrieve(final ItemStack stack) { |
95 | | - final Player playerEntity = this.shadow$getPlayerOwner(); |
96 | | - |
97 | | - if (!this.shadow$level().isClientSide && playerEntity != null) { |
98 | | - int i = 0; |
99 | | - |
100 | | - // Sponge start |
101 | | - final List<Transaction<@NonNull ItemStackSnapshot>> transactions; |
102 | | - if (this.nibble > 0) { |
103 | | - // Moved from below |
104 | | - final LootParams.Builder lootcontext$builder = new LootParams.Builder((ServerLevel) this.shadow$level()) |
105 | | - .withParameter(LootContextParams.ORIGIN, this.shadow$position()) |
106 | | - .withParameter(LootContextParams.TOOL, stack) |
107 | | - .withParameter(LootContextParams.THIS_ENTITY, (FishingHook) (Object) this) |
108 | | - .withLuck((float)this.luck + playerEntity.getLuck()); |
109 | | - final LootTable lootTable = this.shadow$level().getServer().reloadableRegistries().getLootTable(BuiltInLootTables.FISHING); |
110 | | - final List<ItemStack> list = lootTable.getRandomItems(lootcontext$builder.create(LootContextParamSets.FISHING)); |
111 | | - transactions = list.stream().map(ItemStackUtil::snapshotOf) |
112 | | - .map(snapshot -> new Transaction<>(snapshot, snapshot)) |
113 | | - .collect(Collectors.toList()); |
114 | | - CriteriaTriggers.FISHING_ROD_HOOKED.trigger((ServerPlayer)playerEntity, stack, (FishingHook) (Object) this, list); |
115 | | - } else { |
116 | | - transactions = new ArrayList<>(); |
117 | | - } |
118 | | - PhaseTracker.getInstance().pushCause(playerEntity); |
119 | | - |
120 | | - if (SpongeCommon.post(SpongeEventFactory.createFishingEventStop(PhaseTracker.getInstance().currentCause(), ((FishingBobber) this), transactions))) { |
121 | | - // Event is cancelled |
122 | | - return 0; |
123 | | - } |
124 | | - // Sponge end |
125 | | - |
126 | | - if (this.hookedIn != null) { |
127 | | - this.shadow$pullEntity(this.hookedIn); |
128 | | - CriteriaTriggers.FISHING_ROD_HOOKED.trigger((ServerPlayer) playerEntity, stack, (FishingHook) (Object) this, Collections.emptyList()); |
129 | | - this.shadow$level().broadcastEntityEvent((FishingHook) (Object) this, (byte) 31); |
130 | | - i = this.hookedIn instanceof ItemEntity ? 3 : 5; |
131 | | - } // Sponge: Remove else |
132 | | - |
133 | | - // Sponge start - Moved up to event call |
134 | | - if (!transactions.isEmpty()) { // Sponge: Check if we have any transactions instead |
135 | | - //LootContext.Builder lootcontext$builder = new LootContext.Builder((WorldServer) this.world); |
136 | | - //lootcontext$builder.withLuck((float) this.field_191518_aw + playerEntity.getLuck()); |
| 72 | + @Inject(method = "retrieve", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/projectile/FishingHook;pullEntity(Lnet/minecraft/world/entity/Entity;)V"), cancellable = true) |
| 73 | + private void impl$onRetrieveHookedEntity(final ItemStack tool, final CallbackInfoReturnable<Integer> cir) { |
| 74 | + if (SpongeCommon.post(SpongeEventFactory.createFishingEventStop(PhaseTracker.getInstance().currentCause(), ((FishingBobber) this), List.of()))) { |
| 75 | + cir.setReturnValue(0); |
| 76 | + } |
| 77 | + } |
137 | 78 |
|
138 | | - // Use transactions |
139 | | - for (final Transaction<@NonNull ItemStackSnapshot> transaction : transactions) { |
140 | | - if (!transaction.isValid()) { |
141 | | - continue; |
142 | | - } |
143 | | - final ItemStack itemstack = (ItemStack) (Object) transaction.finalReplacement().asMutable(); |
144 | | - // Sponge end |
| 79 | + @WrapOperation(method = "retrieve", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/storage/loot/LootTable;getRandomItems(Lnet/minecraft/world/level/storage/loot/LootParams;)Lit/unimi/dsi/fastutil/objects/ObjectArrayList;")) |
| 80 | + private ObjectArrayList<ItemStack> impl$onRetrieveLootTable(final LootTable lootTable, final LootParams lootParams, final Operation<ObjectArrayList<ItemStack>> original, final @Cancellable CallbackInfoReturnable<Integer> cir) { |
| 81 | + final List<Transaction<@NotNull ItemStackSnapshot>> transactions = original.call(lootTable, lootParams) |
| 82 | + .stream().map(ItemStackUtil::snapshotOf).map(snapshot -> new Transaction<>(snapshot, snapshot)).toList(); |
145 | 83 |
|
146 | | - final ItemEntity entityitem = new ItemEntity(this.shadow$level(), this.shadow$getX(), this.shadow$getY(), this.shadow$getZ(), itemstack); |
147 | | - final double d0 = playerEntity.getX() - this.shadow$getX(); |
148 | | - final double d1 = playerEntity.getY() - this.shadow$getY(); |
149 | | - final double d2 = playerEntity.getZ() - this.shadow$getZ(); |
150 | | - final double d3 = Math.sqrt(d0 * d0 + d1 * d1 + d2 * d2); |
151 | | - //double d4 = 0.1D; |
152 | | - entityitem.setDeltaMovement(d0 * 0.1D, d1 * 0.1D + Math.sqrt(d3) * 0.08D, d2 * 0.1D); |
153 | | - this.shadow$level().addFreshEntity(entityitem); |
154 | | - playerEntity.level().addFreshEntity(new ExperienceOrb(playerEntity.level(), playerEntity.getX(), playerEntity.getY() + 0.5D, |
155 | | - playerEntity.getZ() + 0.5D, |
156 | | - this.random.nextInt(6) + 1)); |
| 84 | + if (SpongeCommon.post(SpongeEventFactory.createFishingEventStop(PhaseTracker.getInstance().currentCause(), ((FishingBobber) this), transactions))) { |
| 85 | + cir.setReturnValue(0); |
| 86 | + return ObjectArrayList.of(); |
| 87 | + } |
157 | 88 |
|
158 | | - if (itemstack.is(ItemTags.FISHES)) { |
159 | | - playerEntity.awardStat(Stats.FISH_CAUGHT, 1); |
160 | | - } |
161 | | - } |
162 | | - PhaseTracker.getInstance().popCause(); |
| 89 | + return transactions.stream().filter(Transaction::isValid) |
| 90 | + .map(t -> (ItemStack) (Object) t.finalReplacement().asMutable()).collect(ObjectArrayList.toList()); |
| 91 | + } |
163 | 92 |
|
164 | | - i = Math.max(i, 1); // Sponge: Don't lower damage if we've also caught an entity |
165 | | - } |
| 93 | + @WrapMethod(method = "retrieve") |
| 94 | + private int impl$wrapRetrieveWithCause(final ItemStack tool, final Operation<Integer> original) { |
| 95 | + final Entity owner = this.shadow$getOwner(); |
166 | 96 |
|
167 | | - if (this.shadow$onGround()) { |
168 | | - i = 2; |
169 | | - } |
| 97 | + if (owner == null) { |
| 98 | + return original.call(tool); |
| 99 | + } |
170 | 100 |
|
171 | | - this.shadow$discard(); |
172 | | - return i; |
173 | | - } else { |
174 | | - return 0; |
| 101 | + try (final CauseStackManager.StackFrame frame = PhaseTracker.getInstance().pushCauseFrame()) { |
| 102 | + frame.pushCause(owner); |
| 103 | + return original.call(tool); |
175 | 104 | } |
176 | 105 | } |
177 | 106 |
|
|
0 commit comments