|
25 | 25 | package org.spongepowered.common.mixin.tracker.world.level.block; |
26 | 26 |
|
27 | 27 | import com.google.common.collect.ImmutableList; |
| 28 | +import com.llamalad7.mixinextras.injector.wrapmethod.WrapMethod; |
| 29 | +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; |
| 30 | +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; |
| 31 | +import com.llamalad7.mixinextras.sugar.Share; |
| 32 | +import com.llamalad7.mixinextras.sugar.ref.LocalRef; |
28 | 33 | import net.minecraft.core.BlockPos; |
29 | 34 | import net.minecraft.core.dispenser.BlockSource; |
30 | 35 | import net.minecraft.core.dispenser.DispenseItemBehavior; |
|
33 | 38 | import net.minecraft.world.level.block.DispenserBlock; |
34 | 39 | import net.minecraft.world.level.block.entity.DispenserBlockEntity; |
35 | 40 | import net.minecraft.world.level.block.state.BlockState; |
| 41 | +import org.checkerframework.checker.nullness.qual.NonNull; |
| 42 | +import org.checkerframework.checker.nullness.qual.Nullable; |
36 | 43 | import org.spongepowered.api.event.CauseStackManager; |
37 | 44 | import org.spongepowered.api.event.SpongeEventFactory; |
38 | 45 | import org.spongepowered.api.event.item.inventory.DropItemEvent; |
39 | 46 | import org.spongepowered.api.item.inventory.ItemStackSnapshot; |
40 | 47 | import org.spongepowered.api.world.BlockChangeFlags; |
41 | 48 | import org.spongepowered.asm.mixin.Mixin; |
42 | 49 | import org.spongepowered.asm.mixin.injection.At; |
43 | | -import org.spongepowered.asm.mixin.injection.Inject; |
44 | | -import org.spongepowered.asm.mixin.injection.Redirect; |
45 | 50 | import org.spongepowered.asm.mixin.injection.Slice; |
46 | | -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; |
47 | | -import org.spongepowered.asm.mixin.injection.callback.LocalCapture; |
48 | 51 | import org.spongepowered.common.SpongeCommon; |
49 | 52 | import org.spongepowered.common.block.SpongeBlockSnapshot; |
50 | 53 | import org.spongepowered.common.bridge.world.TrackedWorldBridge; |
|
56 | 59 |
|
57 | 60 | import java.util.ArrayList; |
58 | 61 | import java.util.List; |
59 | | -import java.util.function.Supplier; |
60 | 62 |
|
61 | 63 | @Mixin(DispenserBlock.class) |
62 | 64 | public abstract class DispenserBlockMixin_Tracker { |
63 | | - private Supplier<ItemStack> tracker$originalItem = () -> ItemStack.EMPTY; |
64 | | - private PhaseContext<?> tracker$context = PhaseContext.empty(); |
65 | 65 |
|
66 | | - @Inject(method = "dispenseFrom", at = @At(value = "HEAD")) |
67 | | - private void tracker$createContextOnDispensing(final ServerLevel worldIn, final BlockState state, final BlockPos pos, final CallbackInfo ci) { |
| 66 | + @WrapMethod(method = "dispenseFrom") |
| 67 | + private void tracker$createContextOnDispensing(final ServerLevel worldIn, final BlockState state, final BlockPos pos, final Operation<Void> original) { |
68 | 68 | final SpongeBlockSnapshot spongeBlockSnapshot = ((TrackedWorldBridge) worldIn).bridge$createSnapshot(state, pos, BlockChangeFlags.ALL); |
69 | 69 | final LevelChunkBridge mixinChunk = (LevelChunkBridge) worldIn.getChunkAt(pos); |
70 | | - this.tracker$context = BlockPhase.State.DISPENSE.createPhaseContext(PhaseTracker.SERVER) |
| 70 | + try (final @Nullable PhaseContext<@NonNull ?> context = BlockPhase.State.DISPENSE |
| 71 | + .createPhaseContext(PhaseTracker.SERVER) |
71 | 72 | .source(spongeBlockSnapshot) |
72 | 73 | .creator(() -> mixinChunk.bridge$getBlockCreatorUUID(pos)) |
73 | | - .notifier(() -> mixinChunk.bridge$getBlockNotifierUUID(pos)) |
74 | | - .buildAndSwitch(); |
| 74 | + .notifier(() -> mixinChunk.bridge$getBlockNotifierUUID(pos))) { |
| 75 | + context.buildAndSwitch(); |
| 76 | + original.call(worldIn, state, pos); |
| 77 | + } |
75 | 78 | } |
76 | 79 |
|
77 | 80 |
|
78 | | - @Inject(method = "dispenseFrom", at = @At(value = "RETURN")) |
79 | | - private void tracker$closeContextOnDispensing(final ServerLevel worldIn, final BlockState state, final BlockPos pos, final CallbackInfo ci) { |
80 | | - this.tracker$context.close(); |
81 | | - this.tracker$context = PhaseContext.empty(); |
82 | | - } |
83 | | - |
84 | | - @Inject(method = "dispenseFrom", |
85 | | - at = @At( |
86 | | - value = "INVOKE", |
87 | | - target = "Lnet/minecraft/core/dispenser/DispenseItemBehavior;dispense(Lnet/minecraft/core/dispenser/BlockSource;Lnet/minecraft/world/item/ItemStack;)Lnet/minecraft/world/item/ItemStack;" |
88 | | - ), |
89 | | - slice = @Slice( |
90 | | - from = @At(value = "FIELD", |
91 | | - target = "Lnet/minecraft/core/dispenser/DispenseItemBehavior;NOOP:Lnet/minecraft/core/dispenser/DispenseItemBehavior;"), |
92 | | - to = @At("TAIL") |
93 | | - ), |
94 | | - locals = LocalCapture.CAPTURE_FAILSOFT |
| 81 | + @WrapOperation(method = "dispenseFrom", |
| 82 | + at = @At( |
| 83 | + value = "INVOKE", |
| 84 | + target = "Lnet/minecraft/core/dispenser/DispenseItemBehavior;dispense(Lnet/minecraft/core/dispenser/BlockSource;Lnet/minecraft/world/item/ItemStack;)Lnet/minecraft/world/item/ItemStack;" |
| 85 | + ), |
| 86 | + slice = @Slice( |
| 87 | + from = @At(value = "FIELD", |
| 88 | + target = "Lnet/minecraft/core/dispenser/DispenseItemBehavior;NOOP:Lnet/minecraft/core/dispenser/DispenseItemBehavior;"), |
| 89 | + to = @At("TAIL") |
| 90 | + ) |
95 | 91 | ) |
96 | | - private void tracker$storeOriginalItem(final ServerLevel worldIn, final BlockState state, final BlockPos pos, final CallbackInfo ci, |
97 | | - final DispenserBlockEntity dispenser, final BlockSource source, final int slotIndex, final ItemStack dispensedItem, final DispenseItemBehavior behavior) { |
98 | | - final ItemStack tracker$originalItem = ItemStackUtil.cloneDefensiveNative(dispensedItem); |
99 | | - this.tracker$originalItem = () -> tracker$originalItem; |
| 92 | + private ItemStack tracker$storeOriginalItem(final DispenseItemBehavior instance, final BlockSource blockSource, final ItemStack itemStack, |
| 93 | + final Operation<ItemStack> original, final @Share("original-item") LocalRef<ItemStack> originalItemRef) { |
| 94 | + originalItemRef.set(ItemStackUtil.cloneDefensiveNative(itemStack)); |
| 95 | + return original.call(instance, blockSource, itemStack); |
100 | 96 | } |
101 | 97 |
|
102 | | - |
103 | | - @Redirect(method = "dispenseFrom", |
| 98 | + @WrapOperation(method = "dispenseFrom", |
104 | 99 | at = @At(value = "INVOKE", |
105 | 100 | target = "Lnet/minecraft/world/level/block/entity/DispenserBlockEntity;setItem(ILnet/minecraft/world/item/ItemStack;)V")) |
106 | | - private void tracker$setInventoryContentsCallEvent(final DispenserBlockEntity dispenserTileEntity, final int index, final ItemStack stack) { |
| 101 | + private void tracker$setInventoryContentsCallEvent(final DispenserBlockEntity dispenserTileEntity, final int index, final ItemStack stack, |
| 102 | + final Operation<Void> original, final @Share("original-item") LocalRef<ItemStack> originalItemRef) { |
107 | 103 | final ItemStack dispensedItem = ItemStack.EMPTY; |
108 | 104 | final ItemStackSnapshot snapshot = ItemStackUtil.snapshotOf(dispensedItem); |
109 | | - final List<ItemStackSnapshot> original = new ArrayList<>(); |
110 | | - original.add(snapshot); |
| 105 | + final List<ItemStackSnapshot> items = new ArrayList<>(); |
| 106 | + items.add(snapshot); |
111 | 107 | try (final CauseStackManager.StackFrame frame = PhaseTracker.getInstance().pushCauseFrame()) { |
112 | 108 | frame.pushCause(dispenserTileEntity); |
113 | | - final DropItemEvent.Pre dropEvent = SpongeEventFactory.createDropItemEventPre(frame.currentCause(), ImmutableList.of(snapshot), original); |
114 | | - SpongeCommon.post(dropEvent); |
115 | | - if (dropEvent.isCancelled()) { |
116 | | - dispenserTileEntity.setItem(index, this.tracker$originalItem.get()); |
| 109 | + final DropItemEvent.Pre dropEvent = SpongeEventFactory.createDropItemEventPre(frame.currentCause(), ImmutableList.of(snapshot), items); |
| 110 | + if (SpongeCommon.post(dropEvent)) { |
| 111 | + original.call(dispenserTileEntity, index, originalItemRef.get()); |
117 | 112 | return; |
118 | 113 | } |
119 | 114 |
|
120 | | - dispenserTileEntity.setItem(index, stack); |
121 | | - } finally { |
122 | | - this.tracker$originalItem = () -> ItemStack.EMPTY; |
| 115 | + original.call(dispenserTileEntity, index, stack); |
123 | 116 | } |
124 | 117 | } |
125 | 118 | } |
0 commit comments