1+ package be .isach .ultracosmetics .v1_16_R2 ;
2+
3+ import be .isach .ultracosmetics .UltraCosmeticsData ;
4+ import be .isach .ultracosmetics .util .UCMaterial ;
5+ import be .isach .ultracosmetics .version .AAnvilGUI ;
6+ import be .isach .ultracosmetics .version .IAnvilGUI ;
7+ import net .minecraft .server .v1_16_R2 .*;
8+ import org .apache .commons .lang .Validate ;
9+ import org .bukkit .Bukkit ;
10+ import org .bukkit .craftbukkit .v1_16_R2 .CraftWorld ;
11+ import org .bukkit .craftbukkit .v1_16_R2 .entity .CraftPlayer ;
12+ import org .bukkit .craftbukkit .v1_16_R2 .event .CraftEventFactory ;
13+ import org .bukkit .entity .Player ;
14+ import org .bukkit .event .EventHandler ;
15+ import org .bukkit .event .HandlerList ;
16+ import org .bukkit .event .Listener ;
17+ import org .bukkit .event .inventory .InventoryClickEvent ;
18+ import org .bukkit .event .inventory .InventoryCloseEvent ;
19+ import org .bukkit .inventory .Inventory ;
20+ import org .bukkit .inventory .ItemStack ;
21+ import org .bukkit .inventory .meta .ItemMeta ;
22+
23+ import java .lang .reflect .Field ;
24+ import java .lang .reflect .Modifier ;
25+ import java .util .function .BiFunction ;
26+ import java .util .function .Consumer ;
27+
28+ /**
29+ * @author wesjd
30+ */
31+ public class AnvilGUI implements IAnvilGUI {
32+
33+ /**
34+ * A state that decides where the anvil GUI is able to be closed by the user
35+ */
36+ private final boolean preventClose ;
37+ /**
38+ * An {@link Consumer} that is called when the anvil GUI is closed
39+ */
40+ private final Consumer <Player > closeListener ;
41+ /**
42+ * An {@link BiFunction} that is called when the {@link Slot#OUTPUT} slot has been clicked
43+ */
44+ private final BiFunction <Player , String , AAnvilGUI .Response > completeFunction ;
45+ /**
46+ * The listener holder class
47+ */
48+ private final ListenUp listener = new ListenUp ();
49+ /**
50+ * The text that will be displayed to the user
51+ */
52+ private String text = "" ;
53+ /**
54+ * The ItemStack that is in the {@link Slot#INPUT_LEFT} slot.
55+ */
56+ private ItemStack insert ;
57+ /**
58+ * The container id of the inventory, used for NMS methods
59+ */
60+ private int containerId ;
61+ /**
62+ * The inventory that is used on the Bukkit side of things
63+ */
64+ private Inventory inventory ;
65+ /**
66+ * Represents the state of the inventory being open
67+ */
68+ private boolean open ;
69+ private Player player ;
70+
71+ /**
72+ * Create an AnvilGUI and open it for the player.
73+ *
74+ * @param player The {@link Player} to open the inventory for
75+ * @param text What to have the text already set to
76+ * @param preventClose Whether to prevent the inventory from closing
77+ * @param closeListener A {@link Consumer} when the inventory closes
78+ * @param completeFunction A {@link BiFunction} that is called when the player clicks the {@link Slot#OUTPUT} slot
79+ */
80+ public AnvilGUI (Player player , String text , Boolean preventClose , Consumer <Player > closeListener , BiFunction <Player , String , AAnvilGUI .Response > completeFunction ) {
81+ this .player = player ;
82+ this .text = text ;
83+ this .preventClose = preventClose ;
84+ this .closeListener = closeListener ;
85+ this .completeFunction = completeFunction ;
86+ openInventory ();
87+ }
88+
89+ private void openInventory () {
90+ final ItemStack paper = UCMaterial .PAPER .parseItem ();
91+ final ItemMeta paperMeta = paper .getItemMeta ();
92+ paperMeta .setDisplayName ("Pet name" );
93+ paper .setItemMeta (paperMeta );
94+ this .insert = paper ;
95+
96+ CraftEventFactory .handleInventoryCloseEvent (toNMS (player ));
97+ toNMS (player ).activeContainer = toNMS (player ).defaultContainer ;
98+
99+ Bukkit .getPluginManager ().registerEvents (listener , UltraCosmeticsData .get ().getPlugin ());
100+
101+ final Object container = new AnvilContainer (player , getNextContainerId (player ));
102+
103+ inventory = toBukkitInventory (container );
104+ inventory .setItem (Slot .INPUT_LEFT , this .insert );
105+
106+ containerId = getNextContainerId (player );
107+ toNMS (player ).playerConnection .sendPacket (new PacketPlayOutOpenWindow (containerId , Containers .ANVIL , new ChatMessage ("Repair & Name" )));
108+ toNMS (player ).activeContainer = (Container ) container ;
109+ try {
110+ final Field field = Container .class .getField ("windowId" );
111+
112+ final Field modifiersField = Field .class .getDeclaredField ("modifiers" );
113+ modifiersField .setAccessible (true );
114+ modifiersField .setInt (field , field .getModifiers () & ~Modifier .FINAL );
115+
116+ field .set (container , containerId );
117+ } catch (Exception ex ) {
118+ throw new RuntimeException (ex );
119+ }
120+ ((Container ) container ).addSlotListener (toNMS (player ));
121+ open = true ;
122+ }
123+
124+ public void closeInventory () {
125+ Validate .isTrue (open , "You can't close an inventory that isn't open!" );
126+ open = false ;
127+
128+ CraftEventFactory .handleInventoryCloseEvent (toNMS (player ));
129+ toNMS (player ).activeContainer = toNMS (player ).defaultContainer ;
130+ toNMS (player ).playerConnection .sendPacket (new PacketPlayOutCloseWindow (containerId ));
131+
132+ HandlerList .unregisterAll (listener );
133+
134+ if (closeListener != null ) {
135+ closeListener .accept (player );
136+ }
137+ }
138+
139+ private EntityPlayer toNMS (Player player ) {
140+ return ((CraftPlayer ) player ).getHandle ();
141+ }
142+
143+ public int getNextContainerId (Player player ) {
144+ return toNMS (player ).nextContainerCounter ();
145+ }
146+
147+ public Inventory toBukkitInventory (Object container ) {
148+ return ((Container ) container ).getBukkitView ().getTopInventory ();
149+ }
150+
151+ public static class Slot {
152+
153+ /**
154+ * The slot on the far left, where the first input is inserted. An {@link ItemStack} is always inserted
155+ * here to be renamed
156+ */
157+ public static final int INPUT_LEFT = 0 ;
158+ /**
159+ * Not used, but in a real anvil you are able to put the second item you want to combine here
160+ */
161+ public static final int INPUT_RIGHT = 1 ;
162+ /**
163+ * The output slot, where an item is put when two items are combined from {@link #INPUT_LEFT} and
164+ * {@link #INPUT_RIGHT} or {@link #INPUT_LEFT} is renamed
165+ */
166+ public static final int OUTPUT = 2 ;
167+
168+ }
169+
170+ private class ListenUp implements Listener {
171+
172+ @ EventHandler
173+ public void onInventoryClick (InventoryClickEvent event ) {
174+ if (event .getInventory ().equals (inventory ) && event .getRawSlot () < 3 ) {
175+ event .setCancelled (true );
176+ final Player clicker = (Player ) event .getWhoClicked ();
177+ if (event .getRawSlot () == Slot .OUTPUT ) {
178+ final ItemStack clicked = inventory .getItem (Slot .OUTPUT );
179+ if (clicked == null || (clicked .getType () == UCMaterial .AIR .parseMaterial ()))
180+ return ;
181+
182+ final AAnvilGUI .Response response = completeFunction .apply (clicker , clicked .hasItemMeta () ? clicked .getItemMeta ().getDisplayName () : "" );
183+ if (response .getText () != null ) {
184+ final ItemMeta meta = clicked .getItemMeta ();
185+ meta .setDisplayName (response .getText ());
186+ clicked .setItemMeta (meta );
187+ inventory .setItem (Slot .INPUT_LEFT , clicked );
188+ } else {
189+ closeInventory ();
190+ }
191+ }
192+ }
193+ }
194+
195+ @ EventHandler
196+ public void onInventoryClose (InventoryCloseEvent event ) {
197+ if (open && event .getInventory ().equals (inventory )) {
198+ closeInventory ();
199+ if (preventClose ) {
200+ Bukkit .getScheduler ().runTask (UltraCosmeticsData .get ().getPlugin (), AnvilGUI .this ::openInventory );
201+ }
202+ }
203+ }
204+
205+ }
206+
207+ private class AnvilContainer extends ContainerAnvil {
208+
209+ public AnvilContainer (Player player , int containerId ) {
210+ super (containerId , ((CraftPlayer ) player ).getHandle ().inventory ,
211+ ContainerAccess .at (((CraftWorld ) player .getWorld ()).getHandle (), new BlockPosition (0 , 0 , 0 )));
212+ this .checkReachable = false ;
213+ setTitle (new ChatMessage ("Repair & Name" ));
214+ }
215+
216+ @ Override
217+ public void e () {
218+ super .e ();
219+ this .levelCost .set (0 );
220+ }
221+ }
222+ }
0 commit comments