33import com .google .common .cache .CacheBuilder ;
44import com .google .common .cache .CacheLoader ;
55import com .google .common .cache .LoadingCache ;
6- import com .google .common .collect .MapMaker ;
76import com .google .common .hash .HashCode ;
87import com .mojang .serialization .DynamicOps ;
98import io .papermc .paper .adventure .PaperAdventure ;
4544import xyz .xenondevs .invui .Click ;
4645import xyz .xenondevs .invui .InvUI ;
4746import xyz .xenondevs .invui .internal .network .PacketListener ;
48- import xyz .xenondevs .invui .internal .util .FakeInventoryView ;
49- import xyz .xenondevs .invui .internal .util .InventoryUtils ;
50- import xyz .xenondevs .invui .internal .util .MathUtils ;
51- import xyz .xenondevs .invui .internal .util .PingData ;
47+ import xyz .xenondevs .invui .internal .util .*;
5248import xyz .xenondevs .invui .window .Window ;
5349
5450import java .time .Duration ;
5551import java .util .*;
5652import java .util .concurrent .ConcurrentHashMap ;
5753import java .util .concurrent .ConcurrentLinkedQueue ;
58- import java .util .concurrent .ConcurrentMap ;
5954
6055/**
6156 * A packet-based container menu.
@@ -82,12 +77,7 @@ public abstract class CustomContainerMenu {
8277 */
8378 private static final HashedPatchMap .HashGenerator HASH_GENERATOR = new HashedPatchMap .HashGenerator () {
8479
85- // layer 1 cache uses identity hash code to avoid expensive component hash code calculations
86- private final ConcurrentMap <Object , Integer > layer1 = new MapMaker ()
87- .weakKeys () // also enables identity-based lookup
88- .makeMap ();
89-
90- private final LoadingCache <TypedDataComponent <?>, Integer > layer2 = CacheBuilder .newBuilder ()
80+ private final LoadingCache <TypedDataComponent <?>, Integer > cache = CacheBuilder .newBuilder ()
9181 .expireAfterAccess (Duration .ofMinutes (1 ))
9282 .build (new CacheLoader <>() {
9383
@@ -104,11 +94,8 @@ public Integer load(TypedDataComponent<?> key) {
10494 });
10595
10696 @ Override
107- public Integer apply (TypedDataComponent <?> typedDataComponent ) {
108- return layer1 .computeIfAbsent (
109- typedDataComponent .value (),
110- _ -> layer2 .getUnchecked (typedDataComponent )
111- );
97+ public Integer apply (TypedDataComponent <?> tdc ) {
98+ return cache .getUnchecked (tdc );
11299 }
113100
114101 };
@@ -153,6 +140,23 @@ public Integer apply(TypedDataComponent<?> typedDataComponent) {
153140 private boolean dirtyCarried ;
154141 private boolean dirtyOffHand ;
155142
143+ private final HashedPatchMap .HashGenerator hashGenerator = new HashedPatchMap .HashGenerator () {
144+
145+ private final WeakIdentityToIntMap <Object > cache = new WeakIdentityToIntMap <>();
146+
147+ @ Override
148+ public Integer apply (TypedDataComponent <?> tdc ) {
149+ var c = tdc .value ();
150+ var cachedValue = cache .get (c );
151+ if (cachedValue .isPresent ())
152+ return cachedValue .getAsInt ();
153+ var value = HASH_GENERATOR .apply (tdc );
154+ cache .putAssertAbsent (c , value );
155+ return value ;
156+ }
157+
158+ };
159+
156160 /**
157161 * Creates a new {@link CustomContainerMenu} for the specified player.
158162 *
@@ -168,7 +172,7 @@ protected CustomContainerMenu(MenuType<?> menuType, org.bukkit.entity.Player pla
168172 int size = InventoryUtils .getSizeOf (menuType ) + LOWER_INVENTORY_SIZE ;
169173 this .items = NonNullList .withSize (size , ItemStack .EMPTY );
170174 this .remoteItems = NonNullList .withSize (size , HashedStack .EMPTY );
171- this .remoteOffHand = HashedStack .create (serverPlayer .getOffhandItem (), HASH_GENERATOR );
175+ this .remoteOffHand = HashedStack .create (serverPlayer .getOffhandItem (), hashGenerator );
172176 this .dirtyItems = new BitSet (size );
173177
174178 int dataSize = InventoryUtils .getDataSlotCountOf (menuType );
@@ -249,26 +253,26 @@ public void sendChangesToRemote(int pingId) {
249253 while ((itemSlot = dirtyItems .nextSetBit (itemSlot + 1 )) != -1 ) {
250254 var item = items .get (itemSlot );
251255 var remoteItem = remoteItems .get (itemSlot );
252- if (remoteItem == DIRTY_MARKER || !remoteItem .matches (item , HASH_GENERATOR )) {
256+ if (remoteItem == DIRTY_MARKER || !remoteItem .matches (item , hashGenerator )) {
253257 packets .add (new ClientboundContainerSetSlotPacket (containerId , incrementStateId (), itemSlot , item .copy ()));
254- remoteItems .set (itemSlot , HashedStack .create (item , HASH_GENERATOR ));
258+ remoteItems .set (itemSlot , HashedStack .create (item , hashGenerator ));
255259 }
256260 }
257261 dirtyItems .clear ();
258262
259263 if (dirtyOffHand ) {
260264 var offHand = serverPlayer .getOffhandItem ();
261- if (remoteOffHand == DIRTY_MARKER || !remoteOffHand .matches (offHand , HASH_GENERATOR )) {
265+ if (remoteOffHand == DIRTY_MARKER || !remoteOffHand .matches (offHand , hashGenerator )) {
262266 packets .add (new ClientboundContainerSetSlotPacket (serverPlayer .inventoryMenu .containerId , incrementStateId (), OFF_HAND_SLOT , offHand .copy ()));
263- remoteOffHand = HashedStack .create (offHand , HASH_GENERATOR );
267+ remoteOffHand = HashedStack .create (offHand , hashGenerator );
264268 }
265269 dirtyOffHand = false ;
266270 }
267271
268272 if (dirtyCarried ) {
269- if (remoteCarried == DIRTY_MARKER || !remoteCarried .matches (carried , HASH_GENERATOR )) {
273+ if (remoteCarried == DIRTY_MARKER || !remoteCarried .matches (carried , hashGenerator )) {
270274 packets .add (new ClientboundSetCursorItemPacket (carried .copy ()));
271- remoteCarried = HashedStack .create (carried , HASH_GENERATOR );
275+ remoteCarried = HashedStack .create (carried , hashGenerator );
272276 }
273277 dirtyCarried = false ;
274278 }
@@ -293,7 +297,7 @@ public void sendChangesToRemote(int pingId) {
293297 public void sendCarriedToRemote () {
294298 var content = new ClientboundSetCursorItemPacket (carried .copy ());
295299 PacketListener .getInstance ().injectOutgoing (player , content );
296- remoteCarried = HashedStack .create (carried , HASH_GENERATOR );
300+ remoteCarried = HashedStack .create (carried , hashGenerator );
297301 dirtyCarried = false ;
298302 }
299303
@@ -349,9 +353,9 @@ private List<Packet<? super ClientGamePacketListener>> createContainerInitPacket
349353 */
350354 private void markRemoteSynced () {
351355 for (int i = 0 ; i < items .size (); i ++) {
352- remoteItems .set (i , HashedStack .create (items .get (i ), HASH_GENERATOR ));
356+ remoteItems .set (i , HashedStack .create (items .get (i ), hashGenerator ));
353357 }
354- remoteCarried = HashedStack .create (carried , HASH_GENERATOR );
358+ remoteCarried = HashedStack .create (carried , hashGenerator );
355359 System .arraycopy (dataSlots , 0 , remoteDataSlots , 0 , dataSlots .length );
356360
357361 dirtyItems .clear ();
0 commit comments