Commits
coll1234567 authored and md_5 committed 482c56a0097
255 255 | } |
256 256 | |
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 - | |
265 + | |
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 + | |
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 - | |
286 + | |
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 - | |
294 + | |
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 - | |
308 + | |
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 - | |
322 + | |
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 - | |
331 + | |
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 - | |
340 + | |
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 - | |
361 + | |
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 - | |
369 + | |
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 - | |
378 + | |
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 - | |
387 + | |
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 - | |
403 + | |
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 - | |
439 + | |
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 - | |
447 + | |
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 - | |
519 + | |
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 - | |
589 + | |
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 - | |
604 + | |
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 - | |
612 + | |
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 - | |
661 + | |
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 - | |
669 + | |
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 - | |
677 + | |
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 - | |
685 + | |
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 - | |
735 + | |
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 - | |
744 + | |
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 - | |
758 + | |
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 - | |
778 + | |
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 - | |
795 + | |
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 - | |
822 + | |
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 - | |
834 + | |
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 - | |
847 + | |
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 - | |
875 + | |
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 - | |
888 + | |
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 - | |
897 + | |
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 - | |
1014 + | |
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 - | |
1051 + | |
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 - | |
1114 + | |
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 - | |
1127 + | |
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 - | |
1135 + | |
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 - | |
1188 + | |
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 - | |
1221 + | |
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 - | |
1238 + | |
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 - | |
1262 + | |
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 - | |
1548 + | |
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 - | |
1569 + | |
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 - | |
1577 + | |
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 - | |
1621 + | |
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 - | |
1629 + | |
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 - | |
1648 + | |
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 |