1+ package net .imprex .zip .nms .v1_21_R4 ;
2+
3+ import java .io .ByteArrayInputStream ;
4+ import java .io .ByteArrayOutputStream ;
5+ import java .lang .reflect .InvocationTargetException ;
6+ import java .lang .reflect .Method ;
7+ import java .util .ArrayList ;
8+ import java .util .List ;
9+ import java .util .Optional ;
10+ import java .util .UUID ;
11+ import java .util .function .BiConsumer ;
12+
13+ import org .bukkit .Material ;
14+ import org .bukkit .craftbukkit .v1_21_R4 .CraftRegistry ;
15+ import org .bukkit .craftbukkit .v1_21_R4 .inventory .CraftItemStack ;
16+ import org .bukkit .inventory .ItemStack ;
17+ import org .bukkit .inventory .meta .SkullMeta ;
18+
19+ import com .mojang .authlib .GameProfile ;
20+ import com .mojang .authlib .properties .Property ;
21+
22+ import net .imprex .zip .common .ReflectionUtil ;
23+ import net .imprex .zip .nms .api .NmsManager ;
24+ import net .minecraft .core .RegistryAccess ;
25+ import net .minecraft .nbt .CompoundTag ;
26+ import net .minecraft .nbt .ListTag ;
27+ import net .minecraft .nbt .NbtAccounter ;
28+ import net .minecraft .nbt .NbtIo ;
29+ import net .minecraft .nbt .Tag ;
30+ import net .minecraft .world .item .component .ResolvableProfile ;
31+
32+ public class ZipNmsManager implements NmsManager {
33+
34+ private static final BiConsumer <SkullMeta , GameProfile > SET_PROFILE ;
35+
36+ private static final RegistryAccess DEFAULT_REGISTRY = CraftRegistry .getMinecraftRegistry ();
37+
38+ private static final CompoundTag NBT_EMPTY_ITEMSTACK = new CompoundTag ();
39+
40+ static {
41+ NBT_EMPTY_ITEMSTACK .putString ("id" , "minecraft:air" );
42+
43+ BiConsumer <SkullMeta , GameProfile > setProfile = (meta , profile ) -> {
44+ throw new NullPointerException ("Unable to find 'setProfile' method!" );
45+ };
46+
47+ Class <?> craftMetaSkullClass = new ItemStack (Material .PLAYER_HEAD )
48+ .getItemMeta ()
49+ .getClass ();
50+
51+ Method setResolvableProfileMethod = ReflectionUtil .searchMethod (craftMetaSkullClass , void .class , ResolvableProfile .class );
52+ if (setResolvableProfileMethod != null ) {
53+ setProfile = (meta , profile ) -> {
54+ try {
55+ setResolvableProfileMethod .invoke (meta , new ResolvableProfile (profile ));
56+ } catch (IllegalAccessException | InvocationTargetException e ) {
57+ e .printStackTrace ();
58+ }
59+ };
60+ } else {
61+ Method setProfileMethod = ReflectionUtil .searchMethod (craftMetaSkullClass , void .class , GameProfile .class );
62+ if (setProfileMethod != null ) {
63+ setProfile = (meta , profile ) -> {
64+ try {
65+ setProfileMethod .invoke (meta , profile );
66+ } catch (IllegalAccessException | InvocationTargetException e ) {
67+ e .printStackTrace ();
68+ }
69+ };
70+ }
71+ }
72+
73+ SET_PROFILE = setProfile ;
74+ }
75+
76+ public byte [] nbtToBinary (CompoundTag compound ) {
77+ try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream ()) {
78+ NbtIo .writeCompressed (compound , outputStream );
79+ return outputStream .toByteArray ();
80+ } catch (Exception e ) {
81+ e .printStackTrace ();
82+ }
83+ return null ;
84+ }
85+
86+ public CompoundTag binaryToNBT (byte [] binary ) {
87+ try (ByteArrayInputStream inputStream = new ByteArrayInputStream (binary )) {
88+ return NbtIo .readCompressed (inputStream , NbtAccounter .unlimitedHeap ());
89+ } catch (Exception e ) {
90+ e .printStackTrace ();
91+ }
92+ return new CompoundTag ();
93+ }
94+
95+ @ Override
96+ public byte [] itemstackToBinary (ItemStack [] items ) {
97+ CompoundTag inventory = new CompoundTag ();
98+ ListTag list = new ListTag ();
99+ for (ItemStack itemStack : items ) {
100+ if (itemStack == null || itemStack .getType () == Material .AIR ) {
101+ list .add (NBT_EMPTY_ITEMSTACK );
102+ } else {
103+ net .minecraft .world .item .ItemStack craftItem = CraftItemStack .asNMSCopy (itemStack );
104+ Tag tag = craftItem .save (DEFAULT_REGISTRY );
105+ list .add (tag );
106+ }
107+ }
108+ inventory .put ("i" , list );
109+ return nbtToBinary (inventory );
110+ }
111+
112+ @ Override
113+ public List <ItemStack > binaryToItemStack (byte [] binary ) {
114+ CompoundTag nbt = binaryToNBT (binary );
115+ List <ItemStack > items = new ArrayList <>();
116+ if (nbt .contains ("i" )) {
117+ Optional <ListTag > list = nbt .getList ("i" );
118+ if (list .isEmpty ()) {
119+ return items ;
120+ }
121+
122+ for (Tag base : list .get ()) {
123+ if (base instanceof CompoundTag itemTag ) {
124+ String itemType = itemTag .getString ("id" ).orElse ("" );
125+ if (itemType .equals ("minecraft:air" )) {
126+ items .add (new ItemStack (Material .AIR ));
127+ } else {
128+ Optional <net .minecraft .world .item .ItemStack > optional = net .minecraft .world .item .ItemStack .parse (DEFAULT_REGISTRY , itemTag );
129+ if (optional .isPresent ()) {
130+ items .add (CraftItemStack .asBukkitCopy (optional .get ()));
131+ }
132+ }
133+ }
134+ }
135+ }
136+ return items ;
137+ }
138+
139+ @ Override
140+ public void setSkullProfile (SkullMeta meta , String texture ) {
141+ try {
142+ GameProfile gameProfile = new GameProfile (UUID .randomUUID (), "" );
143+ gameProfile .getProperties ().put ("textures" , new Property ("textures" , texture ));
144+
145+ SET_PROFILE .accept (meta , gameProfile );
146+ } catch (Exception e ) {
147+ e .printStackTrace ();
148+ }
149+ }
150+
151+ @ Override
152+ public boolean isAir (Material material ) {
153+ return material == null || material == Material .AIR ;
154+ }
155+ }
0 commit comments