mod for the islanders smp
1package net.radsteve.islanders.mixin;
2
3import com.google.common.collect.Iterators;
4import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
5import it.unimi.dsi.fastutil.ints.Int2ObjectMaps;
6import net.minecraft.item.Item;
7import net.minecraft.item.Items;
8import net.minecraft.network.packet.c2s.play.ClickSlotC2SPacket;
9import net.minecraft.registry.entry.RegistryEntry;
10import net.minecraft.registry.tag.ItemTags;
11import net.minecraft.screen.ScreenHandler;
12import net.minecraft.screen.slot.Slot;
13import net.minecraft.screen.sync.ItemStackHash;
14import net.minecraft.server.network.ServerPlayNetworkHandler;
15import net.minecraft.server.network.ServerPlayerEntity;
16import net.radsteve.islanders.Islanders;
17import org.spongepowered.asm.mixin.Mixin;
18import org.spongepowered.asm.mixin.Shadow;
19import org.spongepowered.asm.mixin.Unique;
20import org.spongepowered.asm.mixin.injection.At;
21import org.spongepowered.asm.mixin.injection.Inject;
22import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
23
24/// Warning: This is a huge mess and you should not touch this with a ten-foot pole
25/// This prevents special items from being put into bundles.
26/// Time counter: 5h
27@Mixin(ServerPlayNetworkHandler.class)
28public class BundleHandlerMixin {
29 @Shadow
30 public ServerPlayerEntity player;
31
32 /// DIRECTION ONE - item clicked first and dragged onto bundle
33
34 @Unique
35 private ClickSlotC2SPacket islanders$lastClickPacket = null;
36
37 @Unique
38 private Item islanders$lastClickedItem = null;
39
40 @Inject(method = "onClickSlot", at = @At(value = "INVOKE", target = "Lnet/minecraft/screen/ScreenHandler;disableSyncing()V"), cancellable = true)
41 private void islanders$onClickSlot(ClickSlotC2SPacket packet, CallbackInfo ci) {
42 if (islanders$lastClickPacket == null) {
43 islanders$lastClickPacket = packet;
44 return;
45 }
46
47 final var modifiedStacks = packet.modifiedStacks();
48 if (modifiedStacks.size() != 1) {
49 islanders$lastClickPacket = packet;
50 return;
51 }
52
53 final int slotIdx = Iterators.getOnlyElement(modifiedStacks.keySet().iterator());
54 final Slot currentSlot = player.currentScreenHandler.slots.get(slotIdx);
55 if (!currentSlot.getStack().itemMatches((entry) -> entry.isIn(ItemTags.BUNDLES))) {
56 islanders$lastClickPacket = packet;
57 islanders$lastClickedItem = currentSlot.getStack().getItem();
58 return;
59 }
60
61 if (!(modifiedStacks.get(slotIdx) instanceof ItemStackHash.Impl)) {
62 islanders$lastClickPacket = packet;
63 return;
64 }
65
66 final var lastModifiedStacks = islanders$lastClickPacket.modifiedStacks();
67 if (lastModifiedStacks.size() != 1) {
68 islanders$lastClickPacket = packet;
69 return;
70 }
71
72 final Item specialItem = islanders$lastClickedItem;
73
74 if (!(specialItem == Items.DRAGON_EGG || specialItem == Items.MACE || specialItem == Items.POPPED_CHORUS_FRUIT /* TODO: extra validation */)) {
75 islanders$lastClickPacket = packet;
76 return;
77 }
78
79 final ScreenHandler screenHandler = player.currentScreenHandler;
80
81 for (Int2ObjectMap.Entry<ItemStackHash> entry : Int2ObjectMaps.fastIterable(packet.modifiedStacks())) {
82 screenHandler.setReceivedHash(entry.getIntKey(), entry.getValue());
83 }
84
85 screenHandler.setReceivedCursorHash(packet.cursor());
86 screenHandler.enableSyncing();
87 screenHandler.updateToClient();
88 screenHandler.sendContentUpdates();
89 ci.cancel();
90
91 islanders$lastClickPacket = packet;
92
93 Islanders.getLogger().info("{} tried moving special item into bundle", player.getNameForScoreboard());
94 }
95
96 /// DIRECTION TWO - bundle clicked first and dragged onto item
97 /// This is a mess. Do not touch :)
98
99 @Unique
100 private ClickSlotC2SPacket islanders$lastClickPacket$0 = null;
101 @Unique
102 private RegistryEntry<Item> islanders$lastClickedItem$0 = null;
103
104 @Inject(method = "onClickSlot", at = @At(value = "INVOKE", target = "Lnet/minecraft/screen/ScreenHandler;disableSyncing()V"), cancellable = true)
105 private void islanders$onClickSlot$0(ClickSlotC2SPacket packet, CallbackInfo ci) {
106 if (islanders$lastClickPacket$0 == null) {
107 islanders$lastClickPacket$0 = packet;
108 }
109
110 final var modifiedStacks = packet.modifiedStacks();
111
112 if (islanders$lastClickedItem$0 == null) {
113 islanders$lastClickPacket$0 = packet;
114 if (!modifiedStacks.isEmpty()) {
115 final int slotIdx = Iterators.get(modifiedStacks.keySet().iterator(), 0);
116 final Slot currentSlot = player.currentScreenHandler.slots.get(slotIdx);
117 islanders$lastClickedItem$0 = currentSlot.getStack().getRegistryEntry();
118 }
119 return;
120 }
121
122 final boolean lastIsBundle = islanders$lastClickedItem$0.isIn(ItemTags.BUNDLES);
123
124 if (modifiedStacks.isEmpty() && !lastIsBundle) {
125 islanders$lastClickPacket$0 = packet;
126 return;
127 }
128
129 RegistryEntry<Item> currentItem;
130 if (modifiedStacks.isEmpty()) {
131 currentItem = islanders$lastClickedItem$0;
132 } else {
133 final int slotIdx = Iterators.get(modifiedStacks.keySet().iterator(), 0);
134 final Slot currentSlot = player.currentScreenHandler.slots.get(slotIdx);
135 currentItem = currentSlot.getStack().getRegistryEntry();
136 }
137
138 if (islanders$lastClickPacket$0 == null) {
139 return;
140 }
141
142 if (!islanders$lastClickedItem$0.isIn(ItemTags.BUNDLES)) {
143 islanders$lastClickPacket$0 = packet;
144 islanders$lastClickedItem$0 = currentItem;
145 return;
146 }
147
148 final Item specialItem = currentItem.value();
149
150 if (!(specialItem == Items.DRAGON_EGG || specialItem == Items.MACE || specialItem == Items.POPPED_CHORUS_FRUIT /* TODO: extra validation */)) {
151 islanders$lastClickPacket$0 = packet;
152 islanders$lastClickedItem$0 = currentItem;
153 return;
154 }
155
156 final ScreenHandler screenHandler = player.currentScreenHandler;
157
158 for (Int2ObjectMap.Entry<ItemStackHash> entry : Int2ObjectMaps.fastIterable(packet.modifiedStacks())) {
159 screenHandler.setReceivedHash(entry.getIntKey(), entry.getValue());
160 }
161
162 screenHandler.setReceivedCursorHash(packet.cursor());
163 screenHandler.enableSyncing();
164 screenHandler.updateToClient();
165 screenHandler.sendContentUpdates();
166 ci.cancel();
167
168 islanders$lastClickPacket$0 = packet;
169 Islanders.getLogger().info("{} tried moving special item into bundle", player.getNameForScoreboard());
170 }
171}