Skip to content

Commit cd4e58a

Browse files
Fix windowState not correctly synced
1 parent 3591341 commit cd4e58a

4 files changed

Lines changed: 47 additions & 41 deletions

File tree

invui/src/main/java/xyz/xenondevs/invui/internal/menu/CustomContainerMenu.java

Lines changed: 36 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -198,8 +198,10 @@ public org.bukkit.inventory.ItemStack getCursor() {
198198

199199
/**
200200
* Sends all changes to the remote client.
201+
*
202+
* @param pingId Optional ping id to also send a ping packet, or any negative number to not send a ping packet.
201203
*/
202-
public void sendChangesToRemote() {
204+
public void sendChangesToRemote(int pingId) {
203205
var packets = new ArrayList<Packet<? super ClientGamePacketListener>>();
204206

205207
for (int i = 0; i < items.size(); i++) {
@@ -228,6 +230,10 @@ public void sendChangesToRemote() {
228230
}
229231
}
230232

233+
if (pingId >= 0) {
234+
packets.add(createMaskedPingPacket(pingId));
235+
}
236+
231237
PacketListener.getInstance().injectOutgoing(player, packets);
232238
}
233239

@@ -242,9 +248,11 @@ public void sendCarriedToRemote() {
242248

243249
/**
244250
* Sends all data to the remote client.
251+
*
252+
* @param pingId Optional ping id to also send a ping packet, or any negative number to not send a ping packet.
245253
*/
246-
public void sendAllToRemote() {
247-
PacketListener.getInstance().injectOutgoing(player, createContainerInitPacketList());
254+
public void sendAllToRemote(int pingId) {
255+
PacketListener.getInstance().injectOutgoing(player, createContainerInitPacketList(pingId));
248256
markRemoteSynced();
249257
}
250258

@@ -256,7 +264,7 @@ public void sendAllToRemote() {
256264
public void sendOpenPacket(Component title) {
257265
this.title = title;
258266

259-
var packets = createContainerInitPacketList();
267+
var packets = createContainerInitPacketList(-1);
260268
packets.addFirst(new ClientboundOpenScreenPacket(containerId, menuType, PaperAdventure.asVanilla(title)));
261269
PacketListener.getInstance().injectOutgoing(player, packets);
262270
markRemoteSynced();
@@ -265,9 +273,10 @@ public void sendOpenPacket(Component title) {
265273
/**
266274
* Creates the list of packets needed for container initialization, excluding the open screen packet.
267275
*
276+
* @param pingId Optional ping id to also include a ping packet, or any negative number to not include a ping packet.
268277
* @return The list of packets
269278
*/
270-
private List<Packet<? super ClientGamePacketListener>> createContainerInitPacketList() {
279+
private List<Packet<? super ClientGamePacketListener>> createContainerInitPacketList(int pingId) {
271280
var packets = new ArrayList<Packet<? super ClientGamePacketListener>>();
272281
packets.add(new ClientboundContainerSetContentPacket(
273282
containerId,
@@ -278,6 +287,9 @@ private List<Packet<? super ClientGamePacketListener>> createContainerInitPacket
278287
for (int i = 0; i < dataSlots.length; i++) {
279288
packets.add(new ClientboundContainerSetDataPacket(containerId, i, dataSlots[i]));
280289
}
290+
if (pingId >= 0) {
291+
packets.add(createMaskedPingPacket(pingId));
292+
}
281293
return packets;
282294
}
283295

@@ -304,7 +316,7 @@ public void open(Component title) {
304316
pl.redirectIncoming(player, ServerboundContainerClickPacket.class, incoming);
305317
pl.redirectIncoming(player, ServerboundContainerClosePacket.class, incoming);
306318
pl.redirectIncoming(player, ServerboundSelectBundleItemPacket.class, incoming);
307-
pl.listenIncoming(player, ServerboundPongPacket.class, this::handlePongAsync);
319+
pl.listenIncoming(player, ServerboundPongPacket.class, incoming);
308320
pl.discard(player, ClientboundOpenScreenPacket.class);
309321
pl.discard(player, ClientboundContainerSetContentPacket.class);
310322
pl.discard(player, ClientboundContainerSetDataPacket.class);
@@ -343,7 +355,7 @@ public void handleClosed() {
343355
*
344356
* @param id The window state id
345357
*/
346-
public void sendPing(int id) {
358+
private ClientboundPingPacket createMaskedPingPacket(int id) {
347359
// generate new ping id, remember mapping and timestamp
348360
int ping = MathUtils.RANDOM.nextInt();
349361
pendingPongs.put(ping, new PingData(id, System.currentTimeMillis()));
@@ -352,24 +364,7 @@ public void sendPing(int id) {
352364
long now = System.currentTimeMillis();
353365
pendingPongs.values().removeIf(data -> now - data.timestamp() > PING_TIMEOUT_MS);
354366

355-
PacketListener.getInstance().injectOutgoing(player, new ClientboundPingPacket(ping));
356-
}
357-
358-
/**
359-
* Handles a pong packet from the client.
360-
*
361-
* @param packet The packet that was received
362-
*/
363-
public void handlePongAsync(ServerboundPongPacket packet) {
364-
var data = pendingPongs.remove(packet.getId());
365-
if (data == null)
366-
return; // ignore unknown pongs, unrelated to InvUI
367-
368-
player.getScheduler().run(
369-
InvUI.getInstance().getPlugin(),
370-
_ -> getWindowEvents().handlePong(data.id()),
371-
null
372-
);
367+
return new ClientboundPingPacket(ping);
373368
}
374369

375370
//<editor-fold desc="action handlers">
@@ -404,10 +399,25 @@ protected UpdateType processPacket(Packet<? super ServerGamePacketListener> pack
404399
handleClose(p);
405400
yield UpdateType.NONE;
406401
}
407-
default -> UpdateType.NONE; // unhandled packet
402+
case ServerboundPongPacket p -> {
403+
handlePong(p);
404+
yield UpdateType.NONE;
405+
}
406+
default -> throw new UnsupportedOperationException("Unknown packet type: " + packet.getClass().getName());
408407
};
409408
}
410409

410+
/**
411+
* Handles a pong packet from the client, which may or may not be related to a ping packet sent through this menu.
412+
*
413+
* @param packet The packet that was received
414+
*/
415+
private void handlePong(ServerboundPongPacket packet) {
416+
var data = pendingPongs.remove(packet.getId());
417+
if (data != null) // ignore unknown pongs, unrelated to InvUI
418+
getWindowEvents().handlePong(data.id());
419+
}
420+
411421
/**
412422
* Handles a client-initiated inventory close.
413423
*

invui/src/main/java/xyz/xenondevs/invui/internal/menu/CustomStonecutterMenu.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ private void setNmsButtons(List<? extends ItemStack> buttons) {
124124
remoteItems.set(0, HashedStack.EMPTY);
125125
remoteItems.set(1, HashedStack.EMPTY);
126126
remoteDataSlots[0] = -1;
127-
sendChangesToRemote();
127+
sendChangesToRemote(-1);
128128
}
129129

130130
/**

invui/src/main/java/xyz/xenondevs/invui/internal/network/PacketListener.java

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121

2222
import java.util.*;
2323
import java.util.concurrent.ConcurrentHashMap;
24-
import java.util.function.Consumer;
2524
import java.util.stream.StreamSupport;
2625

2726
public class PacketListener implements Listener {
@@ -71,8 +70,8 @@ public boolean removeRedirect(Player player, Class<? extends Packet<ServerGamePa
7170
}
7271

7372
@SuppressWarnings("unchecked")
74-
public <T extends Packet<? super ServerGamePacketListener>> void listenIncoming(Player player, Class<? extends T> clazz, Consumer<? super T> handler) {
75-
getPacketHandler(player.getUniqueId()).listeners.put(clazz, (Consumer<Packet<? super ServerGamePacketListener>>) handler);
73+
public <T extends Packet<? super ServerGamePacketListener>> void listenIncoming(Player player, Class<? extends T> clazz, Queue<? super T> queue) {
74+
getPacketHandler(player.getUniqueId()).listeners.put(clazz, (Queue<Packet<? super ServerGamePacketListener>>) queue);
7675
}
7776

7877
public boolean stopListening(Player player, Class<? extends Packet<? super ServerGamePacketListener>> clazz) {
@@ -122,7 +121,7 @@ private void removeChannelHandler(Player player) {
122121
private static class PacketHandler extends ChannelDuplexHandler {
123122

124123
private final Map<Class<? extends Packet<? super ServerGamePacketListener>>, Queue<Packet<? super ServerGamePacketListener>>> redirections = new ConcurrentHashMap<>();
125-
private final Map<Class<? extends Packet<? super ServerGamePacketListener>>, Consumer<Packet<? super ServerGamePacketListener>>> listeners = new ConcurrentHashMap<>();
124+
private final Map<Class<? extends Packet<? super ServerGamePacketListener>>, Queue<Packet<? super ServerGamePacketListener>>> listeners = new ConcurrentHashMap<>();
126125
private final Set<Class<? extends Packet<ClientGamePacketListener>>> discardRules = Collections.newSetFromMap(new ConcurrentHashMap<>());
127126
private final Player player;
128127
private final Channel channel;
@@ -196,7 +195,7 @@ public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception
196195

197196
var listener = listeners.get(packet.getClass());
198197
if (listener != null) {
199-
listener.accept((Packet<ServerGamePacketListener>) packet);
198+
listener.add((Packet<ServerGamePacketListener>) packet);
200199
}
201200

202201
var queue = redirections.get(packet.getClass());

invui/src/main/java/xyz/xenondevs/invui/window/AbstractWindow.java

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -99,10 +99,7 @@ non-sealed abstract class AbstractWindow<M extends CustomContainerMenu> implemen
9999
.<List<SlotElement>>mapToObj(i -> new ArrayList<>())
100100
.collect(Collectors.toCollection(ArrayList::new));
101101

102-
serverWindowState.observeWeak(this, thisRef -> {
103-
thisRef.updateAndFlush(UpdateType.DIRTY); // important: flush item updates and send packets
104-
thisRef.menu.sendPing(serverWindowState.get());
105-
});
102+
serverWindowState.observeWeak(this, thisRef -> thisRef.updateAndFlush(UpdateType.DIRTY, serverWindowState.get()));
106103

107104
menu.setWindow(this);
108105
}
@@ -205,11 +202,11 @@ public void updateTitle() {
205202

206203
public void handleTick() {
207204
var updateType = menu.processIncoming();
208-
updateAndFlush(updateType);
205+
updateAndFlush(updateType, -1);
209206
windowTick++;
210207
}
211208

212-
private void updateAndFlush(UpdateType updateType) {
209+
private void updateAndFlush(UpdateType updateType, int pingId) {
213210
if (!isOpen())
214211
return;
215212

@@ -222,9 +219,9 @@ private void updateAndFlush(UpdateType updateType) {
222219
} else if (titleSupplier instanceof AnimatedTitle) {
223220
actuallyUpdateTitle();
224221
} else if (updateType == UpdateType.FULL) {
225-
menu.sendAllToRemote();
222+
menu.sendAllToRemote(pingId);
226223
} else if (updateType == UpdateType.DIRTY) {
227-
menu.sendChangesToRemote();
224+
menu.sendChangesToRemote(pingId);
228225
}
229226
}
230227

@@ -610,7 +607,7 @@ protected Component getTitle() {
610607
public void sendAllDataToViewer() {
611608
if (!isOpen())
612609
return;
613-
menu.sendAllToRemote();
610+
menu.sendAllToRemote(-1);
614611
}
615612

616613
@Override

0 commit comments

Comments
 (0)