Commits

riking authored and md_5 committed 73a2c749beb
Process conversation input on the main thread.

Fixes BUKKIT-5611.
No tags

nms-patches/PlayerConnection.patch

Modified
839 839 +
840 840 + boolean isSync = packetplayinchat.b().startsWith("/");
841 841 + if (packetplayinchat.b().startsWith("/")) {
842 842 + PlayerConnectionUtils.ensureMainThread(packetplayinchat, this, this.player.getWorldServer());
843 843 + }
844 844 + // CraftBukkit end
845 845 + if (this.player.dead || this.player.getChatFlags() == EntityHuman.EnumChatVisibility.HIDDEN) { // CraftBukkit - dead men tell no tales
846 846 this.sendPacket(new PacketPlayOutChat((new ChatMessage("chat.cannotSend", new Object[0])).a(EnumChatFormat.RED)));
847 847 } else {
848 848 this.player.resetIdleTimer();
849 -@@ -891,39 +1405,249 @@
849 +@@ -891,39 +1405,255 @@
850 850
851 851 for (int i = 0; i < s.length(); ++i) {
852 852 if (!SharedConstants.isAllowedChatCharacter(s.charAt(i))) {
853 853 - this.disconnect(new ChatMessage("multiplayer.disconnect.illegal_characters", new Object[0]));
854 854 + // CraftBukkit start - threadsafety
855 855 + if (!isSync) {
856 856 + Waitable waitable = new Waitable() {
857 857 + @Override
858 858 + protected Object evaluate() {
859 859 + PlayerConnection.this.disconnect(new ChatMessage("multiplayer.disconnect.illegal_characters", new Object[0]));
884 884 + if (isSync) {
885 885 + try {
886 886 + this.minecraftServer.server.playerCommandState = true;
887 887 + this.handleCommand(s);
888 888 + } finally {
889 889 + this.minecraftServer.server.playerCommandState = false;
890 890 + }
891 891 + } else if (s.isEmpty()) {
892 892 + LOGGER.warn(this.player.getName() + " tried to send an empty message");
893 893 + } else if (getPlayer().isConversing()) {
894 -+ getPlayer().acceptConversationInput(s);
894 ++ final String conversationInput = s;
895 ++ this.minecraftServer.processQueue.add(new Runnable() {
896 ++ @Override
897 ++ public void run() {
898 ++ getPlayer().acceptConversationInput(conversationInput);
899 ++ }
900 ++ });
895 901 + } else if (this.player.getChatFlags() == EntityHuman.EnumChatVisibility.SYSTEM) { // Re-add "Command Only" flag check
896 902 + ChatMessage chatmessage = new ChatMessage("chat.cannotSend", new Object[0]);
897 903 +
898 904 + chatmessage.getChatModifier().setColor(EnumChatFormat.RED);
899 905 + this.sendPacket(new PacketPlayOutChat(chatmessage));
900 906 + } else if (true) {
901 907 + this.chat(s, true);
902 908 + // CraftBukkit end - the below is for reference. :)
903 909 } else {
904 910 ChatMessage chatmessage = new ChatMessage("chat.type.text", new Object[] { this.player.getScoreboardDisplayName(), s});
1096 1102 +
1097 1103 + if (e2.isCancelled()) {
1098 1104 + return;
1099 1105 + }
1100 1106 + break;
1101 1107 + }
1102 1108 + // CraftBukkit end
1103 1109 this.player.resetIdleTimer();
1104 1110 IJumpable ijumpable;
1105 1111
1106 -@@ -986,6 +1710,7 @@
1112 +@@ -986,6 +1716,7 @@
1107 1113
1108 1114 public void a(PacketPlayInUseEntity packetplayinuseentity) {
1109 1115 PlayerConnectionUtils.ensureMainThread(packetplayinuseentity, this, this.player.getWorldServer());
1110 1116 + if (this.player.isFrozen()) return; // CraftBukkit
1111 1117 WorldServer worldserver = this.minecraftServer.getWorldServer(this.player.dimension);
1112 1118 Entity entity = packetplayinuseentity.a((World) worldserver);
1113 1119
1114 -@@ -1001,20 +1726,73 @@
1120 +@@ -1001,20 +1732,73 @@
1115 1121 if (this.player.h(entity) < d0) {
1116 1122 EnumHand enumhand;
1117 1123
1118 1124 + ItemStack itemInHand = this.player.b(packetplayinuseentity.c() == null ? EnumHand.MAIN_HAND : packetplayinuseentity.c()); // CraftBukkit
1119 1125 +
1120 1126 + if (packetplayinuseentity.b() == PacketPlayInUseEntity.EnumEntityUseAction.INTERACT
1121 1127 + || packetplayinuseentity.b() == PacketPlayInUseEntity.EnumEntityUseAction.INTERACT_AT) {
1122 1128 + // CraftBukkit start
1123 1129 + boolean triggerLeashUpdate = itemInHand != null && itemInHand.getItem() == Items.LEAD && entity instanceof EntityInsentient;
1124 1130 + Item origItem = this.player.inventory.getItemInHand() == null ? null : this.player.inventory.getItemInHand().getItem();
1179 1185 this.player.attack(entity);
1180 1186 +
1181 1187 + // CraftBukkit start
1182 1188 + if (!itemInHand.isEmpty() && itemInHand.getCount() <= -1) {
1183 1189 + this.player.updateInventory(this.player.activeContainer);
1184 1190 + }
1185 1191 + // CraftBukkit end
1186 1192 }
1187 1193 }
1188 1194 }
1189 -@@ -1030,7 +1808,8 @@
1195 +@@ -1030,7 +1814,8 @@
1190 1196 case PERFORM_RESPAWN:
1191 1197 if (this.player.viewingCredits) {
1192 1198 this.player.viewingCredits = false;
1193 1199 - this.player = this.minecraftServer.getPlayerList().moveToWorld(this.player, DimensionManager.OVERWORLD, true);
1194 1200 + // this.player = this.minecraftServer.getPlayerList().moveToWorld(this.player, DimensionManager.OVERWORLD, true);
1195 1201 + this.minecraftServer.getPlayerList().changeDimension(this.player, DimensionManager.OVERWORLD, PlayerTeleportEvent.TeleportCause.END_PORTAL); // CraftBukkit - reroute logic through custom portal management
1196 1202 CriterionTriggers.v.a(this.player, DimensionManager.THE_END, DimensionManager.OVERWORLD);
1197 1203 } else {
1198 1204 if (this.player.getHealth() > 0.0F) {
1199 -@@ -1052,14 +1831,20 @@
1205 +@@ -1052,14 +1837,20 @@
1200 1206
1201 1207 public void a(PacketPlayInCloseWindow packetplayinclosewindow) {
1202 1208 PlayerConnectionUtils.ensureMainThread(packetplayinclosewindow, this, this.player.getWorldServer());
1203 1209 +
1204 1210 + if (this.player.isFrozen()) return; // CraftBukkit
1205 1211 + CraftEventFactory.handleInventoryCloseEvent(this.player); // CraftBukkit
1206 1212 +
1207 1213 this.player.m();
1208 1214 }
1209 1215
1212 1218 + if (this.player.isFrozen()) return; // CraftBukkit
1213 1219 this.player.resetIdleTimer();
1214 1220 - if (this.player.activeContainer.windowId == packetplayinwindowclick.b() && this.player.activeContainer.c(this.player)) {
1215 1221 - if (this.player.isSpectator()) {
1216 1222 + if (this.player.activeContainer.windowId == packetplayinwindowclick.b() && this.player.activeContainer.c(this.player) && this.player.activeContainer.canUse(this.player)) { // CraftBukkit
1217 1223 + boolean cancelled = this.player.isSpectator(); // CraftBukkit - see below if
1218 1224 + if (false/*this.player.isSpectator()*/) { // CraftBukkit
1219 1225 NonNullList<ItemStack> nonnulllist = NonNullList.a();
1220 1226
1221 1227 for (int i = 0; i < this.player.activeContainer.slots.size(); ++i) {
1222 -@@ -1068,8 +1853,274 @@
1228 +@@ -1068,8 +1859,274 @@
1223 1229
1224 1230 this.player.a(this.player.activeContainer, nonnulllist);
1225 1231 } else {
1226 1232 - ItemStack itemstack = this.player.activeContainer.a(packetplayinwindowclick.c(), packetplayinwindowclick.d(), packetplayinwindowclick.g(), this.player);
1227 1233 + // CraftBukkit start - Call InventoryClickEvent
1228 1234 + if (packetplayinwindowclick.c() < -1 && packetplayinwindowclick.c() != -999) {
1229 1235 + return;
1230 1236 + }
1231 1237 +
1232 1238 + InventoryView inventory = this.player.activeContainer.getBukkitView();
1488 1494 + if (event instanceof CraftItemEvent) {
1489 1495 + // Need to update the inventory on crafting to
1490 1496 + // correctly support custom recipes
1491 1497 + player.updateInventory(player.activeContainer);
1492 1498 + }
1493 1499 + }
1494 1500 + // CraftBukkit end
1495 1501 if (ItemStack.matches(packetplayinwindowclick.f(), itemstack)) {
1496 1502 this.player.playerConnection.sendPacket(new PacketPlayOutTransaction(packetplayinwindowclick.b(), packetplayinwindowclick.e(), true));
1497 1503 this.player.f = true;
1498 -@@ -1112,6 +2163,7 @@
1504 +@@ -1112,6 +2169,7 @@
1499 1505
1500 1506 public void a(PacketPlayInEnchantItem packetplayinenchantitem) {
1501 1507 PlayerConnectionUtils.ensureMainThread(packetplayinenchantitem, this, this.player.getWorldServer());
1502 1508 + if (this.player.isFrozen()) return; // CraftBukkit
1503 1509 this.player.resetIdleTimer();
1504 1510 if (this.player.activeContainer.windowId == packetplayinenchantitem.b() && this.player.activeContainer.c(this.player) && !this.player.isSpectator()) {
1505 1511 this.player.activeContainer.a(this.player, packetplayinenchantitem.c());
1506 -@@ -1143,6 +2195,43 @@
1512 +@@ -1143,6 +2201,43 @@
1507 1513
1508 1514 boolean flag1 = packetplayinsetcreativeslot.b() >= 1 && packetplayinsetcreativeslot.b() <= 45;
1509 1515 boolean flag2 = itemstack.isEmpty() || itemstack.getDamage() >= 0 && itemstack.getCount() <= 64 && !itemstack.isEmpty();
1510 1516 + if (flag || (flag1 && !ItemStack.matches(this.player.defaultContainer.getSlot(packetplayinsetcreativeslot.b()).getItem(), packetplayinsetcreativeslot.getItemStack()))) { // Insist on valid slot
1511 1517 + // CraftBukkit start - Call click event
1512 1518 + InventoryView inventory = this.player.defaultContainer.getBukkitView();
1513 1519 + org.bukkit.inventory.ItemStack item = CraftItemStack.asBukkitCopy(packetplayinsetcreativeslot.getItemStack());
1514 1520 +
1515 1521 + SlotType type = SlotType.QUICKBAR;
1516 1522 + if (flag) {
1540 1546 + this.player.playerConnection.sendPacket(new PacketPlayOutSetSlot(this.player.defaultContainer.windowId, packetplayinsetcreativeslot.b(), this.player.defaultContainer.getSlot(packetplayinsetcreativeslot.b()).getItem()));
1541 1547 + this.player.playerConnection.sendPacket(new PacketPlayOutSetSlot(-1, -1, ItemStack.a));
1542 1548 + }
1543 1549 + return;
1544 1550 + }
1545 1551 + }
1546 1552 + // CraftBukkit end
1547 1553
1548 1554 if (flag1 && flag2) {
1549 1555 if (itemstack.isEmpty()) {
1550 -@@ -1166,6 +2255,7 @@
1556 +@@ -1166,6 +2261,7 @@
1551 1557
1552 1558 public void a(PacketPlayInTransaction packetplayintransaction) {
1553 1559 PlayerConnectionUtils.ensureMainThread(packetplayintransaction, this, this.player.getWorldServer());
1554 1560 + if (this.player.isFrozen()) return; // CraftBukkit
1555 1561 Short oshort = (Short) this.k.get(this.player.activeContainer.windowId);
1556 1562
1557 1563 if (oshort != null && packetplayintransaction.c() == oshort && this.player.activeContainer.windowId == packetplayintransaction.b() && !this.player.activeContainer.c(this.player) && !this.player.isSpectator()) {
1558 -@@ -1176,6 +2266,7 @@
1564 +@@ -1176,6 +2272,7 @@
1559 1565
1560 1566 public void a(PacketPlayInUpdateSign packetplayinupdatesign) {
1561 1567 PlayerConnectionUtils.ensureMainThread(packetplayinupdatesign, this, this.player.getWorldServer());
1562 1568 + if (this.player.isFrozen()) return; // CraftBukkit
1563 1569 this.player.resetIdleTimer();
1564 1570 WorldServer worldserver = this.minecraftServer.getWorldServer(this.player.dimension);
1565 1571 BlockPosition blockposition = packetplayinupdatesign.b();
1566 -@@ -1192,14 +2283,30 @@
1572 +@@ -1192,14 +2289,30 @@
1567 1573
1568 1574 if (!tileentitysign.d() || tileentitysign.e() != this.player) {
1569 1575 this.minecraftServer.warning("Player " + this.player.getDisplayName().getString() + " just tried to change non-editable sign");
1570 1576 + this.sendPacket(tileentity.getUpdatePacket()); // CraftBukkit
1571 1577 return;
1572 1578 }
1573 1579
1574 1580 String[] astring = packetplayinupdatesign.c();
1575 1581
1576 1582 + // CraftBukkit start
1588 1594 + this.server.getPluginManager().callEvent(event);
1589 1595 +
1590 1596 + if (!event.isCancelled()) {
1591 1597 + System.arraycopy(org.bukkit.craftbukkit.block.CraftSign.sanitizeLines(event.getLines()), 0, tileentitysign.lines, 0, 4);
1592 1598 + tileentitysign.isEditable = false;
1593 1599 + }
1594 1600 + // CraftBukkit end
1595 1601
1596 1602 tileentitysign.update();
1597 1603 worldserver.notify(blockposition, iblockdata, iblockdata, 3);
1598 -@@ -1208,6 +2315,7 @@
1604 +@@ -1208,6 +2321,7 @@
1599 1605 }
1600 1606
1601 1607 public void a(PacketPlayInKeepAlive packetplayinkeepalive) {
1602 1608 + PlayerConnectionUtils.ensureMainThread(packetplayinkeepalive, this, this.player.getWorldServer()); // CraftBukkit
1603 1609 if (this.awaitingKeepAlive && packetplayinkeepalive.b() == this.h) {
1604 1610 int i = (int) (SystemUtils.getMonotonicMillis() - this.lastKeepAlive);
1605 1611
1606 -@@ -1221,7 +2329,17 @@
1612 +@@ -1221,7 +2335,17 @@
1607 1613
1608 1614 public void a(PacketPlayInAbilities packetplayinabilities) {
1609 1615 PlayerConnectionUtils.ensureMainThread(packetplayinabilities, this, this.player.getWorldServer());
1610 1616 - this.player.abilities.isFlying = packetplayinabilities.isFlying() && this.player.abilities.canFly;
1611 1617 + // CraftBukkit start
1612 1618 + if (this.player.abilities.canFly && this.player.abilities.isFlying != packetplayinabilities.isFlying()) {
1613 1619 + PlayerToggleFlightEvent event = new PlayerToggleFlightEvent(this.server.getPlayer(this.player), packetplayinabilities.isFlying());
1614 1620 + this.server.getPluginManager().callEvent(event);
1615 1621 + if (!event.isCancelled()) {
1616 1622 + this.player.abilities.isFlying = packetplayinabilities.isFlying(); // Actually set the player's flying status
1617 1623 + } else {
1618 1624 + this.player.updateAbilities(); // Tell the player their ability was reverted
1619 1625 + }
1620 1626 + }
1621 1627 + // CraftBukkit end
1622 1628 }
1623 1629
1624 1630 public void a(PacketPlayInSettings packetplayinsettings) {
1625 -@@ -1229,5 +2347,47 @@
1631 +@@ -1229,5 +2353,47 @@
1626 1632 this.player.a(packetplayinsettings);
1627 1633 }
1628 1634
1629 1635 - public void a(PacketPlayInCustomPayload packetplayincustompayload) {}
1630 1636 + // CraftBukkit start
1631 1637 + private static final MinecraftKey CUSTOM_REGISTER = new MinecraftKey("register");
1632 1638 + private static final MinecraftKey CUSTOM_UNREGISTER = new MinecraftKey("unregister");
1633 1639 +
1634 1640 + public void a(PacketPlayInCustomPayload packetplayincustompayload) {
1635 1641 + PlayerConnectionUtils.ensureMainThread(packetplayincustompayload, this, this.player.getWorldServer());

Everything looks good. We'll let you know here if there's anything you should know about.

Add shortcut