Commits
md_5 authored ead719a65bf
1 1 | --- a/net/minecraft/server/network/PlayerConnection.java |
2 2 | +++ b/net/minecraft/server/network/PlayerConnection.java |
3 - | |
3 + | |
4 4 | import org.apache.commons.lang3.StringUtils; |
5 5 | import org.slf4j.Logger; |
6 6 | |
7 7 | +// CraftBukkit start |
8 + | +import java.util.Arrays; |
8 9 | +import java.util.concurrent.ExecutionException; |
9 10 | +import java.util.concurrent.atomic.AtomicInteger; |
10 11 | +import net.minecraft.network.chat.OutgoingPlayerChatMessage; |
11 12 | +import net.minecraft.network.protocol.game.PacketPlayOutAttachEntity; |
13 + | +import net.minecraft.network.protocol.game.PacketPlayOutEntityEquipment; |
12 14 | +import net.minecraft.network.protocol.game.PacketPlayOutEntityMetadata; |
13 15 | +import net.minecraft.network.protocol.game.PacketPlayOutSpawnEntity; |
14 16 | +import net.minecraft.network.protocol.game.PacketPlayOutSpawnPosition; |
15 17 | +import net.minecraft.world.entity.EntityInsentient; |
16 18 | +import net.minecraft.world.entity.animal.Bucketable; |
17 19 | +import net.minecraft.world.entity.EntityLiving; |
20 + | +import net.minecraft.world.entity.EnumItemSlot; |
21 + | +import net.minecraft.world.entity.animal.allay.Allay; |
18 22 | +import net.minecraft.world.inventory.InventoryClickType; |
19 23 | +import net.minecraft.world.inventory.Slot; |
20 24 | +import net.minecraft.world.item.crafting.IRecipe; |
21 25 | +import net.minecraft.world.level.RayTrace; |
22 26 | +import net.minecraft.world.phys.MovingObjectPosition; |
23 27 | +import org.bukkit.Location; |
24 28 | +import org.bukkit.craftbukkit.entity.CraftPlayer; |
25 29 | +import org.bukkit.craftbukkit.event.CraftEventFactory; |
26 30 | +import org.bukkit.craftbukkit.inventory.CraftItemStack; |
27 31 | +import org.bukkit.craftbukkit.util.CraftChatMessage; |
57 61 | +import org.bukkit.event.player.PlayerToggleSprintEvent; |
58 62 | +import org.bukkit.inventory.CraftingInventory; |
59 63 | +import org.bukkit.inventory.EquipmentSlot; |
60 64 | +import org.bukkit.inventory.InventoryView; |
61 65 | +import org.bukkit.inventory.SmithingInventory; |
62 66 | +// CraftBukkit end |
63 67 | + |
64 68 | public class PlayerConnection implements ServerPlayerConnection, TickablePacketListener, PacketListenerPlayIn { |
65 69 | |
66 70 | static final Logger LOGGER = LogUtils.getLogger(); |
67 - | |
71 + | |
68 72 | private long keepAliveTime; |
69 73 | private boolean keepAlivePending; |
70 74 | private long keepAliveChallenge; |
71 75 | - private int chatSpamTickCount; |
72 76 | + // CraftBukkit start - multithreaded fields |
73 77 | + private final AtomicInteger chatSpamTickCount = new AtomicInteger(); |
74 78 | + // CraftBukkit end |
75 79 | private int dropSpamTickCount; |
76 80 | private double firstGoodX; |
77 81 | private double firstGoodY; |
78 - | |
82 + | |
79 83 | this.signedMessageDecoder = SignedMessageChain.a.UNSIGNED; |
80 84 | } |
81 85 | |
82 86 | - this.chatMessageChain = new FutureChain(minecraftserver); |
83 87 | + this.chatMessageChain = new FutureChain(minecraftserver.chatExecutor); // CraftBukkit - async chat |
84 88 | + |
85 89 | + // CraftBukkit start - add fields and methods |
86 90 | + this.cserver = minecraftserver.server; |
87 91 | + } |
88 92 | + |
102 106 | + private float lastYaw = Float.MAX_VALUE; |
103 107 | + private boolean justTeleported = false; |
104 108 | + |
105 109 | + public CraftPlayer getCraftPlayer() { |
106 110 | + return (this.player == null) ? null : (CraftPlayer) this.player.getBukkitEntity(); |
107 111 | } |
108 112 | + // CraftBukkit end |
109 113 | |
110 114 | @Override |
111 115 | public void tick() { |
112 - | |
116 + | |
113 117 | this.server.getProfiler().push("keepAlive"); |
114 118 | long i = SystemUtils.getMillis(); |
115 119 | |
116 120 | - if (i - this.keepAliveTime >= 15000L) { |
117 121 | + if (i - this.keepAliveTime >= 25000L) { // CraftBukkit |
118 122 | if (this.keepAlivePending) { |
119 123 | this.disconnect(IChatBaseComponent.translatable("disconnect.timeout")); |
120 124 | } else { |
121 - | |
125 + | |
122 126 | } |
123 127 | |
124 128 | this.server.getProfiler().pop(); |
125 129 | + // CraftBukkit start |
126 130 | + for (int spam; (spam = this.chatSpamTickCount.get()) > 0 && !chatSpamTickCount.compareAndSet(spam, spam - 1); ) ; |
127 131 | + /* Use thread-safe field access instead |
128 132 | if (this.chatSpamTickCount > 0) { |
129 133 | --this.chatSpamTickCount; |
130 134 | } |
131 135 | + */ |
132 136 | + // CraftBukkit end |
133 137 | |
134 138 | if (this.dropSpamTickCount > 0) { |
135 139 | --this.dropSpamTickCount; |
136 140 | } |
137 141 | |
138 142 | if (this.player.getLastActionTime() > 0L && this.server.getPlayerIdleTimeout() > 0 && SystemUtils.getMillis() - this.player.getLastActionTime() > (long) (this.server.getPlayerIdleTimeout() * 1000 * 60)) { |
139 143 | + this.player.resetLastActionTime(); // CraftBukkit - SPIGOT-854 |
140 144 | this.disconnect(IChatBaseComponent.translatable("multiplayer.disconnect.idling")); |
141 145 | } |
142 146 | |
143 - | |
147 + | |
144 148 | return this.server.isSingleplayerOwner(this.player.getGameProfile()); |
145 149 | } |
146 150 | |
147 151 | + // CraftBukkit start |
148 152 | + @Deprecated |
149 153 | public void disconnect(IChatBaseComponent ichatbasecomponent) { |
150 154 | + disconnect(CraftChatMessage.fromComponent(ichatbasecomponent)); |
151 155 | + } |
152 156 | + // CraftBukkit end |
153 157 | + |
202 206 | MinecraftServer minecraftserver = this.server; |
203 207 | NetworkManager networkmanager = this.connection; |
204 208 | |
205 209 | Objects.requireNonNull(this.connection); |
206 210 | - minecraftserver.executeBlocking(networkmanager::handleDisconnection); |
207 211 | + // CraftBukkit - Don't wait |
208 212 | + minecraftserver.wrapRunnable(networkmanager::handleDisconnection); |
209 213 | } |
210 214 | |
211 215 | private <T, R> CompletableFuture<R> filterTextPacket(T t0, BiFunction<ITextFilter, T, CompletableFuture<R>> bifunction) { |
212 - | |
216 + | |
213 217 | double d9 = entity.getDeltaMovement().lengthSqr(); |
214 218 | double d10 = d6 * d6 + d7 * d7 + d8 * d8; |
215 219 | |
216 220 | - if (d10 - d9 > 100.0D && !this.isSingleplayerOwner()) { |
217 221 | + |
218 222 | + // CraftBukkit start - handle custom speeds and skipped ticks |
219 223 | + this.allowedPlayerTicks += (System.currentTimeMillis() / 50) - this.lastTick; |
220 224 | + this.allowedPlayerTicks = Math.max(this.allowedPlayerTicks, 1); |
221 225 | + this.lastTick = (int) (System.currentTimeMillis() / 50); |
222 226 | + |
238 242 | + } else { |
239 243 | + speed = player.getAbilities().walkingSpeed * 10f; |
240 244 | + } |
241 245 | + speed *= 2f; // TODO: Get the speed of the vehicle instead of the player |
242 246 | + |
243 247 | + if (d10 - d9 > Math.max(100.0D, Math.pow((double) (10.0F * (float) i * speed), 2)) && !this.isSingleplayerOwner()) { |
244 248 | + // CraftBukkit end |
245 249 | PlayerConnection.LOGGER.warn("{} (vehicle of {}) moved too quickly! {},{},{}", new Object[]{entity.getName().getString(), this.player.getName().getString(), d6, d7, d8}); |
246 250 | this.connection.send(new PacketPlayOutVehicleMove(entity)); |
247 251 | return; |
248 - | |
252 + | |
249 253 | } |
250 254 | |
251 255 | entity.absMoveTo(d3, d4, d5, f, f1); |
252 256 | + player.absMoveTo(d3, d4, d5, this.player.getYRot(), this.player.getXRot()); // CraftBukkit |
253 257 | boolean flag3 = worldserver.noCollision(entity, entity.getBoundingBox().deflate(0.0625D)); |
254 258 | |
255 259 | if (flag && (flag2 || !flag3)) { |
256 260 | entity.absMoveTo(d0, d1, d2, f, f1); |
257 261 | + player.absMoveTo(d0, d1, d2, this.player.getYRot(), this.player.getXRot()); // CraftBukkit |
258 262 | this.connection.send(new PacketPlayOutVehicleMove(entity)); |
311 315 | + this.justTeleported = false; |
312 316 | + return; |
313 317 | + } |
314 318 | + } |
315 319 | + } |
316 320 | + // CraftBukkit end |
317 321 | + |
318 322 | this.player.getLevel().getChunkSource().move(this.player); |
319 323 | this.player.checkMovementStatistics(this.player.getX() - d0, this.player.getY() - d1, this.player.getZ() - d2); |
320 324 | this.clientVehicleIsFloating = d11 >= -0.03125D && !flag1 && !this.server.isFlightAllowed() && !entity.isNoGravity() && this.noBlocksAround(entity); |
321 - | |
325 + | |
322 326 | } |
323 327 | |
324 328 | this.awaitingPositionFromClient = null; |
325 329 | + this.player.getLevel().getChunkSource().move(this.player); // CraftBukkit |
326 330 | } |
327 331 | |
328 332 | } |
329 - | |
333 + | |
330 334 | @Override |
331 335 | public void handleRecipeBookSeenRecipePacket(PacketPlayInRecipeDisplayed packetplayinrecipedisplayed) { |
332 336 | PlayerConnectionUtils.ensureRunningOnSameThread(packetplayinrecipedisplayed, this, this.player.getLevel()); |
333 337 | - Optional optional = this.server.getRecipeManager().byKey(packetplayinrecipedisplayed.getRecipe()); |
334 338 | + Optional<? extends IRecipe<?>> optional = this.server.getRecipeManager().byKey(packetplayinrecipedisplayed.getRecipe()); // CraftBukkit - decompile error |
335 339 | RecipeBookServer recipebookserver = this.player.getRecipeBook(); |
336 340 | |
337 341 | Objects.requireNonNull(recipebookserver); |
338 - | |
342 + | |
339 343 | @Override |
340 344 | public void handleCustomCommandSuggestions(PacketPlayInTabComplete packetplayintabcomplete) { |
341 345 | PlayerConnectionUtils.ensureRunningOnSameThread(packetplayintabcomplete, this, this.player.getLevel()); |
342 346 | + // CraftBukkit start |
343 347 | + if (chatSpamTickCount.addAndGet(1) > 500 && !this.server.getPlayerList().isOp(this.player.getGameProfile())) { |
344 348 | + this.disconnect(IChatBaseComponent.translatable("disconnect.spam")); |
345 349 | + return; |
346 350 | + } |
347 351 | + // CraftBukkit end |
348 352 | StringReader stringreader = new StringReader(packetplayintabcomplete.getCommand()); |
349 353 | |
350 354 | if (stringreader.canRead() && stringreader.peek() == '/') { |
351 - | |
355 + | |
352 356 | ParseResults<CommandListenerWrapper> parseresults = this.server.getCommands().getDispatcher().parse(stringreader, this.player.createCommandSourceStack()); |
353 357 | |
354 358 | this.server.getCommands().getDispatcher().getCompletionSuggestions(parseresults).thenAccept((suggestions) -> { |
355 359 | + if (suggestions.isEmpty()) return; // CraftBukkit - don't send through empty suggestions - prevents [<args>] from showing for plugins with nothing more to offer |
356 360 | this.connection.send(new PacketPlayOutTabComplete(packetplayintabcomplete.getId(), suggestions)); |
357 361 | }); |
358 362 | } |
359 - | |
363 + | |
360 364 | |
361 365 | if (container instanceof ContainerMerchant) { |
362 366 | ContainerMerchant containermerchant = (ContainerMerchant) container; |
363 367 | + // CraftBukkit start |
364 368 | + final org.bukkit.event.inventory.TradeSelectEvent tradeSelectEvent = CraftEventFactory.callTradeSelectEvent(this.player, i, containermerchant); |
365 369 | + if (tradeSelectEvent.isCancelled()) { |
366 370 | + this.player.getBukkitEntity().updateInventory(); |
367 371 | + return; |
368 372 | + } |
369 373 | + // CraftBukkit end |
370 374 | |
371 375 | if (!containermerchant.stillValid(this.player)) { |
372 376 | PlayerConnection.LOGGER.debug("Player {} interacted with invalid menu {}", this.player, containermerchant); |
373 - | |
377 + | |
374 378 | |
375 379 | @Override |
376 380 | public void handleEditBook(PacketPlayInBEdit packetplayinbedit) { |
377 381 | + // CraftBukkit start |
378 382 | + if (this.lastBookTick + 20 > MinecraftServer.currentTick) { |
379 383 | + this.disconnect("Book edited too quickly!"); |
380 384 | + return; |
381 385 | + } |
382 386 | + this.lastBookTick = MinecraftServer.currentTick; |
383 387 | + // CraftBukkit end |
384 388 | int i = packetplayinbedit.getSlot(); |
385 389 | |
386 390 | if (PlayerInventory.isHotbarSlot(i) || i == 40) { |
387 - | |
391 + | |
388 392 | |
389 393 | Objects.requireNonNull(list); |
390 394 | optional.ifPresent(list::add); |
391 395 | - Stream stream = packetplayinbedit.getPages().stream().limit(100L); |
392 396 | + Stream<String> stream = packetplayinbedit.getPages().stream().limit(100L); // CraftBukkit - decompile error |
393 397 | |
394 398 | Objects.requireNonNull(list); |
395 399 | stream.forEach(list::add); |
396 - | |
400 + | |
397 401 | ItemStack itemstack = this.player.getInventory().getItem(i); |
398 402 | |
399 403 | if (itemstack.is(Items.WRITABLE_BOOK)) { |
400 404 | - this.updateBookPages(list, UnaryOperator.identity(), itemstack); |
401 405 | + this.updateBookPages(list, UnaryOperator.identity(), itemstack.copy(), i, itemstack); // CraftBukkit |
402 406 | } |
403 407 | } |
404 408 | |
405 - | |
409 + | |
406 410 | |
407 411 | this.updateBookPages(list, (s) -> { |
408 412 | return IChatBaseComponent.ChatSerializer.toJson(IChatBaseComponent.literal(s)); |
409 413 | - }, itemstack1); |
410 414 | - this.player.getInventory().setItem(i, itemstack1); |
411 415 | + }, itemstack1, i, itemstack); // CraftBukkit |
412 416 | + this.player.getInventory().setItem(i, itemstack); // CraftBukkit - event factory updates the hand book |
413 417 | } |
414 418 | } |
415 419 | |
416 420 | - private void updateBookPages(List<FilteredText> list, UnaryOperator<String> unaryoperator, ItemStack itemstack) { |
417 421 | + private void updateBookPages(List<FilteredText> list, UnaryOperator<String> unaryoperator, ItemStack itemstack, int slot, ItemStack handItem) { // CraftBukkit |
418 422 | NBTTagList nbttaglist = new NBTTagList(); |
419 423 | |
420 424 | if (this.player.isTextFilteringEnabled()) { |
421 425 | - Stream stream = list.stream().map((filteredtext) -> { |
422 426 | + Stream<NBTTagString> stream = list.stream().map((filteredtext) -> { // CraftBukkit - decompile error |
423 427 | return NBTTagString.valueOf((String) unaryoperator.apply(filteredtext.filteredOrEmpty())); |
424 428 | }); |
425 429 | |
426 - | |
430 + | |
427 431 | } |
428 432 | |
429 433 | itemstack.addTagElement("pages", nbttaglist); |
430 434 | + CraftEventFactory.handleEditBookEvent(player, slot, handItem, itemstack); // CraftBukkit |
431 435 | } |
432 436 | |
433 437 | @Override |
434 - | |
438 + | |
435 439 | } else { |
436 440 | WorldServer worldserver = this.player.getLevel(); |
437 441 | |
438 442 | - if (!this.player.wonGame) { |
439 443 | + if (!this.player.wonGame && !this.player.isImmobile()) { // CraftBukkit |
440 444 | if (this.tickCount == 0) { |
441 445 | this.resetPosition(); |
442 446 | } |
443 - | |
447 + | |
444 448 | this.awaitingTeleportTime = this.tickCount; |
445 449 | this.teleport(this.awaitingPositionFromClient.x, this.awaitingPositionFromClient.y, this.awaitingPositionFromClient.z, this.player.getYRot(), this.player.getXRot()); |
446 450 | } |
447 451 | - |
448 452 | + this.allowedPlayerTicks = 20; // CraftBukkit |
449 453 | } else { |
450 454 | this.awaitingTeleportTime = this.tickCount; |
451 455 | double d0 = clampHorizontal(packetplayinflying.getX(this.player.getX())); |
452 - | |
456 + | |
453 457 | if (this.player.isPassenger()) { |
454 458 | this.player.absMoveTo(this.player.getX(), this.player.getY(), this.player.getZ(), f, f1); |
455 459 | this.player.getLevel().getChunkSource().move(this.player); |
456 460 | + this.allowedPlayerTicks = 20; // CraftBukkit |
457 461 | } else { |
458 462 | + // CraftBukkit - Make sure the move is valid but then reset it for plugins to modify |
459 463 | + double prevX = player.getX(); |
460 464 | + double prevY = player.getY(); |
461 465 | + double prevZ = player.getZ(); |
462 466 | + float prevYaw = player.getYRot(); |
463 467 | + float prevPitch = player.getXRot(); |
464 468 | + // CraftBukkit end |
465 469 | double d3 = this.player.getX(); |
466 470 | double d4 = this.player.getY(); |
467 471 | double d5 = this.player.getZ(); |
468 - | |
472 + | |
469 473 | ++this.receivedMovePacketCount; |
470 474 | int i = this.receivedMovePacketCount - this.knownMovePacketCount; |
471 475 | |
472 476 | - if (i > 5) { |
473 477 | + // CraftBukkit start - handle custom speeds and skipped ticks |
474 478 | + this.allowedPlayerTicks += (System.currentTimeMillis() / 50) - this.lastTick; |
475 479 | + this.allowedPlayerTicks = Math.max(this.allowedPlayerTicks, 1); |
476 480 | + this.lastTick = (int) (System.currentTimeMillis() / 50); |
477 481 | + |
478 482 | + if (i > Math.max(this.allowedPlayerTicks, 5)) { |
494 498 | + |
495 499 | if (!this.player.isChangingDimension() && (!this.player.getLevel().getGameRules().getBoolean(GameRules.RULE_DISABLE_ELYTRA_MOVEMENT_CHECK) || !this.player.isFallFlying())) { |
496 500 | float f2 = this.player.isFallFlying() ? 300.0F : 100.0F; |
497 501 | |
498 502 | - if (d11 - d10 > (double) (f2 * (float) i) && !this.isSingleplayerOwner()) { |
499 503 | + if (d11 - d10 > Math.max(f2, Math.pow((double) (10.0F * (float) i * speed), 2)) && !this.isSingleplayerOwner()) { |
500 504 | + // CraftBukkit end |
501 505 | PlayerConnection.LOGGER.warn("{} moved too quickly! {},{},{}", new Object[]{this.player.getName().getString(), d7, d8, d9}); |
502 506 | this.teleport(this.player.getX(), this.player.getY(), this.player.getZ(), this.player.getYRot(), this.player.getXRot()); |
503 507 | return; |
504 - | |
508 + | |
505 509 | boolean flag1 = this.player.verticalCollisionBelow; |
506 510 | |
507 511 | this.player.move(EnumMoveType.PLAYER, new Vec3D(d7, d8, d9)); |
508 512 | + this.player.onGround = packetplayinflying.isOnGround(); // CraftBukkit - SPIGOT-5810, SPIGOT-5835, SPIGOT-6828: reset by this.player.move |
509 513 | double d12 = d8; |
510 514 | |
511 515 | d7 = d0 - this.player.getX(); |
512 - | |
516 + | |
513 517 | |
514 518 | this.player.absMoveTo(d0, d1, d2, f, f1); |
515 519 | if (!this.player.noPhysics && !this.player.isSleeping() && (flag2 && worldserver.noCollision(this.player, axisalignedbb) || this.isPlayerCollidingWithAnythingNew(worldserver, axisalignedbb))) { |
516 520 | - this.teleport(d3, d4, d5, f, f1); |
517 521 | + this.internalTeleport(d3, d4, d5, f, f1, Collections.emptySet(), false); // 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. |
518 522 | } else { |
519 523 | + // CraftBukkit start - fire PlayerMoveEvent |
520 524 | + // Rest to old location first |
521 525 | + this.player.absMoveTo(prevX, prevY, prevZ, prevYaw, prevPitch); |
522 526 | + |
575 579 | + return; |
576 580 | + } |
577 581 | + } |
578 582 | + } |
579 583 | + this.player.absMoveTo(d0, d1, d2, f, f1); // Copied from above |
580 584 | + // CraftBukkit end |
581 585 | + |
582 586 | this.clientIsFloating = d12 >= -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); |
583 587 | this.player.getLevel().getChunkSource().move(this.player); |
584 588 | this.player.doCheckFallDamage(this.player.getY() - d6, packetplayinflying.isOnGround()); |
585 - | |
589 + | |
586 590 | return true; |
587 591 | } |
588 592 | |
589 593 | + // CraftBukkit start - Delegate to teleport(Location) |
590 594 | public void dismount(double d0, double d1, double d2, float f, float f1) { |
591 595 | - this.teleport(d0, d1, d2, f, f1, Collections.emptySet(), true); |
592 596 | + this.dismount(d0, d1, d2, f, f1, PlayerTeleportEvent.TeleportCause.UNKNOWN); |
593 597 | + } |
594 598 | + |
595 599 | + public void dismount(double d0, double d1, double d2, float f, float f1, PlayerTeleportEvent.TeleportCause cause) { |
605 609 | + this.teleport(d0, d1, d2, f, f1, Collections.emptySet(), false, cause); |
606 610 | } |
607 611 | |
608 612 | public void teleport(double d0, double d1, double d2, float f, float f1, Set<PacketPlayOutPosition.EnumPlayerTeleportFlags> set) { |
609 613 | - this.teleport(d0, d1, d2, f, f1, set, false); |
610 614 | + this.teleport(d0, d1, d2, f, f1, set, PlayerTeleportEvent.TeleportCause.UNKNOWN); |
611 615 | + } |
612 616 | + |
613 617 | + public void teleport(double d0, double d1, double d2, float f, float f1, Set<PacketPlayOutPosition.EnumPlayerTeleportFlags> set, PlayerTeleportEvent.TeleportCause cause) { |
614 618 | + this.teleport(d0, d1, d2, f, f1, set, false, cause); |
615 - | } |
616 - | |
617 - | - public void teleport(double d0, double d1, double d2, float f, float f1, Set<PacketPlayOutPosition.EnumPlayerTeleportFlags> set, boolean flag) { |
619 + | + } |
620 + | + |
618 621 | + public boolean teleport(double d0, double d1, double d2, float f, float f1, Set<PacketPlayOutPosition.EnumPlayerTeleportFlags> set, boolean flag, PlayerTeleportEvent.TeleportCause cause) { // CraftBukkit - Return event status |
619 622 | + Player player = this.getCraftPlayer(); |
620 623 | + Location from = player.getLocation(); |
621 624 | + |
622 625 | + double x = d0; |
623 626 | + double y = d1; |
624 627 | + double z = d2; |
625 628 | + float yaw = f; |
626 629 | + float pitch = f1; |
627 630 | + |
640 643 | + to = event.isCancelled() ? event.getFrom() : event.getTo(); |
641 644 | + d0 = to.getX(); |
642 645 | + d1 = to.getY(); |
643 646 | + d2 = to.getZ(); |
644 647 | + f = to.getYaw(); |
645 648 | + f1 = to.getPitch(); |
646 649 | + } |
647 650 | + |
648 651 | + this.internalTeleport(d0, d1, d2, f, f1, set, flag); |
649 652 | + return event.isCancelled(); // CraftBukkit - Return event status |
650 - | + } |
651 - | + |
653 + | } |
654 + | |
655 + | - public void teleport(double d0, double d1, double d2, float f, float f1, Set<PacketPlayOutPosition.EnumPlayerTeleportFlags> set, boolean flag) { |
652 656 | + public void teleport(Location dest) { |
653 657 | + internalTeleport(dest.getX(), dest.getY(), dest.getZ(), dest.getYaw(), dest.getPitch(), Collections.<PacketPlayOutPosition.EnumPlayerTeleportFlags>emptySet(), true); |
654 658 | + } |
655 659 | + |
656 660 | + private void internalTeleport(double d0, double d1, double d2, float f, float f1, Set<PacketPlayOutPosition.EnumPlayerTeleportFlags> set, boolean flag) { |
657 661 | + // CraftBukkit start |
658 662 | + if (Float.isNaN(f)) { |
659 663 | + f = 0; |
660 664 | + } |
661 665 | + if (Float.isNaN(f1)) { |
662 666 | + f1 = 0; |
663 667 | + } |
664 668 | + |
665 669 | + this.justTeleported = true; |
666 670 | + // CraftBukkit end |
667 671 | double d3 = set.contains(PacketPlayOutPosition.EnumPlayerTeleportFlags.X) ? this.player.getX() : 0.0D; |
668 672 | double d4 = set.contains(PacketPlayOutPosition.EnumPlayerTeleportFlags.Y) ? this.player.getY() : 0.0D; |
669 673 | double d5 = set.contains(PacketPlayOutPosition.EnumPlayerTeleportFlags.Z) ? this.player.getZ() : 0.0D; |
670 - | |
674 + | |
671 675 | this.awaitingTeleport = 0; |
672 676 | } |
673 677 | |
674 678 | + // CraftBukkit start - update last location |
675 679 | + this.lastPosX = this.awaitingPositionFromClient.x; |
676 680 | + this.lastPosY = this.awaitingPositionFromClient.y; |
677 681 | + this.lastPosZ = this.awaitingPositionFromClient.z; |
678 682 | + this.lastYaw = f; |
679 683 | + this.lastPitch = f1; |
680 684 | + // CraftBukkit end |
681 685 | + |
682 686 | this.awaitingTeleportTime = this.tickCount; |
683 687 | this.player.absMoveTo(d0, d1, d2, f, f1); |
684 688 | this.player.connection.send(new PacketPlayOutPosition(d0 - d3, d1 - d4, d2 - d5, f - f2, f1 - f3, set, this.awaitingTeleport, flag)); |
685 - | |
689 + | |
686 690 | @Override |
687 691 | public void handlePlayerAction(PacketPlayInBlockDig packetplayinblockdig) { |
688 692 | PlayerConnectionUtils.ensureRunningOnSameThread(packetplayinblockdig, this, this.player.getLevel()); |
689 693 | + if (this.player.isImmobile()) return; // CraftBukkit |
690 694 | BlockPosition blockposition = packetplayinblockdig.getPos(); |
691 695 | |
692 696 | this.player.resetLastActionTime(); |
693 - | |
697 + | |
694 698 | if (!this.player.isSpectator()) { |
695 699 | ItemStack itemstack = this.player.getItemInHand(EnumHand.OFF_HAND); |
696 700 | |
697 701 | - this.player.setItemInHand(EnumHand.OFF_HAND, this.player.getItemInHand(EnumHand.MAIN_HAND)); |
698 702 | - this.player.setItemInHand(EnumHand.MAIN_HAND, itemstack); |
699 703 | + // CraftBukkit start - inspiration taken from DispenserRegistry (See SpigotCraft#394) |
700 704 | + CraftItemStack mainHand = CraftItemStack.asCraftMirror(itemstack); |
701 705 | + CraftItemStack offHand = CraftItemStack.asCraftMirror(this.player.getItemInHand(EnumHand.MAIN_HAND)); |
702 706 | + PlayerSwapHandItemsEvent swapItemsEvent = new PlayerSwapHandItemsEvent(getCraftPlayer(), mainHand.clone(), offHand.clone()); |
703 707 | + this.cserver.getPluginManager().callEvent(swapItemsEvent); |
732 736 | + if (this.dropCount >= 20) { |
733 737 | + LOGGER.warn(this.player.getScoreboardName() + " dropped their items too quickly!"); |
734 738 | + this.disconnect("You dropped your items too quickly (Hacking?)"); |
735 739 | + return; |
736 740 | + } |
737 741 | + } |
738 742 | + // CraftBukkit end |
739 743 | this.player.drop(false); |
740 744 | } |
741 745 | |
742 - | |
746 + | |
743 747 | @Override |
744 748 | public void handleUseItemOn(PacketPlayInUseItem packetplayinuseitem) { |
745 749 | PlayerConnectionUtils.ensureRunningOnSameThread(packetplayinuseitem, this, this.player.getLevel()); |
746 750 | + if (this.player.isImmobile()) return; // CraftBukkit |
747 751 | this.player.connection.ackBlockChangesUpTo(packetplayinuseitem.getSequence()); |
748 752 | WorldServer worldserver = this.player.getLevel(); |
749 753 | EnumHand enumhand = packetplayinuseitem.getHand(); |
750 - | |
754 + | |
751 755 | |
752 756 | if (blockposition.getY() < i) { |
753 757 | 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)) { |
754 758 | + this.player.stopUsingItem(); // CraftBukkit - SPIGOT-4706 |
755 759 | EnumInteractionResult enuminteractionresult = this.player.gameMode.useItemOn(this.player, worldserver, itemstack, enumhand, movingobjectpositionblock); |
756 760 | |
757 761 | if (enumdirection == EnumDirection.UP && !enuminteractionresult.consumesAction() && blockposition.getY() >= i - 1 && wasBlockPlacementAttempt(this.player, itemstack)) { |
758 - | |
762 + | |
759 763 | @Override |
760 764 | public void handleUseItem(PacketPlayInBlockPlace packetplayinblockplace) { |
761 765 | PlayerConnectionUtils.ensureRunningOnSameThread(packetplayinblockplace, this, this.player.getLevel()); |
762 766 | + if (this.player.isImmobile()) return; // CraftBukkit |
763 767 | this.ackBlockChangesUpTo(packetplayinblockplace.getSequence()); |
764 768 | WorldServer worldserver = this.player.getLevel(); |
765 769 | EnumHand enumhand = packetplayinblockplace.getHand(); |
766 - | |
770 + | |
767 771 | |
768 772 | this.player.resetLastActionTime(); |
769 773 | if (!itemstack.isEmpty()) { |
770 774 | + // CraftBukkit start |
771 775 | + // Raytrace to look for 'rogue armswings' |
772 776 | + float f1 = this.player.getXRot(); |
773 777 | + float f2 = this.player.getYRot(); |
774 778 | + double d0 = this.player.getX(); |
775 779 | + double d1 = this.player.getY() + (double) this.player.getEyeHeight(); |
776 780 | + double d2 = this.player.getZ(); |
801 805 | + player.gameMode.firedInteract = false; |
802 806 | + } |
803 807 | + |
804 808 | + if (cancelled) { |
805 809 | + this.player.getBukkitEntity().updateInventory(); // SPIGOT-2524 |
806 810 | + return; |
807 811 | + } |
808 812 | EnumInteractionResult enuminteractionresult = this.player.gameMode.useItem(this.player, worldserver, itemstack, enumhand); |
809 813 | |
810 814 | if (enuminteractionresult.shouldSwing()) { |
811 - | |
815 + | |
812 816 | Entity entity = packetplayinspectate.getEntity(worldserver); |
813 817 | |
814 818 | if (entity != null) { |
815 819 | - this.player.teleportTo(worldserver, entity.getX(), entity.getY(), entity.getZ(), entity.getYRot(), entity.getXRot()); |
816 820 | + this.player.teleportTo(worldserver, entity.getX(), entity.getY(), entity.getZ(), entity.getYRot(), entity.getXRot(), org.bukkit.event.player.PlayerTeleportEvent.TeleportCause.SPECTATE); // CraftBukkit |
817 821 | return; |
818 822 | } |
819 823 | } |
820 - | |
824 + | |
821 825 | PlayerConnection.LOGGER.info("Disconnecting {} due to resource pack rejection", this.player.getName()); |
822 826 | this.disconnect(IChatBaseComponent.translatable("multiplayer.requiredTexturePrompt.disconnect")); |
823 827 | } |
824 828 | + this.cserver.getPluginManager().callEvent(new PlayerResourcePackStatusEvent(getCraftPlayer(), PlayerResourcePackStatusEvent.Status.values()[packetplayinresourcepackstatus.action.ordinal()])); // CraftBukkit |
825 829 | |
826 830 | } |
827 831 | |
828 - | |
832 + | |
829 833 | |
830 834 | @Override |
831 835 | public void onDisconnect(IChatBaseComponent ichatbasecomponent) { |
832 836 | + // CraftBukkit start - Rarely it would send a disconnect line twice |
833 837 | + if (this.processedDisconnect) { |
834 838 | + return; |
835 839 | + } else { |
836 840 | + this.processedDisconnect = true; |
837 841 | + } |
838 842 | + // CraftBukkit end |
846 850 | this.player.disconnect(); |
847 851 | - this.server.getPlayerList().remove(this.player); |
848 852 | + String quitMessage = this.server.getPlayerList().remove(this.player); |
849 853 | + if ((quitMessage != null) && (quitMessage.length() > 0)) { |
850 854 | + this.server.getPlayerList().broadcastMessage(CraftChatMessage.fromString(quitMessage)); |
851 855 | + } |
852 856 | + // CraftBukkit end |
853 857 | this.player.getTextFilter().leave(); |
854 858 | if (this.isSingleplayerOwner()) { |
855 859 | PlayerConnection.LOGGER.info("Stopping singleplayer server as player logged out"); |
856 - | |
860 + | |
857 861 | } |
858 862 | |
859 863 | public void send(Packet<?> packet, @Nullable PacketSendListener packetsendlistener) { |
860 864 | + // CraftBukkit start |
861 865 | + if (packet == null) { |
862 866 | + return; |
863 867 | + } else if (packet instanceof PacketPlayOutSpawnPosition) { |
864 868 | + PacketPlayOutSpawnPosition packet6 = (PacketPlayOutSpawnPosition) packet; |
865 869 | + this.player.compassTarget = new Location(this.getCraftPlayer().getWorld(), packet6.pos.getX(), packet6.pos.getY(), packet6.pos.getZ()); |
866 870 | + } |
867 871 | + // CraftBukkit end |
868 872 | + |
869 873 | try { |
870 874 | this.connection.send(packet, packetsendlistener); |
871 875 | } catch (Throwable throwable) { |
872 - | |
876 + | |
873 877 | @Override |
874 878 | public void handleSetCarriedItem(PacketPlayInHeldItemSlot packetplayinhelditemslot) { |
875 879 | PlayerConnectionUtils.ensureRunningOnSameThread(packetplayinhelditemslot, this, this.player.getLevel()); |
876 880 | + if (this.player.isImmobile()) return; // CraftBukkit |
877 881 | if (packetplayinhelditemslot.getSlot() >= 0 && packetplayinhelditemslot.getSlot() < PlayerInventory.getSelectionSize()) { |
878 882 | + PlayerItemHeldEvent event = new PlayerItemHeldEvent(this.getCraftPlayer(), this.player.getInventory().selected, packetplayinhelditemslot.getSlot()); |
879 883 | + this.cserver.getPluginManager().callEvent(event); |
880 884 | + if (event.isCancelled()) { |
881 885 | + this.send(new PacketPlayOutHeldItemSlot(this.player.getInventory().selected)); |
882 886 | + this.player.resetLastActionTime(); |
883 887 | + return; |
884 888 | + } |
885 889 | + // CraftBukkit end |
886 890 | if (this.player.getInventory().selected != packetplayinhelditemslot.getSlot() && this.player.getUsedItemHand() == EnumHand.MAIN_HAND) { |
887 891 | this.player.stopUsingItem(); |
888 892 | } |
889 - | |
893 + | |
890 894 | this.player.resetLastActionTime(); |
891 895 | } else { |
892 896 | PlayerConnection.LOGGER.warn("{} tried to set an invalid carried item", this.player.getName().getString()); |
893 897 | + this.disconnect("Invalid hotbar selection (Hacking?)"); // CraftBukkit |
894 898 | } |
895 899 | } |
896 900 | |
897 901 | @Override |
898 902 | public void handleChat(PacketPlayInChat packetplayinchat) { |
899 903 | + // CraftBukkit start - async chat |
904 908 | + // CraftBukkit end |
905 909 | if (isChatMessageIllegal(packetplayinchat.message())) { |
906 910 | this.disconnect(IChatBaseComponent.translatable("multiplayer.disconnect.illegal_characters")); |
907 911 | } else { |
908 912 | if (this.tryHandleChat(packetplayinchat.message(), packetplayinchat.timeStamp(), packetplayinchat.lastSeenMessages())) { |
909 913 | - this.server.submit(() -> { |
910 914 | + // this.server.submit(() -> { // CraftBukkit - async chat |
911 915 | PlayerChatMessage playerchatmessage = this.getSignedMessage(packetplayinchat); |
912 916 | |
913 917 | if (this.verifyChatMessage(playerchatmessage)) { |
914 - | |
918 + | |
915 919 | PlayerChatMessage playerchatmessage1 = ((PlayerChatMessage) completablefuture1.join()).filter(filtermask); |
916 920 | |
917 921 | this.broadcastChatMessage(playerchatmessage1); |
918 922 | - }, this.server); |
919 923 | + }, this.server.chatExecutor); // CraftBukkit - async chat |
920 924 | }); |
921 925 | } |
922 926 | - }); |
923 927 | + // }); // CraftBukkit - async chat |
924 928 | } |
925 929 | |
926 930 | } |
927 - | |
931 + | |
928 932 | } |
929 933 | |
930 934 | private void performChatCommand(ServerboundChatCommandPacket serverboundchatcommandpacket) { |
931 935 | - ParseResults<CommandListenerWrapper> parseresults = this.parseCommand(serverboundchatcommandpacket.command()); |
932 936 | - Map<String, PlayerChatMessage> map = this.collectSignedArguments(serverboundchatcommandpacket, PreviewableCommand.of(parseresults)); |
933 937 | + // CraftBukkit start |
934 938 | + String command = "/" + serverboundchatcommandpacket.command(); |
935 939 | + PlayerConnection.LOGGER.info(this.player.getScoreboardName() + " issued server command: " + command); |
936 940 | + |
937 941 | + PlayerCommandPreprocessEvent event = new PlayerCommandPreprocessEvent(getCraftPlayer(), command, new LazyPlayerSet(server)); |
941 945 | + return; |
942 946 | + } |
943 947 | + command = event.getMessage().substring(1); |
944 948 | + |
945 949 | + ParseResults<CommandListenerWrapper> parseresults = this.parseCommand(command); |
946 950 | + Map<String, PlayerChatMessage> map = (serverboundchatcommandpacket.command().equals(command)) ? this.collectSignedArguments(serverboundchatcommandpacket, PreviewableCommand.of(parseresults)) : Collections.emptyMap(); |
947 951 | + // CraftBukkit end |
948 952 | Iterator iterator = map.values().iterator(); |
949 953 | |
950 954 | PlayerChatMessage playerchatmessage; |
951 - | |
955 + | |
952 956 | parseresults = CommandDispatcher.mapSource(parseresults, (commandlistenerwrapper) -> { |
953 957 | return commandlistenerwrapper.withSigningContext(commandsigningcontext_a); |
954 958 | }); |
955 959 | - this.server.getCommands().performCommand(parseresults, serverboundchatcommandpacket.command()); |
956 960 | + this.server.getCommands().performCommand(parseresults, command); // CraftBukkit |
957 961 | return; |
958 962 | } |
959 963 | |
960 - | |
964 + | |
961 965 | PlayerConnection.LOGGER.warn("{} sent out-of-order chat: '{}'", this.player.getName().getString(), s); |
962 966 | this.disconnect(IChatBaseComponent.translatable("multiplayer.disconnect.out_of_order_chat")); |
963 967 | return false; |
964 968 | - } else if (this.player.getChatVisibility() == EnumChatVisibility.HIDDEN) { |
965 969 | + } else if (this.player.isRemoved() || this.player.getChatVisibility() == EnumChatVisibility.HIDDEN) { // CraftBukkit - dead men tell no tales |
966 970 | this.send(new ClientboundSystemChatPacket(IChatBaseComponent.translatable("chat.disabled.options").withStyle(EnumChatFormat.RED), false)); |
967 971 | return false; |
968 972 | } else { |
969 - | |
973 + | |
970 974 | return false; |
971 975 | } |
972 976 | |
973 977 | + // CraftBukkit start - add method |
974 978 | + public void chat(String s, PlayerChatMessage original, boolean async) { |
975 979 | + if (s.isEmpty() || this.player.getChatVisibility() == EnumChatVisibility.HIDDEN) { |
976 980 | + return; |
977 981 | + } |
978 982 | + OutgoingPlayerChatMessage outgoing = OutgoingPlayerChatMessage.create(original); |
979 983 | + |
1095 1099 | + player.sendMessage(org.bukkit.ChatColor.RED + "An internal error occurred while attempting to perform this command"); |
1096 1100 | + java.util.logging.Logger.getLogger(PlayerConnection.class.getName()).log(java.util.logging.Level.SEVERE, null, ex); |
1097 1101 | + return; |
1098 1102 | + } |
1099 1103 | + } |
1100 1104 | + // CraftBukkit end |
1101 1105 | + |
1102 1106 | private PlayerChatMessage getSignedMessage(PacketPlayInChat packetplayinchat) { |
1103 1107 | MessageSigner messagesigner = packetplayinchat.getSigner(this.player); |
1104 1108 | SignedMessageChain.c signedmessagechain_c = new SignedMessageChain.c(packetplayinchat.signature()); |
1105 - | |
1109 + | |
1106 1110 | } |
1107 1111 | |
1108 1112 | private void broadcastChatMessage(PlayerChatMessage playerchatmessage) { |
1109 1113 | - this.server.getPlayerList().broadcastChatMessage(playerchatmessage, this.player, ChatMessageType.bind(ChatMessageType.CHAT, (Entity) this.player)); |
1110 1114 | + // CraftBukkit start |
1111 1115 | + String s = playerchatmessage.signedContent().plain(); |
1112 1116 | + if (s.isEmpty()) { |
1113 1117 | + LOGGER.warn(this.player.getScoreboardName() + " tried to send an empty message"); |
1114 1118 | + } else if (getCraftPlayer().isConversing()) { |
1115 1119 | + final String conversationInput = s; |
1122 1126 | + } else if (this.player.getChatVisibility() == EnumChatVisibility.SYSTEM) { // Re-add "Command Only" flag check |
1123 1127 | + this.send(new ClientboundSystemChatPacket(IChatBaseComponent.translatable("chat.cannotSend").withStyle(EnumChatFormat.RED), false)); |
1124 1128 | + } else { |
1125 1129 | + this.chat(s, playerchatmessage, true); |
1126 1130 | + } |
1127 1131 | + // this.server.getPlayerList().broadcastChatMessage(playerchatmessage, this.player, ChatMessageType.bind(ChatMessageType.CHAT, (Entity) this.player)); |
1128 1132 | + // CraftBukkit end |
1129 1133 | this.detectRateSpam(); |
1130 1134 | } |
1131 1135 | |
1132 - | |
1136 + | |
1133 1137 | } |
1134 1138 | |
1135 1139 | private void detectRateSpam() { |
1136 1140 | - this.chatSpamTickCount += 20; |
1137 1141 | - if (this.chatSpamTickCount > 200 && !this.server.getPlayerList().isOp(this.player.getGameProfile())) { |
1138 1142 | + // CraftBukkit start - replaced with thread safe throttle |
1139 1143 | + // this.chatSpamTickCount += 20; |
1140 1144 | + if (this.chatSpamTickCount.addAndGet(20) > 200 && !this.server.getPlayerList().isOp(this.player.getGameProfile())) { |
1141 1145 | + // CraftBukkit end |
1142 1146 | this.disconnect(IChatBaseComponent.translatable("disconnect.spam")); |
1143 1147 | } |
1144 1148 | |
1145 - | |
1149 + | |
1146 1150 | List<PreviewableCommand.a<CommandListenerWrapper>> list = previewablecommand.arguments(); |
1147 1151 | |
1148 1152 | if (list.isEmpty()) { |
1149 1153 | - return CompletableFuture.completedFuture((Object) null); |
1150 1154 | + return CompletableFuture.completedFuture(null); // CraftBukkit - decompile error |
1151 1155 | } else { |
1152 1156 | for (int i = list.size() - 1; i >= 0; --i) { |
1153 1157 | PreviewableCommand.a previewablecommand_a = (PreviewableCommand.a) list.get(i); |
1154 - | |
1158 + | |
1155 1159 | return completablefuture; |
1156 1160 | } |
1157 1161 | } catch (CommandSyntaxException commandsyntaxexception) { |
1158 1162 | - return CompletableFuture.completedFuture((Object) null); |
1159 1163 | + return CompletableFuture.completedFuture(null); // CraftBukkit - decompile error |
1160 1164 | } |
1161 1165 | } |
1162 1166 | |
1163 1167 | - return CompletableFuture.completedFuture((Object) null); |
1164 1168 | + return CompletableFuture.completedFuture(null); // CraftBukkit - decompile error |
1165 1169 | } |
1166 1170 | } |
1167 1171 | |
1168 - | |
1172 + | |
1169 1173 | @Override |
1170 1174 | public void handleAnimate(PacketPlayInArmAnimation packetplayinarmanimation) { |
1171 1175 | PlayerConnectionUtils.ensureRunningOnSameThread(packetplayinarmanimation, this, this.player.getLevel()); |
1172 1176 | + if (this.player.isImmobile()) return; // CraftBukkit |
1173 1177 | this.player.resetLastActionTime(); |
1174 1178 | + // CraftBukkit start - Raytrace to look for 'rogue armswings' |
1175 1179 | + float f1 = this.player.getXRot(); |
1176 1180 | + float f2 = this.player.getYRot(); |
1177 1181 | + double d0 = this.player.getX(); |
1178 1182 | + double d1 = this.player.getY() + (double) this.player.getEyeHeight(); |
1224 1228 | + |
1225 1229 | + if (e2.isCancelled()) { |
1226 1230 | + return; |
1227 1231 | + } |
1228 1232 | + break; |
1229 1233 | + } |
1230 1234 | + // CraftBukkit end |
1231 1235 | this.player.resetLastActionTime(); |
1232 1236 | IJumpable ijumpable; |
1233 1237 | |
1234 - | |
1238 + | |
1235 1239 | @Override |
1236 1240 | public void handleInteract(PacketPlayInUseEntity packetplayinuseentity) { |
1237 1241 | PlayerConnectionUtils.ensureRunningOnSameThread(packetplayinuseentity, this, this.player.getLevel()); |
1238 1242 | + if (this.player.isImmobile()) return; // CraftBukkit |
1239 1243 | WorldServer worldserver = this.player.getLevel(); |
1240 1244 | final Entity entity = packetplayinuseentity.getTarget(worldserver); |
1241 1245 | |
1242 - | |
1246 + | |
1243 1247 | |
1244 1248 | if (entity.distanceToSqr(this.player.getEyePosition()) < PlayerConnection.MAX_INTERACTION_DISTANCE) { |
1245 1249 | packetplayinuseentity.dispatch(new PacketPlayInUseEntity.c() { |
1246 1250 | - private void performInteraction(EnumHand enumhand, PlayerConnection.a playerconnection_a) { |
1247 1251 | + private void performInteraction(EnumHand enumhand, PlayerConnection.a playerconnection_a, PlayerInteractEntityEvent event) { // CraftBukkit |
1248 1252 | ItemStack itemstack = PlayerConnection.this.player.getItemInHand(enumhand).copy(); |
1249 1253 | + // CraftBukkit start |
1250 1254 | + ItemStack itemInHand = PlayerConnection.this.player.getItemInHand(enumhand); |
1251 1255 | + boolean triggerLeashUpdate = itemInHand != null && itemInHand.getItem() == Items.LEAD && entity instanceof EntityInsentient; |
1252 1256 | + Item origItem = player.getInventory().getSelected() == null ? null : player.getInventory().getSelected().getItem(); |
1260 1264 | + } |
1261 1265 | + |
1262 1266 | + if (triggerLeashUpdate && (event.isCancelled() || player.getInventory().getSelected() == null || player.getInventory().getSelected().getItem() != origItem)) { |
1263 1267 | + // Refresh the current leash state |
1264 1268 | + send(new PacketPlayOutAttachEntity(entity, ((EntityInsentient) entity).getLeashHolder())); |
1265 1269 | + } |
1266 1270 | + |
1267 1271 | + if (event.isCancelled() || player.getInventory().getSelected() == null || player.getInventory().getSelected().getItem() != origItem) { |
1268 1272 | + // Refresh the current entity metadata |
1269 1273 | + send(new PacketPlayOutEntityMetadata(entity.getId(), entity.getEntityData(), true)); |
1274 + | + // SPIGOT-7136 - Allays |
1275 + | + if (entity instanceof Allay) { |
1276 + | + send(new PacketPlayOutEntityEquipment(entity.getId(), Arrays.stream(EnumItemSlot.values()).map((slot) -> Pair.of(slot, ((EntityLiving) entity).getItemBySlot(slot).copy())).collect(Collectors.toList()))); |
1277 + | + player.containerMenu.sendAllDataToRemote(); |
1278 + | + } |
1270 1279 | + } |
1271 1280 | + |
1272 1281 | + if (event.isCancelled()) { |
1273 1282 | + return; |
1274 1283 | + } |
1275 1284 | + // CraftBukkit end |
1276 1285 | + |
1277 1286 | EnumInteractionResult enuminteractionresult = playerconnection_a.run(PlayerConnection.this.player, entity, enumhand); |
1278 1287 | |
1279 1288 | + // CraftBukkit start |
1280 1289 | + if (!itemInHand.isEmpty() && itemInHand.getCount() <= -1) { |
1281 - | + player.containerMenu.sendAllDataToRemote(); |
1290 + | + player.containerMenu.sendAllDataToRemote(); |
1282 1291 | + } |
1283 1292 | + // CraftBukkit end |
1284 1293 | + |
1285 1294 | if (enuminteractionresult.consumesAction()) { |
1286 1295 | CriterionTriggers.PLAYER_INTERACTED_WITH_ENTITY.trigger(PlayerConnection.this.player, itemstack, entity); |
1287 1296 | if (enuminteractionresult.shouldSwing()) { |
1288 - | |
1297 + | |
1289 1298 | |
1290 1299 | @Override |
1291 1300 | public void onInteraction(EnumHand enumhand) { |
1292 1301 | - this.performInteraction(enumhand, EntityHuman::interactOn); |
1293 1302 | + this.performInteraction(enumhand, EntityHuman::interactOn, new PlayerInteractEntityEvent(getCraftPlayer(), entity.getBukkitEntity(), (enumhand == EnumHand.OFF_HAND) ? EquipmentSlot.OFF_HAND : EquipmentSlot.HAND)); |
1294 1303 | } |
1295 1304 | |
1296 1305 | @Override |
1297 1306 | public void onInteraction(EnumHand enumhand, Vec3D vec3d) { |
1298 1307 | this.performInteraction(enumhand, (entityplayer, entity1, enumhand1) -> { |
1309 1318 | + ItemStack itemInHand = PlayerConnection.this.player.getMainHandItem(); |
1310 1319 | PlayerConnection.this.player.attack(entity); |
1311 1320 | + |
1312 1321 | + if (!itemInHand.isEmpty() && itemInHand.getCount() <= -1) { |
1313 1322 | + player.containerMenu.sendAllDataToRemote(); |
1314 1323 | + } |
1315 1324 | + // CraftBukkit end |
1316 1325 | } else { |
1317 1326 | PlayerConnection.this.disconnect(IChatBaseComponent.translatable("multiplayer.disconnect.invalid_entity_attacked")); |
1318 1327 | PlayerConnection.LOGGER.warn("Player {} tried to attack an invalid entity", PlayerConnection.this.player.getName().getString()); |
1319 - | |
1328 + | |
1320 1329 | @Override |
1321 1330 | public void handleContainerClose(PacketPlayInCloseWindow packetplayinclosewindow) { |
1322 1331 | PlayerConnectionUtils.ensureRunningOnSameThread(packetplayinclosewindow, this, this.player.getLevel()); |
1323 1332 | + |
1324 1333 | + if (this.player.isImmobile()) return; // CraftBukkit |
1325 1334 | + CraftEventFactory.handleInventoryCloseEvent(this.player); // CraftBukkit |
1326 1335 | + |
1327 1336 | this.player.doCloseContainer(); |
1328 1337 | } |
1329 1338 | |
1333 1342 | + if (this.player.isImmobile()) return; // CraftBukkit |
1334 1343 | this.player.resetLastActionTime(); |
1335 1344 | - if (this.player.containerMenu.containerId == packetplayinwindowclick.getContainerId()) { |
1336 1345 | - if (this.player.isSpectator()) { |
1337 1346 | + if (this.player.containerMenu.containerId == packetplayinwindowclick.getContainerId() && this.player.containerMenu.stillValid(this.player)) { // CraftBukkit |
1338 1347 | + boolean cancelled = this.player.isSpectator(); // CraftBukkit - see below if |
1339 1348 | + if (false/*this.player.isSpectator()*/) { // CraftBukkit |
1340 1349 | this.player.containerMenu.sendAllDataToRemote(); |
1341 1350 | } else if (!this.player.containerMenu.stillValid(this.player)) { |
1342 1351 | PlayerConnection.LOGGER.debug("Player {} interacted with invalid menu {}", this.player, this.player.containerMenu); |
1343 - | |
1352 + | |
1344 1353 | boolean flag = packetplayinwindowclick.getStateId() != this.player.containerMenu.getStateId(); |
1345 1354 | |
1346 1355 | this.player.containerMenu.suppressRemoteUpdates(); |
1347 1356 | - this.player.containerMenu.clicked(i, packetplayinwindowclick.getButtonNum(), packetplayinwindowclick.getClickType(), this.player); |
1348 1357 | + // CraftBukkit start - Call InventoryClickEvent |
1349 1358 | + if (packetplayinwindowclick.getSlotNum() < -1 && packetplayinwindowclick.getSlotNum() != -999) { |
1350 1359 | + return; |
1351 1360 | + } |
1352 1361 | + |
1353 1362 | + InventoryView inventory = this.player.containerMenu.getBukkitView(); |
1619 1628 | + if (event instanceof CraftItemEvent || event instanceof SmithItemEvent) { |
1620 1629 | + // Need to update the inventory on crafting to |
1621 1630 | + // correctly support custom recipes |
1622 1631 | + player.containerMenu.sendAllDataToRemote(); |
1623 1632 | + } |
1624 1633 | + } |
1625 1634 | + // CraftBukkit end |
1626 1635 | ObjectIterator objectiterator = Int2ObjectMaps.fastIterable(packetplayinwindowclick.getChangedSlots()).iterator(); |
1627 1636 | |
1628 1637 | while (objectiterator.hasNext()) { |
1629 - | |
1638 + | |
1630 1639 | @Override |
1631 1640 | public void handleContainerButtonClick(PacketPlayInEnchantItem packetplayinenchantitem) { |
1632 1641 | PlayerConnectionUtils.ensureRunningOnSameThread(packetplayinenchantitem, this, this.player.getLevel()); |
1633 1642 | + if (this.player.isImmobile()) return; // CraftBukkit |
1634 1643 | this.player.resetLastActionTime(); |
1635 1644 | if (this.player.containerMenu.containerId == packetplayinenchantitem.getContainerId() && !this.player.isSpectator()) { |
1636 1645 | if (!this.player.containerMenu.stillValid(this.player)) { |
1637 - | |
1646 + | |
1638 1647 | |
1639 1648 | boolean flag1 = packetplayinsetcreativeslot.getSlotNum() >= 1 && packetplayinsetcreativeslot.getSlotNum() <= 45; |
1640 1649 | boolean flag2 = itemstack.isEmpty() || itemstack.getDamageValue() >= 0 && itemstack.getCount() <= 64 && !itemstack.isEmpty(); |
1641 1650 | + if (flag || (flag1 && !ItemStack.matches(this.player.inventoryMenu.getSlot(packetplayinsetcreativeslot.getSlotNum()).getItem(), packetplayinsetcreativeslot.getItem()))) { // Insist on valid slot |
1642 1651 | + // CraftBukkit start - Call click event |
1643 1652 | + InventoryView inventory = this.player.inventoryMenu.getBukkitView(); |
1644 1653 | + org.bukkit.inventory.ItemStack item = CraftItemStack.asBukkitCopy(packetplayinsetcreativeslot.getItem()); |
1645 1654 | + |
1646 1655 | + SlotType type = SlotType.QUICKBAR; |
1647 1656 | + if (flag) { |
1671 1680 | + this.player.connection.send(new PacketPlayOutSetSlot(this.player.inventoryMenu.containerId, this.player.inventoryMenu.incrementStateId(), packetplayinsetcreativeslot.getSlotNum(), this.player.inventoryMenu.getSlot(packetplayinsetcreativeslot.getSlotNum()).getItem())); |
1672 1681 | + this.player.connection.send(new PacketPlayOutSetSlot(-1, this.player.inventoryMenu.incrementStateId(), -1, ItemStack.EMPTY)); |
1673 1682 | + } |
1674 1683 | + return; |
1675 1684 | + } |
1676 1685 | + } |
1677 1686 | + // CraftBukkit end |
1678 1687 | |
1679 1688 | if (flag1 && flag2) { |
1680 1689 | this.player.inventoryMenu.getSlot(packetplayinsetcreativeslot.getSlotNum()).set(itemstack); |
1681 - | |
1690 + | |
1682 1691 | } |
1683 1692 | |
1684 1693 | private void updateSignText(PacketPlayInUpdateSign packetplayinupdatesign, List<FilteredText> list) { |
1685 1694 | + if (this.player.isImmobile()) return; // CraftBukkit |
1686 1695 | this.player.resetLastActionTime(); |
1687 1696 | WorldServer worldserver = this.player.getLevel(); |
1688 1697 | BlockPosition blockposition = packetplayinupdatesign.getPos(); |
1689 - | |
1698 + | |
1690 1699 | |
1691 1700 | if (!tileentitysign.isEditable() || !this.player.getUUID().equals(tileentitysign.getPlayerWhoMayEdit())) { |
1692 1701 | PlayerConnection.LOGGER.warn("Player {} just tried to change non-editable sign", this.player.getName().getString()); |
1693 1702 | + this.send(tileentity.getUpdatePacket()); // CraftBukkit |
1694 1703 | return; |
1695 1704 | } |
1696 1705 | |
1697 1706 | + // CraftBukkit start |
1698 1707 | + Player player = this.player.getBukkitEntity(); |
1699 1708 | + int x = packetplayinupdatesign.getPos().getX(); |
1719 1728 | + IChatBaseComponent[] components = org.bukkit.craftbukkit.block.CraftSign.sanitizeLines(event.getLines()); |
1720 1729 | + for (int i = 0; i < components.length; i++) { |
1721 1730 | + tileentitysign.setMessage(i, components[i]); |
1722 1731 | } |
1723 1732 | + tileentitysign.isEditable = false; |
1724 1733 | } |
1725 1734 | + // CraftBukkit end |
1726 1735 | |
1727 1736 | tileentitysign.setChanged(); |
1728 1737 | worldserver.sendBlockUpdated(blockposition, iblockdata, iblockdata, 3); |
1729 - | |
1738 + | |
1730 1739 | |
1731 1740 | @Override |
1732 1741 | public void handleKeepAlive(PacketPlayInKeepAlive packetplayinkeepalive) { |
1733 1742 | + PlayerConnectionUtils.ensureRunningOnSameThread(packetplayinkeepalive, this, this.player.getLevel()); // CraftBukkit |
1734 1743 | if (this.keepAlivePending && packetplayinkeepalive.getId() == this.keepAliveChallenge) { |
1735 1744 | int i = (int) (SystemUtils.getMillis() - this.keepAliveTime); |
1736 1745 | |
1737 - | |
1746 + | |
1738 1747 | @Override |
1739 1748 | public void handlePlayerAbilities(PacketPlayInAbilities packetplayinabilities) { |
1740 1749 | PlayerConnectionUtils.ensureRunningOnSameThread(packetplayinabilities, this, this.player.getLevel()); |
1741 1750 | - this.player.getAbilities().flying = packetplayinabilities.isFlying() && this.player.getAbilities().mayfly; |
1742 1751 | + // CraftBukkit start |
1743 1752 | + if (this.player.getAbilities().mayfly && this.player.getAbilities().flying != packetplayinabilities.isFlying()) { |
1744 1753 | + PlayerToggleFlightEvent event = new PlayerToggleFlightEvent(this.player.getBukkitEntity(), packetplayinabilities.isFlying()); |
1745 1754 | + this.cserver.getPluginManager().callEvent(event); |
1746 1755 | + if (!event.isCancelled()) { |
1747 1756 | + this.player.getAbilities().flying = packetplayinabilities.isFlying(); // Actually set the player's flying status |
1748 1757 | + } else { |
1749 1758 | + this.player.onUpdateAbilities(); // Tell the player their ability was reverted |
1750 1759 | + } |
1751 1760 | + } |
1752 1761 | + // CraftBukkit end |
1753 1762 | } |
1754 1763 | |
1755 1764 | @Override |
1756 - | |
1765 + | |
1757 1766 | this.player.updateOptions(packetplayinsettings); |
1758 1767 | } |
1759 1768 | |
1760 1769 | - @Override |
1761 1770 | - public void handleCustomPayload(PacketPlayInCustomPayload packetplayincustompayload) {} |
1762 1771 | + // CraftBukkit start |
1763 1772 | + private static final MinecraftKey CUSTOM_REGISTER = new MinecraftKey("register"); |
1764 1773 | + private static final MinecraftKey CUSTOM_UNREGISTER = new MinecraftKey("unregister"); |
1765 1774 | + |
1766 1775 | + @Override |