Commits

coll1234567 authored and md_5 committed 482c56a0097
#1285: Add PlayerRecipeBookSettingsChangeEvent
No tags

nms-patches/net/minecraft/server/network/PlayerConnection.patch

Modified
255 255 }
256 256 @@ -478,7 +648,7 @@
257 257 @Override
258 258 public void handleRecipeBookSeenRecipePacket(PacketPlayInRecipeDisplayed packetplayinrecipedisplayed) {
259 259 PlayerConnectionUtils.ensureRunningOnSameThread(packetplayinrecipedisplayed, this, this.player.serverLevel());
260 260 - Optional optional = this.server.getRecipeManager().byKey(packetplayinrecipedisplayed.getRecipe());
261 261 + Optional<? extends RecipeHolder<?>> optional = this.server.getRecipeManager().byKey(packetplayinrecipedisplayed.getRecipe()); // CraftBukkit - decompile error
262 262 RecipeBookServer recipebookserver = this.player.getRecipeBook();
263 263
264 264 Objects.requireNonNull(recipebookserver);
265 -@@ -508,6 +678,12 @@
265 +@@ -488,6 +658,7 @@
266 + @Override
267 + public void handleRecipeBookChangeSettingsPacket(PacketPlayInRecipeSettings packetplayinrecipesettings) {
268 + PlayerConnectionUtils.ensureRunningOnSameThread(packetplayinrecipesettings, this, this.player.serverLevel());
269 ++ CraftEventFactory.callRecipeBookSettingsEvent(this.player, packetplayinrecipesettings.getBookType(), packetplayinrecipesettings.isOpen(), packetplayinrecipesettings.isFiltering()); // CraftBukkit
270 + this.player.getRecipeBook().setBookSetting(packetplayinrecipesettings.getBookType(), packetplayinrecipesettings.isOpen(), packetplayinrecipesettings.isFiltering());
271 + }
272 +
273 +@@ -508,6 +679,12 @@
266 274 @Override
267 275 public void handleCustomCommandSuggestions(PacketPlayInTabComplete packetplayintabcomplete) {
268 276 PlayerConnectionUtils.ensureRunningOnSameThread(packetplayintabcomplete, this, this.player.serverLevel());
269 277 + // CraftBukkit start
270 278 + if (chatSpamTickCount.addAndGet(1) > 500 && !this.server.getPlayerList().isOp(this.player.getGameProfile())) {
271 279 + this.disconnect(IChatBaseComponent.translatable("disconnect.spam"));
272 280 + return;
273 281 + }
274 282 + // CraftBukkit end
275 283 StringReader stringreader = new StringReader(packetplayintabcomplete.getCommand());
276 284
277 285 if (stringreader.canRead() && stringreader.peek() == '/') {
278 -@@ -517,6 +693,7 @@
286 +@@ -517,6 +694,7 @@
279 287 ParseResults<CommandListenerWrapper> parseresults = this.server.getCommands().getDispatcher().parse(stringreader, this.player.createCommandSourceStack());
280 288
281 289 this.server.getCommands().getDispatcher().getCompletionSuggestions(parseresults).thenAccept((suggestions) -> {
282 290 + if (suggestions.isEmpty()) return; // CraftBukkit - don't send through empty suggestions - prevents [<args>] from showing for plugins with nothing more to offer
283 291 this.send(new PacketPlayOutTabComplete(packetplayintabcomplete.getId(), suggestions));
284 292 });
285 293 }
286 -@@ -762,6 +939,13 @@
294 +@@ -762,6 +940,13 @@
287 295
288 296 if (container instanceof ContainerMerchant) {
289 297 ContainerMerchant containermerchant = (ContainerMerchant) container;
290 298 + // CraftBukkit start
291 299 + final org.bukkit.event.inventory.TradeSelectEvent tradeSelectEvent = CraftEventFactory.callTradeSelectEvent(this.player, i, containermerchant);
292 300 + if (tradeSelectEvent.isCancelled()) {
293 301 + this.player.getBukkitEntity().updateInventory();
294 302 + return;
295 303 + }
296 304 + // CraftBukkit end
297 305
298 306 if (!containermerchant.stillValid(this.player)) {
299 307 PlayerConnection.LOGGER.debug("Player {} interacted with invalid menu {}", this.player, containermerchant);
300 -@@ -776,6 +960,13 @@
308 +@@ -776,6 +961,13 @@
301 309
302 310 @Override
303 311 public void handleEditBook(PacketPlayInBEdit packetplayinbedit) {
304 312 + // CraftBukkit start
305 313 + if (this.lastBookTick + 20 > MinecraftServer.currentTick) {
306 314 + this.disconnect("Book edited too quickly!");
307 315 + return;
308 316 + }
309 317 + this.lastBookTick = MinecraftServer.currentTick;
310 318 + // CraftBukkit end
311 319 int i = packetplayinbedit.getSlot();
312 320
313 321 if (PlayerInventory.isHotbarSlot(i) || i == 40) {
314 -@@ -784,7 +975,7 @@
322 +@@ -784,7 +976,7 @@
315 323
316 324 Objects.requireNonNull(list);
317 325 optional.ifPresent(list::add);
318 326 - Stream stream = packetplayinbedit.getPages().stream().limit(100L);
319 327 + Stream<String> stream = packetplayinbedit.getPages().stream().limit(100L); // CraftBukkit - decompile error
320 328
321 329 Objects.requireNonNull(list);
322 330 stream.forEach(list::add);
323 -@@ -802,7 +993,7 @@
331 +@@ -802,7 +994,7 @@
324 332 ItemStack itemstack = this.player.getInventory().getItem(i);
325 333
326 334 if (itemstack.is(Items.WRITABLE_BOOK)) {
327 335 - this.updateBookPages(list, UnaryOperator.identity(), itemstack);
328 336 + this.updateBookPages(list, UnaryOperator.identity(), itemstack.copy(), i, itemstack); // CraftBukkit
329 337 }
330 338 }
331 339
332 -@@ -827,16 +1018,16 @@
340 +@@ -827,16 +1019,16 @@
333 341
334 342 this.updateBookPages(list, (s) -> {
335 343 return IChatBaseComponent.ChatSerializer.toJson(IChatBaseComponent.literal(s));
336 344 - }, itemstack1);
337 345 - this.player.getInventory().setItem(i, itemstack1);
338 346 + }, itemstack1, i, itemstack); // CraftBukkit
339 347 + this.player.getInventory().setItem(i, itemstack); // CraftBukkit - event factory updates the hand book
340 348 }
341 349 }
342 350
343 351 - private void updateBookPages(List<FilteredText> list, UnaryOperator<String> unaryoperator, ItemStack itemstack) {
344 352 + private void updateBookPages(List<FilteredText> list, UnaryOperator<String> unaryoperator, ItemStack itemstack, int slot, ItemStack handItem) { // CraftBukkit
345 353 NBTTagList nbttaglist = new NBTTagList();
346 354
347 355 if (this.player.isTextFilteringEnabled()) {
348 356 - Stream stream = list.stream().map((filteredtext) -> {
349 357 + Stream<NBTTagString> stream = list.stream().map((filteredtext) -> { // CraftBukkit - decompile error
350 358 return NBTTagString.valueOf((String) unaryoperator.apply(filteredtext.filteredOrEmpty()));
351 359 });
352 360
353 -@@ -862,6 +1053,7 @@
361 +@@ -862,6 +1054,7 @@
354 362 }
355 363
356 364 itemstack.addTagElement("pages", nbttaglist);
357 365 + CraftEventFactory.handleEditBookEvent(player, slot, handItem, itemstack); // CraftBukkit
358 366 }
359 367
360 368 @Override
361 -@@ -898,7 +1090,7 @@
369 +@@ -898,7 +1091,7 @@
362 370 } else {
363 371 WorldServer worldserver = this.player.serverLevel();
364 372
365 373 - if (!this.player.wonGame) {
366 374 + if (!this.player.wonGame && !this.player.isImmobile()) { // CraftBukkit
367 375 if (this.tickCount == 0) {
368 376 this.resetPosition();
369 377 }
370 -@@ -908,7 +1100,7 @@
378 +@@ -908,7 +1101,7 @@
371 379 this.awaitingTeleportTime = this.tickCount;
372 380 this.teleport(this.awaitingPositionFromClient.x, this.awaitingPositionFromClient.y, this.awaitingPositionFromClient.z, this.player.getYRot(), this.player.getXRot());
373 381 }
374 382 -
375 383 + this.allowedPlayerTicks = 20; // CraftBukkit
376 384 } else {
377 385 this.awaitingTeleportTime = this.tickCount;
378 386 double d0 = clampHorizontal(packetplayinflying.getX(this.player.getX()));
379 -@@ -920,7 +1112,15 @@
387 +@@ -920,7 +1113,15 @@
380 388 if (this.player.isPassenger()) {
381 389 this.player.absMoveTo(this.player.getX(), this.player.getY(), this.player.getZ(), f, f1);
382 390 this.player.serverLevel().getChunkSource().move(this.player);
383 391 + this.allowedPlayerTicks = 20; // CraftBukkit
384 392 } else {
385 393 + // CraftBukkit - Make sure the move is valid but then reset it for plugins to modify
386 394 + double prevX = player.getX();
387 395 + double prevY = player.getY();
388 396 + double prevZ = player.getZ();
389 397 + float prevYaw = player.getYRot();
390 398 + float prevPitch = player.getXRot();
391 399 + // CraftBukkit end
392 400 double d3 = this.player.getX();
393 401 double d4 = this.player.getY();
394 402 double d5 = this.player.getZ();
395 -@@ -939,15 +1139,33 @@
403 +@@ -939,15 +1140,33 @@
396 404 ++this.receivedMovePacketCount;
397 405 int i = this.receivedMovePacketCount - this.knownMovePacketCount;
398 406
399 407 - if (i > 5) {
400 408 + // CraftBukkit start - handle custom speeds and skipped ticks
401 409 + this.allowedPlayerTicks += (System.currentTimeMillis() / 50) - this.lastTick;
402 410 + this.allowedPlayerTicks = Math.max(this.allowedPlayerTicks, 1);
403 411 + this.lastTick = (int) (System.currentTimeMillis() / 50);
404 412 +
405 413 + if (i > Math.max(this.allowedPlayerTicks, 5)) {
421 429 +
422 430 if (!this.player.isChangingDimension() && (!this.player.level().getGameRules().getBoolean(GameRules.RULE_DISABLE_ELYTRA_MOVEMENT_CHECK) || !this.player.isFallFlying())) {
423 431 float f2 = this.player.isFallFlying() ? 300.0F : 100.0F;
424 432
425 433 - if (d10 - d9 > (double) (f2 * (float) i) && !this.isSingleplayerOwner()) {
426 434 + if (d10 - d9 > Math.max(f2, Math.pow((double) (10.0F * (float) i * speed), 2)) && !this.isSingleplayerOwner()) {
427 435 + // CraftBukkit end
428 436 PlayerConnection.LOGGER.warn("{} moved too quickly! {},{},{}", new Object[]{this.player.getName().getString(), d6, d7, d8});
429 437 this.teleport(this.player.getX(), this.player.getY(), this.player.getZ(), this.player.getYRot(), this.player.getXRot());
430 438 return;
431 -@@ -968,6 +1186,7 @@
439 +@@ -968,6 +1187,7 @@
432 440 boolean flag1 = this.player.verticalCollisionBelow;
433 441
434 442 this.player.move(EnumMoveType.PLAYER, new Vec3D(d6, d7, d8));
435 443 + this.player.onGround = packetplayinflying.isOnGround(); // CraftBukkit - SPIGOT-5810, SPIGOT-5835, SPIGOT-6828: reset by this.player.move
436 444 double d11 = d7;
437 445
438 446 d6 = d0 - this.player.getX();
439 -@@ -986,9 +1205,70 @@
447 +@@ -986,9 +1206,70 @@
440 448 }
441 449
442 450 if (!this.player.noPhysics && !this.player.isSleeping() && (flag2 && worldserver.noCollision(this.player, axisalignedbb) || this.isPlayerCollidingWithAnythingNew(worldserver, axisalignedbb, d0, d1, d2))) {
443 451 - this.teleport(d3, d4, d5, f, f1);
444 452 + this.internalTeleport(d3, d4, d5, f, f1, Collections.emptySet()); // CraftBukkit - SPIGOT-1807: Don't call teleport event, when the client thinks the player is falling, because the chunks are not loaded on the client yet.
445 453 this.player.doCheckFallDamage(this.player.getX() - d3, this.player.getY() - d4, this.player.getZ() - d5, packetplayinflying.isOnGround());
446 454 } else {
447 455 + // CraftBukkit start - fire PlayerMoveEvent
448 456 + // Reset to old location first
449 457 + this.player.absMoveTo(prevX, prevY, prevZ, prevYaw, prevPitch);
501 509 + if (!from.equals(this.getCraftPlayer().getLocation()) && this.justTeleported) {
502 510 + this.justTeleported = false;
503 511 + return;
504 512 + }
505 513 + }
506 514 + }
507 515 + // CraftBukkit end
508 516 this.player.absMoveTo(d0, d1, d2, f, f1);
509 517 this.clientIsFloating = d11 >= -0.03125D && !flag1 && this.player.gameMode.getGameModeForPlayer() != EnumGamemode.SPECTATOR && !this.server.isFlightAllowed() && !this.player.getAbilities().mayfly && !this.player.hasEffect(MobEffects.LEVITATION) && !this.player.isFallFlying() && !this.player.isAutoSpinAttack() && this.noBlocksAround(this.player);
510 518 this.player.serverLevel().getChunkSource().move(this.player);
511 -@@ -1029,11 +1309,68 @@
519 +@@ -1029,11 +1310,68 @@
512 520 return true;
513 521 }
514 522
515 523 + // CraftBukkit start - Delegate to teleport(Location)
516 524 public void teleport(double d0, double d1, double d2, float f, float f1) {
517 525 - this.teleport(d0, d1, d2, f, f1, Collections.emptySet());
518 526 + this.teleport(d0, d1, d2, f, f1, PlayerTeleportEvent.TeleportCause.UNKNOWN);
519 527 + }
520 528 +
521 529 + public void teleport(double d0, double d1, double d2, float f, float f1, PlayerTeleportEvent.TeleportCause cause) {
571 579 + }
572 580 + if (Float.isNaN(f1)) {
573 581 + f1 = 0;
574 582 + }
575 583 +
576 584 + this.justTeleported = true;
577 585 + // CraftBukkit end
578 586 double d3 = set.contains(RelativeMovement.X) ? this.player.getX() : 0.0D;
579 587 double d4 = set.contains(RelativeMovement.Y) ? this.player.getY() : 0.0D;
580 588 double d5 = set.contains(RelativeMovement.Z) ? this.player.getZ() : 0.0D;
581 -@@ -1045,6 +1382,14 @@
589 +@@ -1045,6 +1383,14 @@
582 590 this.awaitingTeleport = 0;
583 591 }
584 592
585 593 + // CraftBukkit start - update last location
586 594 + this.lastPosX = this.awaitingPositionFromClient.x;
587 595 + this.lastPosY = this.awaitingPositionFromClient.y;
588 596 + this.lastPosZ = this.awaitingPositionFromClient.z;
589 597 + this.lastYaw = f;
590 598 + this.lastPitch = f1;
591 599 + // CraftBukkit end
592 600 +
593 601 this.awaitingTeleportTime = this.tickCount;
594 602 this.player.absMoveTo(d0, d1, d2, f, f1);
595 603 this.player.connection.send(new PacketPlayOutPosition(d0 - d3, d1 - d4, d2 - d5, f - f2, f1 - f3, set, this.awaitingTeleport));
596 -@@ -1053,6 +1398,7 @@
604 +@@ -1053,6 +1399,7 @@
597 605 @Override
598 606 public void handlePlayerAction(PacketPlayInBlockDig packetplayinblockdig) {
599 607 PlayerConnectionUtils.ensureRunningOnSameThread(packetplayinblockdig, this, this.player.serverLevel());
600 608 + if (this.player.isImmobile()) return; // CraftBukkit
601 609 BlockPosition blockposition = packetplayinblockdig.getPos();
602 610
603 611 this.player.resetLastActionTime();
604 -@@ -1063,14 +1409,46 @@
612 +@@ -1063,14 +1410,46 @@
605 613 if (!this.player.isSpectator()) {
606 614 ItemStack itemstack = this.player.getItemInHand(EnumHand.OFF_HAND);
607 615
608 616 - this.player.setItemInHand(EnumHand.OFF_HAND, this.player.getItemInHand(EnumHand.MAIN_HAND));
609 617 - this.player.setItemInHand(EnumHand.MAIN_HAND, itemstack);
610 618 + // CraftBukkit start - inspiration taken from DispenserRegistry (See SpigotCraft#394)
611 619 + CraftItemStack mainHand = CraftItemStack.asCraftMirror(itemstack);
612 620 + CraftItemStack offHand = CraftItemStack.asCraftMirror(this.player.getItemInHand(EnumHand.MAIN_HAND));
613 621 + PlayerSwapHandItemsEvent swapItemsEvent = new PlayerSwapHandItemsEvent(getCraftPlayer(), mainHand.clone(), offHand.clone());
614 622 + this.cserver.getPluginManager().callEvent(swapItemsEvent);
643 651 + if (this.dropCount >= 20) {
644 652 + LOGGER.warn(this.player.getScoreboardName() + " dropped their items too quickly!");
645 653 + this.disconnect("You dropped your items too quickly (Hacking?)");
646 654 + return;
647 655 + }
648 656 + }
649 657 + // CraftBukkit end
650 658 this.player.drop(false);
651 659 }
652 660
653 -@@ -1108,6 +1486,7 @@
661 +@@ -1108,6 +1487,7 @@
654 662 @Override
655 663 public void handleUseItemOn(PacketPlayInUseItem packetplayinuseitem) {
656 664 PlayerConnectionUtils.ensureRunningOnSameThread(packetplayinuseitem, this, this.player.serverLevel());
657 665 + if (this.player.isImmobile()) return; // CraftBukkit
658 666 this.player.connection.ackBlockChangesUpTo(packetplayinuseitem.getSequence());
659 667 WorldServer worldserver = this.player.serverLevel();
660 668 EnumHand enumhand = packetplayinuseitem.getHand();
661 -@@ -1131,6 +1510,7 @@
669 +@@ -1131,6 +1511,7 @@
662 670
663 671 if (blockposition.getY() < i) {
664 672 if (this.awaitingPositionFromClient == null && this.player.distanceToSqr((double) blockposition.getX() + 0.5D, (double) blockposition.getY() + 0.5D, (double) blockposition.getZ() + 0.5D) < 64.0D && worldserver.mayInteract(this.player, blockposition)) {
665 673 + this.player.stopUsingItem(); // CraftBukkit - SPIGOT-4706
666 674 EnumInteractionResult enuminteractionresult = this.player.gameMode.useItemOn(this.player, worldserver, itemstack, enumhand, movingobjectpositionblock);
667 675
668 676 if (enumdirection == EnumDirection.UP && !enuminteractionresult.consumesAction() && blockposition.getY() >= i - 1 && wasBlockPlacementAttempt(this.player, itemstack)) {
669 -@@ -1159,6 +1539,7 @@
677 +@@ -1159,6 +1540,7 @@
670 678 @Override
671 679 public void handleUseItem(PacketPlayInBlockPlace packetplayinblockplace) {
672 680 PlayerConnectionUtils.ensureRunningOnSameThread(packetplayinblockplace, this, this.player.serverLevel());
673 681 + if (this.player.isImmobile()) return; // CraftBukkit
674 682 this.ackBlockChangesUpTo(packetplayinblockplace.getSequence());
675 683 WorldServer worldserver = this.player.serverLevel();
676 684 EnumHand enumhand = packetplayinblockplace.getHand();
677 -@@ -1166,6 +1547,49 @@
685 +@@ -1166,6 +1548,49 @@
678 686
679 687 this.player.resetLastActionTime();
680 688 if (!itemstack.isEmpty() && itemstack.isItemEnabled(worldserver.enabledFeatures())) {
681 689 + // CraftBukkit start
682 690 + // Raytrace to look for 'rogue armswings'
683 691 + float f1 = this.player.getXRot();
684 692 + float f2 = this.player.getYRot();
685 693 + double d0 = this.player.getX();
686 694 + double d1 = this.player.getY() + (double) this.player.getEyeHeight();
687 695 + double d2 = this.player.getZ();
717 725 + return;
718 726 + }
719 727 + itemstack = this.player.getItemInHand(enumhand); // Update in case it was changed in the event
720 728 + if (itemstack.isEmpty()) {
721 729 + return;
722 730 + }
723 731 + // CraftBukkit end
724 732 EnumInteractionResult enuminteractionresult = this.player.gameMode.useItem(this.player, worldserver, itemstack, enumhand);
725 733
726 734 if (enuminteractionresult.shouldSwing()) {
727 -@@ -1186,7 +1610,7 @@
735 +@@ -1186,7 +1611,7 @@
728 736 Entity entity = packetplayinspectate.getEntity(worldserver);
729 737
730 738 if (entity != null) {
731 739 - this.player.teleportTo(worldserver, entity.getX(), entity.getY(), entity.getZ(), entity.getYRot(), entity.getXRot());
732 740 + this.player.teleportTo(worldserver, entity.getX(), entity.getY(), entity.getZ(), entity.getYRot(), entity.getXRot(), org.bukkit.event.player.PlayerTeleportEvent.TeleportCause.SPECTATE); // CraftBukkit
733 741 return;
734 742 }
735 743 }
736 -@@ -1209,6 +1633,13 @@
744 +@@ -1209,6 +1634,13 @@
737 745
738 746 @Override
739 747 public void onDisconnect(IChatBaseComponent ichatbasecomponent) {
740 748 + // CraftBukkit start - Rarely it would send a disconnect line twice
741 749 + if (this.processedDisconnect) {
742 750 + return;
743 751 + } else {
744 752 + this.processedDisconnect = true;
745 753 + }
746 754 + // CraftBukkit end
747 755 PlayerConnection.LOGGER.info("{} lost connection: {}", this.player.getName().getString(), ichatbasecomponent.getString());
748 756 this.removePlayerFromWorld();
749 757 super.onDisconnect(ichatbasecomponent);
750 -@@ -1216,10 +1647,18 @@
758 +@@ -1216,10 +1648,18 @@
751 759
752 760 private void removePlayerFromWorld() {
753 761 this.chatMessageChain.close();
754 762 + // CraftBukkit start - Replace vanilla quit message handling with our own.
755 763 + /*
756 764 this.server.invalidateStatus();
757 765 this.server.getPlayerList().broadcastSystemMessage(IChatBaseComponent.translatable("multiplayer.player.left", this.player.getDisplayName()).withStyle(EnumChatFormat.YELLOW), false);
758 766 + */
759 767 +
760 768 this.player.disconnect();
761 769 - this.server.getPlayerList().remove(this.player);
762 770 + String quitMessage = this.server.getPlayerList().remove(this.player);
763 771 + if ((quitMessage != null) && (quitMessage.length() > 0)) {
764 772 + this.server.getPlayerList().broadcastMessage(CraftChatMessage.fromString(quitMessage));
765 773 + }
766 774 + // CraftBukkit end
767 775 this.player.getTextFilter().leave();
768 776 }
769 777
770 -@@ -1234,7 +1673,16 @@
778 +@@ -1234,7 +1674,16 @@
771 779 @Override
772 780 public void handleSetCarriedItem(PacketPlayInHeldItemSlot packetplayinhelditemslot) {
773 781 PlayerConnectionUtils.ensureRunningOnSameThread(packetplayinhelditemslot, this, this.player.serverLevel());
774 782 + if (this.player.isImmobile()) return; // CraftBukkit
775 783 if (packetplayinhelditemslot.getSlot() >= 0 && packetplayinhelditemslot.getSlot() < PlayerInventory.getSelectionSize()) {
776 784 + PlayerItemHeldEvent event = new PlayerItemHeldEvent(this.getCraftPlayer(), this.player.getInventory().selected, packetplayinhelditemslot.getSlot());
777 785 + this.cserver.getPluginManager().callEvent(event);
778 786 + if (event.isCancelled()) {
779 787 + this.send(new PacketPlayOutHeldItemSlot(this.player.getInventory().selected));
780 788 + this.player.resetLastActionTime();
781 789 + return;
782 790 + }
783 791 + // CraftBukkit end
784 792 if (this.player.getInventory().selected != packetplayinhelditemslot.getSlot() && this.player.getUsedItemHand() == EnumHand.MAIN_HAND) {
785 793 this.player.stopUsingItem();
786 794 }
787 -@@ -1243,18 +1691,25 @@
795 +@@ -1243,18 +1692,25 @@
788 796 this.player.resetLastActionTime();
789 797 } else {
790 798 PlayerConnection.LOGGER.warn("{} tried to set an invalid carried item", this.player.getName().getString());
791 799 + this.disconnect("Invalid hotbar selection (Hacking?)"); // CraftBukkit
792 800 }
793 801 }
794 802
795 803 @Override
796 804 public void handleChat(PacketPlayInChat packetplayinchat) {
797 805 + // CraftBukkit start - async chat
804 812 this.disconnect(IChatBaseComponent.translatable("multiplayer.disconnect.illegal_characters"));
805 813 } else {
806 814 Optional<LastSeenMessages> optional = this.tryHandleChat(packetplayinchat.message(), packetplayinchat.timeStamp(), packetplayinchat.lastSeenMessages());
807 815
808 816 if (optional.isPresent()) {
809 817 - this.server.submit(() -> {
810 818 + // this.server.submit(() -> { // CraftBukkit - async chat
811 819 PlayerChatMessage playerchatmessage;
812 820
813 821 try {
814 -@@ -1272,9 +1727,9 @@
822 +@@ -1272,9 +1728,9 @@
815 823 PlayerChatMessage playerchatmessage1 = playerchatmessage.withUnsignedContent(ichatbasecomponent).filter(filteredtext.mask());
816 824
817 825 this.broadcastChatMessage(playerchatmessage1);
818 826 - }, executor);
819 827 + }, this.server.chatExecutor); // CraftBukkit - async chat
820 828 });
821 829 - });
822 830 + // }); // CraftBukkit - async chat
823 831 }
824 832
825 833 }
826 -@@ -1289,6 +1744,12 @@
834 +@@ -1289,6 +1745,12 @@
827 835
828 836 if (optional.isPresent()) {
829 837 this.server.submit(() -> {
830 838 + // CraftBukkit start - SPIGOT-7346: Prevent disconnected players from executing commands
831 839 + if (player.hasDisconnected()) {
832 840 + return;
833 841 + }
834 842 + // CraftBukkit end
835 843 +
836 844 this.performChatCommand(serverboundchatcommandpacket, (LastSeenMessages) optional.get());
837 845 this.detectRateSpam();
838 846 });
839 -@@ -1298,12 +1759,25 @@
847 +@@ -1298,12 +1760,25 @@
840 848 }
841 849
842 850 private void performChatCommand(ServerboundChatCommandPacket serverboundchatcommandpacket, LastSeenMessages lastseenmessages) {
843 851 - ParseResults parseresults = this.parseCommand(serverboundchatcommandpacket.command());
844 852 + // CraftBukkit start
845 853 + String command = "/" + serverboundchatcommandpacket.command();
846 854 + PlayerConnection.LOGGER.info(this.player.getScoreboardName() + " issued server command: " + command);
847 855 +
848 856 + PlayerCommandPreprocessEvent event = new PlayerCommandPreprocessEvent(getCraftPlayer(), command, new LazyPlayerSet(server));
849 857 + this.cserver.getPluginManager().callEvent(event);
857 865 + // CraftBukkit end
858 866
859 867 Map map;
860 868
861 869 try {
862 870 - map = this.collectSignedArguments(serverboundchatcommandpacket, SignableCommand.of(parseresults), lastseenmessages);
863 871 + map = (serverboundchatcommandpacket.command().equals(command)) ? this.collectSignedArguments(serverboundchatcommandpacket, SignableCommand.of(parseresults), lastseenmessages) : Collections.emptyMap(); // CraftBukkit
864 872 } catch (SignedMessageChain.a signedmessagechain_a) {
865 873 this.handleMessageDecodeFailure(signedmessagechain_a);
866 874 return;
867 -@@ -1311,10 +1785,10 @@
875 +@@ -1311,10 +1786,10 @@
868 876
869 877 CommandSigningContext.a commandsigningcontext_a = new CommandSigningContext.a(map);
870 878
871 879 - parseresults = CommandDispatcher.mapSource(parseresults, (commandlistenerwrapper) -> {
872 880 + parseresults = CommandDispatcher.<CommandListenerWrapper>mapSource(parseresults, (commandlistenerwrapper) -> { // CraftBukkit - decompile error
873 881 return commandlistenerwrapper.withSigningContext(commandsigningcontext_a, this.chatMessageChain);
874 882 });
875 883 - this.server.getCommands().performCommand(parseresults, serverboundchatcommandpacket.command());
876 884 + this.server.getCommands().performCommand(parseresults, command); // CraftBukkit
877 885 }
878 886
879 887 private void handleMessageDecodeFailure(SignedMessageChain.a signedmessagechain_a) {
880 -@@ -1355,7 +1829,7 @@
888 +@@ -1355,7 +1830,7 @@
881 889 } else {
882 890 Optional<LastSeenMessages> optional = this.unpackAndApplyLastSeen(lastseenmessages_b);
883 891
884 892 - if (this.player.getChatVisibility() == EnumChatVisibility.HIDDEN) {
885 893 + if (this.player.isRemoved() || this.player.getChatVisibility() == EnumChatVisibility.HIDDEN) { // CraftBukkit - dead men tell no tales
886 894 this.send(new ClientboundSystemChatPacket(IChatBaseComponent.translatable("chat.disabled.options").withStyle(EnumChatFormat.RED), false));
887 895 return Optional.empty();
888 896 } else {
889 -@@ -1403,6 +1877,116 @@
897 +@@ -1403,6 +1878,116 @@
890 898 return false;
891 899 }
892 900
893 901 + // CraftBukkit start - add method
894 902 + public void chat(String s, PlayerChatMessage original, boolean async) {
895 903 + if (s.isEmpty() || this.player.getChatVisibility() == EnumChatVisibility.HIDDEN) {
896 904 + return;
897 905 + }
898 906 + OutgoingChatMessage outgoing = OutgoingChatMessage.create(original);
899 907 +
996 1004 + player.sendMessage(org.bukkit.ChatColor.RED + "An internal error occurred while attempting to perform this command");
997 1005 + java.util.logging.Logger.getLogger(PlayerConnection.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
998 1006 + return;
999 1007 + }
1000 1008 + }
1001 1009 + // CraftBukkit end
1002 1010 +
1003 1011 private PlayerChatMessage getSignedMessage(PacketPlayInChat packetplayinchat, LastSeenMessages lastseenmessages) throws SignedMessageChain.a {
1004 1012 SignedMessageBody signedmessagebody = new SignedMessageBody(packetplayinchat.message(), packetplayinchat.timeStamp(), packetplayinchat.salt(), lastseenmessages);
1005 1013
1006 -@@ -1410,13 +1994,33 @@
1014 +@@ -1410,13 +1995,33 @@
1007 1015 }
1008 1016
1009 1017 private void broadcastChatMessage(PlayerChatMessage playerchatmessage) {
1010 1018 - this.server.getPlayerList().broadcastChatMessage(playerchatmessage, this.player, ChatMessageType.bind(ChatMessageType.CHAT, (Entity) this.player));
1011 1019 + // CraftBukkit start
1012 1020 + String s = playerchatmessage.signedContent();
1013 1021 + if (s.isEmpty()) {
1014 1022 + LOGGER.warn(this.player.getScoreboardName() + " tried to send an empty message");
1015 1023 + } else if (getCraftPlayer().isConversing()) {
1016 1024 + final String conversationInput = s;
1033 1041 private void detectRateSpam() {
1034 1042 - this.chatSpamTickCount += 20;
1035 1043 - if (this.chatSpamTickCount > 200 && !this.server.getPlayerList().isOp(this.player.getGameProfile())) {
1036 1044 + // CraftBukkit start - replaced with thread safe throttle
1037 1045 + // this.chatSpamTickCount += 20;
1038 1046 + if (this.chatSpamTickCount.addAndGet(20) > 200 && !this.server.getPlayerList().isOp(this.player.getGameProfile())) {
1039 1047 + // CraftBukkit end
1040 1048 this.disconnect(IChatBaseComponent.translatable("disconnect.spam"));
1041 1049 }
1042 1050
1043 -@@ -1438,13 +2042,62 @@
1051 +@@ -1438,13 +2043,62 @@
1044 1052 @Override
1045 1053 public void handleAnimate(PacketPlayInArmAnimation packetplayinarmanimation) {
1046 1054 PlayerConnectionUtils.ensureRunningOnSameThread(packetplayinarmanimation, this, this.player.serverLevel());
1047 1055 + if (this.player.isImmobile()) return; // CraftBukkit
1048 1056 this.player.resetLastActionTime();
1049 1057 + // CraftBukkit start - Raytrace to look for 'rogue armswings'
1050 1058 + float f1 = this.player.getXRot();
1051 1059 + float f2 = this.player.getYRot();
1052 1060 + double d0 = this.player.getX();
1053 1061 + double d1 = this.player.getY() + (double) this.player.getEyeHeight();
1096 1104 +
1097 1105 + if (e2.isCancelled()) {
1098 1106 + return;
1099 1107 + }
1100 1108 + break;
1101 1109 + }
1102 1110 + // CraftBukkit end
1103 1111 this.player.resetLastActionTime();
1104 1112 Entity entity;
1105 1113 IJumpable ijumpable;
1106 -@@ -1526,6 +2179,12 @@
1114 +@@ -1526,6 +2180,12 @@
1107 1115 }
1108 1116
1109 1117 public void sendPlayerChatMessage(PlayerChatMessage playerchatmessage, ChatMessageType.a chatmessagetype_a) {
1110 1118 + // CraftBukkit start - SPIGOT-7262: if hidden we have to send as disguised message. Query whether we should send at all (but changing this may not be expected).
1111 1119 + if (!getCraftPlayer().canSee(playerchatmessage.link().sender())) {
1112 1120 + sendDisguisedChatMessage(playerchatmessage.decoratedContent(), chatmessagetype_a);
1113 1121 + return;
1114 1122 + }
1115 1123 + // CraftBukkit end
1116 1124 this.send(new ClientboundPlayerChatPacket(playerchatmessage.link().sender(), playerchatmessage.link().index(), playerchatmessage.signature(), playerchatmessage.signedBody().pack(this.messageSignatureCache), playerchatmessage.unsignedContent(), playerchatmessage.filterMask(), chatmessagetype_a.toNetwork(this.player.level().registryAccess())));
1117 1125 this.addPendingMessage(playerchatmessage);
1118 1126 }
1119 -@@ -1552,6 +2211,7 @@
1127 +@@ -1552,6 +2212,7 @@
1120 1128 @Override
1121 1129 public void handleInteract(PacketPlayInUseEntity packetplayinuseentity) {
1122 1130 PlayerConnectionUtils.ensureRunningOnSameThread(packetplayinuseentity, this, this.player.serverLevel());
1123 1131 + if (this.player.isImmobile()) return; // CraftBukkit
1124 1132 final WorldServer worldserver = this.player.serverLevel();
1125 1133 final Entity entity = packetplayinuseentity.getTarget(worldserver);
1126 1134
1127 -@@ -1566,13 +2226,51 @@
1135 +@@ -1566,13 +2227,51 @@
1128 1136
1129 1137 if (axisalignedbb.distanceToSqr(this.player.getEyePosition()) < PlayerConnection.MAX_INTERACTION_DISTANCE) {
1130 1138 packetplayinuseentity.dispatch(new PacketPlayInUseEntity.c() {
1131 1139 - private void performInteraction(EnumHand enumhand, PlayerConnection.a playerconnection_a) {
1132 1140 + private void performInteraction(EnumHand enumhand, PlayerConnection.a playerconnection_a, PlayerInteractEntityEvent event) { // CraftBukkit
1133 1141 ItemStack itemstack = PlayerConnection.this.player.getItemInHand(enumhand);
1134 1142
1135 1143 if (itemstack.isItemEnabled(worldserver.enabledFeatures())) {
1136 1144 ItemStack itemstack1 = itemstack.copy();
1137 1145 + // CraftBukkit start
1170 1178
1171 1179 + // CraftBukkit start
1172 1180 + if (!itemInHand.isEmpty() && itemInHand.getCount() <= -1) {
1173 1181 + player.containerMenu.sendAllDataToRemote();
1174 1182 + }
1175 1183 + // CraftBukkit end
1176 1184 +
1177 1185 if (enuminteractionresult.consumesAction()) {
1178 1186 CriterionTriggers.PLAYER_INTERACTED_WITH_ENTITY.trigger(PlayerConnection.this.player, itemstack1, entity);
1179 1187 if (enuminteractionresult.shouldSwing()) {
1180 -@@ -1585,23 +2283,29 @@
1188 +@@ -1585,23 +2284,29 @@
1181 1189
1182 1190 @Override
1183 1191 public void onInteraction(EnumHand enumhand) {
1184 1192 - this.performInteraction(enumhand, EntityHuman::interactOn);
1185 1193 + this.performInteraction(enumhand, EntityHuman::interactOn, new PlayerInteractEntityEvent(getCraftPlayer(), entity.getBukkitEntity(), (enumhand == EnumHand.OFF_HAND) ? EquipmentSlot.OFF_HAND : EquipmentSlot.HAND)); // CraftBukkit
1186 1194 }
1187 1195
1188 1196 @Override
1189 1197 public void onInteraction(EnumHand enumhand, Vec3D vec3d) {
1190 1198 this.performInteraction(enumhand, (entityplayer, entity1, enumhand1) -> {
1203 1211 if (itemstack.isItemEnabled(worldserver.enabledFeatures())) {
1204 1212 PlayerConnection.this.player.attack(entity);
1205 1213 + // CraftBukkit start
1206 1214 + if (!itemstack.isEmpty() && itemstack.getCount() <= -1) {
1207 1215 + player.containerMenu.sendAllDataToRemote();
1208 1216 + }
1209 1217 + // CraftBukkit end
1210 1218 }
1211 1219 } else {
1212 1220 PlayerConnection.this.disconnect(IChatBaseComponent.translatable("multiplayer.disconnect.invalid_entity_attacked"));
1213 -@@ -1624,14 +2328,14 @@
1221 +@@ -1624,14 +2329,14 @@
1214 1222 case PERFORM_RESPAWN:
1215 1223 if (this.player.wonGame) {
1216 1224 this.player.wonGame = false;
1217 1225 - this.player = this.server.getPlayerList().respawn(this.player, true);
1218 1226 + this.player = this.server.getPlayerList().respawn(this.player, true, RespawnReason.END_PORTAL);
1219 1227 CriterionTriggers.CHANGED_DIMENSION.trigger(this.player, World.END, World.OVERWORLD);
1220 1228 } else {
1221 1229 if (this.player.getHealth() > 0.0F) {
1222 1230 return;
1223 1231 }
1224 1232
1225 1233 - this.player = this.server.getPlayerList().respawn(this.player, false);
1226 1234 + this.player = this.server.getPlayerList().respawn(this.player, false, RespawnReason.DEATH);
1227 1235 if (this.server.isHardcore()) {
1228 1236 this.player.setGameMode(EnumGamemode.SPECTATOR);
1229 1237 ((GameRules.GameRuleBoolean) this.player.level().getGameRules().getRule(GameRules.RULE_SPECTATORSGENERATECHUNKS)).set(false, this.server);
1230 -@@ -1647,15 +2351,21 @@
1238 +@@ -1647,15 +2352,21 @@
1231 1239 @Override
1232 1240 public void handleContainerClose(PacketPlayInCloseWindow packetplayinclosewindow) {
1233 1241 PlayerConnectionUtils.ensureRunningOnSameThread(packetplayinclosewindow, this, this.player.serverLevel());
1234 1242 +
1235 1243 + if (this.player.isImmobile()) return; // CraftBukkit
1236 1244 + CraftEventFactory.handleInventoryCloseEvent(this.player); // CraftBukkit
1237 1245 +
1238 1246 this.player.doCloseContainer();
1239 1247 }
1240 1248
1244 1252 + if (this.player.isImmobile()) return; // CraftBukkit
1245 1253 this.player.resetLastActionTime();
1246 1254 - if (this.player.containerMenu.containerId == packetplayinwindowclick.getContainerId()) {
1247 1255 - if (this.player.isSpectator()) {
1248 1256 + if (this.player.containerMenu.containerId == packetplayinwindowclick.getContainerId() && this.player.containerMenu.stillValid(this.player)) { // CraftBukkit
1249 1257 + boolean cancelled = this.player.isSpectator(); // CraftBukkit - see below if
1250 1258 + if (false/*this.player.isSpectator()*/) { // CraftBukkit
1251 1259 this.player.containerMenu.sendAllDataToRemote();
1252 1260 } else if (!this.player.containerMenu.stillValid(this.player)) {
1253 1261 PlayerConnection.LOGGER.debug("Player {} interacted with invalid menu {}", this.player, this.player.containerMenu);
1254 -@@ -1668,7 +2378,284 @@
1262 +@@ -1668,7 +2379,284 @@
1255 1263 boolean flag = packetplayinwindowclick.getStateId() != this.player.containerMenu.getStateId();
1256 1264
1257 1265 this.player.containerMenu.suppressRemoteUpdates();
1258 1266 - this.player.containerMenu.clicked(i, packetplayinwindowclick.getButtonNum(), packetplayinwindowclick.getClickType(), this.player);
1259 1267 + // CraftBukkit start - Call InventoryClickEvent
1260 1268 + if (packetplayinwindowclick.getSlotNum() < -1 && packetplayinwindowclick.getSlotNum() != -999) {
1261 1269 + return;
1262 1270 + }
1263 1271 +
1264 1272 + InventoryView inventory = this.player.containerMenu.getBukkitView();
1530 1538 + if (event instanceof CraftItemEvent || event instanceof SmithItemEvent) {
1531 1539 + // Need to update the inventory on crafting to
1532 1540 + // correctly support custom recipes
1533 1541 + player.containerMenu.sendAllDataToRemote();
1534 1542 + }
1535 1543 + }
1536 1544 + // CraftBukkit end
1537 1545 ObjectIterator objectiterator = Int2ObjectMaps.fastIterable(packetplayinwindowclick.getChangedSlots()).iterator();
1538 1546
1539 1547 while (objectiterator.hasNext()) {
1540 -@@ -1698,9 +2685,18 @@
1548 +@@ -1698,9 +2686,18 @@
1541 1549 if (!this.player.containerMenu.stillValid(this.player)) {
1542 1550 PlayerConnection.LOGGER.debug("Player {} interacted with invalid menu {}", this.player, this.player.containerMenu);
1543 1551 } else {
1544 1552 - this.server.getRecipeManager().byKey(packetplayinautorecipe.getRecipe()).ifPresent((recipeholder) -> {
1545 1553 - ((ContainerRecipeBook) this.player.containerMenu).handlePlacement(packetplayinautorecipe.isShiftDown(), recipeholder, this.player);
1546 1554 + // CraftBukkit start - implement PlayerRecipeBookClickEvent
1547 1555 + org.bukkit.inventory.Recipe recipe = this.cserver.getRecipe(CraftNamespacedKey.fromMinecraft(packetplayinautorecipe.getRecipe()));
1548 1556 + if (recipe == null) {
1549 1557 + return;
1550 1558 + }
1551 1559 + org.bukkit.event.player.PlayerRecipeBookClickEvent event = CraftEventFactory.callRecipeBookClickEvent(this.player, recipe, packetplayinautorecipe.isShiftDown());
1552 1560 +
1553 1561 + // Cast to keyed should be safe as the recipe will never be a MerchantRecipe.
1554 1562 + this.server.getRecipeManager().byKey(CraftNamespacedKey.toMinecraft(((org.bukkit.Keyed) event.getRecipe()).getKey())).ifPresent((recipeholder) -> {
1555 1563 + ((ContainerRecipeBook) this.player.containerMenu).handlePlacement(event.isShiftClick(), recipeholder, this.player);
1556 1564 });
1557 1565 + // CraftBukkit end
1558 1566 }
1559 1567 }
1560 1568 }
1561 -@@ -1708,6 +2704,7 @@
1569 +@@ -1708,6 +2705,7 @@
1562 1570 @Override
1563 1571 public void handleContainerButtonClick(PacketPlayInEnchantItem packetplayinenchantitem) {
1564 1572 PlayerConnectionUtils.ensureRunningOnSameThread(packetplayinenchantitem, this, this.player.serverLevel());
1565 1573 + if (this.player.isImmobile()) return; // CraftBukkit
1566 1574 this.player.resetLastActionTime();
1567 1575 if (this.player.containerMenu.containerId == packetplayinenchantitem.getContainerId() && !this.player.isSpectator()) {
1568 1576 if (!this.player.containerMenu.stillValid(this.player)) {
1569 -@@ -1750,6 +2747,43 @@
1577 +@@ -1750,6 +2748,43 @@
1570 1578
1571 1579 boolean flag1 = packetplayinsetcreativeslot.getSlotNum() >= 1 && packetplayinsetcreativeslot.getSlotNum() <= 45;
1572 1580 boolean flag2 = itemstack.isEmpty() || itemstack.getDamageValue() >= 0 && itemstack.getCount() <= 64 && !itemstack.isEmpty();
1573 1581 + if (flag || (flag1 && !ItemStack.matches(this.player.inventoryMenu.getSlot(packetplayinsetcreativeslot.getSlotNum()).getItem(), packetplayinsetcreativeslot.getItem()))) { // Insist on valid slot
1574 1582 + // CraftBukkit start - Call click event
1575 1583 + InventoryView inventory = this.player.inventoryMenu.getBukkitView();
1576 1584 + org.bukkit.inventory.ItemStack item = CraftItemStack.asBukkitCopy(packetplayinsetcreativeslot.getItem());
1577 1585 +
1578 1586 + SlotType type = SlotType.QUICKBAR;
1579 1587 + if (flag) {
1603 1611 + this.player.connection.send(new PacketPlayOutSetSlot(this.player.inventoryMenu.containerId, this.player.inventoryMenu.incrementStateId(), packetplayinsetcreativeslot.getSlotNum(), this.player.inventoryMenu.getSlot(packetplayinsetcreativeslot.getSlotNum()).getItem()));
1604 1612 + this.player.connection.send(new PacketPlayOutSetSlot(-1, this.player.inventoryMenu.incrementStateId(), -1, ItemStack.EMPTY));
1605 1613 + }
1606 1614 + return;
1607 1615 + }
1608 1616 + }
1609 1617 + // CraftBukkit end
1610 1618
1611 1619 if (flag1 && flag2) {
1612 1620 this.player.inventoryMenu.getSlot(packetplayinsetcreativeslot.getSlotNum()).setByPlayer(itemstack);
1613 -@@ -1772,6 +2806,7 @@
1621 +@@ -1772,6 +2807,7 @@
1614 1622 }
1615 1623
1616 1624 private void updateSignText(PacketPlayInUpdateSign packetplayinupdatesign, List<FilteredText> list) {
1617 1625 + if (this.player.isImmobile()) return; // CraftBukkit
1618 1626 this.player.resetLastActionTime();
1619 1627 WorldServer worldserver = this.player.serverLevel();
1620 1628 BlockPosition blockposition = packetplayinupdatesign.getPos();
1621 -@@ -1793,7 +2828,17 @@
1629 +@@ -1793,7 +2829,17 @@
1622 1630 @Override
1623 1631 public void handlePlayerAbilities(PacketPlayInAbilities packetplayinabilities) {
1624 1632 PlayerConnectionUtils.ensureRunningOnSameThread(packetplayinabilities, this, this.player.serverLevel());
1625 1633 - this.player.getAbilities().flying = packetplayinabilities.isFlying() && this.player.getAbilities().mayfly;
1626 1634 + // CraftBukkit start
1627 1635 + if (this.player.getAbilities().mayfly && this.player.getAbilities().flying != packetplayinabilities.isFlying()) {
1628 1636 + PlayerToggleFlightEvent event = new PlayerToggleFlightEvent(this.player.getBukkitEntity(), packetplayinabilities.isFlying());
1629 1637 + this.cserver.getPluginManager().callEvent(event);
1630 1638 + if (!event.isCancelled()) {
1631 1639 + this.player.getAbilities().flying = packetplayinabilities.isFlying(); // Actually set the player's flying status
1632 1640 + } else {
1633 1641 + this.player.onUpdateAbilities(); // Tell the player their ability was reverted
1634 1642 + }
1635 1643 + }
1636 1644 + // CraftBukkit end
1637 1645 }
1638 1646
1639 1647 @Override
1640 -@@ -1852,7 +2897,7 @@
1648 +@@ -1852,7 +2898,7 @@
1641 1649 if (!this.waitingForSwitchToConfig) {
1642 1650 throw new IllegalStateException("Client acknowledged config, but none was requested");
1643 1651 } else {
1644 1652 - this.connection.setListener(new ServerConfigurationPacketListenerImpl(this.server, this.connection, this.createCookie(this.player.clientInformation())));
1645 1653 + this.connection.setListener(new ServerConfigurationPacketListenerImpl(this.server, this.connection, this.createCookie(this.player.clientInformation()), this.player)); // CraftBukkit
1646 1654 }
1647 1655 }
1648 1656

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

Add shortcut