Commits
Collin authored and md_5 committed 01cae71b7a4
1 1 | --- a/net/minecraft/server/network/PlayerConnection.java |
2 2 | +++ b/net/minecraft/server/network/PlayerConnection.java |
3 - | |
3 + | |
4 4 | import net.minecraft.world.phys.shapes.VoxelShapes; |
5 5 | import org.slf4j.Logger; |
6 6 | |
7 7 | +// CraftBukkit start |
8 8 | +import com.mojang.datafixers.util.Pair; |
9 9 | +import java.util.Arrays; |
10 10 | +import java.util.concurrent.ExecutionException; |
11 11 | +import java.util.concurrent.atomic.AtomicInteger; |
12 12 | +import net.minecraft.network.chat.OutgoingChatMessage; |
13 13 | +import net.minecraft.network.protocol.game.PacketPlayOutAttachEntity; |
18 18 | +import net.minecraft.world.entity.animal.Bucketable; |
19 19 | +import net.minecraft.world.entity.EntityLiving; |
20 20 | +import net.minecraft.world.entity.EnumItemSlot; |
21 21 | +import net.minecraft.world.entity.animal.allay.Allay; |
22 22 | +import net.minecraft.world.inventory.InventoryClickType; |
23 23 | +import net.minecraft.world.inventory.Slot; |
24 24 | +import net.minecraft.world.item.crafting.IRecipe; |
25 25 | +import net.minecraft.world.level.RayTrace; |
26 26 | +import net.minecraft.world.phys.MovingObjectPosition; |
27 27 | +import org.bukkit.Location; |
28 + | +import org.bukkit.craftbukkit.entity.CraftEntity; |
28 29 | +import org.bukkit.craftbukkit.entity.CraftPlayer; |
29 30 | +import org.bukkit.craftbukkit.event.CraftEventFactory; |
30 31 | +import org.bukkit.craftbukkit.inventory.CraftItemStack; |
31 32 | +import org.bukkit.craftbukkit.util.CraftChatMessage; |
32 33 | +import org.bukkit.craftbukkit.util.CraftLocation; |
33 34 | +import org.bukkit.craftbukkit.util.CraftMagicNumbers; |
34 35 | +import org.bukkit.craftbukkit.util.LazyPlayerSet; |
35 36 | +import org.bukkit.craftbukkit.util.Waitable; |
36 37 | +import org.bukkit.entity.Player; |
37 38 | +import org.bukkit.event.Event; |
63 64 | +import org.bukkit.event.player.PlayerToggleSprintEvent; |
64 65 | +import org.bukkit.inventory.CraftingInventory; |
65 66 | +import org.bukkit.inventory.EquipmentSlot; |
66 67 | +import org.bukkit.inventory.InventoryView; |
67 68 | +import org.bukkit.inventory.SmithingInventory; |
68 69 | +// CraftBukkit end |
69 70 | + |
70 71 | public class PlayerConnection implements ServerPlayerConnection, TickablePacketListener, PacketListenerPlayIn { |
71 72 | |
72 73 | static final Logger LOGGER = LogUtils.getLogger(); |
73 - | |
74 + | |
74 75 | private long keepAliveTime; |
75 76 | private boolean keepAlivePending; |
76 77 | private long keepAliveChallenge; |
77 78 | - private int chatSpamTickCount; |
78 79 | + // CraftBukkit start - multithreaded fields |
79 80 | + private final AtomicInteger chatSpamTickCount = new AtomicInteger(); |
80 81 | + // CraftBukkit end |
81 82 | private int dropSpamTickCount; |
82 83 | private double firstGoodX; |
83 84 | private double firstGoodY; |
84 - | |
85 + | |
85 86 | this.keepAliveTime = SystemUtils.getMillis(); |
86 87 | entityplayer.getTextFilter().join(); |
87 88 | this.signedMessageDecoder = minecraftserver.enforceSecureProfile() ? SignedMessageChain.b.REJECT_ALL : SignedMessageChain.b.unsigned(entityplayer.getUUID()); |
88 89 | - this.chatMessageChain = new FutureChain(minecraftserver); |
89 90 | + this.chatMessageChain = new FutureChain(minecraftserver.chatExecutor); // CraftBukkit - async chat |
90 91 | + // CraftBukkit start - add fields and methods |
91 92 | + this.cserver = minecraftserver.server; |
92 93 | + } |
93 94 | + |
94 95 | + private final org.bukkit.craftbukkit.CraftServer cserver; |
107 108 | + private float lastYaw = Float.MAX_VALUE; |
108 109 | + private boolean justTeleported = false; |
109 110 | + |
110 111 | + public CraftPlayer getCraftPlayer() { |
111 112 | + return (this.player == null) ? null : (CraftPlayer) this.player.getBukkitEntity(); |
112 113 | } |
113 114 | + // CraftBukkit end |
114 115 | |
115 116 | @Override |
116 117 | public void tick() { |
117 - | |
118 + | |
118 119 | this.server.getProfiler().push("keepAlive"); |
119 120 | long i = SystemUtils.getMillis(); |
120 121 | |
121 122 | - if (i - this.keepAliveTime >= 15000L) { |
122 123 | + if (i - this.keepAliveTime >= 25000L) { // CraftBukkit |
123 124 | if (this.keepAlivePending) { |
124 125 | this.disconnect(IChatBaseComponent.translatable("disconnect.timeout")); |
125 126 | } else { |
126 - | |
127 + | |
127 128 | } |
128 129 | |
129 130 | this.server.getProfiler().pop(); |
130 131 | + // CraftBukkit start |
131 132 | + for (int spam; (spam = this.chatSpamTickCount.get()) > 0 && !chatSpamTickCount.compareAndSet(spam, spam - 1); ) ; |
132 133 | + /* Use thread-safe field access instead |
133 134 | if (this.chatSpamTickCount > 0) { |
134 135 | --this.chatSpamTickCount; |
135 136 | } |
136 137 | + */ |
137 138 | + // CraftBukkit end |
138 139 | |
139 140 | if (this.dropSpamTickCount > 0) { |
140 141 | --this.dropSpamTickCount; |
141 142 | } |
142 143 | |
143 144 | if (this.player.getLastActionTime() > 0L && this.server.getPlayerIdleTimeout() > 0 && SystemUtils.getMillis() - this.player.getLastActionTime() > (long) this.server.getPlayerIdleTimeout() * 1000L * 60L) { |
144 145 | + this.player.resetLastActionTime(); // CraftBukkit - SPIGOT-854 |
145 146 | this.disconnect(IChatBaseComponent.translatable("multiplayer.disconnect.idling")); |
146 147 | } |
147 148 | |
148 - | |
149 + | |
149 150 | return this.server.isSingleplayerOwner(this.player.getGameProfile()); |
150 151 | } |
151 152 | |
152 153 | + // CraftBukkit start |
153 154 | + @Deprecated |
154 155 | public void disconnect(IChatBaseComponent ichatbasecomponent) { |
155 156 | + disconnect(CraftChatMessage.fromComponent(ichatbasecomponent)); |
156 157 | + } |
157 158 | + // CraftBukkit end |
158 159 | + |
207 208 | MinecraftServer minecraftserver = this.server; |
208 209 | NetworkManager networkmanager = this.connection; |
209 210 | |
210 211 | Objects.requireNonNull(this.connection); |
211 212 | - minecraftserver.executeBlocking(networkmanager::handleDisconnection); |
212 213 | + // CraftBukkit - Don't wait |
213 214 | + minecraftserver.wrapRunnable(networkmanager::handleDisconnection); |
214 215 | } |
215 216 | |
216 217 | private <T, R> CompletableFuture<R> filterTextPacket(T t0, BiFunction<ITextFilter, T, CompletableFuture<R>> bifunction) { |
217 - | |
218 + | |
218 219 | double d9 = entity.getDeltaMovement().lengthSqr(); |
219 220 | double d10 = d6 * d6 + d7 * d7 + d8 * d8; |
220 221 | |
221 222 | - if (d10 - d9 > 100.0D && !this.isSingleplayerOwner()) { |
222 223 | + |
223 224 | + // CraftBukkit start - handle custom speeds and skipped ticks |
224 225 | + this.allowedPlayerTicks += (System.currentTimeMillis() / 50) - this.lastTick; |
225 226 | + this.allowedPlayerTicks = Math.max(this.allowedPlayerTicks, 1); |
226 227 | + this.lastTick = (int) (System.currentTimeMillis() / 50); |
227 228 | + |
243 244 | + } else { |
244 245 | + speed = player.getAbilities().walkingSpeed * 10f; |
245 246 | + } |
246 247 | + speed *= 2f; // TODO: Get the speed of the vehicle instead of the player |
247 248 | + |
248 249 | + if (d10 - d9 > Math.max(100.0D, Math.pow((double) (10.0F * (float) i * speed), 2)) && !this.isSingleplayerOwner()) { |
249 250 | + // CraftBukkit end |
250 251 | PlayerConnection.LOGGER.warn("{} (vehicle of {}) moved too quickly! {},{},{}", new Object[]{entity.getName().getString(), this.player.getName().getString(), d6, d7, d8}); |
251 252 | this.connection.send(new PacketPlayOutVehicleMove(entity)); |
252 253 | return; |
253 - | |
254 + | |
254 255 | } |
255 256 | |
256 257 | entity.absMoveTo(d3, d4, d5, f, f1); |
257 258 | + player.absMoveTo(d3, d4, d5, this.player.getYRot(), this.player.getXRot()); // CraftBukkit |
258 259 | boolean flag3 = worldserver.noCollision(entity, entity.getBoundingBox().deflate(0.0625D)); |
259 260 | |
260 261 | if (flag && (flag2 || !flag3)) { |
261 262 | entity.absMoveTo(d0, d1, d2, f, f1); |
262 263 | + player.absMoveTo(d0, d1, d2, this.player.getYRot(), this.player.getXRot()); // CraftBukkit |
263 264 | this.connection.send(new PacketPlayOutVehicleMove(entity)); |
316 317 | + this.justTeleported = false; |
317 318 | + return; |
318 319 | + } |
319 320 | + } |
320 321 | + } |
321 322 | + // CraftBukkit end |
322 323 | + |
323 324 | this.player.serverLevel().getChunkSource().move(this.player); |
324 325 | this.player.checkMovementStatistics(this.player.getX() - d0, this.player.getY() - d1, this.player.getZ() - d2); |
325 326 | this.clientVehicleIsFloating = d11 >= -0.03125D && !flag1 && !this.server.isFlightAllowed() && !entity.isNoGravity() && this.noBlocksAround(entity); |
326 - | |
327 + | |
327 328 | } |
328 329 | |
329 330 | this.awaitingPositionFromClient = null; |
330 331 | + this.player.serverLevel().getChunkSource().move(this.player); // CraftBukkit |
331 332 | } |
332 333 | |
333 334 | } |
334 - | |
335 + | |
335 336 | @Override |
336 337 | public void handleRecipeBookSeenRecipePacket(PacketPlayInRecipeDisplayed packetplayinrecipedisplayed) { |
337 338 | PlayerConnectionUtils.ensureRunningOnSameThread(packetplayinrecipedisplayed, this, this.player.serverLevel()); |
338 339 | - Optional optional = this.server.getRecipeManager().byKey(packetplayinrecipedisplayed.getRecipe()); |
339 340 | + Optional<? extends IRecipe<?>> optional = this.server.getRecipeManager().byKey(packetplayinrecipedisplayed.getRecipe()); // CraftBukkit - decompile error |
340 341 | RecipeBookServer recipebookserver = this.player.getRecipeBook(); |
341 342 | |
342 343 | Objects.requireNonNull(recipebookserver); |
343 - | |
344 + | |
344 345 | @Override |
345 346 | public void handleCustomCommandSuggestions(PacketPlayInTabComplete packetplayintabcomplete) { |
346 347 | PlayerConnectionUtils.ensureRunningOnSameThread(packetplayintabcomplete, this, this.player.serverLevel()); |
347 348 | + // CraftBukkit start |
348 349 | + if (chatSpamTickCount.addAndGet(1) > 500 && !this.server.getPlayerList().isOp(this.player.getGameProfile())) { |
349 350 | + this.disconnect(IChatBaseComponent.translatable("disconnect.spam")); |
350 351 | + return; |
351 352 | + } |
352 353 | + // CraftBukkit end |
353 354 | StringReader stringreader = new StringReader(packetplayintabcomplete.getCommand()); |
354 355 | |
355 356 | if (stringreader.canRead() && stringreader.peek() == '/') { |
356 - | |
357 + | |
357 358 | ParseResults<CommandListenerWrapper> parseresults = this.server.getCommands().getDispatcher().parse(stringreader, this.player.createCommandSourceStack()); |
358 359 | |
359 360 | this.server.getCommands().getDispatcher().getCompletionSuggestions(parseresults).thenAccept((suggestions) -> { |
360 361 | + if (suggestions.isEmpty()) return; // CraftBukkit - don't send through empty suggestions - prevents [<args>] from showing for plugins with nothing more to offer |
361 362 | this.connection.send(new PacketPlayOutTabComplete(packetplayintabcomplete.getId(), suggestions)); |
362 363 | }); |
363 364 | } |
364 - | |
365 + | |
365 366 | |
366 367 | if (container instanceof ContainerMerchant) { |
367 368 | ContainerMerchant containermerchant = (ContainerMerchant) container; |
368 369 | + // CraftBukkit start |
369 370 | + final org.bukkit.event.inventory.TradeSelectEvent tradeSelectEvent = CraftEventFactory.callTradeSelectEvent(this.player, i, containermerchant); |
370 371 | + if (tradeSelectEvent.isCancelled()) { |
371 372 | + this.player.getBukkitEntity().updateInventory(); |
372 373 | + return; |
373 374 | + } |
374 375 | + // CraftBukkit end |
375 376 | |
376 377 | if (!containermerchant.stillValid(this.player)) { |
377 378 | PlayerConnection.LOGGER.debug("Player {} interacted with invalid menu {}", this.player, containermerchant); |
378 - | |
379 + | |
379 380 | |
380 381 | @Override |
381 382 | public void handleEditBook(PacketPlayInBEdit packetplayinbedit) { |
382 383 | + // CraftBukkit start |
383 384 | + if (this.lastBookTick + 20 > MinecraftServer.currentTick) { |
384 385 | + this.disconnect("Book edited too quickly!"); |
385 386 | + return; |
386 387 | + } |
387 388 | + this.lastBookTick = MinecraftServer.currentTick; |
388 389 | + // CraftBukkit end |
389 390 | int i = packetplayinbedit.getSlot(); |
390 391 | |
391 392 | if (PlayerInventory.isHotbarSlot(i) || i == 40) { |
392 - | |
393 + | |
393 394 | |
394 395 | Objects.requireNonNull(list); |
395 396 | optional.ifPresent(list::add); |
396 397 | - Stream stream = packetplayinbedit.getPages().stream().limit(100L); |
397 398 | + Stream<String> stream = packetplayinbedit.getPages().stream().limit(100L); // CraftBukkit - decompile error |
398 399 | |
399 400 | Objects.requireNonNull(list); |
400 401 | stream.forEach(list::add); |
401 - | |
402 + | |
402 403 | ItemStack itemstack = this.player.getInventory().getItem(i); |
403 404 | |
404 405 | if (itemstack.is(Items.WRITABLE_BOOK)) { |
405 406 | - this.updateBookPages(list, UnaryOperator.identity(), itemstack); |
406 407 | + this.updateBookPages(list, UnaryOperator.identity(), itemstack.copy(), i, itemstack); // CraftBukkit |
407 408 | } |
408 409 | } |
409 410 | |
410 - | |
411 + | |
411 412 | |
412 413 | this.updateBookPages(list, (s) -> { |
413 414 | return IChatBaseComponent.ChatSerializer.toJson(IChatBaseComponent.literal(s)); |
414 415 | - }, itemstack1); |
415 416 | - this.player.getInventory().setItem(i, itemstack1); |
416 417 | + }, itemstack1, i, itemstack); // CraftBukkit |
417 418 | + this.player.getInventory().setItem(i, itemstack); // CraftBukkit - event factory updates the hand book |
418 419 | } |
419 420 | } |
420 421 | |
421 422 | - private void updateBookPages(List<FilteredText> list, UnaryOperator<String> unaryoperator, ItemStack itemstack) { |
422 423 | + private void updateBookPages(List<FilteredText> list, UnaryOperator<String> unaryoperator, ItemStack itemstack, int slot, ItemStack handItem) { // CraftBukkit |
423 424 | NBTTagList nbttaglist = new NBTTagList(); |
424 425 | |
425 426 | if (this.player.isTextFilteringEnabled()) { |
426 427 | - Stream stream = list.stream().map((filteredtext) -> { |
427 428 | + Stream<NBTTagString> stream = list.stream().map((filteredtext) -> { // CraftBukkit - decompile error |
428 429 | return NBTTagString.valueOf((String) unaryoperator.apply(filteredtext.filteredOrEmpty())); |
429 430 | }); |
430 431 | |
431 - | |
432 + | |
432 433 | } |
433 434 | |
434 435 | itemstack.addTagElement("pages", nbttaglist); |
435 436 | + CraftEventFactory.handleEditBookEvent(player, slot, handItem, itemstack); // CraftBukkit |
436 437 | } |
437 438 | |
438 439 | @Override |
439 - | |
440 + | |
440 441 | } else { |
441 442 | WorldServer worldserver = this.player.serverLevel(); |
442 443 | |
443 444 | - if (!this.player.wonGame) { |
444 445 | + if (!this.player.wonGame && !this.player.isImmobile()) { // CraftBukkit |
445 446 | if (this.tickCount == 0) { |
446 447 | this.resetPosition(); |
447 448 | } |
448 - | |
449 + | |
449 450 | this.awaitingTeleportTime = this.tickCount; |
450 451 | this.teleport(this.awaitingPositionFromClient.x, this.awaitingPositionFromClient.y, this.awaitingPositionFromClient.z, this.player.getYRot(), this.player.getXRot()); |
451 452 | } |
452 453 | - |
453 454 | + this.allowedPlayerTicks = 20; // CraftBukkit |
454 455 | } else { |
455 456 | this.awaitingTeleportTime = this.tickCount; |
456 457 | double d0 = clampHorizontal(packetplayinflying.getX(this.player.getX())); |
457 - | |
458 + | |
458 459 | if (this.player.isPassenger()) { |
459 460 | this.player.absMoveTo(this.player.getX(), this.player.getY(), this.player.getZ(), f, f1); |
460 461 | this.player.serverLevel().getChunkSource().move(this.player); |
461 462 | + this.allowedPlayerTicks = 20; // CraftBukkit |
462 463 | } else { |
463 464 | + // CraftBukkit - Make sure the move is valid but then reset it for plugins to modify |
464 465 | + double prevX = player.getX(); |
465 466 | + double prevY = player.getY(); |
466 467 | + double prevZ = player.getZ(); |
467 468 | + float prevYaw = player.getYRot(); |
468 469 | + float prevPitch = player.getXRot(); |
469 470 | + // CraftBukkit end |
470 471 | double d3 = this.player.getX(); |
471 472 | double d4 = this.player.getY(); |
472 473 | double d5 = this.player.getZ(); |
473 - | |
474 + | |
474 475 | ++this.receivedMovePacketCount; |
475 476 | int i = this.receivedMovePacketCount - this.knownMovePacketCount; |
476 477 | |
477 478 | - if (i > 5) { |
478 479 | + // CraftBukkit start - handle custom speeds and skipped ticks |
479 480 | + this.allowedPlayerTicks += (System.currentTimeMillis() / 50) - this.lastTick; |
480 481 | + this.allowedPlayerTicks = Math.max(this.allowedPlayerTicks, 1); |
481 482 | + this.lastTick = (int) (System.currentTimeMillis() / 50); |
482 483 | + |
483 484 | + if (i > Math.max(this.allowedPlayerTicks, 5)) { |
499 500 | + |
500 501 | if (!this.player.isChangingDimension() && (!this.player.level().getGameRules().getBoolean(GameRules.RULE_DISABLE_ELYTRA_MOVEMENT_CHECK) || !this.player.isFallFlying())) { |
501 502 | float f2 = this.player.isFallFlying() ? 300.0F : 100.0F; |
502 503 | |
503 504 | - if (d10 - d9 > (double) (f2 * (float) i) && !this.isSingleplayerOwner()) { |
504 505 | + if (d10 - d9 > Math.max(f2, Math.pow((double) (10.0F * (float) i * speed), 2)) && !this.isSingleplayerOwner()) { |
505 506 | + // CraftBukkit end |
506 507 | PlayerConnection.LOGGER.warn("{} moved too quickly! {},{},{}", new Object[]{this.player.getName().getString(), d6, d7, d8}); |
507 508 | this.teleport(this.player.getX(), this.player.getY(), this.player.getZ(), this.player.getYRot(), this.player.getXRot()); |
508 509 | return; |
509 - | |
510 + | |
510 511 | boolean flag1 = this.player.verticalCollisionBelow; |
511 512 | |
512 513 | this.player.move(EnumMoveType.PLAYER, new Vec3D(d6, d7, d8)); |
513 514 | + this.player.onGround = packetplayinflying.isOnGround(); // CraftBukkit - SPIGOT-5810, SPIGOT-5835, SPIGOT-6828: reset by this.player.move |
514 515 | double d11 = d7; |
515 516 | |
516 517 | d6 = d0 - this.player.getX(); |
517 - | |
518 + | |
518 519 | } |
519 520 | |
520 521 | if (!this.player.noPhysics && !this.player.isSleeping() && (flag2 && worldserver.noCollision(this.player, axisalignedbb) || this.isPlayerCollidingWithAnythingNew(worldserver, axisalignedbb, d0, d1, d2))) { |
521 522 | - this.teleport(d3, d4, d5, f, f1); |
522 523 | + 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. |
523 524 | this.player.doCheckFallDamage(this.player.getX() - d3, this.player.getY() - d4, this.player.getZ() - d5, packetplayinflying.isOnGround()); |
524 525 | } else { |
525 526 | + // CraftBukkit start - fire PlayerMoveEvent |
526 527 | + // Reset to old location first |
527 528 | + this.player.absMoveTo(prevX, prevY, prevZ, prevYaw, prevPitch); |
579 580 | + if (!from.equals(this.getCraftPlayer().getLocation()) && this.justTeleported) { |
580 581 | + this.justTeleported = false; |
581 582 | + return; |
582 583 | + } |
583 584 | + } |
584 585 | + } |
585 586 | + // CraftBukkit end |
586 587 | this.player.absMoveTo(d0, d1, d2, f, f1); |
587 588 | 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); |
588 589 | this.player.serverLevel().getChunkSource().move(this.player); |
589 - | |
590 + | |
590 591 | return true; |
591 592 | } |
592 593 | |
593 594 | + // CraftBukkit start - Delegate to teleport(Location) |
594 595 | public void teleport(double d0, double d1, double d2, float f, float f1) { |
595 596 | - this.teleport(d0, d1, d2, f, f1, Collections.emptySet()); |
596 597 | + this.teleport(d0, d1, d2, f, f1, PlayerTeleportEvent.TeleportCause.UNKNOWN); |
597 598 | + } |
598 599 | + |
599 600 | + public void teleport(double d0, double d1, double d2, float f, float f1, PlayerTeleportEvent.TeleportCause cause) { |
649 650 | + } |
650 651 | + if (Float.isNaN(f1)) { |
651 652 | + f1 = 0; |
652 653 | + } |
653 654 | + |
654 655 | + this.justTeleported = true; |
655 656 | + // CraftBukkit end |
656 657 | double d3 = set.contains(RelativeMovement.X) ? this.player.getX() : 0.0D; |
657 658 | double d4 = set.contains(RelativeMovement.Y) ? this.player.getY() : 0.0D; |
658 659 | double d5 = set.contains(RelativeMovement.Z) ? this.player.getZ() : 0.0D; |
659 - | |
660 + | |
660 661 | this.awaitingTeleport = 0; |
661 662 | } |
662 663 | |
663 664 | + // CraftBukkit start - update last location |
664 665 | + this.lastPosX = this.awaitingPositionFromClient.x; |
665 666 | + this.lastPosY = this.awaitingPositionFromClient.y; |
666 667 | + this.lastPosZ = this.awaitingPositionFromClient.z; |
667 668 | + this.lastYaw = f; |
668 669 | + this.lastPitch = f1; |
669 670 | + // CraftBukkit end |
670 671 | + |
671 672 | this.awaitingTeleportTime = this.tickCount; |
672 673 | this.player.absMoveTo(d0, d1, d2, f, f1); |
673 674 | this.player.connection.send(new PacketPlayOutPosition(d0 - d3, d1 - d4, d2 - d5, f - f2, f1 - f3, set, this.awaitingTeleport)); |
674 - | |
675 + | |
675 676 | @Override |
676 677 | public void handlePlayerAction(PacketPlayInBlockDig packetplayinblockdig) { |
677 678 | PlayerConnectionUtils.ensureRunningOnSameThread(packetplayinblockdig, this, this.player.serverLevel()); |
678 679 | + if (this.player.isImmobile()) return; // CraftBukkit |
679 680 | BlockPosition blockposition = packetplayinblockdig.getPos(); |
680 681 | |
681 682 | this.player.resetLastActionTime(); |
682 - | |
683 + | |
683 684 | if (!this.player.isSpectator()) { |
684 685 | ItemStack itemstack = this.player.getItemInHand(EnumHand.OFF_HAND); |
685 686 | |
686 687 | - this.player.setItemInHand(EnumHand.OFF_HAND, this.player.getItemInHand(EnumHand.MAIN_HAND)); |
687 688 | - this.player.setItemInHand(EnumHand.MAIN_HAND, itemstack); |
688 689 | + // CraftBukkit start - inspiration taken from DispenserRegistry (See SpigotCraft#394) |
689 690 | + CraftItemStack mainHand = CraftItemStack.asCraftMirror(itemstack); |
690 691 | + CraftItemStack offHand = CraftItemStack.asCraftMirror(this.player.getItemInHand(EnumHand.MAIN_HAND)); |
691 692 | + PlayerSwapHandItemsEvent swapItemsEvent = new PlayerSwapHandItemsEvent(getCraftPlayer(), mainHand.clone(), offHand.clone()); |
692 693 | + this.cserver.getPluginManager().callEvent(swapItemsEvent); |
721 722 | + if (this.dropCount >= 20) { |
722 723 | + LOGGER.warn(this.player.getScoreboardName() + " dropped their items too quickly!"); |
723 724 | + this.disconnect("You dropped your items too quickly (Hacking?)"); |
724 725 | + return; |
725 726 | + } |
726 727 | + } |
727 728 | + // CraftBukkit end |
728 729 | this.player.drop(false); |
729 730 | } |
730 731 | |
731 - | |
732 + | |
732 733 | @Override |
733 734 | public void handleUseItemOn(PacketPlayInUseItem packetplayinuseitem) { |
734 735 | PlayerConnectionUtils.ensureRunningOnSameThread(packetplayinuseitem, this, this.player.serverLevel()); |
735 736 | + if (this.player.isImmobile()) return; // CraftBukkit |
736 737 | this.player.connection.ackBlockChangesUpTo(packetplayinuseitem.getSequence()); |
737 738 | WorldServer worldserver = this.player.serverLevel(); |
738 739 | EnumHand enumhand = packetplayinuseitem.getHand(); |
739 - | |
740 + | |
740 741 | |
741 742 | if (blockposition.getY() < i) { |
742 743 | 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)) { |
743 744 | + this.player.stopUsingItem(); // CraftBukkit - SPIGOT-4706 |
744 745 | EnumInteractionResult enuminteractionresult = this.player.gameMode.useItemOn(this.player, worldserver, itemstack, enumhand, movingobjectpositionblock); |
745 746 | |
746 747 | if (enumdirection == EnumDirection.UP && !enuminteractionresult.consumesAction() && blockposition.getY() >= i - 1 && wasBlockPlacementAttempt(this.player, itemstack)) { |
747 - | |
748 + | |
748 749 | @Override |
749 750 | public void handleUseItem(PacketPlayInBlockPlace packetplayinblockplace) { |
750 751 | PlayerConnectionUtils.ensureRunningOnSameThread(packetplayinblockplace, this, this.player.serverLevel()); |
751 752 | + if (this.player.isImmobile()) return; // CraftBukkit |
752 753 | this.ackBlockChangesUpTo(packetplayinblockplace.getSequence()); |
753 754 | WorldServer worldserver = this.player.serverLevel(); |
754 755 | EnumHand enumhand = packetplayinblockplace.getHand(); |
755 - | |
756 + | |
756 757 | |
757 758 | this.player.resetLastActionTime(); |
758 759 | if (!itemstack.isEmpty() && itemstack.isItemEnabled(worldserver.enabledFeatures())) { |
759 760 | + // CraftBukkit start |
760 761 | + // Raytrace to look for 'rogue armswings' |
761 762 | + float f1 = this.player.getXRot(); |
762 763 | + float f2 = this.player.getYRot(); |
763 764 | + double d0 = this.player.getX(); |
764 765 | + double d1 = this.player.getY() + (double) this.player.getEyeHeight(); |
765 766 | + double d2 = this.player.getZ(); |
795 796 | + return; |
796 797 | + } |
797 798 | + itemstack = this.player.getItemInHand(enumhand); // Update in case it was changed in the event |
798 799 | + if (itemstack.isEmpty()) { |
799 800 | + return; |
800 801 | + } |
801 802 | + // CraftBukkit end |
802 803 | EnumInteractionResult enuminteractionresult = this.player.gameMode.useItem(this.player, worldserver, itemstack, enumhand); |
803 804 | |
804 805 | if (enuminteractionresult.shouldSwing()) { |
805 - | |
806 + | |
806 807 | Entity entity = packetplayinspectate.getEntity(worldserver); |
807 808 | |
808 809 | if (entity != null) { |
809 810 | - this.player.teleportTo(worldserver, entity.getX(), entity.getY(), entity.getZ(), entity.getYRot(), entity.getXRot()); |
810 811 | + this.player.teleportTo(worldserver, entity.getX(), entity.getY(), entity.getZ(), entity.getYRot(), entity.getXRot(), org.bukkit.event.player.PlayerTeleportEvent.TeleportCause.SPECTATE); // CraftBukkit |
811 812 | return; |
812 813 | } |
813 814 | } |
814 - | |
815 + | |
815 816 | PlayerConnection.LOGGER.info("Disconnecting {} due to resource pack rejection", this.player.getName()); |
816 817 | this.disconnect(IChatBaseComponent.translatable("multiplayer.requiredTexturePrompt.disconnect")); |
817 818 | } |
818 819 | + this.cserver.getPluginManager().callEvent(new PlayerResourcePackStatusEvent(getCraftPlayer(), PlayerResourcePackStatusEvent.Status.values()[packetplayinresourcepackstatus.action.ordinal()])); // CraftBukkit |
819 820 | |
820 821 | } |
821 822 | |
822 - | |
823 + | |
823 824 | |
824 825 | @Override |
825 826 | public void onDisconnect(IChatBaseComponent ichatbasecomponent) { |
826 827 | + // CraftBukkit start - Rarely it would send a disconnect line twice |
827 828 | + if (this.processedDisconnect) { |
828 829 | + return; |
829 830 | + } else { |
830 831 | + this.processedDisconnect = true; |
831 832 | + } |
832 833 | + // CraftBukkit end |
841 842 | this.player.disconnect(); |
842 843 | - this.server.getPlayerList().remove(this.player); |
843 844 | + String quitMessage = this.server.getPlayerList().remove(this.player); |
844 845 | + if ((quitMessage != null) && (quitMessage.length() > 0)) { |
845 846 | + this.server.getPlayerList().broadcastMessage(CraftChatMessage.fromString(quitMessage)); |
846 847 | + } |
847 848 | + // CraftBukkit end |
848 849 | this.player.getTextFilter().leave(); |
849 850 | if (this.isSingleplayerOwner()) { |
850 851 | PlayerConnection.LOGGER.info("Stopping singleplayer server as player logged out"); |
851 - | |
852 + | |
852 853 | } |
853 854 | |
854 855 | public void send(Packet<?> packet, @Nullable PacketSendListener packetsendlistener) { |
855 856 | + // CraftBukkit start |
856 857 | + if (packet == null) { |
857 858 | + return; |
858 859 | + } else if (packet instanceof PacketPlayOutSpawnPosition) { |
859 860 | + PacketPlayOutSpawnPosition packet6 = (PacketPlayOutSpawnPosition) packet; |
860 861 | + this.player.compassTarget = CraftLocation.toBukkit(packet6.pos, this.getCraftPlayer().getWorld()); |
861 862 | + } |
862 863 | + // CraftBukkit end |
863 864 | + |
864 865 | try { |
865 866 | this.connection.send(packet, packetsendlistener); |
866 867 | } catch (Throwable throwable) { |
867 - | |
868 + | |
868 869 | @Override |
869 870 | public void handleSetCarriedItem(PacketPlayInHeldItemSlot packetplayinhelditemslot) { |
870 871 | PlayerConnectionUtils.ensureRunningOnSameThread(packetplayinhelditemslot, this, this.player.serverLevel()); |
871 872 | + if (this.player.isImmobile()) return; // CraftBukkit |
872 873 | if (packetplayinhelditemslot.getSlot() >= 0 && packetplayinhelditemslot.getSlot() < PlayerInventory.getSelectionSize()) { |
873 874 | + PlayerItemHeldEvent event = new PlayerItemHeldEvent(this.getCraftPlayer(), this.player.getInventory().selected, packetplayinhelditemslot.getSlot()); |
874 875 | + this.cserver.getPluginManager().callEvent(event); |
875 876 | + if (event.isCancelled()) { |
876 877 | + this.send(new PacketPlayOutHeldItemSlot(this.player.getInventory().selected)); |
877 878 | + this.player.resetLastActionTime(); |
878 879 | + return; |
879 880 | + } |
880 881 | + // CraftBukkit end |
881 882 | if (this.player.getInventory().selected != packetplayinhelditemslot.getSlot() && this.player.getUsedItemHand() == EnumHand.MAIN_HAND) { |
882 883 | this.player.stopUsingItem(); |
883 884 | } |
884 - | |
885 + | |
885 886 | this.player.resetLastActionTime(); |
886 887 | } else { |
887 888 | PlayerConnection.LOGGER.warn("{} tried to set an invalid carried item", this.player.getName().getString()); |
888 889 | + this.disconnect("Invalid hotbar selection (Hacking?)"); // CraftBukkit |
889 890 | } |
890 891 | } |
891 892 | |
892 893 | @Override |
893 894 | public void handleChat(PacketPlayInChat packetplayinchat) { |
894 895 | + // CraftBukkit start - async chat |
901 902 | this.disconnect(IChatBaseComponent.translatable("multiplayer.disconnect.illegal_characters")); |
902 903 | } else { |
903 904 | Optional<LastSeenMessages> optional = this.tryHandleChat(packetplayinchat.message(), packetplayinchat.timeStamp(), packetplayinchat.lastSeenMessages()); |
904 905 | |
905 906 | if (optional.isPresent()) { |
906 907 | - this.server.submit(() -> { |
907 908 | + // this.server.submit(() -> { // CraftBukkit - async chat |
908 909 | PlayerChatMessage playerchatmessage; |
909 910 | |
910 911 | try { |
911 - | |
912 + | |
912 913 | PlayerChatMessage playerchatmessage1 = playerchatmessage.withUnsignedContent((IChatBaseComponent) completablefuture1.join()).filter(((FilteredText) completablefuture.join()).mask()); |
913 914 | |
914 915 | this.broadcastChatMessage(playerchatmessage1); |
915 916 | - }, executor); |
916 917 | + }, this.server.chatExecutor); // CraftBukkit - async chat |
917 918 | }); |
918 919 | - }); |
919 920 | + // }); // CraftBukkit - async chat |
920 921 | } |
921 922 | |
922 923 | } |
923 - | |
924 + | |
924 925 | |
925 926 | if (optional.isPresent()) { |
926 927 | this.server.submit(() -> { |
927 928 | + // CraftBukkit start - SPIGOT-7346: Prevent disconnected players from executing commands |
928 929 | + if (player.hasDisconnected()) { |
929 930 | + return; |
930 931 | + } |
931 932 | + // CraftBukkit end |
932 933 | + |
933 934 | this.performChatCommand(serverboundchatcommandpacket, (LastSeenMessages) optional.get()); |
934 935 | this.detectRateSpam(); |
935 936 | }); |
936 - | |
937 + | |
937 938 | } |
938 939 | |
939 940 | private void performChatCommand(ServerboundChatCommandPacket serverboundchatcommandpacket, LastSeenMessages lastseenmessages) { |
940 941 | - ParseResults parseresults = this.parseCommand(serverboundchatcommandpacket.command()); |
941 942 | + // CraftBukkit start |
942 943 | + String command = "/" + serverboundchatcommandpacket.command(); |
943 944 | + PlayerConnection.LOGGER.info(this.player.getScoreboardName() + " issued server command: " + command); |
944 945 | + |
945 946 | + PlayerCommandPreprocessEvent event = new PlayerCommandPreprocessEvent(getCraftPlayer(), command, new LazyPlayerSet(server)); |
946 947 | + this.cserver.getPluginManager().callEvent(event); |
954 955 | + // CraftBukkit end |
955 956 | |
956 957 | Map map; |
957 958 | |
958 959 | try { |
959 960 | - map = this.collectSignedArguments(serverboundchatcommandpacket, SignableCommand.of(parseresults), lastseenmessages); |
960 961 | + map = (serverboundchatcommandpacket.command().equals(command)) ? this.collectSignedArguments(serverboundchatcommandpacket, SignableCommand.of(parseresults), lastseenmessages) : Collections.emptyMap(); // CraftBukkit |
961 962 | } catch (SignedMessageChain.a signedmessagechain_a) { |
962 963 | this.handleMessageDecodeFailure(signedmessagechain_a); |
963 964 | return; |
964 - | |
965 + | |
965 966 | |
966 967 | CommandSigningContext.a commandsigningcontext_a = new CommandSigningContext.a(map); |
967 968 | |
968 969 | - parseresults = CommandDispatcher.mapSource(parseresults, (commandlistenerwrapper) -> { |
969 970 | + parseresults = CommandDispatcher.<CommandListenerWrapper>mapSource(parseresults, (commandlistenerwrapper) -> { // CraftBukkit - decompile error |
970 971 | return commandlistenerwrapper.withSigningContext(commandsigningcontext_a); |
971 972 | }); |
972 973 | - this.server.getCommands().performCommand(parseresults, serverboundchatcommandpacket.command()); |
973 974 | + this.server.getCommands().performCommand(parseresults, command); // CraftBukkit |
974 975 | } |
975 976 | |
976 977 | private void handleMessageDecodeFailure(SignedMessageChain.a signedmessagechain_a) { |
977 - | |
978 + | |
978 979 | } else { |
979 980 | Optional<LastSeenMessages> optional = this.unpackAndApplyLastSeen(lastseenmessages_b); |
980 981 | |
981 982 | - if (this.player.getChatVisibility() == EnumChatVisibility.HIDDEN) { |
982 983 | + if (this.player.isRemoved() || this.player.getChatVisibility() == EnumChatVisibility.HIDDEN) { // CraftBukkit - dead men tell no tales |
983 984 | this.send(new ClientboundSystemChatPacket(IChatBaseComponent.translatable("chat.disabled.options").withStyle(EnumChatFormat.RED), false)); |
984 985 | return Optional.empty(); |
985 986 | } else { |
986 - | |
987 + | |
987 988 | return false; |
988 989 | } |
989 990 | |
990 991 | + // CraftBukkit start - add method |
991 992 | + public void chat(String s, PlayerChatMessage original, boolean async) { |
992 993 | + if (s.isEmpty() || this.player.getChatVisibility() == EnumChatVisibility.HIDDEN) { |
993 994 | + return; |
994 995 | + } |
995 996 | + OutgoingChatMessage outgoing = OutgoingChatMessage.create(original); |
996 997 | + |
1099 1100 | + player.sendMessage(org.bukkit.ChatColor.RED + "An internal error occurred while attempting to perform this command"); |
1100 1101 | + java.util.logging.Logger.getLogger(PlayerConnection.class.getName()).log(java.util.logging.Level.SEVERE, null, ex); |
1101 1102 | + return; |
1102 1103 | + } |
1103 1104 | + } |
1104 1105 | + // CraftBukkit end |
1105 1106 | + |
1106 1107 | private PlayerChatMessage getSignedMessage(PacketPlayInChat packetplayinchat, LastSeenMessages lastseenmessages) throws SignedMessageChain.a { |
1107 1108 | SignedMessageBody signedmessagebody = new SignedMessageBody(packetplayinchat.message(), packetplayinchat.timeStamp(), packetplayinchat.salt(), lastseenmessages); |
1108 1109 | |
1109 - | |
1110 + | |
1110 1111 | } |
1111 1112 | |
1112 1113 | private void broadcastChatMessage(PlayerChatMessage playerchatmessage) { |
1113 1114 | - this.server.getPlayerList().broadcastChatMessage(playerchatmessage, this.player, ChatMessageType.bind(ChatMessageType.CHAT, (Entity) this.player)); |
1114 1115 | + // CraftBukkit start |
1115 1116 | + String s = playerchatmessage.signedContent(); |
1116 1117 | + if (s.isEmpty()) { |
1117 1118 | + LOGGER.warn(this.player.getScoreboardName() + " tried to send an empty message"); |
1118 1119 | + } else if (getCraftPlayer().isConversing()) { |
1119 1120 | + final String conversationInput = s; |
1136 1137 | private void detectRateSpam() { |
1137 1138 | - this.chatSpamTickCount += 20; |
1138 1139 | - if (this.chatSpamTickCount > 200 && !this.server.getPlayerList().isOp(this.player.getGameProfile())) { |
1139 1140 | + // CraftBukkit start - replaced with thread safe throttle |
1140 1141 | + // this.chatSpamTickCount += 20; |
1141 1142 | + if (this.chatSpamTickCount.addAndGet(20) > 200 && !this.server.getPlayerList().isOp(this.player.getGameProfile())) { |
1142 1143 | + // CraftBukkit end |
1143 1144 | this.disconnect(IChatBaseComponent.translatable("disconnect.spam")); |
1144 1145 | } |
1145 1146 | |
1146 - | |
1147 + | |
1147 1148 | @Override |
1148 1149 | public void handleAnimate(PacketPlayInArmAnimation packetplayinarmanimation) { |
1149 1150 | PlayerConnectionUtils.ensureRunningOnSameThread(packetplayinarmanimation, this, this.player.serverLevel()); |
1150 1151 | + if (this.player.isImmobile()) return; // CraftBukkit |
1151 1152 | this.player.resetLastActionTime(); |
1152 1153 | + // CraftBukkit start - Raytrace to look for 'rogue armswings' |
1153 1154 | + float f1 = this.player.getXRot(); |
1154 1155 | + float f2 = this.player.getYRot(); |
1155 1156 | + double d0 = this.player.getX(); |
1156 1157 | + double d1 = this.player.getY() + (double) this.player.getEyeHeight(); |
1157 1158 | + double d2 = this.player.getZ(); |
1158 1159 | + Location origin = new Location(this.player.level().getWorld(), d0, d1, d2, f2, f1); |
1159 1160 | + |
1160 1161 | + double d3 = player.gameMode.getGameModeForPlayer() == EnumGamemode.CREATIVE ? 5.0D : 4.5D; |
1161 1162 | + // SPIGOT-5607: Only call interact event if no block or entity is being clicked. Use bukkit ray trace method, because it handles blocks and entities at the same time |
1162 - | + org.bukkit.util.RayTraceResult result = this.player.level().getWorld().rayTrace(origin, origin.getDirection(), d3, org.bukkit.FluidCollisionMode.NEVER, false, 0.1, entity -> entity != this.player.getBukkitEntity() && this.player.getBukkitEntity().canSee(entity)); |
1163 - | + |
1163 + | + // SPIGOT-7429: Make sure to call PlayerInteractEvent for spectators and non-pickable entities |
1164 + | + org.bukkit.util.RayTraceResult result = this.player.level().getWorld().rayTrace(origin, origin.getDirection(), d3, org.bukkit.FluidCollisionMode.NEVER, false, 0.1, entity -> { |
1165 + | + Entity handle = ((CraftEntity) entity).getHandle(); |
1166 + | + return entity != this.player.getBukkitEntity() && this.player.getBukkitEntity().canSee(entity) && !handle.isSpectator() && handle.isPickable() && !handle.isPassengerOfSameVehicle(player); |
1167 + | + }); |
1164 1168 | + if (result == null) { |
1165 1169 | + CraftEventFactory.callPlayerInteractEvent(this.player, Action.LEFT_CLICK_AIR, this.player.getInventory().getSelected(), EnumHand.MAIN_HAND); |
1166 1170 | + } |
1167 1171 | + |
1168 1172 | + // Arm swing animation |
1169 1173 | + PlayerAnimationEvent event = new PlayerAnimationEvent(this.getCraftPlayer(), (packetplayinarmanimation.getHand() == EnumHand.MAIN_HAND) ? PlayerAnimationType.ARM_SWING : PlayerAnimationType.OFF_ARM_SWING); |
1170 1174 | + this.cserver.getPluginManager().callEvent(event); |
1171 1175 | + |
1172 1176 | + if (event.isCancelled()) return; |
1173 1177 | + // CraftBukkit end |
1196 1200 | + |
1197 1201 | + if (e2.isCancelled()) { |
1198 1202 | + return; |
1199 1203 | + } |
1200 1204 | + break; |
1201 1205 | + } |
1202 1206 | + // CraftBukkit end |
1203 1207 | this.player.resetLastActionTime(); |
1204 1208 | Entity entity; |
1205 1209 | IJumpable ijumpable; |
1206 - | |
1210 + | |
1207 1211 | } |
1208 1212 | |
1209 1213 | public void sendPlayerChatMessage(PlayerChatMessage playerchatmessage, ChatMessageType.a chatmessagetype_a) { |
1210 1214 | + // 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). |
1211 1215 | + if (!getCraftPlayer().canSee(playerchatmessage.link().sender())) { |
1212 1216 | + sendDisguisedChatMessage(playerchatmessage.decoratedContent(), chatmessagetype_a); |
1213 1217 | + return; |
1214 1218 | + } |
1215 1219 | + // CraftBukkit end |
1216 1220 | 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()))); |
1217 1221 | this.addPendingMessage(playerchatmessage); |
1218 1222 | } |
1219 - | |
1223 + | |
1220 1224 | @Override |
1221 1225 | public void handleInteract(PacketPlayInUseEntity packetplayinuseentity) { |
1222 1226 | PlayerConnectionUtils.ensureRunningOnSameThread(packetplayinuseentity, this, this.player.serverLevel()); |
1223 1227 | + if (this.player.isImmobile()) return; // CraftBukkit |
1224 1228 | final WorldServer worldserver = this.player.serverLevel(); |
1225 1229 | final Entity entity = packetplayinuseentity.getTarget(worldserver); |
1226 1230 | |
1227 - | |
1231 + | |
1228 1232 | |
1229 1233 | if (axisalignedbb.distanceToSqr(this.player.getEyePosition()) < PlayerConnection.MAX_INTERACTION_DISTANCE) { |
1230 1234 | packetplayinuseentity.dispatch(new PacketPlayInUseEntity.c() { |
1231 1235 | - private void performInteraction(EnumHand enumhand, PlayerConnection.a playerconnection_a) { |
1232 1236 | + private void performInteraction(EnumHand enumhand, PlayerConnection.a playerconnection_a, PlayerInteractEntityEvent event) { // CraftBukkit |
1233 1237 | ItemStack itemstack = PlayerConnection.this.player.getItemInHand(enumhand); |
1234 1238 | |
1235 1239 | if (itemstack.isItemEnabled(worldserver.enabledFeatures())) { |
1236 1240 | ItemStack itemstack1 = itemstack.copy(); |
1237 1241 | + // CraftBukkit start |
1270 1274 | |
1271 1275 | + // CraftBukkit start |
1272 1276 | + if (!itemInHand.isEmpty() && itemInHand.getCount() <= -1) { |
1273 1277 | + player.containerMenu.sendAllDataToRemote(); |
1274 1278 | + } |
1275 1279 | + // CraftBukkit end |
1276 1280 | + |
1277 1281 | if (enuminteractionresult.consumesAction()) { |
1278 1282 | CriterionTriggers.PLAYER_INTERACTED_WITH_ENTITY.trigger(PlayerConnection.this.player, itemstack1, entity); |
1279 1283 | if (enuminteractionresult.shouldSwing()) { |
1280 - | |
1284 + | |
1281 1285 | |
1282 1286 | @Override |
1283 1287 | public void onInteraction(EnumHand enumhand) { |
1284 1288 | - this.performInteraction(enumhand, EntityHuman::interactOn); |
1285 1289 | + this.performInteraction(enumhand, EntityHuman::interactOn, new PlayerInteractEntityEvent(getCraftPlayer(), entity.getBukkitEntity(), (enumhand == EnumHand.OFF_HAND) ? EquipmentSlot.OFF_HAND : EquipmentSlot.HAND)); // CraftBukkit |
1286 1290 | } |
1287 1291 | |
1288 1292 | @Override |
1289 1293 | public void onInteraction(EnumHand enumhand, Vec3D vec3d) { |
1290 1294 | this.performInteraction(enumhand, (entityplayer, entity1, enumhand1) -> { |
1303 1307 | if (itemstack.isItemEnabled(worldserver.enabledFeatures())) { |
1304 1308 | PlayerConnection.this.player.attack(entity); |
1305 1309 | + // CraftBukkit start |
1306 1310 | + if (!itemstack.isEmpty() && itemstack.getCount() <= -1) { |
1307 1311 | + player.containerMenu.sendAllDataToRemote(); |
1308 1312 | + } |
1309 1313 | + // CraftBukkit end |
1310 1314 | } |
1311 1315 | } else { |
1312 1316 | PlayerConnection.this.disconnect(IChatBaseComponent.translatable("multiplayer.disconnect.invalid_entity_attacked")); |
1313 - | |
1317 + | |
1314 1318 | case PERFORM_RESPAWN: |
1315 1319 | if (this.player.wonGame) { |
1316 1320 | this.player.wonGame = false; |
1317 1321 | - this.player = this.server.getPlayerList().respawn(this.player, true); |
1318 1322 | + this.player = this.server.getPlayerList().respawn(this.player, true, RespawnReason.END_PORTAL); |
1319 1323 | CriterionTriggers.CHANGED_DIMENSION.trigger(this.player, World.END, World.OVERWORLD); |
1320 1324 | } else { |
1321 1325 | if (this.player.getHealth() > 0.0F) { |
1322 1326 | return; |
1323 1327 | } |
1324 1328 | |
1325 1329 | - this.player = this.server.getPlayerList().respawn(this.player, false); |
1326 1330 | + this.player = this.server.getPlayerList().respawn(this.player, false, RespawnReason.DEATH); |
1327 1331 | if (this.server.isHardcore()) { |
1328 1332 | this.player.setGameMode(EnumGamemode.SPECTATOR); |
1329 1333 | ((GameRules.GameRuleBoolean) this.player.level().getGameRules().getRule(GameRules.RULE_SPECTATORSGENERATECHUNKS)).set(false, this.server); |
1330 - | |
1334 + | |
1331 1335 | @Override |
1332 1336 | public void handleContainerClose(PacketPlayInCloseWindow packetplayinclosewindow) { |
1333 1337 | PlayerConnectionUtils.ensureRunningOnSameThread(packetplayinclosewindow, this, this.player.serverLevel()); |
1334 1338 | + |
1335 1339 | + if (this.player.isImmobile()) return; // CraftBukkit |
1336 1340 | + CraftEventFactory.handleInventoryCloseEvent(this.player); // CraftBukkit |
1337 1341 | + |
1338 1342 | this.player.doCloseContainer(); |
1339 1343 | } |
1340 1344 | |
1344 1348 | + if (this.player.isImmobile()) return; // CraftBukkit |
1345 1349 | this.player.resetLastActionTime(); |
1346 1350 | - if (this.player.containerMenu.containerId == packetplayinwindowclick.getContainerId()) { |
1347 1351 | - if (this.player.isSpectator()) { |
1348 1352 | + if (this.player.containerMenu.containerId == packetplayinwindowclick.getContainerId() && this.player.containerMenu.stillValid(this.player)) { // CraftBukkit |
1349 1353 | + boolean cancelled = this.player.isSpectator(); // CraftBukkit - see below if |
1350 1354 | + if (false/*this.player.isSpectator()*/) { // CraftBukkit |
1351 1355 | this.player.containerMenu.sendAllDataToRemote(); |
1352 1356 | } else if (!this.player.containerMenu.stillValid(this.player)) { |
1353 1357 | PlayerConnection.LOGGER.debug("Player {} interacted with invalid menu {}", this.player, this.player.containerMenu); |
1354 - | |
1358 + | |
1355 1359 | boolean flag = packetplayinwindowclick.getStateId() != this.player.containerMenu.getStateId(); |
1356 1360 | |
1357 1361 | this.player.containerMenu.suppressRemoteUpdates(); |
1358 1362 | - this.player.containerMenu.clicked(i, packetplayinwindowclick.getButtonNum(), packetplayinwindowclick.getClickType(), this.player); |
1359 1363 | + // CraftBukkit start - Call InventoryClickEvent |
1360 1364 | + if (packetplayinwindowclick.getSlotNum() < -1 && packetplayinwindowclick.getSlotNum() != -999) { |
1361 1365 | + return; |
1362 1366 | + } |
1363 1367 | + |
1364 1368 | + InventoryView inventory = this.player.containerMenu.getBukkitView(); |
1630 1634 | + if (event instanceof CraftItemEvent || event instanceof SmithItemEvent) { |
1631 1635 | + // Need to update the inventory on crafting to |
1632 1636 | + // correctly support custom recipes |
1633 1637 | + player.containerMenu.sendAllDataToRemote(); |
1634 1638 | + } |
1635 1639 | + } |
1636 1640 | + // CraftBukkit end |
1637 1641 | ObjectIterator objectiterator = Int2ObjectMaps.fastIterable(packetplayinwindowclick.getChangedSlots()).iterator(); |
1638 1642 | |
1639 1643 | while (objectiterator.hasNext()) { |
1640 - | |
1644 + | |
1641 1645 | @Override |
1642 1646 | public void handleContainerButtonClick(PacketPlayInEnchantItem packetplayinenchantitem) { |
1643 1647 | PlayerConnectionUtils.ensureRunningOnSameThread(packetplayinenchantitem, this, this.player.serverLevel()); |
1644 1648 | + if (this.player.isImmobile()) return; // CraftBukkit |
1645 1649 | this.player.resetLastActionTime(); |
1646 1650 | if (this.player.containerMenu.containerId == packetplayinenchantitem.getContainerId() && !this.player.isSpectator()) { |
1647 1651 | if (!this.player.containerMenu.stillValid(this.player)) { |
1648 - | |
1652 + | |
1649 1653 | |
1650 1654 | boolean flag1 = packetplayinsetcreativeslot.getSlotNum() >= 1 && packetplayinsetcreativeslot.getSlotNum() <= 45; |
1651 1655 | boolean flag2 = itemstack.isEmpty() || itemstack.getDamageValue() >= 0 && itemstack.getCount() <= 64 && !itemstack.isEmpty(); |
1652 1656 | + if (flag || (flag1 && !ItemStack.matches(this.player.inventoryMenu.getSlot(packetplayinsetcreativeslot.getSlotNum()).getItem(), packetplayinsetcreativeslot.getItem()))) { // Insist on valid slot |
1653 1657 | + // CraftBukkit start - Call click event |
1654 1658 | + InventoryView inventory = this.player.inventoryMenu.getBukkitView(); |
1655 1659 | + org.bukkit.inventory.ItemStack item = CraftItemStack.asBukkitCopy(packetplayinsetcreativeslot.getItem()); |
1656 1660 | + |
1657 1661 | + SlotType type = SlotType.QUICKBAR; |
1658 1662 | + if (flag) { |
1682 1686 | + this.player.connection.send(new PacketPlayOutSetSlot(this.player.inventoryMenu.containerId, this.player.inventoryMenu.incrementStateId(), packetplayinsetcreativeslot.getSlotNum(), this.player.inventoryMenu.getSlot(packetplayinsetcreativeslot.getSlotNum()).getItem())); |
1683 1687 | + this.player.connection.send(new PacketPlayOutSetSlot(-1, this.player.inventoryMenu.incrementStateId(), -1, ItemStack.EMPTY)); |
1684 1688 | + } |
1685 1689 | + return; |
1686 1690 | + } |
1687 1691 | + } |
1688 1692 | + // CraftBukkit end |
1689 1693 | |
1690 1694 | if (flag1 && flag2) { |
1691 1695 | this.player.inventoryMenu.getSlot(packetplayinsetcreativeslot.getSlotNum()).setByPlayer(itemstack); |
1692 - | |
1696 + | |
1693 1697 | } |
1694 1698 | |
1695 1699 | private void updateSignText(PacketPlayInUpdateSign packetplayinupdatesign, List<FilteredText> list) { |
1696 1700 | + if (this.player.isImmobile()) return; // CraftBukkit |
1697 1701 | this.player.resetLastActionTime(); |
1698 1702 | WorldServer worldserver = this.player.serverLevel(); |
1699 1703 | BlockPosition blockposition = packetplayinupdatesign.getPos(); |
1700 - | |
1704 + | |
1701 1705 | |
1702 1706 | @Override |
1703 1707 | public void handleKeepAlive(PacketPlayInKeepAlive packetplayinkeepalive) { |
1704 1708 | + PlayerConnectionUtils.ensureRunningOnSameThread(packetplayinkeepalive, this, this.player.serverLevel()); // CraftBukkit |
1705 1709 | if (this.keepAlivePending && packetplayinkeepalive.getId() == this.keepAliveChallenge) { |
1706 1710 | int i = (int) (SystemUtils.getMillis() - this.keepAliveTime); |
1707 1711 | |
1708 - | |
1712 + | |
1709 1713 | @Override |
1710 1714 | public void handlePlayerAbilities(PacketPlayInAbilities packetplayinabilities) { |
1711 1715 | PlayerConnectionUtils.ensureRunningOnSameThread(packetplayinabilities, this, this.player.serverLevel()); |
1712 1716 | - this.player.getAbilities().flying = packetplayinabilities.isFlying() && this.player.getAbilities().mayfly; |
1713 1717 | + // CraftBukkit start |
1714 1718 | + if (this.player.getAbilities().mayfly && this.player.getAbilities().flying != packetplayinabilities.isFlying()) { |
1715 1719 | + PlayerToggleFlightEvent event = new PlayerToggleFlightEvent(this.player.getBukkitEntity(), packetplayinabilities.isFlying()); |
1716 1720 | + this.cserver.getPluginManager().callEvent(event); |
1717 1721 | + if (!event.isCancelled()) { |
1718 1722 | + this.player.getAbilities().flying = packetplayinabilities.isFlying(); // Actually set the player's flying status |
1719 1723 | + } else { |
1720 1724 | + this.player.onUpdateAbilities(); // Tell the player their ability was reverted |
1721 1725 | + } |
1722 1726 | + } |
1723 1727 | + // CraftBukkit end |
1724 1728 | } |
1725 1729 | |
1726 1730 | @Override |
1727 - | |
1731 + | |
1728 1732 | this.player.updateOptions(packetplayinsettings); |
1729 1733 | } |
1730 1734 | |
1731 1735 | - @Override |
1732 1736 | - public void handleCustomPayload(PacketPlayInCustomPayload packetplayincustompayload) {} |
1733 1737 | + // CraftBukkit start |
1734 1738 | + private static final MinecraftKey CUSTOM_REGISTER = new MinecraftKey("register"); |
1735 1739 | + private static final MinecraftKey CUSTOM_UNREGISTER = new MinecraftKey("unregister"); |
1736 1740 | + |
1737 1741 | + @Override |